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>
200 lines
6.4 KiB
Go
200 lines
6.4 KiB
Go
// Copyright (c) 2017-2026 Lethean (https://lt.hn)
|
|
//
|
|
// Licensed under the European Union Public Licence (EUPL) version 1.2.
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
package config
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestMainnetConstants_Good(t *testing.T) {
|
|
// Verify tokenomics match C++ source (default.cmake).
|
|
if Coin != 1_000_000_000_000 {
|
|
t.Errorf("Coin: got %d, want 1000000000000", Coin)
|
|
}
|
|
if DisplayDecimalPoint != 12 {
|
|
t.Errorf("DisplayDecimalPoint: got %d, want 12", DisplayDecimalPoint)
|
|
}
|
|
if BlockReward != 1_000_000_000_000 {
|
|
t.Errorf("BlockReward: got %d, want 1000000000000", BlockReward)
|
|
}
|
|
if DefaultFee != 10_000_000_000 {
|
|
t.Errorf("DefaultFee: got %d, want 10000000000", DefaultFee)
|
|
}
|
|
if MinimumFee != 10_000_000_000 {
|
|
t.Errorf("MinimumFee: got %d, want 10000000000", MinimumFee)
|
|
}
|
|
if BaseRewardDustThreshold != 1_000_000 {
|
|
t.Errorf("BaseRewardDustThreshold: got %d, want 1000000", BaseRewardDustThreshold)
|
|
}
|
|
if DefaultDustThreshold != 0 {
|
|
t.Errorf("DefaultDustThreshold: got %d, want 0", DefaultDustThreshold)
|
|
}
|
|
}
|
|
|
|
func TestMainnetAddressPrefixes_Good(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
got uint64
|
|
want uint64
|
|
}{
|
|
{"AddressPrefix", AddressPrefix, 0x1eaf7},
|
|
{"IntegratedAddressPrefix", IntegratedAddressPrefix, 0xdeaf7},
|
|
{"AuditableAddressPrefix", AuditableAddressPrefix, 0x3ceff7},
|
|
{"AuditableIntegratedAddressPrefix", AuditableIntegratedAddressPrefix, 0x8b077},
|
|
}
|
|
for _, tt := range tests {
|
|
if tt.got != tt.want {
|
|
t.Errorf("%s: got 0x%x, want 0x%x", tt.name, tt.got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMainnetPorts_Good(t *testing.T) {
|
|
if Mainnet.P2PPort != 36942 {
|
|
t.Errorf("Mainnet P2P port: got %d, want 36942", Mainnet.P2PPort)
|
|
}
|
|
if Mainnet.RPCPort != 36941 {
|
|
t.Errorf("Mainnet RPC port: got %d, want 36941", Mainnet.RPCPort)
|
|
}
|
|
if Mainnet.StratumPort != 36940 {
|
|
t.Errorf("Mainnet Stratum port: got %d, want 36940", Mainnet.StratumPort)
|
|
}
|
|
}
|
|
|
|
func TestTestnetPortDifferences_Good(t *testing.T) {
|
|
if Testnet.P2PPort != 46942 {
|
|
t.Errorf("Testnet P2P port: got %d, want 46942", Testnet.P2PPort)
|
|
}
|
|
if Testnet.RPCPort != 46941 {
|
|
t.Errorf("Testnet RPC port: got %d, want 46941", Testnet.RPCPort)
|
|
}
|
|
if Testnet.StratumPort != 46940 {
|
|
t.Errorf("Testnet Stratum port: got %d, want 46940", Testnet.StratumPort)
|
|
}
|
|
if Testnet.P2PPort == Mainnet.P2PPort {
|
|
t.Error("Testnet and Mainnet P2P ports must differ")
|
|
}
|
|
}
|
|
|
|
func TestDifficultyConstants_Good(t *testing.T) {
|
|
if DifficultyPowTarget != 120 {
|
|
t.Errorf("DifficultyPowTarget: got %d, want 120", DifficultyPowTarget)
|
|
}
|
|
if DifficultyPosTarget != 120 {
|
|
t.Errorf("DifficultyPosTarget: got %d, want 120", DifficultyPosTarget)
|
|
}
|
|
if DifficultyTotalTarget != 60 {
|
|
t.Errorf("DifficultyTotalTarget: got %d, want 60 ((120+120)/4)", DifficultyTotalTarget)
|
|
}
|
|
if DifficultyWindow != 720 {
|
|
t.Errorf("DifficultyWindow: got %d, want 720", DifficultyWindow)
|
|
}
|
|
if DifficultyLag != 15 {
|
|
t.Errorf("DifficultyLag: got %d, want 15", DifficultyLag)
|
|
}
|
|
if DifficultyCut != 60 {
|
|
t.Errorf("DifficultyCut: got %d, want 60", DifficultyCut)
|
|
}
|
|
if DifficultyBlocksCount != 735 {
|
|
t.Errorf("DifficultyBlocksCount: got %d, want 735 (720+15)", DifficultyBlocksCount)
|
|
}
|
|
}
|
|
|
|
func TestNetworkIdentity_Good(t *testing.T) {
|
|
if CurrencyFormationVersion != 84 {
|
|
t.Errorf("CurrencyFormationVersion: got %d, want 84", CurrencyFormationVersion)
|
|
}
|
|
if CurrencyFormationVersionTestnet != 100 {
|
|
t.Errorf("CurrencyFormationVersionTestnet: got %d, want 100", CurrencyFormationVersionTestnet)
|
|
}
|
|
if P2PNetworkIDVer != 84 {
|
|
t.Errorf("P2PNetworkIDVer: got %d, want 84 (84+0)", P2PNetworkIDVer)
|
|
}
|
|
}
|
|
|
|
func TestChainConfigStruct_Good(t *testing.T) {
|
|
// Verify Mainnet struct fields are populated correctly.
|
|
if Mainnet.Name != "Lethean" {
|
|
t.Errorf("Mainnet.Name: got %q, want %q", Mainnet.Name, "Lethean")
|
|
}
|
|
if Mainnet.Abbreviation != "LTHN" {
|
|
t.Errorf("Mainnet.Abbreviation: got %q, want %q", Mainnet.Abbreviation, "LTHN")
|
|
}
|
|
if Mainnet.IsTestnet {
|
|
t.Error("Mainnet.IsTestnet should be false")
|
|
}
|
|
if !Testnet.IsTestnet {
|
|
t.Error("Testnet.IsTestnet should be true")
|
|
}
|
|
if Testnet.Name != "Lethean_testnet" {
|
|
t.Errorf("Testnet.Name: got %q, want %q", Testnet.Name, "Lethean_testnet")
|
|
}
|
|
}
|
|
|
|
func TestTransactionLimits_Good(t *testing.T) {
|
|
if TxMaxAllowedInputs != 256 {
|
|
t.Errorf("TxMaxAllowedInputs: got %d, want 256", TxMaxAllowedInputs)
|
|
}
|
|
if TxMaxAllowedOutputs != 2000 {
|
|
t.Errorf("TxMaxAllowedOutputs: got %d, want 2000", TxMaxAllowedOutputs)
|
|
}
|
|
if DefaultDecoySetSize != 10 {
|
|
t.Errorf("DefaultDecoySetSize: got %d, want 10", DefaultDecoySetSize)
|
|
}
|
|
if HF4MandatoryDecoySetSize != 15 {
|
|
t.Errorf("HF4MandatoryDecoySetSize: got %d, want 15", HF4MandatoryDecoySetSize)
|
|
}
|
|
}
|
|
|
|
func TestTransactionVersionConstants_Good(t *testing.T) {
|
|
if TransactionVersionInitial != 0 {
|
|
t.Errorf("TransactionVersionInitial: got %d, want 0", TransactionVersionInitial)
|
|
}
|
|
if TransactionVersionPreHF4 != 1 {
|
|
t.Errorf("TransactionVersionPreHF4: got %d, want 1", TransactionVersionPreHF4)
|
|
}
|
|
if TransactionVersionPostHF4 != 2 {
|
|
t.Errorf("TransactionVersionPostHF4: got %d, want 2", TransactionVersionPostHF4)
|
|
}
|
|
if TransactionVersionPostHF5 != 3 {
|
|
t.Errorf("TransactionVersionPostHF5: got %d, want 3", TransactionVersionPostHF5)
|
|
}
|
|
if CurrentTransactionVersion != 3 {
|
|
t.Errorf("CurrentTransactionVersion: got %d, want 3", CurrentTransactionVersion)
|
|
}
|
|
}
|
|
|
|
func TestNetworkID_Good(t *testing.T) {
|
|
// In the C++ source, #ifndef TESTNET (mainnet) sets
|
|
// P2P_NETWORK_ID_TESTNET_FLAG=1 and #else (testnet) sets it to 0.
|
|
// The naming is counter-intuitive but matches the compiled binaries.
|
|
|
|
// Mainnet: byte 10 = 1 (flag from #ifndef branch), byte 15 = 84 (0x54)
|
|
if NetworkIDMainnet[10] != 0x01 {
|
|
t.Errorf("mainnet flag: got %x, want 0x01", NetworkIDMainnet[10])
|
|
}
|
|
if NetworkIDMainnet[15] != 0x54 {
|
|
t.Errorf("mainnet version: got %x, want 0x54", NetworkIDMainnet[15])
|
|
}
|
|
// Testnet: byte 10 = 0 (flag from #else branch), byte 15 = 100 (0x64)
|
|
if NetworkIDTestnet[10] != 0x00 {
|
|
t.Errorf("testnet flag: got %x, want 0x00", NetworkIDTestnet[10])
|
|
}
|
|
if NetworkIDTestnet[15] != 0x64 {
|
|
t.Errorf("testnet version: got %x, want 0x64", NetworkIDTestnet[15])
|
|
}
|
|
// The two IDs must differ.
|
|
if NetworkIDMainnet == NetworkIDTestnet {
|
|
t.Error("mainnet and testnet IDs must differ")
|
|
}
|
|
// ChainConfig should have them
|
|
if Mainnet.NetworkID != NetworkIDMainnet {
|
|
t.Error("Mainnet.NetworkID mismatch")
|
|
}
|
|
if Testnet.NetworkID != NetworkIDTestnet {
|
|
t.Error("Testnet.NetworkID mismatch")
|
|
}
|
|
}
|