mirror of
https://github.com/luxfi/node.git
synced 2026-10-30 15:24:05 +00:00
The module already called itself github.com/luxfi/node while containing no node in Go: cmd/luxd was twenty-one lines that printed the size of a few types, and the Go column of the matrix measured a VM plugin. A repo that fetches the thing it claims to be has not replaced it, so the Go sources move in — 1515 files, the daemon and everything under it — and the build reaches outside this module for nothing. Rust and C++ sit beside it unchanged and are still measured against it by the differential. That is the point of one repo: the reference implementation and the two ports are the same checkout, so parity is a thing you can run rather than a thing you assert. Verified: builds, and the closure carries no lux-private — checked at build time rather than believed. The daemon starts twelve chains on a local network (P X C Q Z A B G K M F, plus D through its plugin) and reports healthy.
222 lines
5.2 KiB
Go
222 lines
5.2 KiB
Go
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package block
|
|
|
|
import (
|
|
"crypto"
|
|
"encoding/hex"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/node/staking"
|
|
"github.com/luxfi/zap"
|
|
)
|
|
|
|
func TestParseBlocks(t *testing.T) {
|
|
parentID := ids.ID{1}
|
|
timestamp := time.Unix(123, 0)
|
|
pChainHeight := uint64(2)
|
|
innerBlockBytes := []byte{3}
|
|
chainID := ids.ID{4}
|
|
|
|
tlsCert, err := staking.NewTLSCert()
|
|
require.NoError(t, err)
|
|
|
|
cert, err := staking.ParseCertificate(tlsCert.Leaf.Raw)
|
|
require.NoError(t, err)
|
|
key := tlsCert.PrivateKey.(crypto.Signer)
|
|
|
|
signedBlock, err := Build(
|
|
parentID,
|
|
timestamp,
|
|
pChainHeight,
|
|
Epoch{},
|
|
cert,
|
|
innerBlockBytes,
|
|
chainID,
|
|
key,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
signedBlockBytes := signedBlock.Bytes()
|
|
malformedBlockBytes := make([]byte, len(signedBlockBytes)-1)
|
|
copy(malformedBlockBytes, signedBlockBytes)
|
|
|
|
for _, testCase := range []struct {
|
|
name string
|
|
input [][]byte
|
|
output []ParseResult
|
|
}{
|
|
{
|
|
name: "ValidThenInvalid",
|
|
input: [][]byte{signedBlockBytes, malformedBlockBytes},
|
|
output: []ParseResult{{Block: &statelessBlock{bytes: signedBlockBytes}}, {Err: zap.ErrBufferTooSmall}},
|
|
},
|
|
{
|
|
name: "InvalidThenValid",
|
|
input: [][]byte{malformedBlockBytes, signedBlockBytes},
|
|
output: []ParseResult{{Err: zap.ErrBufferTooSmall}, {Block: &statelessBlock{bytes: signedBlockBytes}}},
|
|
},
|
|
} {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
results := ParseBlocks(testCase.input, chainID)
|
|
for i := range testCase.output {
|
|
if testCase.output[i].Block == nil {
|
|
require.Nil(t, results[i].Block)
|
|
require.ErrorIs(t, results[i].Err, testCase.output[i].Err)
|
|
} else {
|
|
require.Equal(t, testCase.output[i].Block.Bytes(), results[i].Block.Bytes())
|
|
require.NoError(t, results[i].Err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParse(t *testing.T) {
|
|
parentID := ids.ID{1}
|
|
timestamp := time.Unix(123, 0)
|
|
pChainHeight := uint64(2)
|
|
innerBlockBytes := []byte{3}
|
|
chainID := ids.ID{4}
|
|
|
|
tlsCert, err := staking.NewTLSCert()
|
|
require.NoError(t, err)
|
|
|
|
cert, err := staking.ParseCertificate(tlsCert.Leaf.Raw)
|
|
require.NoError(t, err)
|
|
key := tlsCert.PrivateKey.(crypto.Signer)
|
|
|
|
signedBlock, err := Build(
|
|
parentID,
|
|
timestamp,
|
|
pChainHeight,
|
|
Epoch{},
|
|
cert,
|
|
innerBlockBytes,
|
|
chainID,
|
|
key,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
unsignedBlock, err := BuildUnsigned(parentID, timestamp, pChainHeight, Epoch{}, innerBlockBytes)
|
|
require.NoError(t, err)
|
|
|
|
// A block that carries no proposer identity must have no signature suffix.
|
|
// Reject it at the wire boundary so an unsigned block ID has one encoding.
|
|
unsignedWithSignature := concat(unsignedBlock.Bytes(), buildSigBuffer([]byte{5}))
|
|
_, err = ParseWithoutVerification(unsignedWithSignature)
|
|
require.ErrorIs(t, err, errNonCanonicalWire)
|
|
|
|
optionBlock, err := BuildOption(parentID, innerBlockBytes)
|
|
require.NoError(t, err)
|
|
|
|
tests := []struct {
|
|
name string
|
|
block Block
|
|
chainID ids.ID
|
|
expectedErr error
|
|
}{
|
|
{
|
|
name: "correct chainID",
|
|
block: signedBlock,
|
|
chainID: chainID,
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "invalid chainID",
|
|
block: signedBlock,
|
|
chainID: ids.ID{5},
|
|
expectedErr: staking.ErrECDSAVerificationFailure,
|
|
},
|
|
{
|
|
name: "unsigned block",
|
|
block: unsignedBlock,
|
|
chainID: chainID,
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
name: "option block",
|
|
block: optionBlock,
|
|
chainID: chainID,
|
|
expectedErr: nil,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
blockBytes := test.block.Bytes()
|
|
parsedBlockWithoutVerification, err := ParseWithoutVerification(blockBytes)
|
|
require.NoError(err)
|
|
equal(require, test.block, parsedBlockWithoutVerification)
|
|
|
|
parsedBlock, err := Parse(blockBytes, test.chainID)
|
|
require.ErrorIs(err, test.expectedErr)
|
|
if test.expectedErr == nil {
|
|
equal(require, test.block, parsedBlock)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseBytes(t *testing.T) {
|
|
chainID := ids.ID{4}
|
|
tests := []struct {
|
|
name string
|
|
hex string
|
|
expectedErr error
|
|
}{
|
|
{
|
|
// Fewer than zap.HeaderSize bytes: rejected at the wire boundary.
|
|
name: "too short",
|
|
hex: "000102030405",
|
|
expectedErr: zap.ErrBufferTooSmall,
|
|
},
|
|
{
|
|
// A 16-byte frame with a valid size field (=16) but the wrong magic
|
|
// bytes: rejected by zap.Parse.
|
|
name: "invalid magic",
|
|
hex: "00000000000000000000000010000000",
|
|
expectedErr: zap.ErrInvalidMagic,
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
bytes, err := hex.DecodeString(test.hex)
|
|
require.NoError(err)
|
|
|
|
_, err = Parse(bytes, chainID)
|
|
require.ErrorIs(err, test.expectedErr)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseHeader(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
chainID := ids.ID{1}
|
|
parentID := ids.ID{2}
|
|
bodyID := ids.ID{3}
|
|
|
|
builtHeader, err := BuildHeader(
|
|
chainID,
|
|
parentID,
|
|
bodyID,
|
|
)
|
|
require.NoError(err)
|
|
|
|
builtHeaderBytes := builtHeader.Bytes()
|
|
|
|
parsedHeader, err := ParseHeader(builtHeaderBytes)
|
|
require.NoError(err)
|
|
|
|
equalHeader(require, builtHeader, parsedHeader)
|
|
}
|