6 Commits

Author SHA1 Message Date
e67c178ea7 feat: Add initial mempool bids function
All checks were successful
Build Docker / Build Image (push) Successful in 55s
2025-07-16 17:41:32 +10:00
631d558377 tmp: Add debugging for bids
All checks were successful
Build Docker / Build Image (push) Successful in 1m1s
2025-07-16 16:53:14 +10:00
1d5ed059b3 fix: Allow rescan while not in bidding
All checks were successful
Build Docker / Build Image (push) Successful in 3m35s
2025-07-16 16:30:08 +10:00
747ac575fa fix: Auto reset cache if incorrect format
All checks were successful
Build Docker / Build Image (push) Successful in 1m53s
2025-07-14 16:28:50 +10:00
e574933302 feat: Add link on names in tx history
All checks were successful
Build Docker / Build Image (push) Successful in 1m11s
2025-07-12 21:47:14 +10:00
c0f0dc5010 fix: Open tx for bid in new tab 2025-07-12 21:35:04 +10:00
3 changed files with 110 additions and 4 deletions

View File

@@ -867,10 +867,12 @@ def rescan_auction(account, domain):
return {
"error": "Invalid domain"
}
if 'bidPeriodStart' not in response['result']['info']['stats']:
if 'height' not in response['result']['info']:
return {
"error": "Not in auction"
"error": "Can't find start"
}
height = response['result']['info']['height']-1
response = hsw.rpc_importName(domain, height)
return response
@@ -1153,6 +1155,87 @@ def createBatch(account, batch):
}
}
# region Mempool
def getMempoolTxs():
# hsd-cli rpc getrawmempool
response = hsd.rpc_getRawMemPool()
if 'error' in response and response['error'] is not None:
return []
return response['result'] if 'result' in response else []
def getMempoolBids():
mempoolTxs = getMempoolTxs()
bids = {}
for txid in mempoolTxs:
tx = hsd.getTxByHash(txid)
if 'error' in tx and tx['error'] is not None:
print(f"Error getting tx {txid}: {tx['error']}")
continue
# bid_data.append({
# 'bid': bid,
# 'lockup': lockup,
# 'revealed': revealed,
# 'value': value,
# 'sort_value': value if revealed else lockup # Use value for sorting if revealed, otherwise lockup
# })
if 'outputs' not in tx:
print(f"Error getting outputs for tx {txid}")
continue
for output in tx['outputs']:
if output['covenant']['action'] not in ["BID", "REVEAL"]:
continue
if output['covenant']['action'] == "REVEAL":
# Try to find bid tx from inputs
namehash = output['covenant']['items'][0]
for txInput in tx['inputs']:
if txInput['coin']['covenant']['action'] != "BID":
continue
if txInput['coin']['covenant']['items'][0] != namehash:
continue
name = txInput['coin']['covenant']['items'][2]
# Convert name from hex to ascii
name = bytes.fromhex(name).decode('ascii')
bid = {
'txid': txid,
'lockup': txInput['coin']['value'],
'revealed': True,
'height': -1,
'value': output['value'],
'sort_value': txInput['coin']['value']
}
if name not in bids:
bids[name] = []
bids[name].append(bid)
continue
name = output['covenant']['items'][2]
# Convert name from hex to ascii
name = bytes.fromhex(name).decode('ascii')
if name not in bids:
bids[name] = []
bid = {
'txid': txid,
'value': -1000000, # Default value if not found
'lockup': output['value'],
'revealed': False,
'height': -1,
'sort_value': output['value']
}
bids[name].append(bid)
return bids
# endregion
# region settingsAPIs
def rescan():

View File

@@ -1542,6 +1542,10 @@ def api_hsd(function):
return jsonify({"result": account_module.hsdVersion(False)})
if function == "height":
return jsonify({"result": account_module.getBlockHeight()})
if function == "mempool":
return jsonify({"result": account_module.getMempoolTxs()})
if function == "mempoolBids":
return jsonify({"result": account_module.getMempoolBids()})
return jsonify({"error": "Invalid function", "result": "Invalid function"}), 400

View File

@@ -40,6 +40,24 @@ if TX_EXPLORER_URL is None:
NAMEHASH_CACHE = 'user_data/namehash_cache.json'
# Validate cache version
if os.path.exists(NAMEHASH_CACHE):
with open(NAMEHASH_CACHE, 'r') as f:
cache = json.load(f)
if not isinstance(cache, dict):
print("Invalid namehash cache format. Resetting cache.")
with open(NAMEHASH_CACHE, 'w') as f:
json.dump({}, f)
# Check if cache entries are valid
for key in cache:
if not cache[key].startswith("<a href='/manage/"):
print(f"Invalid cache entry for {key}. Resetting cache.")
with open(NAMEHASH_CACHE, 'w') as f:
json.dump({}, f)
break
CACHE_LOCK = threading.Lock()
@@ -302,7 +320,6 @@ def bids(bids,reveals):
'value': value,
'sort_value': value if revealed else lockup # Use value for sorting if revealed, otherwise lockup
})
# Sort by the sort_value in descending order (highest first)
bid_data.sort(key=lambda x: x['sort_value'], reverse=True)
@@ -330,7 +347,7 @@ def bids(bids,reveals):
else:
html += f"<td>Unknown</td>"
html += f"<td><a class='text-decoration-none' style='color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));' href='{TX_EXPLORER_URL}{bid['prevout']['hash']}'>Bid TX 🔗</a></td>"
html += f"<td><a class='text-decoration-none' style='color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));' target='_blank' href='{TX_EXPLORER_URL}{bid['prevout']['hash']}'>Bid TX 🔗</a></td>"
html += "</tr>"
return html
@@ -547,6 +564,8 @@ def renderDomainAsync(namehash: str) -> None:
if name["error"] is None:
name = name["result"]
rendered = renderDomain(name)
rendered = f"<a href='/manage/{name}' target='_blank' style='color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));'>{rendered}</a>"
with CACHE_LOCK:
with open(NAMEHASH_CACHE, 'r') as f: