Files
zeekayandHanzo Dev 1a0b7f8835 Merge the four runtime ports, and put the Go generator beside its output
port/xvm-cpp, port/xvm-rust, port/platformvm-rust and port/platformvm-cpp
land on main; the only overlaps were documents, taken from the ports.

The xvm C++ port kept its Go golden-vector generator in the directory with the
C++ tests it feeds, which Go refuses to build as a package. It lives in
test/golden/ now; the comments and the recipe that name it follow it. The
sums the ports' Go test helpers need were never tidied in; they are.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-04 11:05:35 -07:00

317 lines
9.3 KiB
Go

// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// SPDX-License-Identifier: BSD-3-Clause-Eco
//
// Reference-vector generator: builds X-Chain values with the GO implementation
// (github.com/luxfi/node/vms/xvm) and prints their canonical wire bytes as a C++
// header. The C++ port's wire test asserts against these bytes verbatim, so the
// two implementations cannot drift without a test failing.
//
// Run from the node checkout: GOWORK=off go run <this file> > golden.hpp
package main
import (
"fmt"
"os"
"time"
"github.com/luxfi/ids"
"github.com/luxfi/node/vms/components/verify"
"github.com/luxfi/node/vms/xvm"
"github.com/luxfi/node/vms/xvm/block"
"github.com/luxfi/node/vms/xvm/fxs"
"github.com/luxfi/node/vms/xvm/txs"
lux "github.com/luxfi/utxo"
"github.com/luxfi/utxo/nftfx"
"github.com/luxfi/utxo/propertyfx"
"github.com/luxfi/utxo/secp256k1fx"
"github.com/luxfi/utxo/wire"
)
func emit(name string, b []byte) {
fmt.Printf("inline constexpr const char* %s =\n \"%x\";\n", name, b)
}
func addr(n byte) ids.ShortID {
var a ids.ShortID
for i := range a {
a[i] = n + byte(i)
}
return a
}
func id(n byte) ids.ID {
var a ids.ID
for i := range a {
a[i] = n + byte(i)
}
return a
}
func sig(n byte) [65]byte {
var s [65]byte
for i := range s {
s[i] = n + byte(i)
}
return s
}
func main() {
fmt.Println("// Copyright (C) 2026, Lux Industries Inc. All rights reserved.")
fmt.Println("// SPDX-License-Identifier: BSD-3-Clause-Eco")
fmt.Println("//")
fmt.Println("// GENERATED by chains/cpp/xvm/test/golden_gen.go — do not edit.")
fmt.Println("//")
fmt.Println("// Every constant is the hex of a canonical wire buffer produced by the GO")
fmt.Println("// X-Chain (github.com/luxfi/node/vms/xvm). They are the port's contract: the")
fmt.Println("// C++ implementation must emit these bytes, or the two are different chains.")
fmt.Println("#pragma once")
fmt.Println("namespace lux::xvm::golden {")
// ---- fx primitives ----
owners := secp256k1fx.OutputOwners{Locktime: 12345, Threshold: 1, Addrs: []ids.ShortID{addr(1)}}
emit("kOutputOwners", owners.Bytes())
twoOwners := secp256k1fx.OutputOwners{Locktime: 0, Threshold: 2, Addrs: []ids.ShortID{addr(1), addr(40)}}
emit("kOutputOwnersTwo", twoOwners.Bytes())
transferOut := &secp256k1fx.TransferOutput{Amt: 54321, OutputOwners: owners}
emit("kTransferOutput", transferOut.Bytes())
transferIn := &secp256k1fx.TransferInput{Amt: 54321, Input: secp256k1fx.Input{SigIndices: []uint32{0, 3}}}
emit("kTransferInput", transferIn.Bytes())
mintOut := &secp256k1fx.MintOutput{OutputOwners: owners}
emit("kMintOutput", mintOut.Bytes())
mintOp := &secp256k1fx.MintOperation{
MintInput: secp256k1fx.Input{SigIndices: []uint32{0}},
MintOutput: *mintOut,
TransferOutput: *transferOut,
}
emit("kMintOperation", mintOp.Bytes())
cred := &secp256k1fx.Credential{Sigs: [][65]byte{sig(7), sig(9)}}
emit("kCredential", cred.Bytes())
nftMintOut := &nftfx.MintOutput{GroupID: 7, OutputOwners: owners}
emit("kNFTMintOutput", nftMintOut.Bytes())
nftTransferOut := &nftfx.TransferOutput{GroupID: 7, Payload: []byte("hello nft"), OutputOwners: owners}
emit("kNFTTransferOutput", nftTransferOut.Bytes())
nftMintOp := &nftfx.MintOperation{
MintInput: secp256k1fx.Input{SigIndices: []uint32{0}},
GroupID: 7,
Payload: []byte("hello nft"),
Outputs: []*secp256k1fx.OutputOwners{&owners, &twoOwners},
}
emit("kNFTMintOperation", nftMintOp.Bytes())
nftTransferOp := &nftfx.TransferOperation{
Input: secp256k1fx.Input{SigIndices: []uint32{0, 1}},
Output: *nftTransferOut,
}
emit("kNFTTransferOperation", nftTransferOp.Bytes())
nftCred := &nftfx.Credential{Credential: secp256k1fx.Credential{Sigs: [][65]byte{sig(3)}}}
emit("kNFTCredential", nftCred.Bytes())
propMintOut := &propertyfx.MintOutput{OutputOwners: owners}
emit("kPropertyMintOutput", propMintOut.Bytes())
propOwnedOut := &propertyfx.OwnedOutput{OutputOwners: twoOwners}
emit("kPropertyOwnedOutput", propOwnedOut.Bytes())
propMintOp := &propertyfx.MintOperation{
MintInput: secp256k1fx.Input{SigIndices: []uint32{1}},
MintOutput: *propMintOut,
OwnedOutput: *propOwnedOut,
}
emit("kPropertyMintOperation", propMintOp.Bytes())
propBurnOp := &propertyfx.BurnOperation{Input: secp256k1fx.Input{SigIndices: []uint32{0}}}
emit("kPropertyBurnOperation", propBurnOp.Bytes())
propCred := &propertyfx.Credential{Credential: secp256k1fx.Credential{Sigs: [][65]byte{sig(11)}}}
emit("kPropertyCredential", propCred.Bytes())
// ---- UTXO ----
utxo := &lux.UTXO{
UTXOID: lux.UTXOID{TxID: id(100), OutputIndex: 3},
Asset: lux.Asset{ID: id(50)},
Out: transferOut,
}
utxoBytes, err := utxo.WireBytes()
if err != nil {
panic(err)
}
emit("kUTXO", utxoBytes)
emit("kUTXOInputID", func() []byte { i := utxo.InputID(); return i[:] }())
// ---- the five transactions ----
networkID := uint32(10)
chainID := id(200)
baseFields := lux.BaseTx{
NetworkID: networkID,
BlockchainID: chainID,
Outs: []*lux.TransferableOutput{{
Asset: lux.Asset{ID: id(50)},
Out: transferOut,
}},
Ins: []*lux.TransferableInput{{
UTXOID: lux.UTXOID{TxID: id(100), OutputIndex: 3},
Asset: lux.Asset{ID: id(50)},
In: transferIn,
}},
Memo: []byte("memo bytes"),
}
baseTx := &txs.BaseTx{BaseTx: baseFields}
baseUnsigned, err := txs.UnsignedBytes(baseTx)
if err != nil {
panic(err)
}
emit("kBaseTxUnsigned", baseUnsigned)
signedBase := &txs.Tx{Unsigned: baseTx, Creds: []*fxs.FxCredential{{Credential: cred}}}
if err := signedBase.Initialize(); err != nil {
panic(err)
}
emit("kBaseTxSigned", signedBase.Bytes())
emit("kBaseTxID", func() []byte { i := signedBase.ID(); return i[:] }())
createAssetTx := &txs.CreateAssetTx{
BaseTx: txs.BaseTx{BaseTx: baseFields},
Name: "Lux Test Asset",
Symbol: "LTA",
Denomination: 9,
States: []*txs.InitialState{{
FxIndex: 0,
Outs: []verify.State{mintOut, transferOut},
}},
}
// The genesis outputs must be in canonical wire order.
createAssetTx.States[0].Sort()
caUnsigned, err := txs.UnsignedBytes(createAssetTx)
if err != nil {
panic(err)
}
emit("kCreateAssetTxUnsigned", caUnsigned)
stateBytes, err := createAssetTx.States[0].Bytes()
if err != nil {
panic(err)
}
emit("kInitialState", stateBytes)
op := &txs.Operation{
Asset: lux.Asset{ID: id(50)},
UTXOIDs: []*lux.UTXOID{{TxID: id(100), OutputIndex: 1}, {TxID: id(100), OutputIndex: 4}},
Op: mintOp,
}
opBytes, err := op.Bytes()
if err != nil {
panic(err)
}
emit("kOperation", opBytes)
opTx := &txs.OperationTx{
BaseTx: txs.BaseTx{BaseTx: baseFields},
Ops: []*txs.Operation{op},
}
opUnsigned, err := txs.UnsignedBytes(opTx)
if err != nil {
panic(err)
}
emit("kOperationTxUnsigned", opUnsigned)
importTx := &txs.ImportTx{
BaseTx: txs.BaseTx{BaseTx: baseFields},
SourceChain: id(77),
ImportedIns: []*lux.TransferableInput{{
UTXOID: lux.UTXOID{TxID: id(150), OutputIndex: 0},
Asset: lux.Asset{ID: id(50)},
In: transferIn,
}},
}
importUnsigned, err := txs.UnsignedBytes(importTx)
if err != nil {
panic(err)
}
emit("kImportTxUnsigned", importUnsigned)
exportTx := &txs.ExportTx{
BaseTx: txs.BaseTx{BaseTx: baseFields},
DestinationChain: id(88),
ExportedOuts: []*lux.TransferableOutput{{
Asset: lux.Asset{ID: id(50)},
Out: transferOut,
}},
}
exportUnsigned, err := txs.UnsignedBytes(exportTx)
if err != nil {
panic(err)
}
emit("kExportTxUnsigned", exportUnsigned)
// ---- a block carrying that signed BaseTx ----
blk, err := block.NewStandardBlock(id(210), 7, time.Unix(1730000000, 0), []*txs.Tx{signedBase})
if err != nil {
panic(err)
}
emit("kStandardBlock", blk.Bytes())
emit("kStandardBlockID", func() []byte { i := blk.ID(); return i[:] }())
blkRoot, err := block.NewStandardBlockWithRoot(id(210), 7, time.Unix(1730000000, 0), id(220), []*txs.Tx{signedBase})
if err != nil {
panic(err)
}
emit("kStandardBlockWithRoot", blkRoot.Bytes())
// ---- the XVMBaseTx envelope alone, and the SignedTx envelope alone ----
emit("kXVMBaseTxEnvelope", wire.NewXVMBaseTx(wire.XVMBaseTxInput{
NetworkID: networkID,
BlockchainID: [32]byte(chainID),
Outs: []wire.XVMTransferOut{{AssetID: id(50), Output: transferOut.Bytes()}},
Ins: []wire.XVMTransferIn{{
TxID: id(100), OutputIndex: 3, AssetID: id(50), Input: transferIn.Bytes(),
}},
Memo: []byte("memo bytes"),
}))
// ---- the genesis buffer a host hands the chain ----
//
// Two assets, so the alias/tx length lists carry more than one entry and a
// C++ reader that only ever reads element zero would be caught.
secondAsset := &txs.CreateAssetTx{
BaseTx: txs.BaseTx{BaseTx: lux.BaseTx{NetworkID: networkID, BlockchainID: ids.Empty}},
Name: "Second Asset",
Symbol: "SEC",
Denomination: 0,
States: []*txs.InitialState{{
FxIndex: 0,
Outs: []verify.State{mintOut},
}},
}
secondAsset.States[0].Sort()
gen := &xvm.Genesis{Txs: []*xvm.GenesisAsset{
{Alias: "LTA", CreateAssetTx: *createAssetTx},
{Alias: "SEC", CreateAssetTx: *secondAsset},
}}
genBytes, err := gen.Bytes()
if err != nil {
panic(err)
}
emit("kGenesis", genBytes)
firstAssetID, err := xvm.AssetIDFromGenesisBytes(genBytes)
if err != nil {
panic(err)
}
emit("kGenesisFeeAssetID", firstAssetID[:])
fmt.Println("} // namespace lux::xvm::golden")
_ = os.Stdout
}