Skip to content

Releases

v0.25.51 PQ CORE SmartHoldem

Choose a tag to compare

@technologiespro technologiespro released this 11 Nov 16:40

🐞 Fixed:
• PQ delegates no longer lose their PQ status - announces are verified against the originating node, not the last relay hop
• A node no longer "forgets" a peer after a failed first connection

✨ Improved:
• ⚡ At startup the node picks the fastest relay and skips a dead one instead of waiting 30s
• 🔍 Metrics now show why a delegate is not PQ: no announce, stale announce, bad signature, clock skew…
• 🕸 More direct neighbours in the gossip mesh
• 🧰 Build on 2–4 GB RAM machines: cargo build --profile release-lowmem -j 2

🛠 Upgrade: stop the node -> replace the binary -> start. No config or database changes.

Download
wget http://smartholdem.io/download/core/sth-core

Mandatory Network Upgrade

Important

This is a mandatory (consensus-breaking) release. All delegates, relay nodes, exchanges, explorers and wallet
backends must upgrade to v0.25.50 before block height 12,500,000. Nodes running an older version will reject
blocks produced under the new rules and will fork off the network.

Version 0.25.50
Activation height 12,500,000
Minimum core version after activation 0.25.50
Upgrade type Hard fork (milestone activation)
Urgency 🔴 High required for all node operators

Block time is 8 seconds (~10,800 blocks per day). Check the current height via
curl -s $API/api/blockchain | jq .data.block.height and plan your upgrade with a safe margin.


✨ Highlights

At block 12,500,000 the SmartHoldem mainnet activates a major set of protocol features that turn STH into a
multi-asset network with a built-in on-chain market.

🪙 Native Tokens (typeGroup 3, SHIP-14)

First-class tokens issued directly on the SmartHoldem blockchain no smart contracts, no extra layers.

  • TokenInit register a token with its ticker, decimals, initial supply, supply cap and mintable / burnable flags.
  • TokenTransfer send tokens to one or many recipients in a single transaction.
  • TokenMint issue additional supply (only if the token is mintable, never above the cap).
  • TokenBurn permanently destroy tokens (only if the token is burnable).
  • TokenMeta publish an on-chain token manifest (name, description, logo, links).

📈 Token Market on-chain DEX (SHIP-43)

A native order book for tokens, settled in STH by consensus.

  • TokenSell place a sell order.
  • TokenBuy fill an order; tokens and STH are swapped atomically in the same block.
  • TokenCancel withdraw an open order.
  • Up to 64 open orders per seller per token.

🧩 SmartObjects V2

  • ntfryData now accepts any UTF-8 payload up to 255 bytes.
  • SmartObject names of type 5 act as token tickers (unique ticker registry).
  • SmartObjects can be transferred, listed for sale and bought directly on-chain.

🛡️ Strict Balance Enforcement

  • A block containing any transaction whose amount + fee is not covered by the sender's balance is rejected
    (InsufficientBalanceError). This closes edge cases inherited from the legacy core.

🔥 Token Economics & Burn

Registering a token is intentionally priced as a premium action to protect the ticker namespace from spam and to make
STH deflationary.

  • Token registration (TokenInit) costs 5,000 STH.
  • 50% of the registration fee 2,500 STH is burned forever (sent to the network burn address and removed
    from circulating supply). The remaining 50% goes to the forging delegate.
  • The burn share (tokenFees.initBurnPercent) is a milestone parameter (SHIP-17) and can be changed by a future
    milestone without a code fork.
  • The total burned supply is visible on the node API and in sth-cli status.

Fee schedule after block 12,500,000

Operation Fee (STH) Notes
TokenInit (token registration) 5,000 50% burned (2,500 STH)
TokenTransfer 0.1 + 0.01 per additional recipient
TokenMint 1
TokenBurn 0.1
TokenMeta (on-chain manifest) 100
TokenSell (place order) 1
TokenBuy (fill order) 0.1
TokenCancel (cancel order) 0.1

Fees are exact (static): a transaction paying a different fee is rejected with StaticFeeMismatchError.


⚙️ Changes Since v0.25.49

  • Mainnet activation height moved from 12,365,000 to 12,500,000.
  • Default token registration fee (tokenFees.init) raised from 500 STH -> 5,000 STH.
  • TokenMeta fee raised from 10 STH -> 100 STH.
  • minCoreVersion bumped to 0.25.50.

Activation milestone (embedded in the binary, network/mainnet/milestones.json):

{
  "height": 12500000,
  "tokens": true,
  "sobjV2": true,
  "strictBalance": true,
  "tokenFees": { "meta": 10000000000 },
  "tokenMarket": { "enabled": true, "maxOpenOrders": 64 },
  "minCoreVersion": "0.25.50"
}

Warning

If your node uses a custom network_dir in node.yaml, you must replace the old 12365000 milestone in your
own milestones.json with the entry above. A mismatch will fork your node.


🛠️ Upgrade Instructions

  1. Stop the node.
  2. Replace the binary with v0.25.50 (or rebuild from source: cargo build --release).
  3. Update your custom milestones.json if you use network_dir (see above).
  4. Start the node and verify the version and milestone:
    curl -s $API/api/node/configuration | jq '.data.constants | {tokens, sobjV2, strictBalance, minCoreVersion}'
    Before height 12,500,000 the flags are false; after activation they become true.
  5. Delegates: confirm on /metrics -> Delegates that your node is shown as up to date (no "outdated" badge).

No database resync is required.

Who must upgrade

Role Action
Forging delegates Required otherwise blocks are rejected and slots are missed
Relay / API nodes Required otherwise the node forks off
Exchanges & custodians Required update deposit/withdrawal monitoring for typeGroup 3 transactions
Explorers & wallets Required support the new token and market transaction types
Legacy Node.js relays Must be replaced with Rust nodes they cannot process typeGroup 3 blocks

⚠️ Compatibility Notes

  • Nothing is created automatically at the activation height; the first token is registered by a regular TokenInit
    transaction.
  • Transactions of typeGroup 3 sent before height 12,500,000 are rejected.
  • REST API remains 100% backward compatible; new endpoints cover tokens and the token market.

✅ Verification

cargo test --lib config::tests::mainnet_tokens_market_at_12_500_000
cargo test

All 209 tests pass on this release.


Thank you to all delegates and node operators for keeping the SmartHoldem network secure.
Please upgrade early and report any issues in the GitHub issue tracker.

@technologiespro @bratunya2019

v0.25.50 PQ CORE SmartHoldem

Choose a tag to compare

@technologiespro technologiespro released this 09 Nov 05:36

Mandatory Network Upgrade

Important

This is a mandatory (consensus-breaking) release. All delegates, relay nodes, exchanges, explorers and wallet
backends must upgrade to v0.25.50 before block height 12,500,000. Nodes running an older version will reject
blocks produced under the new rules and will fork off the network.

Version 0.25.50
Activation height 12,500,000
Minimum core version after activation 0.25.50
Upgrade type Hard fork (milestone activation)
Urgency 🔴 High required for all node operators

Block time is 8 seconds (~10,800 blocks per day). Check the current height via
curl -s $API/api/blockchain | jq .data.block.height and plan your upgrade with a safe margin.


✨ Highlights

At block 12,500,000 the SmartHoldem mainnet activates a major set of protocol features that turn STH into a
multi-asset network with a built-in on-chain market.

🪙 Native Tokens (typeGroup 3, SHIP-14)

First-class tokens issued directly on the SmartHoldem blockchain no smart contracts, no extra layers.

  • TokenInit register a token with its ticker, decimals, initial supply, supply cap and mintable / burnable flags.
  • TokenTransfer send tokens to one or many recipients in a single transaction.
  • TokenMint issue additional supply (only if the token is mintable, never above the cap).
  • TokenBurn permanently destroy tokens (only if the token is burnable).
  • TokenMeta publish an on-chain token manifest (name, description, logo, links).

📈 Token Market on-chain DEX (SHIP-43)

A native order book for tokens, settled in STH by consensus.

  • TokenSell place a sell order.
  • TokenBuy fill an order; tokens and STH are swapped atomically in the same block.
  • TokenCancel withdraw an open order.
  • Up to 64 open orders per seller per token.

🧩 SmartObjects V2

  • ntfryData now accepts any UTF-8 payload up to 255 bytes.
  • SmartObject names of type 5 act as token tickers (unique ticker registry).
  • SmartObjects can be transferred, listed for sale and bought directly on-chain.

🛡️ Strict Balance Enforcement

  • A block containing any transaction whose amount + fee is not covered by the sender's balance is rejected
    (InsufficientBalanceError). This closes edge cases inherited from the legacy core.

🔥 Token Economics & Burn

Registering a token is intentionally priced as a premium action to protect the ticker namespace from spam and to make
STH deflationary.

  • Token registration (TokenInit) costs 5,000 STH.
  • 50% of the registration fee 2,500 STH is burned forever (sent to the network burn address and removed
    from circulating supply). The remaining 50% goes to the forging delegate.
  • The burn share (tokenFees.initBurnPercent) is a milestone parameter (SHIP-17) and can be changed by a future
    milestone without a code fork.
  • The total burned supply is visible on the node API and in sth-cli status.

Fee schedule after block 12,500,000

Operation Fee (STH) Notes
TokenInit (token registration) 5,000 50% burned (2,500 STH)
TokenTransfer 0.1 + 0.01 per additional recipient
TokenMint 1
TokenBurn 0.1
TokenMeta (on-chain manifest) 100
TokenSell (place order) 1
TokenBuy (fill order) 0.1
TokenCancel (cancel order) 0.1

Fees are exact (static): a transaction paying a different fee is rejected with StaticFeeMismatchError.


⚙️ Changes Since v0.25.49

  • Mainnet activation height moved from 12,365,000 to 12,500,000.
  • Default token registration fee (tokenFees.init) raised from 500 STH -> 5,000 STH.
  • TokenMeta fee raised from 10 STH -> 100 STH.
  • minCoreVersion bumped to 0.25.50.

Activation milestone (embedded in the binary, network/mainnet/milestones.json):

{
  "height": 12500000,
  "tokens": true,
  "sobjV2": true,
  "strictBalance": true,
  "tokenFees": { "meta": 10000000000 },
  "tokenMarket": { "enabled": true, "maxOpenOrders": 64 },
  "minCoreVersion": "0.25.50"
}

Warning

If your node uses a custom network_dir in node.yaml, you must replace the old 12365000 milestone in your
own milestones.json with the entry above. A mismatch will fork your node.


🛠️ Upgrade Instructions

  1. Stop the node.
  2. Replace the binary with v0.25.50 (or rebuild from source: cargo build --release).
  3. Update your custom milestones.json if you use network_dir (see above).
  4. Start the node and verify the version and milestone:
    curl -s $API/api/node/configuration | jq '.data.constants | {tokens, sobjV2, strictBalance, minCoreVersion}'
    Before height 12,500,000 the flags are false; after activation they become true.
  5. Delegates: confirm on /metrics -> Delegates that your node is shown as up to date (no "outdated" badge).

No database resync is required.

Who must upgrade

Role Action
Forging delegates Required otherwise blocks are rejected and slots are missed
Relay / API nodes Required otherwise the node forks off
Exchanges & custodians Required update deposit/withdrawal monitoring for typeGroup 3 transactions
Explorers & wallets Required support the new token and market transaction types
Legacy Node.js relays Must be replaced with Rust nodes they cannot process typeGroup 3 blocks

⚠️ Compatibility Notes

  • Nothing is created automatically at the activation height; the first token is registered by a regular TokenInit
    transaction.
  • Transactions of typeGroup 3 sent before height 12,500,000 are rejected.
  • REST API remains 100% backward compatible; new endpoints cover tokens and the token market.

✅ Verification

cargo test --lib config::tests::mainnet_tokens_market_at_12_500_000
cargo test

All 209 tests pass on this release.


Thank you to all delegates and node operators for keeping the SmartHoldem network secure.
Please upgrade early and report any issues in the GitHub issue tracker.

Download
wget http://smartholdem.io/download/core/sth-core

@technologiespro @bratunya2019

v0.25.48 PQ CORE SmartHoldem

Choose a tag to compare

@technologiespro technologiespro released this 20 Oct 03:25

First Start

sth-core init
sth-core run --p2p

@technologiespro @bratunya2019

v0.25.45 PQ CORE SmartHoldem

Choose a tag to compare

@technologiespro technologiespro released this 20 Oct 01:02

First Start

sth-core init
sth-core run --p2p

@technologiespro @bratunya2019

v0.25.44 SmartHoldem PQ CORE

Choose a tag to compare

@technologiespro technologiespro released this 12 Oct 03:49

Changed metrics page: a resolved fork no longer screams

  • The forging card showed ⚠ SAME-HEIGHT FORK … other side must roll back until restart. Once finality has passed
    the height (or the chain is 21+ blocks beyond it) the line turns into a dim fork at H (A vs B) resolved by the majority chain, finalized · 3h ago, and disappears after 24 h. The wording no longer talks about legacy rollbacks.

Changed sth-core init defaults for an all-PQ network

  • discovery.listen_port: 4004 (was 0 = random): a fixed public UDP port gives stable direct dial info across restarts
    and makes relay-down mode effective. Open UDP 4004 in the firewall.
  • p2p.legacy_listen: "0.0.0.0:4001" (was empty): every node serves blocks over the legacy TCP port too the second,
    relay-independent transport that carried the chain through the gossip outage. Open TCP 4001. A bind failure is
    logged, not fatal. Existing node.yaml files are not changed set both values by hand.

Changed SAME-HEIGHT FORK alert names the culprit

  • The alert now says which block came first and therefore whose node failed to spread it (X's block (slot …) did not reach Y within 8s, so Y forged the same height), that the majority chain wins and the minority rolls back on its own,
    and what to check on X's node (gossip neighbours, peers[].path = direct, record on the PQ MAP, clock). The legacy
    rollback hint is gone there are no legacy forgers left.

First Start

sth-core init
sth-core run --p2p

@technologiespro @bratunya2019

v0.25.41 PQ CORE SmartHoldem

Choose a tag to compare

@technologiespro technologiespro released this 10 Oct 12:14

Full Changelog: 0.25.23...0.25.41

v0.25.26 PQ CORE SmartHoldem

Choose a tag to compare

@technologiespro technologiespro released this 30 Sep 00:28

live audit, mempool antispam, security audit fixes

This release prepares the network for the final step of the transition: all 21 forging delegates on the Rust PQ node,
legacy Node.js nodes remaining as relay / API only. It adds operator tooling that no longer requires stopping a delegate,
a spam policy for the transaction pool, and closes the findings of a static security audit of the whole codebase.

Highlights

audit-all without stopping the node

sth-core audit-all [--fix] used to need systemctl stop because Sled holds an exclusive lock on the database - for a
forging delegate that meant missed slots. Now the CLI detects a running node and asks it to audit itself through the local
API (POST /api/ntfry/audit, loopback only, refused behind a reverse proxy) and follows the progress:

node is running -> live audit through http://127.0.0.1:4003 (forging is not interrupted)
  scanned 10,000 of 11,990,120 blocks…
height 11,990,131 · wallets 61,204 · compared 61,190 · skipped 14 · drifted 0 · 143.2s (live)
OK: every wallet matches the chain history

The full chain walk and the wallet comparison run without any lock; the block-apply lock is held only for milliseconds to
book the blocks applied meanwhile and re-check the candidates. A fork rollback during the scan aborts the audit safely.
--fix repairs drifted wallets and rebuilds the vote index in the same critical section. Nightly cron no longer needs a
stop/start pair: sth-core audit-all --fix --json.

sth-core alerts-test

Validates the Telegram bot token, lists the chats the bot has seen when telegram_chat_id is empty (ready to paste into
node.yaml), otherwise sends a test message to Telegram and the webhook and explains any refusal (chat not found ->
send the bot /start).

mempool.antispam - pool policy against cheap-transaction floods

Never consensus: blocks are not judged by it. All values are defaults in node.yaml:

mempool:
  antispam:
    enabled: true
    max_per_sender: 64          # pending transactions per address (a same-nonce replacement does not count)
    max_bytes_per_sender: 65536
    peer_tx_per_min: 600        # per legacy IP / iroh EndpointId; the rest of a batch is dropped before verification
    peer_invalid_per_min: 20    # bad signatures / bytes / network (nonce faults are NOT counted) -> ban for ban_secs
    ban_secs: 3600              # transactions only - blocks from that peer are still accepted
    replace_by_fee: true        # full pool: higher fee-per-byte evicts the cheapest pending (a sender's last nonce only)
    deny_peers: []              # IPs / EndpointIds always dropped
    alert_drops_per_min: 500    # alert `spam-wave`

Metrics: mempool.antispam { counters, banned[], topSenders[] } in /api/ntfry/metrics and a line in the mempool card.
New rejection code ERR_SPAM_SENDER.

Security audit

A static (read-only) security review of the codebase was performed before the delegate migration. Consensus-critical
controls were confirmed: a block cannot be applied twice or off the tip (apply lock + in-transaction tip check), every
network intake path verifies signatures before touching state, lock poisoning cannot panic the node, the iroh address
book is signed and bounded, balance arithmetic is checked i128. No fund-theft or consensus fault was found. Three
availability findings were fixed in this release:

Severity Finding Fix
High Legacy P2P postBlock / getBlocks used the header's numberOfTransactions for Vec::with_capacity before any check - a peer could make the node reserve gigabytes and abort count bounded by the milestone maxTransactions and by the payload size before allocating
Medium Legacy P2P postTransactions accepted unlimited transactions per request (unbounded ML-DSA verification); WebSocket messages up to 64 MiB 40 transactions per request (legacy maxTransactionsPerRequest), 20 MiB message / frame cap (legacy maxPayload)
Medium The new live audit held the apply lock across a full wallet scan comparison moved out of the lock; only candidates re-checked under it
Low &block_id[..8] could panic on a short id get(..8)

Upgrade

systemctl stop sth-core && cp sth-core /usr/local/bin/ && systemctl start sth-core
sth-core alerts-test          # optional: verify Telegram / webhook
sth-core audit-all            # optional: state check on the running node

No database migration; node.yaml gains the mempool.antispam section with defaults (nothing to change).
Versions 0.25.24 -> 0.25.26 (0.25.25 = live audit + alerts-test, 0.25.26 = antispam + audit fixes).


For Update on Linux:

pm2 stop all # stop legacy node
pm2 delete all
pm2 delete 0
pm2 save
mkdir pq-node
cd pq-node
wget http://smartholdem.io/download/core/sth-core
chmod +x sth-core
wget http://smartholdem.io/download/core/snapshot/data.tgz
tar -zxvf data.tgz
rm data.tgz
./sth-core init
./sth-core run

v0.25.23

Choose a tag to compare

@technologiespro technologiespro released this 29 Sep 18:45

First work release

for update

pm2 stop all # stop legacy node
pm2 delete all
pm2 delete 0
pm2 save
mkdir pq-node
cd pq-node
wget http://smartholdem.io/download/core/sth-core
chmod +x sth-core
wget http://smartholdem.io/download/core/snapshot/data.tgz
tar zxvf data.tgz
rm data.tgz
./sth-core init
./sth-core run

SmartHoldem CORE v0.9.0

Choose a tag to compare

@technologiespro technologiespro released this 04 Sep 19:00

SmartHoldem Core on Rust

sth-core init
sth-core run --p2p

or

CORE_API_HOST=0.0.0.0 CORE_API_PORT=4003 nohup ./sth-core --db-path ./data run --p2p &
tail -f nohup.out

NETFORY WEB4 Decentralized Network based on SmartHoldem

SmartHoldem CORE v0.8.1

Choose a tag to compare

@technologiespro technologiespro released this 03 Sep 20:03

First implementation SmartHoldem Core on Rust

sth-core init
sth-core run --p2p

or

CORE_API_HOST=0.0.0.0 CORE_API_PORT=4003 nohup ./sth-core --db-path ./data run --p2p &
tail -f nohup.out