go-blockchain/config/config.go
Claude fcb867d53b
fix(p2p): correct network IDs and serialisation for C++ daemon compat
Three bugs found by integration testing against the C++ testnet daemon:

1. NetworkIDMainnet/Testnet had byte 10 swapped — the C++ #ifndef TESTNET
   branch (mainnet) sets P2P_NETWORK_ID_TESTNET_FLAG=1, and the #else
   (testnet) sets it to 0. Counter-intuitive but matches compiled binaries.

2. ClientVersion format "Lethean/go-blockchain 0.1.0" was rejected by the
   daemon's parse_client_version which expects "major.minor.rev.build[commit]".
   Changed to "6.0.1.2[go-blockchain]".

3. RequestChain, RequestGetObjects, and ResponseGetObjects used StringArrayVal
   for hash fields, but the C++ daemon uses KV_SERIALIZE_CONTAINER_POD_AS_BLOB
   which packs all 32-byte hashes into a single concatenated blob. Also,
   ResponseChainEntry.m_block_ids is an object array of block_context_info
   (hash + cumulative size), not a simple hash list.

Co-Authored-By: Charon <charon@lethean.io>
2026-02-21 21:17:48 +00:00

501 lines
19 KiB
Go

// Copyright (c) 2017-2026 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// You may obtain a copy of the licence at:
//
// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
//
// SPDX-License-Identifier: EUPL-1.2
// Package config defines chain parameters for the Lethean blockchain.
//
// All constants are derived from the canonical C++ source files
// currency_config.h.in and default.cmake. Mainnet and Testnet configurations
// are provided as package-level variables.
package config
// ---------------------------------------------------------------------------
// Tokenomics
// ---------------------------------------------------------------------------
// Coin is the number of smallest indivisible units in one LTHN.
// 1 LTHN = 10^12 atomic units.
const Coin uint64 = 1_000_000_000_000
// DisplayDecimalPoint is the number of decimal places used when displaying
// amounts in human-readable form.
const DisplayDecimalPoint = 12
// BlockReward is the fixed reward per block in atomic units (1.0 LTHN).
const BlockReward uint64 = 1_000_000_000_000
// DefaultFee is the standard transaction fee in atomic units (0.01 LTHN).
const DefaultFee uint64 = 10_000_000_000
// MinimumFee is the lowest acceptable transaction fee in atomic units (0.01 LTHN).
const MinimumFee uint64 = 10_000_000_000
// Premine is the total pre-mined supply in atomic units (10,000,000 LTHN).
// This covers the coinswap allocation (13,827,203 LTHN reserved) and the
// initial premine (3,690,000 LTHN). The raw value from cmake is
// 10,000,000,000,000,000,000 but that exceeds uint64 range. The C++ code
// uses an unsigned literal suffix; we store the value faithfully.
const Premine uint64 = 10_000_000_000_000_000_000
// BaseRewardDustThreshold is the minimum meaningful fraction of a block
// reward in atomic units.
const BaseRewardDustThreshold uint64 = 1_000_000
// DefaultDustThreshold is the dust threshold for normal transactions.
const DefaultDustThreshold uint64 = 0
// ---------------------------------------------------------------------------
// Address prefixes
// ---------------------------------------------------------------------------
// Address prefix constants determine the leading characters of base58-encoded
// addresses. Each prefix is varint-encoded before the public keys.
const (
// AddressPrefix is the standard public address prefix.
// Produces addresses starting with "iTHN".
AddressPrefix uint64 = 0x1eaf7
// IntegratedAddressPrefix is the prefix for integrated addresses
// (address + embedded payment ID). Produces addresses starting with "iTHn".
IntegratedAddressPrefix uint64 = 0xdeaf7
// AuditableAddressPrefix is the prefix for auditable addresses.
// Produces addresses starting with "iThN".
AuditableAddressPrefix uint64 = 0x3ceff7
// AuditableIntegratedAddressPrefix is the prefix for auditable
// integrated addresses. Produces addresses starting with "iThn".
AuditableIntegratedAddressPrefix uint64 = 0x8b077
)
// ---------------------------------------------------------------------------
// P2P and RPC ports
// ---------------------------------------------------------------------------
const (
MainnetP2PPort uint16 = 36942
MainnetRPCPort uint16 = 36941
MainnetStratumPort uint16 = 36940
TestnetP2PPort uint16 = 46942
TestnetRPCPort uint16 = 46941
TestnetStratumPort uint16 = 46940
)
// ---------------------------------------------------------------------------
// Timing and difficulty
// ---------------------------------------------------------------------------
const (
// DifficultyPowTarget is the target block interval for PoW blocks in seconds.
DifficultyPowTarget uint64 = 120
// DifficultyPosTarget is the target block interval for PoS blocks in seconds.
DifficultyPosTarget uint64 = 120
// DifficultyTotalTarget is the effective combined target:
// (PoW + PoS) / 4 = 60 seconds.
DifficultyTotalTarget uint64 = (DifficultyPowTarget + DifficultyPosTarget) / 4
// DifficultyWindow is the number of blocks used for difficulty calculation.
DifficultyWindow uint64 = 720
// DifficultyLag is the additional lookback beyond the window.
DifficultyLag uint64 = 15
// DifficultyCut is the number of timestamps cut from each end after sorting.
DifficultyCut uint64 = 60
// DifficultyBlocksCount is the total number of blocks considered
// (Window + Lag).
DifficultyBlocksCount uint64 = DifficultyWindow + DifficultyLag
// DifficultyPowStarter is the initial PoW difficulty.
DifficultyPowStarter uint64 = 1
// DifficultyPosStarter is the initial PoS difficulty.
DifficultyPosStarter uint64 = 1
// DifficultyPowTargetHF6 is the PoW target after hardfork 6 (240s).
DifficultyPowTargetHF6 uint64 = 240
// DifficultyPosTargetHF6 is the PoS target after hardfork 6 (240s).
DifficultyPosTargetHF6 uint64 = 240
// DifficultyTotalTargetHF6 is the combined target after HF6.
DifficultyTotalTargetHF6 uint64 = (DifficultyPowTargetHF6 + DifficultyPosTargetHF6) / 4
)
// ---------------------------------------------------------------------------
// Block and transaction limits
// ---------------------------------------------------------------------------
const (
// MaxBlockNumber is the absolute maximum block height.
MaxBlockNumber uint64 = 500_000_000
// MaxBlockSize is the maximum block header blob size in bytes.
MaxBlockSize uint64 = 500_000_000
// TxMaxAllowedInputs is the maximum number of inputs per transaction.
// Limited primarily by the asset surjection proof.
TxMaxAllowedInputs uint64 = 256
// TxMaxAllowedOutputs is the maximum number of outputs per transaction.
TxMaxAllowedOutputs uint64 = 2000
// TxMinAllowedOutputs is the minimum number of outputs (effective from HF4 Zarcanum).
TxMinAllowedOutputs uint64 = 2
// DefaultDecoySetSize is the ring size for pre-HF4 transactions.
DefaultDecoySetSize uint64 = 10
// HF4MandatoryDecoySetSize is the ring size required from HF4 onwards.
HF4MandatoryDecoySetSize uint64 = 15
// HF4MandatoryMinCoinage is the minimum coinage in blocks required for HF4.
HF4MandatoryMinCoinage uint64 = 10
// MinedMoneyUnlockWindow is the number of blocks before mined coins
// can be spent.
MinedMoneyUnlockWindow uint64 = 10
// BlockGrantedFullRewardZone is the block size threshold in bytes after
// which block reward is calculated using the actual block size.
BlockGrantedFullRewardZone uint64 = 125_000
// CoinbaseBlobReservedSize is the reserved space for the coinbase
// transaction blob in bytes.
CoinbaseBlobReservedSize uint64 = 1100
// MaxTransactionBlobSize is the maximum serialised transaction size in bytes.
// Derived from BlockGrantedFullRewardZone - 2*CoinbaseBlobReservedSize
// but the canonical C++ value is 374,600.
MaxTransactionBlobSize uint64 = 374_600
// BlockFutureTimeLimit is the maximum acceptable future timestamp for
// PoW blocks in seconds (2 hours).
BlockFutureTimeLimit uint64 = 60 * 60 * 2
// PosBlockFutureTimeLimit is the maximum acceptable future timestamp
// for PoS blocks in seconds (20 minutes).
PosBlockFutureTimeLimit uint64 = 60 * 20
// TimestampCheckWindow is the number of blocks used when checking
// whether a block timestamp is valid.
TimestampCheckWindow uint64 = 60
// PosStartHeight is the block height from which PoS is enabled.
PosStartHeight uint64 = 0
// RewardBlocksWindow is the number of recent blocks used to calculate
// the reward median.
RewardBlocksWindow uint64 = 400
// FreeTxMaxBlobSize is the soft txpool-based limit for free transactions
// in bytes.
FreeTxMaxBlobSize uint64 = 1024
// PreHardforkTxFreezePeriod is the number of blocks before hardfork
// activation when no new transactions are accepted (effective from HF5).
PreHardforkTxFreezePeriod uint64 = 60
)
// ---------------------------------------------------------------------------
// Block version constants
// ---------------------------------------------------------------------------
const (
BlockMajorVersionGenesis uint8 = 1
BlockMinorVersionGenesis uint8 = 0
BlockMajorVersionInitial uint8 = 0
HF1BlockMajorVersion uint8 = 1
HF3BlockMajorVersion uint8 = 2
HF3BlockMinorVersion uint8 = 0
CurrentBlockMajorVersion uint8 = 3
CurrentBlockMinorVersion uint8 = 0
)
// ---------------------------------------------------------------------------
// Transaction version constants
// ---------------------------------------------------------------------------
const (
TransactionVersionInitial uint8 = 0
TransactionVersionPreHF4 uint8 = 1
TransactionVersionPostHF4 uint8 = 2
TransactionVersionPostHF5 uint8 = 3
CurrentTransactionVersion uint8 = 3
)
// ---------------------------------------------------------------------------
// PoS constants
// ---------------------------------------------------------------------------
const (
PosScanWindow uint64 = 60 * 10 // 10 minutes in seconds
PosScanStep uint64 = 15 // seconds
PosModifierInterval uint64 = 10
PosMinimumCoinstakeAge uint64 = 10 // blocks
PosStrictSequenceLimit uint64 = 20
PosStarterKernelHash = "00000000000000000006382a8d8f94588ce93a1351924f6ccb9e07dd287c6e4b"
)
// ---------------------------------------------------------------------------
// P2P constants
// ---------------------------------------------------------------------------
const (
P2PLocalWhitePeerlistLimit uint64 = 1000
P2PLocalGrayPeerlistLimit uint64 = 5000
P2PDefaultConnectionsCount uint64 = 8
P2PDefaultHandshakeInterval uint64 = 60 // seconds
P2PDefaultPacketMaxSize uint64 = 50_000_000
P2PIPBlockTime uint64 = 60 * 60 * 24 // 24 hours
P2PIPFailsBeforeBlock uint64 = 10
)
// ---------------------------------------------------------------------------
// Network identity
// ---------------------------------------------------------------------------
const (
// CurrencyFormationVersion identifies the mainnet network.
CurrencyFormationVersion uint64 = 84
// CurrencyFormationVersionTestnet identifies the testnet network.
CurrencyFormationVersionTestnet uint64 = 100
// P2PNetworkIDVer is derived from CurrencyFormationVersion + 0.
P2PNetworkIDVer uint64 = CurrencyFormationVersion + 0
)
// NetworkIDMainnet is the 16-byte network UUID for mainnet P2P handshake.
// From net_node.inl: bytes 0-9 are fixed, byte 10 = P2P_NETWORK_ID_TESTNET_FLAG,
// bytes 11-14 fixed, byte 15 = formation version (84 = 0x54).
// NOTE: In the C++ source, the #ifndef TESTNET branch (i.e. mainnet) sets
// P2P_NETWORK_ID_TESTNET_FLAG = 1 and the #else (testnet) sets it to 0.
// The naming is counter-intuitive but matches the compiled binaries.
var NetworkIDMainnet = [16]byte{
0x11, 0x10, 0x01, 0x11, 0x01, 0x01, 0x11, 0x01,
0x10, 0x11, 0x01, 0x11, 0x01, 0x11, 0x21, 0x54,
}
// NetworkIDTestnet is the 16-byte network UUID for testnet P2P handshake.
// Byte 10 = 0x00 (P2P_NETWORK_ID_TESTNET_FLAG in testnet build),
// byte 15 = formation version (100 = 0x64).
var NetworkIDTestnet = [16]byte{
0x11, 0x10, 0x01, 0x11, 0x01, 0x01, 0x11, 0x01,
0x10, 0x11, 0x00, 0x11, 0x01, 0x11, 0x21, 0x64,
}
// ClientVersion is the version string sent in CORE_SYNC_DATA.
// The C++ daemon parses this as "major.minor.revision.build[commit]"
// and rejects connections where it cannot parse or the build number
// is below the minimum for the current hard-fork era.
const ClientVersion = "6.0.1.2[go-blockchain]"
// ---------------------------------------------------------------------------
// Currency identity
// ---------------------------------------------------------------------------
const (
CurrencyNameAbbreviation = "LTHN"
CurrencyNameBase = "Lethean"
CurrencyNameShort = "Lethean"
)
// ---------------------------------------------------------------------------
// Alias constants
// ---------------------------------------------------------------------------
const (
AliasMinimumPublicShortNameAllowed uint64 = 6
AliasNameMaxLen uint64 = 255
AliasValidChars = "0123456789abcdefghijklmnopqrstuvwxyz-."
AliasCommentMaxSizeBytes uint64 = 400
MaxAliasPerBlock uint64 = 1000
)
// ---------------------------------------------------------------------------
// ChainConfig aggregates all chain parameters into a single struct.
// ---------------------------------------------------------------------------
// ChainConfig holds the complete set of parameters for a particular chain
// (mainnet or testnet).
type ChainConfig struct {
// Name is the human-readable chain name.
Name string
// Abbreviation is the ticker symbol.
Abbreviation string
// IsTestnet indicates whether this is a test network.
IsTestnet bool
// CurrencyFormationVersion identifies the network.
CurrencyFormationVersion uint64
// Coin is the number of atomic units per coin.
Coin uint64
// DisplayDecimalPoint is the number of decimal places.
DisplayDecimalPoint uint8
// BlockReward is the fixed block reward in atomic units.
BlockReward uint64
// DefaultFee is the default transaction fee in atomic units.
DefaultFee uint64
// MinimumFee is the minimum acceptable fee in atomic units.
MinimumFee uint64
// Premine is the pre-mined amount in atomic units.
Premine uint64
// AddressPrefix is the base58 prefix for standard addresses.
AddressPrefix uint64
// IntegratedAddressPrefix is the base58 prefix for integrated addresses.
IntegratedAddressPrefix uint64
// AuditableAddressPrefix is the base58 prefix for auditable addresses.
AuditableAddressPrefix uint64
// AuditableIntegratedAddressPrefix is the base58 prefix for auditable
// integrated addresses.
AuditableIntegratedAddressPrefix uint64
// P2PPort is the default peer-to-peer port.
P2PPort uint16
// RPCPort is the default RPC port.
RPCPort uint16
// StratumPort is the default stratum mining port.
StratumPort uint16
// DifficultyPowTarget is the target PoW block interval in seconds.
DifficultyPowTarget uint64
// DifficultyPosTarget is the target PoS block interval in seconds.
DifficultyPosTarget uint64
// DifficultyWindow is the number of blocks in the difficulty window.
DifficultyWindow uint64
// DifficultyLag is the additional lookback beyond the window.
DifficultyLag uint64
// DifficultyCut is the number of timestamps cut after sorting.
DifficultyCut uint64
// DifficultyPowStarter is the initial PoW difficulty.
DifficultyPowStarter uint64
// DifficultyPosStarter is the initial PoS difficulty.
DifficultyPosStarter uint64
// MaxBlockNumber is the absolute maximum block height.
MaxBlockNumber uint64
// TxMaxAllowedInputs is the maximum inputs per transaction.
TxMaxAllowedInputs uint64
// TxMaxAllowedOutputs is the maximum outputs per transaction.
TxMaxAllowedOutputs uint64
// DefaultDecoySetSize is the default ring size.
DefaultDecoySetSize uint64
// HF4MandatoryDecoySetSize is the mandatory ring size from HF4.
HF4MandatoryDecoySetSize uint64
// MinedMoneyUnlockWindow is the maturity period for mined coins.
MinedMoneyUnlockWindow uint64
// P2PMaintainersPubKey is the hex-encoded maintainers public key.
P2PMaintainersPubKey string
// NetworkID is the 16-byte network UUID for P2P handshake.
NetworkID [16]byte
}
// Mainnet holds the chain configuration for the Lethean mainnet.
var Mainnet = ChainConfig{
Name: CurrencyNameBase,
Abbreviation: CurrencyNameAbbreviation,
IsTestnet: false,
CurrencyFormationVersion: CurrencyFormationVersion,
Coin: Coin,
DisplayDecimalPoint: DisplayDecimalPoint,
BlockReward: BlockReward,
DefaultFee: DefaultFee,
MinimumFee: MinimumFee,
Premine: Premine,
AddressPrefix: AddressPrefix,
IntegratedAddressPrefix: IntegratedAddressPrefix,
AuditableAddressPrefix: AuditableAddressPrefix,
AuditableIntegratedAddressPrefix: AuditableIntegratedAddressPrefix,
P2PPort: MainnetP2PPort,
RPCPort: MainnetRPCPort,
StratumPort: MainnetStratumPort,
DifficultyPowTarget: DifficultyPowTarget,
DifficultyPosTarget: DifficultyPosTarget,
DifficultyWindow: DifficultyWindow,
DifficultyLag: DifficultyLag,
DifficultyCut: DifficultyCut,
DifficultyPowStarter: DifficultyPowStarter,
DifficultyPosStarter: DifficultyPosStarter,
MaxBlockNumber: MaxBlockNumber,
TxMaxAllowedInputs: TxMaxAllowedInputs,
TxMaxAllowedOutputs: TxMaxAllowedOutputs,
DefaultDecoySetSize: DefaultDecoySetSize,
HF4MandatoryDecoySetSize: HF4MandatoryDecoySetSize,
MinedMoneyUnlockWindow: MinedMoneyUnlockWindow,
P2PMaintainersPubKey: "8f138bb73f6d663a3746a542770781a09579a7b84cb4125249e95530824ee607",
NetworkID: NetworkIDMainnet,
}
// Testnet holds the chain configuration for the Lethean testnet.
var Testnet = ChainConfig{
Name: CurrencyNameBase + "_testnet",
Abbreviation: CurrencyNameAbbreviation,
IsTestnet: true,
CurrencyFormationVersion: CurrencyFormationVersionTestnet,
Coin: Coin,
DisplayDecimalPoint: DisplayDecimalPoint,
BlockReward: BlockReward,
DefaultFee: DefaultFee,
MinimumFee: MinimumFee,
Premine: Premine,
AddressPrefix: AddressPrefix,
IntegratedAddressPrefix: IntegratedAddressPrefix,
AuditableAddressPrefix: AuditableAddressPrefix,
AuditableIntegratedAddressPrefix: AuditableIntegratedAddressPrefix,
P2PPort: TestnetP2PPort,
RPCPort: TestnetRPCPort,
StratumPort: TestnetStratumPort,
DifficultyPowTarget: DifficultyPowTarget,
DifficultyPosTarget: DifficultyPosTarget,
DifficultyWindow: DifficultyWindow,
DifficultyLag: DifficultyLag,
DifficultyCut: DifficultyCut,
DifficultyPowStarter: DifficultyPowStarter,
DifficultyPosStarter: DifficultyPosStarter,
MaxBlockNumber: MaxBlockNumber,
TxMaxAllowedInputs: TxMaxAllowedInputs,
TxMaxAllowedOutputs: TxMaxAllowedOutputs,
DefaultDecoySetSize: DefaultDecoySetSize,
HF4MandatoryDecoySetSize: HF4MandatoryDecoySetSize,
MinedMoneyUnlockWindow: MinedMoneyUnlockWindow,
P2PMaintainersPubKey: "8f138bb73f6d663a3746a542770781a09579a7b84cb4125249e95530824ee607",
NetworkID: NetworkIDTestnet,
}