Published: 23 Aug 2025 › Updated: 23 Aug 2025
PeakeCoin CrossChain Transfer - hive_bridge
Attempting to work on and debug our backend cross-chain swapping actions. We try and keep all code accessible.
hive_bridge/main.py
from common.config import HIVE_BRIDGE_ACCOUNT, PEK_TOKEN_SYMBOL
from common.logger import logger
from common.db import init_db, get_db
from beem import Hive
from beem.account import Account
from beem.nodelist import NodeList
import json as pyjson
import re
import signal
import sys
import time
import sqlite3
HIVE_NODES_FALLBACK = [
"https://api.hive.blog",
"https://anyx.io",
"https://rpc.ausbit.dev",
"https://hive.roelandp.nl",
]
# ---- graceful shutdown -------------------------------------------------------
_shutdown = False
def _handle_sigint(signum, frame):
global _shutdown
_shutdown = True
signal.signal(signal.SIGINT, _handle_sigint)
signal.signal(signal.SIGTERM, _handle_sigint)
# ---- simple KV state (last processed block) ----------------------------------
def _get_state(key: str, default=None):
conn = get_db()
try:
c = conn.cursor()
c.execute("CREATE TABLE IF NOT EXISTS state (key TEXT PRIMARY KEY, value TEXT)")
c.execute("SELECT value FROM state WHERE key = ?", (key,))
row = c.fetchone()
return row[0] if row else default
finally:
conn.close()
def _set_state(key: str, value: str):
conn = get_db()
try:
c = conn.cursor()
c.execute("INSERT INTO state(key, value) VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value", (key, str(value)))
conn.commit()
finally:
conn.close()
# ---- event insert with dedupe ------------------------------------------------
def _insert_event(source: str, tx_id: str, amount: float, to_address: str):
conn = get_db()
try:
c = conn.cursor()
# Make sure your common.db init created a UNIQUE index like:
# CREATE UNIQUE INDEX IF NOT EXISTS ux_events_source_txid ON events(source, tx_id);
c.execute(
"INSERT OR IGNORE INTO events (source, tx_id, amount, to_address, status) VALUES (?, ?, ?, ?, ?)",
(source, tx_id, amount, to_address, 'pending')
)
conn.commit()
return c.rowcount > 0
finally:
conn.close()
# ---- validation --------------------------------------------------------------
_polygon_addr_re = re.compile(r"^0x[a-fA-F0-9]{40}$")
def _is_polygon_address(s: str) -> bool:
return bool(s and _polygon_addr_re.match(s.strip()))
# ---- hive client w/ rotation -------------------------------------------------
def _make_hive(nodes):
# Do not broadcast, short timeouts, auto-retries
return Hive(node=nodes, nobroadcast=True, timeout=30, num_retries=3)
def monitor_hive_transfers(poll_interval_sec: int = 2, backoff_max: int = 16):
logger.info("Monitoring Hive Engine for PEK → bridge transfers …")
# Build node list (prefer live list, fall back to static)
try:
nl = NodeList()
nl.update_nodes()
hive_nodes = nl.get_nodes(normal=True, appbase=True) or HIVE_NODES_FALLBACK[:]
except Exception:
hive_nodes = HIVE_NODES_FALLBACK[:]
hive = _make_hive(hive_nodes)
backoff = 1
# Start from last irreversible block to reduce dupes; persist progress
last_processed = _get_state("hive_last_processed_block")
try:
dgp = hive.get_dynamic_global_properties()
lib = dgp["last_irreversible_block_num"]
except Exception as e:
logger.warning(f"Could not fetch DGP at start: {e}")
lib = None
if last_processed is None:
# First run: start a bit behind LIB (or head) to be safe
try:
head = hive.get_dynamic_global_properties()["head_block_number"]
except Exception:
head = None
start_from = (lib or head or 0) - 5
last_processed = max(start_from, 0)
_set_state("hive_last_processed_block", last_processed)
logger.info(f"Initialized last_processed to {last_processed}")
last_processed = int(last_processed)
while not _shutdown:
try:
dgp = hive.get_dynamic_global_properties()
head = dgp["head_block_number"]
lib = dgp["last_irreversible_block_num"]
# Only process up to LIB to avoid reorgs
target = lib
if target <= last_processed:
time.sleep(poll_interval_sec)
continue
# Process blocks (cap each loop to avoid huge catch-ups)
end = min(last_processed + 200, target)
for block_num in range(last_processed + 1, end + 1):
block = hive.rpc.get_block(block_num)
if not block:
continue
txs = block.get("transactions", [])
for tx in txs:
# NOTE: HIVE "transactions" don't always include tx_id here.
# We derive tx_id from the operation receipt returned by nodes that provide it,
# but some RPCs won't. Fallback: compose a pseudo-id for dedupe.
tx_id = tx.get("transaction_id") or f"{block_num}:{hash(pyjson.dumps(tx, sort_keys=True))}"
for op in tx.get("operations", []):
if not isinstance(op, (list, tuple)) or len(op) != 2:
continue
op_name, op_data = op
if op_name != "custom_json":
continue
if op_data.get("id") != "ssc-mainnet-hive":
continue
raw_json = op_data.get("json")
try:
data = pyjson.loads(raw_json) if isinstance(raw_json, str) else (raw_json or {})
except Exception as e:
logger.debug(f"custom_json parse error at block {block_num}: {e}")
continue
# Looking for: tokens.transfer to bridge account with PEK symbol
if data.get("contractName") == "tokens" and data.get("contractAction") == "transfer":
payload = data.get("contractPayload") or {}
if (
payload.get("symbol") == PEK_TOKEN_SYMBOL
and payload.get("to") == HIVE_BRIDGE_ACCOUNT
):
# quantity can be string; memo should be polygon address
try:
amount = float(payload.get("quantity", 0))
except Exception:
amount = 0.0
memo = (payload.get("memo") or "").strip()
if not _is_polygon_address(memo):
logger.warning(
f"Ignoring transfer (invalid Polygon memo): memo='{memo}' tx={tx_id} blk={block_num}"
)
continue
if _insert_event("hive", tx_id, amount, memo):
logger.info(
f"Bridge event recorded: {amount:g} {PEK_TOKEN_SYMBOL} → {memo} (tx={tx_id}, blk={block_num})"
)
else:
logger.debug(f"Duplicate event ignored (tx={tx_id})")
last_processed = block_num
if block_num % 20 == 0:
_set_state("hive_last_processed_block", last_processed)
# Persist after each batch
_set_state("hive_last_processed_block", last_processed)
# Healthy pass → reset backoff
backoff = 1
time.sleep(poll_interval_sec)
except Exception as e:
logger.error(f"Hive monitor error: {e}")
# Rotate nodes
try:
hive_nodes.append(hive_nodes.pop(0))
hive = _make_hive(hive_nodes)
except Exception as e2:
logger.error(f"Node rotation failed: {e2}")
# Backoff (capped)
time.sleep(backoff)
backoff = min(backoff * 2, backoff_max)
logger.info("Shutdown requested; saving state …")
_set_state("hive_last_processed_block", last_processed)
if __name__ == "__main__":
# Ensure DB has the structures we need. Your common.db should create:
# - events(id PK, source TEXT, tx_id TEXT, amount REAL, to_address TEXT, status TEXT, created_at default now)
# - UNIQUE index on (source, tx_id)
# - state(key PRIMARY KEY, value TEXT)
init_db()
monitor_hive_transfers()
Leave PeakeCoin CrossChain Transfer - hive_bridge to:
Read more #hive-169321 posts
Best Posts From PeakeCoin
We have not curated any of peakecoin's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.
More Posts From PeakeCoin
- Mine Crypto With You're Old Phones
- Bridging PeakeCoin (PEK) from Hive Engine to Polygon — A Rough-Draft That Works
- PeakeCoin CrossChain Transfer - hive_bridge
- Automating Remote Python Dashboards with a Bash Script
- # 🚀 Cross-Posting to Hive, Blurt, and Steemit – Automatically with PEK Support!
- PeakeCoin - uni_bot.py
- PeakeCoin Bots - dashboard.py
- 🧬 A Silent Collapse: The Generational Loss of Black America
- PeakeCoin Swap App – Real Progress, Real Problems (Happy Fathers Day)
- Atomic PEK Swap UI — Robust Memo-Based Tracking Is Live!