Skip to content

Commit

Permalink
Merge pull request #110 from atomicals/accept-next-bitwork
Browse files Browse the repository at this point in the history
Allow perpetual dft mining to correctly accept the next bitwork
  • Loading branch information
atomicals authored Feb 2, 2024
2 parents e3ec78a + b3c5a5e commit 2372c56
Show file tree
Hide file tree
Showing 4 changed files with 608 additions and 17 deletions.
2 changes: 2 additions & 0 deletions electrumx/lib/coins.py
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ class Bitcoin(BitcoinMixin, Coin):
ATOMICALS_ACTIVATION_HEIGHT_DMINT = 819181
ATOMICALS_ACTIVATION_HEIGHT_COMMITZ = 822800
ATOMICALS_ACTIVATION_HEIGHT_DENSITY = 828128
ATOMICALS_ACTIVATION_HEIGHT_DFT_BITWORK_ROLLOVER = 828628

@classmethod
def warn_old_client_on_tx_broadcast(cls, client_ver):
Expand Down Expand Up @@ -933,6 +934,7 @@ class BitcoinTestnet(BitcoinTestnetMixin, Coin):
ATOMICALS_ACTIVATION_HEIGHT_DMINT = 2540296
ATOMICALS_ACTIVATION_HEIGHT_COMMITZ = 2543936
ATOMICALS_ACTIVATION_HEIGHT_DENSITY = 2572729
ATOMICALS_ACTIVATION_HEIGHT_DFT_BITWORK_ROLLOVER = 2576412

@classmethod
def warn_old_client_on_tx_broadcast(cls, client_ver):
Expand Down
27 changes: 23 additions & 4 deletions electrumx/lib/util_atomicals.py
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,6 @@ def format_name_type_candidates_to_rpc_for_subname(raw_entries, atomical_id_to_c
for base_candidate in reformatted:
dataset = atomical_id_to_candidate_info_map[compact_to_location_id_bytes(base_candidate['atomical_id'])]
base_atomical_id = base_candidate['atomical_id']
print(f'data atomical_id_to_candidate_info_map atomicalId= {base_atomical_id}')
base_candidate['payment'] = dataset.get('payment')
base_candidate['payment_type'] = dataset.get('payment_type')
base_candidate['payment_subtype'] = dataset.get('payment_subtype')
Expand Down Expand Up @@ -1664,6 +1663,26 @@ def get_subname_request_candidate_status(current_height, atomical_info, status,
'pending_candidate_atomical_id': candidate_id_compact
}

def get_next_bitwork_full_str(bitwork_vec, current_prefix_len):
base_bitwork_padded = bitwork_vec.ljust(32, '0')
if current_prefix_len >= 31:
return base_bitwork_padded
return base_bitwork_padded[:current_prefix_len + 1]

# Whether txid is valid for the current and next bitwork
def is_txid_valid_for_perpetual_bitwork(txid, bitwork_vec, actual_mints, max_mints, target_increment, starting_target, allow_higher):
expected_minimum_bitwork = calculate_expected_bitwork(bitwork_vec, actual_mints, max_mints, target_increment, starting_target)
if is_mint_pow_valid(txid, expected_minimum_bitwork):
return True, expected_minimum_bitwork
# If we allow the next bitwork also to be accepted
if allow_higher:
bitwork_str, parts = is_valid_bitwork_string(expected_minimum_bitwork)
prefix = parts['prefix']
next_full_bitwork_prefix = get_next_bitwork_full_str(bitwork_vec, len(prefix))
if is_mint_pow_valid(txid, next_full_bitwork_prefix):
return True, next_full_bitwork_prefix
return False, None

def calculate_expected_bitwork(bitwork_vec, actual_mints, max_mints, target_increment, starting_target):
if starting_target < 64 or starting_target > 256:
raise Exception(f'Invalid starting target {starting_target}')
Expand All @@ -1675,16 +1694,16 @@ def calculate_expected_bitwork(bitwork_vec, actual_mints, max_mints, target_incr
current_target = starting_target + (target_steps * target_increment)
return derive_bitwork_prefix_from_target(bitwork_vec, current_target)

# Derive a bitwork string based on purely using an increment difficulty factor
def derive_bitwork_prefix_from_target(base_bitwork_prefix, target):
if target < 16:
raise Exception(f'increments must be at least 16. Provided: {target}')
base_bitwork_padded = base_bitwork_prefix.ljust(32, '0')
multiples = target / 16
full_amount = int(math.floor(multiples))
modulo = target % 16

bitwork_prefix = base_bitwork_padded[:full_amount]
bitwork_prefix = base_bitwork_padded
if full_amount < 32:
bitwork_prefix = base_bitwork_padded[:full_amount]
if modulo > 0:
return bitwork_prefix + '.' + str(modulo)
return bitwork_prefix
Expand Down
39 changes: 27 additions & 12 deletions electrumx/server/block_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
is_seal_operation,
is_event_operation,
encode_atomical_ids_hex,
is_mint_pow_valid
is_mint_pow_valid,
is_txid_valid_for_perpetual_bitwork
)

from electrumx.lib.atomicals_blueprint_builder import AtomicalsTransferBlueprintBuilder
Expand Down Expand Up @@ -2489,6 +2490,9 @@ def populate_extended_atomical_subtype_info(self, atomical):
self.populate_dmitem_subtype_specific_fields(atomical)
return atomical

def is_dft_bitwork_rollover_activated(self, height):
return height >= self.coin.ATOMICALS_ACTIVATION_HEIGHT_DFT_BITWORK_ROLLOVER

# Create a distributed mint output as long as the rules are satisfied
def create_or_delete_decentralized_mint_output(self, atomicals_operations_found_at_inputs, tx_num, tx_hash, tx, height, ticker_cache, Delete):
if not atomicals_operations_found_at_inputs:
Expand Down Expand Up @@ -2572,19 +2576,30 @@ def create_or_delete_decentralized_mint_output(self, atomicals_operations_found_

# If there was a commit bitwork required, then assess the stage of the minimum we expect to allow the mint
if mint_bitworkc_inc:
mint_bitworkc_start = mint_info_for_ticker.get('$mint_bitworkc_start')
expected_minimum_bitworkc = calculate_expected_bitwork(mint_bitwork_vec, decentralized_mints, max_mints, mint_bitworkc_inc, mint_bitworkc_start)
if not is_mint_pow_valid(atomicals_operations_found_at_inputs['commit_txid'], expected_minimum_bitworkc):
self.logger.warning(f'create_or_delete_decentralized_mint_output: mint_bitworkc_inc not is_mint_pow_valid {hash_to_hex_str(tx_hash)}, expected_minimum_bitworkc={expected_minimum_bitworkc}, atomicals_operations_found_at_inputs={atomicals_operations_found_at_inputs}...')
return None
mint_bitworkc_start = mint_info_for_ticker.get('$mint_bitworkc_start')
if self.is_dft_bitwork_rollover_activated(height):
success, bitwork_str = is_txid_valid_for_perpetual_bitwork(atomicals_operations_found_at_inputs['commit_txid'], mint_bitwork_vec, decentralized_mints, max_mints, mint_bitworkc_inc, mint_bitworkc_start, True)
if not success:
self.logger.warning(f'create_or_delete_decentralized_mint_output: mint_bitworkc_inc not is_mint_pow_valid {hash_to_hex_str(tx_hash)}, atomicals_operations_found_at_inputs={atomicals_operations_found_at_inputs}...')
return None
else:
success, bitwork_str = is_txid_valid_for_perpetual_bitwork(atomicals_operations_found_at_inputs['commit_txid'], mint_bitwork_vec, decentralized_mints, max_mints, mint_bitworkc_inc, mint_bitworkc_start, False)
if not success:
self.logger.warning(f'create_or_delete_decentralized_mint_output: mint_bitworkc_inc not is_mint_pow_valid {hash_to_hex_str(tx_hash)}, atomicals_operations_found_at_inputs={atomicals_operations_found_at_inputs}...')
return None

# If there was a reveal bitwork required, then assess the stage of the minimum we expect to allow the mint
if mint_bitworkr_inc:
mint_bitworkr_start = mint_info_for_ticker.get('$mint_bitworkr_start')
expected_minimum_bitworkr = calculate_expected_bitwork(mint_bitwork_vec, decentralized_mints, max_mints, mint_bitworkr_inc, mint_bitworkr_start)
if not is_mint_pow_valid(atomicals_operations_found_at_inputs['reveal_location_txid'], expected_minimum_bitworkr):
self.logger.warning(f'create_or_delete_decentralized_mint_output: mint_bitworkr_inc not is_mint_pow_valid {hash_to_hex_str(tx_hash)}, expected_minimum_bitworkr={expected_minimum_bitworkr}, atomicals_operations_found_at_inputs={atomicals_operations_found_at_inputs}...')
return None

mint_bitworkr_start = mint_info_for_ticker.get('$mint_bitworkr_start')
if self.is_dft_bitwork_rollover_activated(height):
if not is_txid_valid_for_perpetual_bitwork(atomicals_operations_found_at_inputs['reveal_location_txid'], mint_bitwork_vec, decentralized_mints, max_mints, mint_bitworkr_inc, mint_bitworkr_start, True):
self.logger.warning(f'create_or_delete_decentralized_mint_output: mint_bitworkr_inc not is_mint_pow_valid {hash_to_hex_str(tx_hash)}, atomicals_operations_found_at_inputs={atomicals_operations_found_at_inputs}...')
return None
else:
if not is_txid_valid_for_perpetual_bitwork(atomicals_operations_found_at_inputs['reveal_location_txid'], mint_bitwork_vec, decentralized_mints, max_mints, mint_bitworkr_inc, mint_bitworkr_start, False):
self.logger.warning(f'create_or_delete_decentralized_mint_output: mint_bitworkr_inc not is_mint_pow_valid {hash_to_hex_str(tx_hash)}, atomicals_operations_found_at_inputs={atomicals_operations_found_at_inputs}...')
return None

allow_mint = True
else:
# It is the 'fixed' mint mode and the bitworkc/r is static
Expand Down
Loading

0 comments on commit 2372c56

Please sign in to comment.