Skip to content

Commit c71fd33

Browse files
committed
feat(params,consensus/XDPoS): log stable structured v2 startup config
Add V2.StableLogValue to expose full deterministic startup config data, including sorted allConfigs and explicit configIndex. Switch XDPoS.New to log the structured stable view directly so terminal output avoids escaped JSON strings while retaining complete diagnostics coverage.
1 parent 29e51ce commit c71fd33

5 files changed

Lines changed: 122 additions & 2 deletions

File tree

consensus/XDPoS/XDPoS.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,6 @@ func New(chainConfig *params.ChainConfig, db ethdb.Database) (*XDPoS, error) {
9999
return nil, errors.New("missing XDPoS config")
100100
}
101101

102-
log.Info("xdc config loading", "v2 config", config.V2)
103-
104102
minePeriodCh := make(chan int)
105103
newRoundCh := make(chan types.Round, newRoundChanSize)
106104
engineV2, err := engine_v2.New(chainConfig, db, minePeriodCh, newRoundCh)

eth/backend.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin
149149
if err != nil {
150150
return nil, err
151151
}
152+
logXDPoSConfig(chainConfig, compatErr)
152153

153154
// Assemble the Ethereum object.
154155
eth := &Ethereum{
@@ -462,6 +463,14 @@ func (e *Ethereum) APIs() []rpc.API {
462463
}...)
463464
}
464465

466+
func logXDPoSConfig(chainConfig *params.ChainConfig, compatErr *params.ConfigCompatError) {
467+
if compatErr != nil || chainConfig == nil || chainConfig.XDPoS == nil || chainConfig.XDPoS.V2 == nil {
468+
return
469+
}
470+
471+
log.Info("Load xdc config", "config.V2", chainConfig.XDPoS.V2.StableLogValue())
472+
}
473+
465474
func (e *Ethereum) ResetWithGenesisBlock(gb *types.Block) {
466475
e.blockchain.ResetWithGenesisBlock(gb)
467476
}

eth/backend_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package eth
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"math/big"
7+
"strings"
68
"testing"
79

810
"github.com/XinFinOrg/XDPoSChain/common"
911
"github.com/XinFinOrg/XDPoSChain/core"
1012
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
1113
"github.com/XinFinOrg/XDPoSChain/core/types"
1214
"github.com/XinFinOrg/XDPoSChain/eth/util"
15+
"github.com/XinFinOrg/XDPoSChain/log"
1316
"github.com/XinFinOrg/XDPoSChain/params"
1417
)
1518

@@ -44,6 +47,29 @@ func TestRewardInflationUsesChainConfigTIPNoHalvingMNReward(t *testing.T) {
4447
}
4548
}
4649

50+
func TestLogXDPoSConfigSkipsOnCompatError(t *testing.T) {
51+
var logBuf bytes.Buffer
52+
prevLog := log.Root()
53+
glog := log.NewGlogHandler(log.NewTerminalHandlerWithLevel(&logBuf, log.LevelTrace, false))
54+
glog.Verbosity(log.LevelTrace)
55+
log.SetDefault(log.NewLogger(glog))
56+
defer log.SetDefault(prevLog)
57+
58+
logXDPoSConfig(params.TestnetChainConfig, &params.ConfigCompatError{What: "XDPoS.V2"})
59+
if got := logBuf.String(); got != "" {
60+
t.Fatalf("expected no XDPoS config log on compat error, got %q", got)
61+
}
62+
63+
logXDPoSConfig(params.TestnetChainConfig, nil)
64+
got := logBuf.String()
65+
if !strings.Contains(got, "Load xdc config") {
66+
t.Fatalf("expected XDPoS config log on healthy startup, got %q", got)
67+
}
68+
if !strings.Contains(got, "config.V2") {
69+
t.Fatalf("expected V2 config details in startup log, got %q", got)
70+
}
71+
}
72+
4773
type testChainReader struct {
4874
cfg *params.ChainConfig
4975
}

params/config_xdpos.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,54 @@ func (v2 *V2) String() string {
521521
return fmt.Sprintf("V2{SwitchEpoch: %v, SwitchBlock: %v, %s}", snapshot.switchEpoch, snapshot.switchBlock, snapshot.currentConfig.String())
522522
}
523523

524+
type stableLogConfigEntry struct {
525+
Round uint64 `json:"round"`
526+
Config *V2Config `json:"config"`
527+
}
528+
529+
type stableLogView struct {
530+
SwitchEpoch uint64 `json:"switchEpoch"`
531+
SwitchBlock string `json:"switchBlock"`
532+
CurrentConfig *V2Config `json:"currentConfig"`
533+
AllConfigs []stableLogConfigEntry `json:"allConfigs"`
534+
ConfigIndex []uint64 `json:"configIndex"`
535+
}
536+
537+
// StableLogValue returns a full, deterministic structured value for startup
538+
// logs. Callers can pass the returned object directly as a field value to
539+
// avoid JSON string escaping in terminal log output.
540+
func (v2 *V2) StableLogValue() stableLogView {
541+
if v2 == nil {
542+
return stableLogView{}
543+
}
544+
545+
snapshot := snapshotV2ReadOnly(v2)
546+
547+
keys := slices.Collect(maps.Keys(snapshot.allConfigs))
548+
slices.Sort(keys)
549+
550+
allConfigs := make([]stableLogConfigEntry, 0, len(keys))
551+
for _, round := range keys {
552+
allConfigs = append(allConfigs, stableLogConfigEntry{
553+
Round: round,
554+
Config: snapshot.allConfigs[round].Clone(),
555+
})
556+
}
557+
558+
var switchBlock string
559+
if snapshot.switchBlock != nil {
560+
switchBlock = snapshot.switchBlock.String()
561+
}
562+
563+
return stableLogView{
564+
SwitchEpoch: snapshot.switchEpoch,
565+
SwitchBlock: switchBlock,
566+
CurrentConfig: snapshot.currentConfig.Clone(),
567+
AllConfigs: allConfigs,
568+
ConfigIndex: append([]uint64(nil), snapshot.configIndex...),
569+
}
570+
}
571+
524572
// Description returns a human-readable description of V2
525573
// NOTE: don't append "\n" to end
526574
func (v2 *V2) Description(indent int) string {

params/config_xdpos_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package params
1919
import (
2020
"encoding/json"
2121
"math/big"
22+
"strings"
2223
"sync"
2324
"testing"
2425

@@ -192,6 +193,44 @@ func TestV2StringConcurrentWithUpdateConfig(t *testing.T) {
192193
wg.Wait()
193194
}
194195

196+
func TestV2StableLogValueDeterministicAndComplete(t *testing.T) {
197+
v2 := &V2{
198+
SwitchEpoch: 63143,
199+
SwitchBlock: big.NewInt(56828700),
200+
CurrentConfig: &V2Config{
201+
MaxMasternodes: 15,
202+
},
203+
AllConfigs: map[uint64]*V2Config{
204+
10: {SwitchRound: 10, MaxMasternodes: 16},
205+
0: {SwitchRound: 0, MaxMasternodes: 15},
206+
},
207+
configIndex: []uint64{10, 0},
208+
}
209+
210+
firstBytes, err := json.Marshal(v2.StableLogValue())
211+
assert.NoError(t, err)
212+
secondBytes, err := json.Marshal(v2.StableLogValue())
213+
assert.NoError(t, err)
214+
215+
first := string(firstBytes)
216+
second := string(secondBytes)
217+
assert.Equal(t, first, second)
218+
219+
assert.Contains(t, first, `"switchEpoch":63143`)
220+
assert.Contains(t, first, `"switchBlock":"56828700"`)
221+
assert.Contains(t, first, `"configIndex":[10,0]`)
222+
assert.Contains(t, first, `"currentConfig"`)
223+
224+
idxRound0 := strings.Index(first, `"round":0`)
225+
idxRound10 := strings.Index(first, `"round":10`)
226+
if idxRound0 == -1 || idxRound10 == -1 {
227+
t.Fatalf("expected allConfigs rounds in stable log output, got %q", first)
228+
}
229+
if idxRound0 > idxRound10 {
230+
t.Fatalf("expected allConfigs rounds sorted ascending, got %q", first)
231+
}
232+
}
233+
195234
func TestBuildConfigIndex(t *testing.T) {
196235
TestXDPoSMockChainConfig.XDPoS.V2.BuildConfigIndex()
197236
index := TestXDPoSMockChainConfig.XDPoS.V2.ConfigIndex()

0 commit comments

Comments
 (0)