Skip to content

Commit 0c39c03

Browse files
authored
Merge pull request #184 from atomicals/feat/is-custom-coloring-activated
Apply the activation height to the custom coloring
2 parents 55bbba5 + 9a070a0 commit 0c39c03

File tree

4 files changed

+56
-45
lines changed

4 files changed

+56
-45
lines changed

electrumx/lib/atomicals_blueprint_builder.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def build_reverse_output_to_atomical_id_exponent_map(atomical_id_to_output_index
4949
def get_nominal_atomical_value(value):
5050
return value
5151

52-
def calculate_outputs_to_color_for_ft_atomical_ids(tx, ft_atomicals, sort_by_fifo, is_split_activated) -> FtColoringSummary:
52+
def calculate_outputs_to_color_for_ft_atomical_ids(tx, ft_atomicals, sort_by_fifo, is_custom_coloring_activated) -> FtColoringSummary:
5353
num_fts = len(ft_atomicals.keys())
5454
if num_fts == 0:
5555
return None
@@ -63,10 +63,10 @@ def calculate_outputs_to_color_for_ft_atomical_ids(tx, ft_atomicals, sort_by_fif
6363
for item in atomical_list:
6464
atomical_id = item.atomical_id
6565
# If a target exponent was provided, then use that instead
66-
cleanly_assigned, expected_outputs, remaining_value_from_assign = AtomicalsTransferBlueprintBuilder.assign_expected_outputs_basic(item.total_atomical_value, tx, next_start_out_idx, is_split_activated)
66+
cleanly_assigned, expected_outputs, remaining_value_from_assign = AtomicalsTransferBlueprintBuilder.assign_expected_outputs_basic(item.total_atomical_value, tx, next_start_out_idx, is_custom_coloring_activated)
6767
if not cleanly_assigned:
6868
utxo_cleanly_assigned = False
69-
if not is_split_activated:
69+
if not is_custom_coloring_activated:
7070
if cleanly_assigned and len(expected_outputs) > 0:
7171
next_start_out_idx = expected_outputs[-1] + 1
7272
potential_atomical_ids_to_output_idxs_map[atomical_id] = ExpectedOutputSet(expected_outputs, item.total_atomical_value)
@@ -93,7 +93,7 @@ def calculate_outputs_to_color_for_ft_atomical_ids(tx, ft_atomicals, sort_by_fif
9393
potential_atomical_ids_to_output_idxs_map = {}
9494
for item in atomical_list:
9595
atomical_id = item.atomical_id
96-
cleanly_assigned, expected_outputs, remaining_value_from_assign = AtomicalsTransferBlueprintBuilder.assign_expected_outputs_basic(item.total_atomical_value, tx, 0, is_split_activated)
96+
cleanly_assigned, expected_outputs, remaining_value_from_assign = AtomicalsTransferBlueprintBuilder.assign_expected_outputs_basic(item.total_atomical_value, tx, 0, is_custom_coloring_activated)
9797
potential_atomical_ids_to_output_idxs_map[atomical_id] = ExpectedOutputSet(expected_outputs, item.total_atomical_value)
9898
if remaining_value_from_assign > 0:
9999
fts_burned[atomical_id] = remaining_value_from_assign
@@ -185,19 +185,29 @@ def order_ft_inputs(ft_atomicals: AtomicalInputSummary, sort_by_fifo):
185185

186186
class AtomicalsTransferBlueprintBuilder:
187187
'''Atomicals transfer blueprint builder for calculating outputs to color'''
188-
def __init__(self, logger, atomicals_spent_at_inputs, operations_found_at_inputs, tx_hash, tx, get_atomicals_id_mint_info, sort_fifo, is_split_activated):
188+
def __init__(
189+
self,
190+
logger,
191+
atomicals_spent_at_inputs,
192+
operations_found_at_inputs,
193+
tx_hash,
194+
tx,
195+
get_atomicals_id_mint_info,
196+
sort_fifo,
197+
is_custom_coloring_activated
198+
):
189199
self.logger = logger
190200
self.atomicals_spent_at_inputs = atomicals_spent_at_inputs
191201
self.operations_found_at_inputs = operations_found_at_inputs
192202
self.tx_hash = tx_hash
193203
self.tx = tx
194204
self.get_atomicals_id_mint_info = get_atomicals_id_mint_info
195205
self.sort_fifo = sort_fifo
196-
self.is_split_activated = is_split_activated
206+
self.is_custom_coloring_activated = is_custom_coloring_activated
197207
nft_atomicals, ft_atomicals, atomical_ids_spent = AtomicalsTransferBlueprintBuilder.build_atomical_input_summaries_by_type(self.get_atomicals_id_mint_info, atomicals_spent_at_inputs)
198208
self.nft_atomicals = nft_atomicals
199209
self.ft_atomicals = ft_atomicals
200-
nft_output_blueprint, ft_output_blueprint = AtomicalsTransferBlueprintBuilder.calculate_output_blueprint(self.get_atomicals_id_mint_info, self.tx, self.nft_atomicals, self.ft_atomicals, self.atomicals_spent_at_inputs, self.operations_found_at_inputs, self.sort_fifo, self.is_split_activated)
210+
nft_output_blueprint, ft_output_blueprint = AtomicalsTransferBlueprintBuilder.calculate_output_blueprint(self.get_atomicals_id_mint_info, self.tx, self.nft_atomicals, self.ft_atomicals, self.atomicals_spent_at_inputs, self.operations_found_at_inputs, self.sort_fifo, self.is_custom_coloring_activated)
201211
self.nft_output_blueprint = nft_output_blueprint
202212
self.ft_output_blueprint = ft_output_blueprint
203213
# if len(ft_atomicals) > 0 or len(nft_atomicals) > 0:
@@ -318,20 +328,20 @@ def calculate_output_blueprint_nfts(cls, get_atomicals_id_mint_info, tx, nft_ato
318328
return AtomicalsTransferBlueprintBuilder.calculate_nft_atomicals_regular(nft_map, nft_atomicals, tx, operations_found_at_inputs, sort_fifo)
319329

320330
@classmethod
321-
def calculate_output_blueprint_fts(cls, tx, ft_atomicals, operations_found_at_inputs, sort_fifo, is_split_activated):
331+
def calculate_output_blueprint_fts(cls, tx, ft_atomicals, operations_found_at_inputs, sort_fifo, is_custom_coloring_activated):
322332
if not ft_atomicals or len(ft_atomicals) == 0:
323333
return AtomicalFtOutputBlueprintAssignmentSummary({}, {}, True, None)
324334

325335
# Split apart multiple NFT/FT from a UTXO
326336
should_split_ft_atomicals = is_split_operation(operations_found_at_inputs)
327337
if should_split_ft_atomicals:
328-
return AtomicalsTransferBlueprintBuilder.color_ft_atomicals_split(ft_atomicals, operations_found_at_inputs, tx, is_split_activated)
338+
return AtomicalsTransferBlueprintBuilder.color_ft_atomicals_split(ft_atomicals, operations_found_at_inputs, tx, is_custom_coloring_activated)
329339

330-
should_custom_colored_ft_atomicals = is_custom_colored_operation(operations_found_at_inputs)
340+
should_custom_colored_ft_atomicals = is_custom_colored_operation(operations_found_at_inputs) and is_custom_coloring_activated
331341
if should_custom_colored_ft_atomicals:
332342
return AtomicalsTransferBlueprintBuilder.custom_color_ft_atomicals(ft_atomicals, operations_found_at_inputs, tx)
333343
# Normal assignment in all cases including fall through of failure to provide a target exponent in the above resubstantiation
334-
return AtomicalsTransferBlueprintBuilder.color_ft_atomicals_regular(ft_atomicals, tx, sort_fifo, is_split_activated)
344+
return AtomicalsTransferBlueprintBuilder.color_ft_atomicals_regular(ft_atomicals, tx, sort_fifo, is_custom_coloring_activated)
335345

336346
@classmethod
337347
def custom_color_ft_atomicals(cls, ft_atomicals, operations_found_at_inputs, tx):
@@ -363,7 +373,7 @@ def custom_color_ft_atomicals(cls, ft_atomicals, operations_found_at_inputs, tx)
363373
return AtomicalFtOutputBlueprintAssignmentSummary(output_colored_map, fts_burned, cleanly_assigned, None)
364374

365375
@classmethod
366-
def color_ft_atomicals_split(cls, ft_atomicals, operations_found_at_inputs, tx, is_split_activated):
376+
def color_ft_atomicals_split(cls, ft_atomicals, operations_found_at_inputs, tx, is_custom_coloring_activated):
367377
output_colored_map = {}
368378
fts_burned = {}
369379
cleanly_assigned = True
@@ -381,7 +391,9 @@ def color_ft_atomicals_split(cls, ft_atomicals, operations_found_at_inputs, tx,
381391
if isinstance(total_amount_to_skip_potential, int) and total_amount_to_skip_potential >= 0:
382392
total_amount_to_skip = total_amount_to_skip_potential
383393
total_skipped_so_far = 0
384-
if is_split_activated:
394+
# is_custom_coloring logic
395+
# use if else keep it simple
396+
if is_custom_coloring_activated:
385397
for out_idx, txout in enumerate(tx.outputs):
386398
# If the first output should be skipped and we have not yet done so, then skip/ignore it
387399
if total_amount_to_skip > 0 and total_skipped_so_far < total_amount_to_skip:
@@ -405,8 +417,6 @@ def color_ft_atomicals_split(cls, ft_atomicals, operations_found_at_inputs, tx,
405417
cleanly_assigned = False
406418
fts_burned[atomical_id] = remaining_value
407419
else:
408-
# is_split_activated logic
409-
# use if else keep it simple
410420
for out_idx, txout in enumerate(tx.outputs):
411421
if total_amount_to_skip > 0 and total_skipped_so_far < total_amount_to_skip:
412422
total_skipped_so_far += txout.value
@@ -431,17 +441,17 @@ def color_ft_atomicals_split(cls, ft_atomicals, operations_found_at_inputs, tx,
431441
return AtomicalFtOutputBlueprintAssignmentSummary(output_colored_map, fts_burned, cleanly_assigned, None)
432442

433443
@classmethod
434-
def color_ft_atomicals_regular(cls, ft_atomicals, tx, sort_fifo, is_split_activated):
444+
def color_ft_atomicals_regular(cls, ft_atomicals, tx, sort_fifo, is_custom_coloring_activated):
435445
output_colored_map = {}
436-
ft_coloring_summary = calculate_outputs_to_color_for_ft_atomical_ids(tx, ft_atomicals, sort_fifo, is_split_activated)
446+
ft_coloring_summary = calculate_outputs_to_color_for_ft_atomical_ids(tx, ft_atomicals, sort_fifo, is_custom_coloring_activated)
437447
if not ft_coloring_summary:
438448
return AtomicalFtOutputBlueprintAssignmentSummary({}, {}, True, None)
439449

440450
first_atomical_id = None
441451
if ft_coloring_summary.atomicals_list and len(ft_coloring_summary.atomicals_list):
442452
first_atomical_id = ft_coloring_summary.atomicals_list[0].atomical_id
443453

444-
if not is_split_activated:
454+
if not is_custom_coloring_activated:
445455
for atomical_id, atomical_info in ft_coloring_summary.atomical_id_to_expected_outs_map.items():
446456
for expected_output_index in atomical_info.expected_outputs:
447457
txout = tx.outputs[expected_output_index]
@@ -467,9 +477,9 @@ def color_ft_atomicals_regular(cls, ft_atomicals, tx, sort_fifo, is_split_activa
467477
return AtomicalFtOutputBlueprintAssignmentSummary(output_colored_map, ft_coloring_summary.fts_burned, cleanly_assigned, first_atomical_id)
468478

469479
@classmethod
470-
def calculate_output_blueprint(cls, get_atomicals_id_mint_info, tx, nft_atomicals, ft_atomicals, atomicals_spent_at_inputs, operations_found_at_inputs, sort_fifo, is_split_activated):
480+
def calculate_output_blueprint(cls, get_atomicals_id_mint_info, tx, nft_atomicals, ft_atomicals, atomicals_spent_at_inputs, operations_found_at_inputs, sort_fifo, is_custom_coloring_activated):
471481
nft_blueprint = AtomicalsTransferBlueprintBuilder.calculate_output_blueprint_nfts(get_atomicals_id_mint_info, tx, nft_atomicals, atomicals_spent_at_inputs, operations_found_at_inputs, sort_fifo)
472-
ft_blueprint = AtomicalsTransferBlueprintBuilder.calculate_output_blueprint_fts(tx, ft_atomicals, operations_found_at_inputs, sort_fifo, is_split_activated)
482+
ft_blueprint = AtomicalsTransferBlueprintBuilder.calculate_output_blueprint_fts(tx, ft_atomicals, operations_found_at_inputs, sort_fifo, is_custom_coloring_activated)
473483
return nft_blueprint, ft_blueprint
474484

475485
# Builds a map and image of all the inputs and their sat_value and atomical_value (adjusted by exponent)
@@ -541,7 +551,7 @@ def calculate_nft_output_index_legacy(cls, input_idx, tx, operations_found_at_in
541551
# Returns the sequence of output indexes that matches until the final one that matched
542552
# Also returns whether it fit cleanly in (ie: exact with no left overs or under)
543553
@classmethod
544-
def assign_expected_outputs_basic(cls, total_value_to_assign, tx, start_out_idx, is_split_activated):
554+
def assign_expected_outputs_basic(cls, total_value_to_assign, tx, start_out_idx, is_custom_coloring_activated):
545555
expected_output_indexes = []
546556
remaining_value = total_value_to_assign
547557
idx_count = 0
@@ -556,7 +566,7 @@ def assign_expected_outputs_basic(cls, total_value_to_assign, tx, start_out_idx,
556566
if is_unspendable_genesis(txout.pk_script) or is_unspendable_legacy(txout.pk_script):
557567
idx_count += 1
558568
continue
559-
if is_split_activated:
569+
if is_custom_coloring_activated:
560570
# Add out_idx
561571
expected_output_indexes.append(out_idx)
562572
remaining_value -= txout.value
@@ -623,7 +633,7 @@ def are_payments_satisfied(self, expected_payment_outputs):
623633
expected_output_keys_satisfied[output_script_key] = False
624634

625635
# Prepare the mapping of which ARC20 is paid at which output
626-
ft_coloring_summary = calculate_outputs_to_color_for_ft_atomical_ids(self.tx, self.ft_atomicals, self.sort_fifo, self.is_split_activated)
636+
ft_coloring_summary = calculate_outputs_to_color_for_ft_atomical_ids(self.tx, self.ft_atomicals, self.sort_fifo, self.is_custom_coloring_activated)
627637
output_idx_to_atomical_id_map = {}
628638
if ft_coloring_summary:
629639
output_idx_to_atomical_id_map = build_reverse_output_to_atomical_id_exponent_map(ft_coloring_summary.atomical_id_to_expected_outs_map)

electrumx/lib/coins.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ class AtomicalsCoinMixin:
289289
ATOMICALS_ACTIVATION_HEIGHT_COMMITZ: int
290290
ATOMICALS_ACTIVATION_HEIGHT_DENSITY: int
291291
ATOMICALS_ACTIVATION_HEIGHT_DFT_BITWORK_ROLLOVER: int
292+
ATOMICALS_ACTIVATION_HEIGHT_CUSTOM_COLORING: int
292293

293294

294295
class AuxPowMixin:
@@ -675,7 +676,7 @@ class Bitcoin(BitcoinMixin, AtomicalsCoinMixin, Coin):
675676
ATOMICALS_ACTIVATION_HEIGHT_COMMITZ = 822800
676677
ATOMICALS_ACTIVATION_HEIGHT_DENSITY = 828128
677678
ATOMICALS_ACTIVATION_HEIGHT_DFT_BITWORK_ROLLOVER = 828628
678-
ATOMICALS_ACTIVATION_SPLIT = 845000
679+
ATOMICALS_ACTIVATION_HEIGHT_CUSTOM_COLORING = 847000
679680

680681
@classmethod
681682
def warn_old_client_on_tx_broadcast(cls, client_ver):
@@ -944,7 +945,7 @@ class BitcoinTestnet(BitcoinTestnetMixin, AtomicalsCoinMixin, Coin):
944945
ATOMICALS_ACTIVATION_HEIGHT_COMMITZ = 2543936
945946
ATOMICALS_ACTIVATION_HEIGHT_DENSITY = 2572729
946947
ATOMICALS_ACTIVATION_HEIGHT_DFT_BITWORK_ROLLOVER = 2576412
947-
ATOMICALS_ACTIVATION_SPLIT = 2584936
948+
ATOMICALS_ACTIVATION_HEIGHT_CUSTOM_COLORING = 2584936
948949

949950
@classmethod
950951
def warn_old_client_on_tx_broadcast(cls, client_ver):

electrumx/server/block_processor.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ def validate_ft_rules_raw_tx(self, raw_tx):
548548
# Build a structure of organizing into NFT and FTs
549549
# Note: We do not validate anything with NFTs, just FTs
550550
# Build the "blueprint" for how to assign all atomicals
551-
blueprint_builder = AtomicalsTransferBlueprintBuilder(self.logger, atomicals_spent_at_inputs, operations_found_at_inputs, tx_hash, tx, self.get_atomicals_id_mint_info, True, self.is_split_activated(self.height))
551+
blueprint_builder = AtomicalsTransferBlueprintBuilder(self.logger, atomicals_spent_at_inputs, operations_found_at_inputs, tx_hash, tx, self.get_atomicals_id_mint_info, True, self.is_custom_coloring_activated(self.height))
552552
ft_output_blueprint = blueprint_builder.get_ft_output_blueprint()
553553
# Log that there were tokens burned due to not being cleanly assigned
554554
if blueprint_builder.get_are_fts_burned():
@@ -1744,7 +1744,7 @@ def put_ft_outputs_by_blueprint(self, ft_blueprint, operations_found_at_inputs,
17441744
# Apply the rules to color the outputs of the atomicals
17451745
def color_atomicals_outputs(self, operations_found_at_inputs, atomicals_spent_at_inputs, tx, tx_hash, tx_num, height):
17461746
# Build the "blueprint" for how to assign all atomicals
1747-
blueprint_builder = AtomicalsTransferBlueprintBuilder(self.logger, atomicals_spent_at_inputs, operations_found_at_inputs, tx_hash, tx, self.get_atomicals_id_mint_info, self.is_dmint_activated(height), self.is_split_activated(height))
1747+
blueprint_builder = AtomicalsTransferBlueprintBuilder(self.logger, atomicals_spent_at_inputs, operations_found_at_inputs, tx_hash, tx, self.get_atomicals_id_mint_info, self.is_dmint_activated(height), self.is_custom_coloring_activated(height))
17481748

17491749
nft_output_blueprint = blueprint_builder.get_nft_output_blueprint()
17501750
if nft_output_blueprint and len(nft_output_blueprint.outputs):
@@ -2829,8 +2829,8 @@ def is_density_activated(self, height):
28292829
return True
28302830
return False
28312831

2832-
def is_split_activated(self, height):
2833-
if height >= self.coin.ATOMICALS_ACTIVATION_SPLIT:
2832+
def is_custom_coloring_activated(self, height):
2833+
if height >= self.coin.ATOMICALS_ACTIVATION_HEIGHT_CUSTOM_COLORING:
28342834
return True
28352835
if height <= 0:
28362836
return True
@@ -3162,7 +3162,7 @@ def create_or_delete_subname_payment_output_if_valid(self, tx_hash, tx, tx_num,
31623162
return None, False
31633163

31643164
# Rebuild the blueprint builder here
3165-
blueprint_builder = AtomicalsTransferBlueprintBuilder(self.logger, atomicals_spent_at_inputs, operations_found_at_inputs, tx_hash, tx, self.get_atomicals_id_mint_info, self.is_dmint_activated(height), self.is_split_activated(height))
3165+
blueprint_builder = AtomicalsTransferBlueprintBuilder(self.logger, atomicals_spent_at_inputs, operations_found_at_inputs, tx_hash, tx, self.get_atomicals_id_mint_info, self.is_dmint_activated(height), self.is_custom_coloring_activated(height))
31663166
if blueprint_builder.is_split_operation():
31673167
self.logger.warning(f'create_or_delete_subname_payment_output_if_valid: invalid payment split op found tx_hash={hash_to_hex_str(tx_hash)}')
31683168
return tx_hash, False

0 commit comments

Comments
 (0)