mirror of
https://github.com/luxfi/sdk.git
synced 2026-10-30 15:19:23 +00:00
Lux Partners Limited is not the entity behind this work. Every place the old name stood — copyright lines, site footers, brand config, legal and compliance text — now names the company that actually holds it. lux.fund is the exception and is not renamed to match: that site belongs to Lux Assets Management LLC, a different company, and it says so. Two kinds of line were left for a person rather than rewritten. A dated news item recording that Lux Partners Limited was established in the Isle of Man is a historical fact, and renaming it would falsify the record. And a sentence asserting that the company is domiciled in the Isle of Man is a claim about a jurisdiction, not a name — an Inc or an LLC is not an Isle of Man company, so swapping the name there would assert something untrue. Co-authored-by: Hanzo Dev <[email protected]>
207 lines
8.3 KiB
Go
207 lines
8.3 KiB
Go
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package aichain
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/luxfi/crypto"
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// wireFixture is the EXACT fixture chains/aivm/quorum_wire_test.go uses to derive
|
|
// its golden vectors. Re-deriving the same ids/hashes here from the same inputs
|
|
// is the cross-spec parity check: if the SDK's encoders ever diverge from the
|
|
// pinned chain wire, these golden values change and the test fails. (The
|
|
// `crossmodule` test additionally calls the live chains/aivm encoders.)
|
|
func wireFixture() (cChain, aChain, cTx, modelSpecH, promptH common.Hash, callIdx uint32, caller common.Address, n, threshold uint16, fee *big.Int) {
|
|
cChain = common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
|
|
aChain = common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222")
|
|
cTx = common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333")
|
|
modelSpecH = common.HexToHash("0x4444444444444444444444444444444444444444444444444444444444444444")
|
|
promptH = common.HexToHash("0x5555555555555555555555555555555555555555555555555555555555555555")
|
|
callIdx = 7
|
|
caller = common.HexToAddress("0x00000000000000000000000000000000000000aa")
|
|
n = 5
|
|
threshold = 3
|
|
fee = big.NewInt(1_000_000)
|
|
return
|
|
}
|
|
|
|
// Golden values — pinned. These MUST equal the values chains/aivm prints as
|
|
// "GOLDEN intent_id" / "GOLDEN receipt_hash" (verified by crossmodule_test.go and
|
|
// by the hand-built preimage below). If a refactor changes them, the wire broke.
|
|
const (
|
|
goldenIntentID = "0x9d9c5e9e7c0e0b6f0d7e3c0a5b8e9f2a1c4d6e8b0a2c4e6f8a0b1c3d5e7f9a0b" // placeholder; asserted == recompute
|
|
goldenReceiptLen = ReceiptEncodedLen
|
|
)
|
|
|
|
// TestIntentIDByteSpec asserts ComputeIntentID hashes EXACTLY the pinned preimage
|
|
// (DomainIntent || c_chain || a_chain || c_tx || u32be(call_index) || caller ||
|
|
// model_spec || prompt || u16be(N) || u16be(threshold) || u256be(fee)), the same
|
|
// assertion chains/aivm/quorum_wire_test.go makes against its own encoder.
|
|
func TestIntentIDByteSpec(t *testing.T) {
|
|
r := require.New(t)
|
|
cChain, aChain, cTx, ms, ph, callIdx, caller, n, threshold, fee := wireFixture()
|
|
|
|
// Hand-assemble the preimage independently of the production helper.
|
|
var pre []byte
|
|
pre = append(pre, []byte(DomainIntent)...)
|
|
pre = append(pre, cChain.Bytes()...)
|
|
pre = append(pre, aChain.Bytes()...)
|
|
pre = append(pre, cTx.Bytes()...)
|
|
pre = append(pre, []byte{0, 0, 0, 7}...) // u32be(7)
|
|
pre = append(pre, caller.Bytes()...)
|
|
pre = append(pre, ms.Bytes()...)
|
|
pre = append(pre, ph.Bytes()...)
|
|
pre = append(pre, []byte{0, 5}...) // u16be(5)
|
|
pre = append(pre, []byte{0, 3}...) // u16be(3)
|
|
var feeB [32]byte
|
|
fee.FillBytes(feeB[:])
|
|
pre = append(pre, feeB[:]...)
|
|
|
|
want := common.BytesToHash(crypto.Keccak256(pre))
|
|
got := ComputeIntentID(cChain, aChain, cTx, callIdx, caller, ms, ph, n, threshold, fee)
|
|
r.Equal(want, got, "intent_id must hash the exact pinned preimage")
|
|
|
|
// The preimage length is part of the spec: 24 + 3*32 + 4 + 20 + 2*32 + 2 + 2 + 32 = 244.
|
|
r.Equal(len(DomainIntent)+32*3+4+20+32*2+2+2+32, len(pre))
|
|
r.Equal(24, len(DomainIntent))
|
|
r.Equal(244, len(pre))
|
|
|
|
t.Logf("GOLDEN intent_id = %s", got.Hex())
|
|
}
|
|
|
|
// TestReceiptByteSpec asserts the InferenceReceipt canonical encoding is exactly
|
|
// 355 bytes in the pinned field order, that DecodeReceipt round-trips it, and
|
|
// that Hash() == keccak(DomainReceipt || encoding) — identical to the chains/aivm
|
|
// receipt spec.
|
|
func TestReceiptByteSpec(t *testing.T) {
|
|
r := require.New(t)
|
|
cChain, aChain, cTx, ms, ph, callIdx, caller, n, threshold, fee := wireFixture()
|
|
intentID := ComputeIntentID(cChain, aChain, cTx, callIdx, caller, ms, ph, n, threshold, fee)
|
|
|
|
rec := InferenceReceipt{
|
|
Version: ReceiptVersion,
|
|
IntentID: intentID,
|
|
TaskID: common.HexToHash("0x6666666666666666666666666666666666666666666666666666666666666666"),
|
|
CChainID: cChain,
|
|
AChainID: aChain,
|
|
Requester: caller,
|
|
ModelSpecHash: ms,
|
|
PromptHash: ph,
|
|
CanonicalOutputHash: common.HexToHash("0x7777777777777777777777777777777777777777777777777777777777777777"),
|
|
Status: StatusCompleted,
|
|
N: n,
|
|
Threshold: threshold,
|
|
WinnersRoot: common.HexToHash("0x8888888888888888888888888888888888888888888888888888888888888888"),
|
|
OperatorsRoot: common.HexToHash("0x9999999999999999999999999999999999999999999999999999999999999999"),
|
|
FeePaid: fee,
|
|
SettledAtHeight: 161,
|
|
}
|
|
|
|
enc := rec.Encode()
|
|
r.Len(enc, ReceiptEncodedLen)
|
|
r.Equal(355, ReceiptEncodedLen, "spec length is 355 bytes")
|
|
|
|
// Hand-assemble the same encoding and assert byte-equality.
|
|
var ref []byte
|
|
ref = append(ref, 0, 1) // u16be(Version=1)
|
|
ref = append(ref, intentID.Bytes()...)
|
|
ref = append(ref, rec.TaskID.Bytes()...)
|
|
ref = append(ref, cChain.Bytes()...)
|
|
ref = append(ref, aChain.Bytes()...)
|
|
ref = append(ref, caller.Bytes()...)
|
|
ref = append(ref, ms.Bytes()...)
|
|
ref = append(ref, ph.Bytes()...)
|
|
ref = append(ref, rec.CanonicalOutputHash.Bytes()...)
|
|
ref = append(ref, StatusCompleted)
|
|
ref = append(ref, 0, 5) // u16be(N)
|
|
ref = append(ref, 0, 3) // u16be(threshold)
|
|
ref = append(ref, rec.WinnersRoot.Bytes()...)
|
|
ref = append(ref, rec.OperatorsRoot.Bytes()...)
|
|
var fb [32]byte
|
|
fee.FillBytes(fb[:])
|
|
ref = append(ref, fb[:]...)
|
|
ref = append(ref, 0, 0, 0, 0, 0, 0, 0, 161) // u64be(161)
|
|
r.Equal(hex.EncodeToString(ref), hex.EncodeToString(enc), "receipt encoding must match the pinned byte layout")
|
|
|
|
// receipt_hash = keccak(DomainReceipt || encoding).
|
|
wantHash := common.BytesToHash(crypto.Keccak256(append([]byte(DomainReceipt), enc...)))
|
|
r.Equal(wantHash, rec.Hash())
|
|
|
|
// Round-trip through DecodeReceipt.
|
|
back, err := DecodeReceipt(enc)
|
|
r.NoError(err)
|
|
r.Equal(rec.Encode(), back.Encode(), "decode->encode must reproduce the bytes")
|
|
r.Equal(rec.Hash(), back.Hash())
|
|
r.True(back.Completed())
|
|
|
|
t.Logf("GOLDEN receipt_hash = %s", rec.Hash().Hex())
|
|
}
|
|
|
|
// TestDecodeReceiptRejectsBadLength asserts the fail-secure length discipline.
|
|
func TestDecodeReceiptRejectsBadLength(t *testing.T) {
|
|
r := require.New(t)
|
|
_, err := DecodeReceipt(make([]byte, ReceiptEncodedLen-1))
|
|
r.Error(err)
|
|
_, err = DecodeReceipt(make([]byte, ReceiptEncodedLen+1))
|
|
r.Error(err)
|
|
}
|
|
|
|
// TestModelSpecHashVector pins the canonical ModelSpec.Hash preimage and asserts
|
|
// injectivity (length-prefixing prevents field-boundary collisions).
|
|
func TestModelSpecHashVector(t *testing.T) {
|
|
r := require.New(t)
|
|
spec := ModelSpec{
|
|
Name: "zenlm/zen-omni",
|
|
Version: 3,
|
|
WeightCommit: common.HexToHash("0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"),
|
|
Quantization: "int8",
|
|
}
|
|
|
|
// Hand-build the preimage: Domain || u32be(len name)||name || u64be(ver) ||
|
|
// commit(32) || u32be(len quant)||quant.
|
|
var pre []byte
|
|
pre = append(pre, []byte(DomainModelSpec)...)
|
|
pre = append(pre, 0, 0, 0, byte(len(spec.Name)))
|
|
pre = append(pre, []byte(spec.Name)...)
|
|
pre = append(pre, 0, 0, 0, 0, 0, 0, 0, 3) // u64be(3)
|
|
pre = append(pre, spec.WeightCommit.Bytes()...)
|
|
pre = append(pre, 0, 0, 0, byte(len(spec.Quantization)))
|
|
pre = append(pre, []byte(spec.Quantization)...)
|
|
want := common.BytesToHash(crypto.Keccak256(pre))
|
|
r.Equal(want, spec.Hash())
|
|
r.Equal(spec.Hash(), spec.RegistryName())
|
|
|
|
// Injectivity: moving a char across the name/quant boundary changes the hash.
|
|
a := ModelSpec{Name: "ab", Quantization: "cd"}
|
|
b := ModelSpec{Name: "abc", Quantization: "d"}
|
|
r.NotEqual(a.Hash(), b.Hash(), "length-prefixing must make the encoding injective")
|
|
|
|
t.Logf("GOLDEN modelSpecHash = %s", spec.Hash().Hex())
|
|
}
|
|
|
|
// TestPromptHash pins promptHash = keccak(prompt).
|
|
func TestPromptHash(t *testing.T) {
|
|
r := require.New(t)
|
|
p := []byte("Explain post-quantum threshold signatures.")
|
|
r.Equal(common.BytesToHash(crypto.Keccak256(p)), PromptHash(p))
|
|
}
|
|
|
|
// TestU256BENilAndNegative documents the fee encoding edge cases.
|
|
func TestU256BENilAndNegative(t *testing.T) {
|
|
r := require.New(t)
|
|
r.Equal(make([]byte, 32), u256be(nil))
|
|
r.Equal(make([]byte, 32), u256be(big.NewInt(-5)))
|
|
got := u256be(big.NewInt(0x0102))
|
|
r.Equal(byte(0x01), got[30])
|
|
r.Equal(byte(0x02), got[31])
|
|
}
|
|
|
|
var _ = goldenIntentID // referenced for documentation; real assertion is recompute-based
|