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)
123 lines
3.7 KiB
Go
123 lines
3.7 KiB
Go
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package xvm
|
|
|
|
import (
|
|
"context"
|
|
"github.com/go-json-experiment/json"
|
|
"errors"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
consensusconfig "github.com/luxfi/consensus/config"
|
|
"github.com/luxfi/constants"
|
|
"github.com/luxfi/database/memdb"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/node/vms/txs/auth"
|
|
xvmfx "github.com/luxfi/node/vms/xvm/fxs"
|
|
"github.com/luxfi/node/vms/xvm/txs"
|
|
"github.com/luxfi/runtime"
|
|
"github.com/luxfi/utxo/nftfx"
|
|
"github.com/luxfi/utxo/propertyfx"
|
|
"github.com/luxfi/utxo/secp256k1fx"
|
|
"github.com/luxfi/vm"
|
|
"github.com/luxfi/vm/chains/atomic"
|
|
)
|
|
|
|
// TestXVMInitialize_WiresSecurityProfileIntoMempool proves the F102
|
|
// close-out wiring on the X-chain: the SecurityProfile carried on
|
|
// xvm.Factory propagates through vm.Initialize → mempool.SetAuthPolicy.
|
|
//
|
|
// Strict-PQ chains refuse classical secp256k1 credentials at gossip
|
|
// time; the X-chain test exercises the unwrap path because X-chain
|
|
// credentials are wrapped in fxs.FxCredential before being checked by
|
|
// the auth policy gate.
|
|
//
|
|
// The test issues the tx via IssueTxFromRPCWithoutVerification, which
|
|
// skips block-state verification but still runs the mempool's
|
|
// SetAuthPolicy gate — that gate is the F102 close-out being verified
|
|
// here.
|
|
func TestXVMInitialize_WiresSecurityProfileIntoMempool(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
strictPQ := consensusconfig.StrictPQ()
|
|
vmImpl := &VM{
|
|
securityProfile: strictPQ,
|
|
classicalCompatRegistry: nil,
|
|
}
|
|
|
|
chainID := ids.GenerateTestID()
|
|
rt := &runtime.Runtime{
|
|
NetworkID: constants.UnitTestID,
|
|
ChainID: chainID,
|
|
XChainID: ids.GenerateTestID(),
|
|
CChainID: ids.GenerateTestID(),
|
|
NodeID: ids.GenerateTestNodeID(),
|
|
ValidatorState: &mockValidatorState{chainID: chainID},
|
|
}
|
|
|
|
baseDB := memdb.New()
|
|
sharedMemory := atomic.NewMemory(memdb.New())
|
|
vmImpl.SharedMemory = &testSharedMemory{mem: sharedMemory.NewSharedMemory(rt.ChainID)}
|
|
|
|
testLock := &sync.Mutex{}
|
|
testLock.Lock()
|
|
|
|
genesisBytes := newGenesisBytesTest(t)
|
|
fxs := []interface{}{
|
|
&vm.Fx{ID: secp256k1fx.ID, Fx: &secp256k1fx.Fx{}},
|
|
&vm.Fx{ID: nftfx.ID, Fx: &nftfx.Fx{}},
|
|
&vm.Fx{ID: propertyfx.ID, Fx: &propertyfx.Fx{}},
|
|
}
|
|
|
|
configBytes, err := json.Marshal(DefaultConfig)
|
|
require.NoError(err)
|
|
|
|
require.NoError(vmImpl.Initialize(
|
|
context.Background(),
|
|
vm.Init{
|
|
Runtime: rt,
|
|
DB: baseDB,
|
|
Genesis: genesisBytes,
|
|
Upgrade: nil,
|
|
Config: configBytes,
|
|
ToEngine: make(chan vm.Message, 1),
|
|
Fx: fxs,
|
|
Sender: &noOpSender{},
|
|
},
|
|
))
|
|
t.Cleanup(func() { _ = vmImpl.Shutdown() })
|
|
|
|
// Linearize so the mempool builder is constructed and SetAuthPolicy
|
|
// has fired with the strict-PQ profile.
|
|
stopVertexID := getCreateTxFromGenesisTest(t, genesisBytes, "LUX").ID()
|
|
require.NoError(vmImpl.Linearize(
|
|
context.Background(),
|
|
stopVertexID,
|
|
make(chan vm.Message, 1),
|
|
))
|
|
|
|
// Construct an X-chain tx whose Creds carry one FxCredential
|
|
// wrapping a classical *secp256k1fx.Credential. The mempool gate
|
|
// unwraps the FxCredential before consulting the auth policy.
|
|
tx := &txs.Tx{
|
|
Unsigned: &txs.BaseTx{},
|
|
Creds: []*xvmfx.FxCredential{
|
|
{Credential: &secp256k1fx.Credential{}},
|
|
},
|
|
}
|
|
|
|
// IssueTxFromRPCWithoutVerification reaches the mempool's
|
|
// AuthPolicy gate without going through block-state verification.
|
|
// The network is unexported on *VM; tests in-package access it
|
|
// directly to assert end-to-end wiring.
|
|
err = vmImpl.network.IssueTxFromRPCWithoutVerification(tx)
|
|
require.True(
|
|
errors.Is(err, auth.ErrLegacyCredentialUnderStrictPQ),
|
|
"IssueTxFromRPCWithoutVerification: got %v, want wrap of ErrLegacyCredentialUnderStrictPQ", err,
|
|
)
|
|
}
|