● Add height-based hard fork detection for CARROT activation

- wallet.js: isCarrotEnabled() now uses sync height and network to
    automatically determine CARROT status based on HF activation heights
  - wallet.js: getHfVersion() derives version from sync height instead
    of relying on manually set value
  - wallet.js: Added _getNetworkId() to map network strings to NETWORK_ID
  - Mainnet CARROT activates at height 334750, testnet/stagenet at 1100
  - Falls back to stored _hfVersion when sync height is 0 (pre-sync)
This commit is contained in:
Matt Hess
2026-01-26 14:14:10 +00:00
parent 6eeadbe8ed
commit 27babe33f6
2 changed files with 145 additions and 4 deletions
+90
View File
@@ -160,6 +160,19 @@ export const MAINNET_CONFIG = {
STAKE_LOCK_PERIOD: 30 * 24 * 30, // blocks
TREASURY_SAL1_MINT_PERIOD: 30 * 24 * 30,
TREASURY_ADDRESS: 'SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA',
// Hard fork heights (from hardforks.cpp)
HARD_FORK_HEIGHTS: {
1: 1, // Genesis
2: 89800, // November 4, 2024
3: 121100, // December 19, 2024
4: 121800, // December 20, 2024
5: 136100, // January 9, 2025
6: 154750, // February 4, 2025 (AUDIT1)
7: 161900, // February 14, 2025 (AUDIT1_PAUSE)
8: 172000, // February 28, 2025 (AUDIT2)
9: 179200, // March 10, 2025 (AUDIT2_PAUSE)
10: 334750, // October 13, 2025 (CARROT)
},
};
export const TESTNET_CONFIG = {
@@ -177,6 +190,19 @@ export const TESTNET_CONFIG = {
STAKE_LOCK_PERIOD: 20,
TREASURY_SAL1_MINT_PERIOD: 20,
TREASURY_ADDRESS: 'SaLvTyLFta9BiAXeUfFkKvViBkFt4ay5nEUBpWyDKewYggtsoxBbtCUVqaBjtcCDyY1euun8Giv7LLEgvztuurLo5a6Km1zskZn36',
// Hard fork heights (from hardforks.cpp)
HARD_FORK_HEIGHTS: {
1: 1, // Genesis
2: 250,
3: 500,
4: 600,
5: 800,
6: 815, // AUDIT1
7: 900, // AUDIT1_PAUSE
8: 950, // AUDIT2
9: 1000, // AUDIT2_PAUSE
10: 1100, // CARROT
},
};
export const STAGENET_CONFIG = {
@@ -194,6 +220,19 @@ export const STAGENET_CONFIG = {
STAKE_LOCK_PERIOD: 20,
TREASURY_SAL1_MINT_PERIOD: 20,
TREASURY_ADDRESS: 'fuLMowH85abK8nz9BBMEem7MAfUbQu4aSHHUV9j5Z86o6Go9Lv2U5ZQiJCWPY9R9HA8p5idburazjAhCqDngLo7fYPCD9ciM9ee1A',
// Hard fork heights - stagenet matches testnet
HARD_FORK_HEIGHTS: {
1: 1, // Genesis
2: 250,
3: 500,
4: 600,
5: 800,
6: 815,
7: 900,
8: 950,
9: 1000,
10: 1100, // CARROT
},
};
/**
@@ -215,6 +254,57 @@ export function getNetworkConfig(network) {
}
}
/**
* Get hard fork version for a given block height
*
* Reference: ~/github/salvium/src/hardforks/hardforks.cpp
*
* @param {number} height - Block height
* @param {number} network - Network type (MAINNET, TESTNET, STAGENET)
* @returns {number} Hard fork version active at this height
*/
export function getHfVersionForHeight(height, network = NETWORK_ID.MAINNET) {
const config = getNetworkConfig(network);
const hfHeights = config.HARD_FORK_HEIGHTS;
if (!hfHeights) {
return 1; // Default to version 1 if no HF heights defined
}
// Find the highest HF version that has been activated at this height
let activeVersion = 1;
for (const [version, activationHeight] of Object.entries(hfHeights)) {
if (height >= activationHeight && parseInt(version) > activeVersion) {
activeVersion = parseInt(version);
}
}
return activeVersion;
}
/**
* Check if a specific hard fork is active at a given height
*
* @param {number} hfVersion - Hard fork version to check
* @param {number} height - Block height
* @param {number} network - Network type
* @returns {boolean} True if the hard fork is active
*/
export function isHfActive(hfVersion, height, network = NETWORK_ID.MAINNET) {
return getHfVersionForHeight(height, network) >= hfVersion;
}
/**
* Check if CARROT outputs are enabled at a given height
*
* @param {number} height - Block height
* @param {number} network - Network type
* @returns {boolean} True if CARROT is active
*/
export function isCarrotActive(height, network = NETWORK_ID.MAINNET) {
return isHfActive(HF_VERSION.CARROT, height, network);
}
// =============================================================================
// BLOCK REWARD CALCULATION
// =============================================================================
+55 -4
View File
@@ -36,7 +36,7 @@ import {
UTXO_STRATEGY
} from './transaction.js';
import { NETWORK, ADDRESS_FORMAT } from './constants.js';
import { getNetworkConfig } from './consensus.js';
import { getNetworkConfig, HF_VERSION, getHfVersionForHeight, isCarrotActive, NETWORK_ID } from './consensus.js';
import { seedToMnemonic, mnemonicToSeed, validateMnemonic } from './mnemonic.js';
// ============================================================================
@@ -300,6 +300,7 @@ export class Wallet {
this._lastBlockHash = null;
this._syncing = false;
this._syncInterval = null;
this._hfVersion = HF_VERSION.CARROT; // Fallback for pre-sync state (overridden by height-based detection during sync)
// Event listeners
this._listeners = [];
@@ -1320,7 +1321,7 @@ export class Wallet {
{
stakeLockPeriod,
assetType,
useCarrot: false // TODO: Support CARROT staking when needed
useCarrot: this.isCarrotEnabled()
}
);
@@ -1443,7 +1444,7 @@ export class Wallet {
},
{
assetType,
useCarrot: false // TODO: Support CARROT burning when needed
useCarrot: this.isCarrotEnabled()
}
);
@@ -1603,7 +1604,7 @@ export class Wallet {
fee: actualFee
},
{
useCarrot: false // TODO: Support CARROT conversion when needed
useCarrot: this.isCarrotEnabled()
}
);
@@ -1924,6 +1925,56 @@ export class Wallet {
return this._syncHeight >= targetHeight;
}
/**
* Map wallet network string to NETWORK_ID integer
* @returns {number} NETWORK_ID constant
* @private
*/
_getNetworkId() {
switch (this.network) {
case 'mainnet': return NETWORK_ID.MAINNET;
case 'testnet': return NETWORK_ID.TESTNET;
case 'stagenet': return NETWORK_ID.STAGENET;
default: return NETWORK_ID.MAINNET;
}
}
/**
* Set the current hard fork version (deprecated - use sync height instead)
* This is kept for backward compatibility but the HF version is now
* automatically determined from the sync height and network.
* @param {number} version - Hard fork version
* @deprecated Use sync height to determine HF version automatically
*/
setHfVersion(version) { this._hfVersion = version; }
/**
* Get the current hard fork version based on sync height and network
* @returns {number} Hard fork version
*/
getHfVersion() {
// Use height-based detection if we have a sync height
if (this._syncHeight > 0) {
return getHfVersionForHeight(this._syncHeight, this._getNetworkId());
}
// Fall back to stored version (for pre-sync state)
return this._hfVersion;
}
/**
* Check if CARROT outputs are enabled at the current sync height
* CARROT is enabled at HF version 10 (mainnet: 334750, testnet: 1100)
* @returns {boolean} True if CARROT outputs should be used
*/
isCarrotEnabled() {
// Use height-based detection if we have a sync height
if (this._syncHeight > 0) {
return isCarrotActive(this._syncHeight, this._getNetworkId());
}
// Fall back to stored version (for pre-sync state)
return this._hfVersion >= HF_VERSION.CARROT;
}
// ===========================================================================
// YIELD TRACKING (Salvium-specific)
// ===========================================================================