mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
External (HTTP / JSON-RPC) is the only place JSON is legitimate. Every
existing encoding/json import in node/ moves to github.com/go-json-experiment/json
(v2 root, not the v1 sub-package). NewEncoder/NewDecoder rewrite to
MarshalWrite/UnmarshalRead. MarshalIndent rewrites to Marshal with
jsontext.WithIndent. json.RawMessage rewrites to jsontext.Value.
*json.SyntaxError rewrites to *jsontext.SyntacticError.
81 files migrated. LLM.md captures the rule + v1->v2 delta table.
Known v2 semantic deltas surfaced by existing tests (followups, not regressions):
- [N]byte fields with no MarshalJSON now marshal as base64 string (v1 marshalled
as JSON array of byte numbers). Affects vms/platformvm/txs/*_test.go fixtures
with embedded BLS proofOfPossession.
- time.Duration has no v2 default representation; configs that wire-format
Duration as nanoseconds (vms/{xvm,platformvm}/config, config/spec) need to
switch to string-form Duration or carry an explicit option. v2 root does not
re-export FormatDurationAsNano.
- v2 enforces strict UTF-8 (vms/chainadapter/messaging fixture has non-UTF-8).
- json.MarshalWrite does not append a trailing '\n' (v1 NewEncoder.Encode did);
service/auth/auth_test.go expectation updated.
- nil []byte round-trips to empty (not nil); config_test deep-equal fixtures
surface this.
All affected sites are at the API boundary; ZAP wire envelope already covers
the internal data paths (state, P2P, consensus, MPC, threshold). Internal
JSON sites that should move to ZAP next (separate work):
- vms/da/store.go (DA blob/cert storage as JSON)
- vms/platformvm/airdrop (airdrop claims as JSON in db)
- vms/chainadapter/appchain (SQLite materializer schema/data blobs)
- vms/chainadapter/messaging (conversation codec)
- staking/kms.go (KMS HTTP client — external technically, leave)
- utils/{bimap,ips} (small marshaler shims — low priority)
162 lines
4.6 KiB
Go
162 lines
4.6 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package info
|
|
|
|
import (
|
|
"errors"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/go-json-experiment/json"
|
|
"github.com/luxfi/mock/gomock"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
apiinfo "github.com/luxfi/api/info"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/log"
|
|
"github.com/luxfi/node/version"
|
|
"github.com/luxfi/node/vms/vmsmock"
|
|
)
|
|
|
|
var errTest = errors.New("non-nil error")
|
|
|
|
type getVMsTest struct {
|
|
info *Info
|
|
mockVMManager *vmsmock.Manager
|
|
}
|
|
|
|
func initGetVMsTest(t *testing.T) *getVMsTest {
|
|
ctrl := gomock.NewController(t)
|
|
mockVMManager := vmsmock.NewManager(ctrl)
|
|
return &getVMsTest{
|
|
info: &Info{
|
|
Parameters: Parameters{
|
|
VMManager: mockVMManager,
|
|
},
|
|
log: log.NewNoOpLogger(),
|
|
},
|
|
mockVMManager: mockVMManager,
|
|
}
|
|
}
|
|
|
|
// TestGetNodeVersionConsensusRoundtrip verifies the consensus subobject is
|
|
// surfaced via info.getNodeVersion when wired through Parameters and is
|
|
// omitted entirely (omitempty) when left unset.
|
|
func TestGetNodeVersionConsensusRoundtrip(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
consensus := &apiinfo.ConsensusInfo{
|
|
Mode: "triple",
|
|
BLS: true,
|
|
Corona: true,
|
|
MLDSA: true,
|
|
PlatformVM: true,
|
|
}
|
|
|
|
app := &version.Application{Name: "lux", Major: 1, Minor: 0, Patch: 0}
|
|
|
|
info := &Info{
|
|
Parameters: Parameters{
|
|
Version: app,
|
|
Consensus: consensus,
|
|
},
|
|
log: log.NewNoOpLogger(),
|
|
}
|
|
|
|
req := httptest.NewRequest("POST", "/ext/info", nil)
|
|
reply := apiinfo.GetNodeVersionReply{}
|
|
require.NoError(info.GetNodeVersion(req, nil, &reply))
|
|
require.NotNil(reply.Consensus)
|
|
require.Equal(*consensus, *reply.Consensus)
|
|
|
|
// Mutating the reply value must not bleed back into Parameters — confirms
|
|
// the handler returns a copy, not a shared pointer.
|
|
reply.Consensus.Mode = "classical"
|
|
require.Equal("triple", info.Consensus.Mode)
|
|
|
|
// JSON omitempty: when Consensus is unset, it must not appear in the
|
|
// serialised reply at all (legacy clients ignore it; new clients can
|
|
// detect "not advertised" vs "classical" mode).
|
|
bare := &Info{
|
|
Parameters: Parameters{Version: app},
|
|
log: log.NewNoOpLogger(),
|
|
}
|
|
bareReply := apiinfo.GetNodeVersionReply{}
|
|
require.NoError(bare.GetNodeVersion(req, nil, &bareReply))
|
|
require.Nil(bareReply.Consensus)
|
|
|
|
encoded, err := json.Marshal(bareReply)
|
|
require.NoError(err)
|
|
require.NotContains(string(encoded), "consensus")
|
|
|
|
encoded, err = json.Marshal(reply)
|
|
require.NoError(err)
|
|
require.Contains(string(encoded), `"consensus"`)
|
|
require.Contains(string(encoded), `"mode":"classical"`)
|
|
}
|
|
|
|
// Tests GetVMs in the happy-case
|
|
func TestGetVMsSuccess(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
resources := initGetVMsTest(t)
|
|
|
|
id1 := ids.GenerateTestID()
|
|
id2 := ids.GenerateTestID()
|
|
|
|
vmIDs := []ids.ID{id1, id2}
|
|
alias1 := "vm1-alias-1"
|
|
alias2 := "vm2-alias-1"
|
|
// Primary alias should be the only returned alias.
|
|
expectedVMRegistry := map[ids.ID][]string{
|
|
id1: []string{alias1},
|
|
id2: []string{alias2},
|
|
}
|
|
|
|
req := httptest.NewRequest("POST", "/ext/info", nil)
|
|
resources.mockVMManager.EXPECT().ListFactories(req.Context()).Times(1).Return(vmIDs, nil)
|
|
resources.mockVMManager.EXPECT().PrimaryAlias(req.Context(), id1).Times(1).Return(alias1, nil)
|
|
resources.mockVMManager.EXPECT().PrimaryAlias(req.Context(), id2).Times(1).Return(alias2, nil)
|
|
|
|
reply := apiinfo.GetVMsReply{}
|
|
require.NoError(resources.info.GetVMs(req, nil, &reply))
|
|
require.Equal(expectedVMRegistry, reply.VMs)
|
|
}
|
|
|
|
// Tests GetVMs if we fail to list our vms.
|
|
func TestGetVMsVMsListFactoriesFails(t *testing.T) {
|
|
resources := initGetVMsTest(t)
|
|
|
|
req := httptest.NewRequest("POST", "/ext/info", nil)
|
|
resources.mockVMManager.EXPECT().ListFactories(req.Context()).Times(1).Return(nil, errTest)
|
|
|
|
reply := apiinfo.GetVMsReply{}
|
|
err := resources.info.GetVMs(req, nil, &reply)
|
|
require.ErrorIs(t, err, errTest)
|
|
}
|
|
|
|
// Tests GetVMs when a VM alias lookup fails.
|
|
func TestGetVMsGetAliasesFails(t *testing.T) {
|
|
require := require.New(t)
|
|
resources := initGetVMsTest(t)
|
|
|
|
id1 := ids.GenerateTestID()
|
|
id2 := ids.GenerateTestID()
|
|
vmIDs := []ids.ID{id1, id2}
|
|
alias1 := "vm1-alias-1"
|
|
|
|
req := httptest.NewRequest("POST", "/ext/info", nil)
|
|
resources.mockVMManager.EXPECT().ListFactories(req.Context()).Times(1).Return(vmIDs, nil)
|
|
resources.mockVMManager.EXPECT().PrimaryAlias(req.Context(), id1).Times(1).Return(alias1, nil)
|
|
resources.mockVMManager.EXPECT().PrimaryAlias(req.Context(), id2).Times(1).Return("", errTest)
|
|
|
|
reply := apiinfo.GetVMsReply{}
|
|
err := resources.info.GetVMs(req, nil, &reply)
|
|
require.NoError(err)
|
|
require.Equal(map[ids.ID][]string{
|
|
id1: []string{alias1},
|
|
id2: nil,
|
|
}, reply.VMs)
|
|
}
|