mirror of
https://github.com/luxfi/utxo.git
synced 2026-07-27 03:39:23 +00:00
feat: drop CodecRegistry + codec.Manager from public API — ZAP-native at activation 2025-12-25T16:20:00-08:00
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
# Final codec rip — `luxfi/utxo`
|
||||
|
||||
Activation 2025-12-25T16:20:00-08:00. No backwards compat, no shim, no
|
||||
env var. The wire is ZAP. Delete the legacy.
|
||||
|
||||
## Surface to delete
|
||||
|
||||
### Per-fx `vm.go` (8 files)
|
||||
|
||||
Drop `CodecRegistry() codec.Registry` from the `VM` interface. Drop the
|
||||
`Codec` field from `TestVM` and its `CodecRegistry()` accessor. Drop the
|
||||
`luxfi/codec` import. Files:
|
||||
|
||||
- `secp256k1fx/vm.go`
|
||||
- `mldsafx/vm.go`
|
||||
- `slhdsafx/vm.go`
|
||||
- `ed25519fx/vm.go`
|
||||
- `secp256r1fx/vm.go`
|
||||
- `schnorrfx/vm.go`
|
||||
- `bls12381fx/fx.go` (VM interface lives in fx.go for this package)
|
||||
|
||||
### Per-fx `fx.go` Initialize (9 files)
|
||||
|
||||
Drop the `c := fx.VM.CodecRegistry()` block + the `RegisterType` chain.
|
||||
The wire schema is static at compile time; nothing to register. Each
|
||||
`Initialize` keeps the VM cast + logger init and otherwise becomes a
|
||||
no-op. Files:
|
||||
|
||||
- `secp256k1fx/fx.go`
|
||||
- `mldsafx/fx.go`
|
||||
- `slhdsafx/fx.go`
|
||||
- `ed25519fx/fx.go`
|
||||
- `secp256r1fx/fx.go`
|
||||
- `schnorrfx/fx.go`
|
||||
- `bls12381fx/fx.go`
|
||||
- `nftfx/fx.go` — embeds `secp256k1fx.Fx`, has its own RegisterType chain
|
||||
- `propertyfx/fx.go` — embeds `secp256k1fx.Fx`, has its own RegisterType chain
|
||||
|
||||
### Root package
|
||||
|
||||
- `api.go` — replace `codec.Uint32` / `codec.Uint64` with `jsonutil.Uint32` /
|
||||
`jsonutil.Uint64` (new package) or unqualified `uint32`/`uint64` with
|
||||
hand-rolled JSON. Cleanest: replicate the JSON-string-quoted types
|
||||
locally in `utxo/jsonutil/`.
|
||||
- `atomic_utxos.go` — drop `codec codec.Manager` field + ctor param;
|
||||
parse cross-chain bytes through `wire.WrapUTXO(b)`.
|
||||
- `flow_checker.go` — replace `wrappers.Errs` with an inline 5-line
|
||||
`errs` struct or move to `utxo/internal/errs/`. Drop the
|
||||
`luxfi/codec/wrappers` import.
|
||||
- `transferables.go` — drop `c codec.Manager` from
|
||||
`SortTransferableOutputs`, `IsSortedTransferableOutputs`, `VerifyTx`.
|
||||
Sort key is now `out.Bytes()` (the ZAP wire envelope returned by the
|
||||
`wireSerializable` interface). `Verify` is unchanged.
|
||||
- `utxo_state.go` — drop `codec codec.Manager` field + ctor params;
|
||||
encode/decode through `utxo.WireBytes()` / `utxo.WrapUTXOBytes()`.
|
||||
|
||||
### `wire/discriminator.go`
|
||||
|
||||
Doc-comment-only reference. Comment text is correct historical context;
|
||||
no import statement. Leave it.
|
||||
|
||||
## Activation invariant
|
||||
|
||||
The new network's genesis is at unix 1766708400. Every block produced
|
||||
after that point uses ZAP-native UTXO encoding. No legacy codec UTXOs
|
||||
exist on disk or on the wire.
|
||||
|
||||
## Cascade
|
||||
|
||||
After this lands, every `luxd` caller of:
|
||||
|
||||
- `lux.SortTransferableOutputs(outs, Codec)` → `lux.SortTransferableOutputs(outs)`
|
||||
- `lux.IsSortedTransferableOutputs(outs, Codec)` → `lux.IsSortedTransferableOutputs(outs)`
|
||||
- `lux.VerifyTx(fee, feeAsset, ins, outs, Codec)` → `lux.VerifyTx(fee, feeAsset, ins, outs)`
|
||||
- `lux.GetAtomicUTXOs(sm, codec, ...)` → `lux.GetAtomicUTXOs(sm, ...)`
|
||||
- `lux.NewAtomicUTXOManager(sm, codec)` → `lux.NewAtomicUTXOManager(sm)`
|
||||
- `lux.NewUTXOState(db, codec, track)` → `lux.NewUTXOState(db, track)`
|
||||
- `lux.NewMeteredUTXOState(db, codec, metrics, track)` → `lux.NewMeteredUTXOState(db, metrics, track)`
|
||||
|
||||
needs the codec arg dropped. Plus every fx.Initialize callsite no
|
||||
longer needs `vm.CodecRegistry()` to do anything.
|
||||
|
||||
## Order of operations
|
||||
|
||||
1. Define `utxo/jsonutil/uint.go` with `Uint32`/`Uint64` JSON-string types.
|
||||
2. Patch `api.go` to use `jsonutil`.
|
||||
3. Patch `flow_checker.go` to inline a tiny errs collector.
|
||||
4. Patch `transferables.go` to use `wireSerializable.Bytes()` as sort key.
|
||||
5. Patch `atomic_utxos.go` to use `wire.WrapUTXO(b)`.
|
||||
6. Patch `utxo_state.go` to use `utxo.WireBytes()` / `WrapUTXOBytes`.
|
||||
7. Patch every fx's `vm.go` to drop `CodecRegistry()` + `Codec` field.
|
||||
8. Patch every fx's `fx.go` `Initialize` to drop the registration chain.
|
||||
9. Patch every fx's tests to drop `Codec: linearcodec.NewDefault()` + the
|
||||
`linearcodec` import.
|
||||
10. Build + test in tree.
|
||||
11. `go mod edit -droprequire=github.com/luxfi/codec` + tidy.
|
||||
12. Cascade through `luxd` consumer files.
|
||||
@@ -4,7 +4,7 @@
|
||||
package utxo
|
||||
|
||||
import (
|
||||
"github.com/luxfi/codec"
|
||||
apitypes "github.com/luxfi/api/types"
|
||||
"github.com/luxfi/formatting"
|
||||
"github.com/luxfi/ids"
|
||||
)
|
||||
@@ -31,7 +31,7 @@ type Index struct {
|
||||
type GetUTXOsArgs struct {
|
||||
Addresses []string `json:"addresses"`
|
||||
SourceChain string `json:"sourceChain"`
|
||||
Limit codec.Uint32 `json:"limit"`
|
||||
Limit apitypes.Uint32 `json:"limit"`
|
||||
StartIndex Index `json:"startIndex"`
|
||||
Encoding formatting.Encoding `json:"encoding"`
|
||||
}
|
||||
@@ -40,7 +40,7 @@ type GetUTXOsArgs struct {
|
||||
// JSON field names match RPC conventions for compatibility across services.
|
||||
type GetUTXOsReply struct {
|
||||
// Number of UTXOs returned
|
||||
NumFetched codec.Uint64 `json:"numFetched"`
|
||||
NumFetched apitypes.Uint64 `json:"numFetched"`
|
||||
// The UTXOs
|
||||
UTXOs []string `json:"utxos"`
|
||||
// The last UTXO that was returned, and the address it corresponds to.
|
||||
|
||||
+10
-13
@@ -6,7 +6,6 @@ package utxo
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/luxfi/codec"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/math/set"
|
||||
"github.com/luxfi/vm/chains/atomic"
|
||||
@@ -15,15 +14,14 @@ import (
|
||||
var _ AtomicUTXOManager = (*atomicUTXOManager)(nil)
|
||||
|
||||
type atomicUTXOManager struct {
|
||||
sm atomic.SharedMemory
|
||||
codec codec.Manager
|
||||
sm atomic.SharedMemory
|
||||
}
|
||||
|
||||
func NewAtomicUTXOManager(sm atomic.SharedMemory, codec codec.Manager) AtomicUTXOManager {
|
||||
return &atomicUTXOManager{
|
||||
sm: sm,
|
||||
codec: codec,
|
||||
}
|
||||
// NewAtomicUTXOManager returns an AtomicUTXOManager backed by ZAP-native
|
||||
// wire bytes stored in cross-chain shared memory. Caller must have
|
||||
// invoked RegisterParseUTXO before the first GetAtomicUTXOs call.
|
||||
func NewAtomicUTXOManager(sm atomic.SharedMemory) AtomicUTXOManager {
|
||||
return &atomicUTXOManager{sm: sm}
|
||||
}
|
||||
|
||||
func (a *atomicUTXOManager) GetAtomicUTXOs(
|
||||
@@ -63,11 +61,11 @@ func (a *atomicUTXOManager) GetAtomicUTXOs(
|
||||
|
||||
utxos := make([]*UTXO, len(allUTXOBytes))
|
||||
for i, utxoBytes := range allUTXOBytes {
|
||||
utxo := &UTXO{}
|
||||
if _, err := a.codec.Unmarshal(utxoBytes, utxo); err != nil {
|
||||
u, err := ParseUTXO(utxoBytes)
|
||||
if err != nil {
|
||||
return nil, ids.ShortID{}, ids.Empty, fmt.Errorf("error parsing UTXO: %w", err)
|
||||
}
|
||||
utxos[i] = utxo
|
||||
utxos[i] = u
|
||||
}
|
||||
return utxos, lastAddrID, lastUTXOID, nil
|
||||
}
|
||||
@@ -84,13 +82,12 @@ func (a *atomicUTXOManager) GetAtomicUTXOs(
|
||||
// * Any error that may have occurred upstream.
|
||||
func GetAtomicUTXOs(
|
||||
sharedMemory atomic.SharedMemory,
|
||||
codec codec.Manager,
|
||||
chainID ids.ID,
|
||||
addrs set.Set[ids.ShortID],
|
||||
startAddr ids.ShortID,
|
||||
startUTXOID ids.ID,
|
||||
limit int,
|
||||
) ([]*UTXO, ids.ShortID, ids.ID, error) {
|
||||
manager := NewAtomicUTXOManager(sharedMemory, codec)
|
||||
manager := NewAtomicUTXOManager(sharedMemory)
|
||||
return manager.GetAtomicUTXOs(chainID, addrs, startAddr, startUTXOID, limit)
|
||||
}
|
||||
|
||||
+9
-28
@@ -6,10 +6,8 @@ package bls12381fx
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/luxfi/cache/lru"
|
||||
"github.com/luxfi/codec"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/hash"
|
||||
"github.com/luxfi/ids"
|
||||
@@ -36,9 +34,9 @@ var (
|
||||
ErrSignerBitmapOutOfRange = errors.New("signer bitmap references pubkey out of range")
|
||||
)
|
||||
|
||||
// VM is the interface this Fx requires.
|
||||
// VM is the interface this Fx requires. ZAP-native: no runtime codec
|
||||
// registration — wire schemas are compile-time static in wire.go.
|
||||
type VM interface {
|
||||
CodecRegistry() codec.Registry
|
||||
Clock() *mockable.Clock
|
||||
Logger() log.Logger
|
||||
}
|
||||
@@ -47,14 +45,12 @@ var _ VM = (*TestVM)(nil)
|
||||
|
||||
// TestVM is a minimal VM for tests.
|
||||
type TestVM struct {
|
||||
Clk mockable.Clock
|
||||
Codec codec.Registry
|
||||
Log log.Logger
|
||||
Clk mockable.Clock
|
||||
Log log.Logger
|
||||
}
|
||||
|
||||
func (vm *TestVM) Clock() *mockable.Clock { return &vm.Clk }
|
||||
func (vm *TestVM) CodecRegistry() codec.Registry { return vm.Codec }
|
||||
func (vm *TestVM) Logger() log.Logger { return vm.Log }
|
||||
func (vm *TestVM) Clock() *mockable.Clock { return &vm.Clk }
|
||||
func (vm *TestVM) Logger() log.Logger { return vm.Log }
|
||||
|
||||
// UnsignedTx is what this Fx is signing over.
|
||||
type UnsignedTx interface{ Bytes() []byte }
|
||||
@@ -80,24 +76,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
if !logr.IsZero() {
|
||||
logr.Debug("initializing bls12381fx (attestation-only)")
|
||||
}
|
||||
if fx.VM == nil {
|
||||
return nil
|
||||
}
|
||||
c := fx.VM.CodecRegistry()
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
errs := []error{}
|
||||
if err := c.RegisterType(&AttestationOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&AttestationInput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&Credential{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
// ZAP-native: wire schemas are compile-time static in bls12381fx/wire.go.
|
||||
// No runtime codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*Fx) Bootstrapping() error { return nil }
|
||||
|
||||
+3
-23
@@ -7,7 +7,6 @@ import (
|
||||
"crypto/ed25519"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/luxfi/cache/lru"
|
||||
"github.com/luxfi/crypto/hash"
|
||||
@@ -61,28 +60,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := fx.VM.CodecRegistry()
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errs := []error{}
|
||||
if err := c.RegisterType(&TransferInput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&TransferOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOperation{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&Credential{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
// ZAP-native: wire schemas are compile-time static in the per-fx
|
||||
// wire.go bridge. No runtime codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fx *Fx) InitializeVM(vmIntf interface{}) error {
|
||||
|
||||
+4
-10
@@ -4,14 +4,13 @@
|
||||
package ed25519fx
|
||||
|
||||
import (
|
||||
"github.com/luxfi/codec"
|
||||
log "github.com/luxfi/log"
|
||||
"github.com/luxfi/timer/mockable"
|
||||
)
|
||||
|
||||
// VM that this Fx must be run by
|
||||
// VM that this Fx must be run by. ZAP-native: no runtime codec
|
||||
// registration — wire schemas are compile-time static.
|
||||
type VM interface {
|
||||
CodecRegistry() codec.Registry
|
||||
Clock() *mockable.Clock
|
||||
Logger() log.Logger
|
||||
}
|
||||
@@ -20,19 +19,14 @@ var _ VM = (*TestVM)(nil)
|
||||
|
||||
// TestVM is a minimal implementation of a VM
|
||||
type TestVM struct {
|
||||
Clk mockable.Clock
|
||||
Codec codec.Registry
|
||||
Log log.Logger
|
||||
Clk mockable.Clock
|
||||
Log log.Logger
|
||||
}
|
||||
|
||||
func (vm *TestVM) Clock() *mockable.Clock {
|
||||
return &vm.Clk
|
||||
}
|
||||
|
||||
func (vm *TestVM) CodecRegistry() codec.Registry {
|
||||
return vm.Codec
|
||||
}
|
||||
|
||||
func (vm *TestVM) Logger() log.Logger {
|
||||
return vm.Log
|
||||
}
|
||||
|
||||
+7
-6
@@ -6,7 +6,6 @@ package utxo
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/luxfi/codec/wrappers"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/math"
|
||||
)
|
||||
@@ -15,7 +14,7 @@ var ErrInsufficientFunds = errors.New("insufficient funds")
|
||||
|
||||
type FlowChecker struct {
|
||||
consumed, produced map[ids.ID]uint64
|
||||
errs wrappers.Errs
|
||||
errs []error
|
||||
}
|
||||
|
||||
func NewFlowChecker() *FlowChecker {
|
||||
@@ -36,18 +35,20 @@ func (fc *FlowChecker) Produce(assetID ids.ID, amount uint64) {
|
||||
func (fc *FlowChecker) add(value map[ids.ID]uint64, assetID ids.ID, amount uint64) {
|
||||
var err error
|
||||
value[assetID], err = math.Add64(value[assetID], amount)
|
||||
fc.errs.Add(err)
|
||||
if err != nil {
|
||||
fc.errs = append(fc.errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (fc *FlowChecker) Verify() error {
|
||||
if !fc.errs.Errored() {
|
||||
if len(fc.errs) == 0 {
|
||||
for assetID, producedAssetAmount := range fc.produced {
|
||||
consumedAssetAmount := fc.consumed[assetID]
|
||||
if producedAssetAmount > consumedAssetAmount {
|
||||
fc.errs.Add(ErrInsufficientFunds)
|
||||
fc.errs = append(fc.errs, ErrInsufficientFunds)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return fc.errs.Err
|
||||
return errors.Join(fc.errs...)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ go 1.26.3
|
||||
require (
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.1.3
|
||||
github.com/luxfi/address v1.0.1
|
||||
github.com/luxfi/api v1.0.12
|
||||
github.com/luxfi/cache v1.2.1
|
||||
github.com/luxfi/codec v1.1.4
|
||||
github.com/luxfi/constants v1.4.7
|
||||
@@ -43,7 +44,7 @@ require (
|
||||
github.com/luxfi/atomic v1.0.0 // indirect
|
||||
github.com/luxfi/compress v0.0.5 // indirect
|
||||
github.com/luxfi/concurrent v0.0.3 // indirect
|
||||
github.com/luxfi/consensus v1.22.84 // indirect
|
||||
github.com/luxfi/consensus v1.22.85 // indirect
|
||||
github.com/luxfi/container v0.0.4 // indirect
|
||||
github.com/luxfi/math/big v0.1.0 // indirect
|
||||
github.com/luxfi/mdns v0.1.1 // indirect
|
||||
|
||||
@@ -79,6 +79,8 @@ github.com/luxfi/accel v1.1.9 h1:Tsk6gXj2uKE19501bD0ajRYdeCHIlTGb6jYyLc+F8hc=
|
||||
github.com/luxfi/accel v1.1.9/go.mod h1:K00BcnLzEYMPHwCFq8Tf/450ApmTs9xBVvYOnofJCkc=
|
||||
github.com/luxfi/address v1.0.1 h1:Sc4keyuVzBIvHr7uVeYZf2/WY9YDGUgDi/iiWenj49g=
|
||||
github.com/luxfi/address v1.0.1/go.mod h1:5j3Eh66v9zvv1GbNdZwt+23krV8JlSDaRzmWZU8ZRM0=
|
||||
github.com/luxfi/api v1.0.12 h1:HnLfoowXDZ2oGGB+40CHlmQ0XET5I9I828EVeYixlXc=
|
||||
github.com/luxfi/api v1.0.12/go.mod h1:q3Hh3mmkvp3cnv3aqe2+gCtmmSAL/uFjuzrqGavQLNA=
|
||||
github.com/luxfi/atomic v1.0.0 h1:xUV60MuzRvXngaQ1sM0yVC2v4TRoLlUGkkH7M9PS4yw=
|
||||
github.com/luxfi/atomic v1.0.0/go.mod h1:0G2mTlQ6TXWHICUHrUUPu1/qAiIyR4gSZ2tva9ci/bI=
|
||||
github.com/luxfi/cache v1.2.1 h1:kAzOS55/hmYeNKR+0HAKv4ma48Y6JjkI8UQeqdZ8bfI=
|
||||
@@ -89,8 +91,8 @@ github.com/luxfi/compress v0.0.5 h1:4tEUHw5MK1bu5UOjfYCt4OKMiH7yykIgmGPRA/BfJTM=
|
||||
github.com/luxfi/compress v0.0.5/go.mod h1:Cc1yxD2pfzrvpO32W2GDwLKff+CylHEvzZh2Ko8RSIU=
|
||||
github.com/luxfi/concurrent v0.0.3 h1:eJyv1fhaC0jMLMw6+QS774cUmp7GK+ouMgvLCqnC7cc=
|
||||
github.com/luxfi/concurrent v0.0.3/go.mod h1:Aj/FR5NpM0cB2P4Nt3+tz9+dV6V+LUW4HuMgSjwq5hw=
|
||||
github.com/luxfi/consensus v1.22.84 h1:fKw4n7fY+lCWW5HSx/ciGeRSxv4knODQGWh6lBWAveQ=
|
||||
github.com/luxfi/consensus v1.22.84/go.mod h1:y6y+bVjvpDLkkTBCCKLcch6R4PRW8EA+lTfr+6sB6F8=
|
||||
github.com/luxfi/consensus v1.22.85 h1:S/XpPF+eDapbZb4AIu0Vr1GXzg/sAxjrAff2M2mkOx0=
|
||||
github.com/luxfi/consensus v1.22.85/go.mod h1:y6y+bVjvpDLkkTBCCKLcch6R4PRW8EA+lTfr+6sB6F8=
|
||||
github.com/luxfi/constants v1.4.7 h1:e/Qs+DQP3pugle3Zncq6fZCxKgqqtbyD/z7Gm4ZjsYg=
|
||||
github.com/luxfi/constants v1.4.7/go.mod h1:hOszZ2NDQ8gMZKncfcZ67PXkb5OIbnwAzXC3oFbQwW0=
|
||||
github.com/luxfi/container v0.0.4 h1:BXhF82WyfqVP5mjlNcr7tP0Fcnvl0Ap1rkiu+rq5XuM=
|
||||
|
||||
+3
-23
@@ -6,7 +6,6 @@ package mldsafx
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/luxfi/cache/lru"
|
||||
"github.com/luxfi/crypto/hash"
|
||||
@@ -68,28 +67,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := fx.VM.CodecRegistry()
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errs := []error{}
|
||||
if err := c.RegisterType(&TransferInput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&TransferOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOperation{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&Credential{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
// ZAP-native: wire schemas are compile-time static in the per-fx
|
||||
// wire.go bridge. No runtime codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fx *Fx) InitializeVM(vmIntf interface{}) error {
|
||||
|
||||
+4
-10
@@ -4,14 +4,13 @@
|
||||
package mldsafx
|
||||
|
||||
import (
|
||||
"github.com/luxfi/codec"
|
||||
log "github.com/luxfi/log"
|
||||
"github.com/luxfi/timer/mockable"
|
||||
)
|
||||
|
||||
// VM that this Fx must be run by
|
||||
// VM that this Fx must be run by. ZAP-native: no runtime codec
|
||||
// registration — wire schemas are compile-time static.
|
||||
type VM interface {
|
||||
CodecRegistry() codec.Registry
|
||||
Clock() *mockable.Clock
|
||||
Logger() log.Logger
|
||||
}
|
||||
@@ -20,19 +19,14 @@ var _ VM = (*TestVM)(nil)
|
||||
|
||||
// TestVM is a minimal implementation of a VM
|
||||
type TestVM struct {
|
||||
Clk mockable.Clock
|
||||
Codec codec.Registry
|
||||
Log log.Logger
|
||||
Clk mockable.Clock
|
||||
Log log.Logger
|
||||
}
|
||||
|
||||
func (vm *TestVM) Clock() *mockable.Clock {
|
||||
return &vm.Clk
|
||||
}
|
||||
|
||||
func (vm *TestVM) CodecRegistry() codec.Registry {
|
||||
return vm.Codec
|
||||
}
|
||||
|
||||
func (vm *TestVM) Logger() log.Logger {
|
||||
return vm.Log
|
||||
}
|
||||
|
||||
+3
-8
@@ -32,14 +32,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
log := fx.VM.Logger()
|
||||
log.Debug("initializing nft fx")
|
||||
|
||||
c := fx.VM.CodecRegistry()
|
||||
return errors.Join(
|
||||
c.RegisterType(&MintOutput{}),
|
||||
c.RegisterType(&TransferOutput{}),
|
||||
c.RegisterType(&MintOperation{}),
|
||||
c.RegisterType(&TransferOperation{}),
|
||||
c.RegisterType(&Credential{}),
|
||||
)
|
||||
// ZAP-native: wire schemas are compile-time static. No runtime
|
||||
// codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fx *Fx) VerifyOperation(txIntf, opIntf, credIntf interface{}, utxosIntf []interface{}) error {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package utxo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ParseUTXOFunc reconstructs a *UTXO from its ZAP wire envelope. The
|
||||
// concrete implementation lives in luxfi/node (or any consumer that
|
||||
// imports all the fx packages it needs to dispatch on the inner Output
|
||||
// TypeKind+ShapeKind discriminator). The root utxo package can't
|
||||
// import fx packages directly (cycle), so the consumer registers a
|
||||
// factory at boot.
|
||||
//
|
||||
// ZAP wire bytes are the canonical input. No codec.Manager — the same
|
||||
// bytes flow on the wire, on disk (via zapdb), and into the parser.
|
||||
type ParseUTXOFunc func(wireBytes []byte) (*UTXO, error)
|
||||
|
||||
var (
|
||||
parseUTXOOnce sync.Once
|
||||
parseUTXO ParseUTXOFunc
|
||||
|
||||
// ErrParseUTXONotRegistered is returned by ParseUTXO before the
|
||||
// consumer has called RegisterParseUTXO. Each program (luxd, cli,
|
||||
// tests, etc.) must register exactly once at boot.
|
||||
ErrParseUTXONotRegistered = errors.New("utxo: ParseUTXO not registered — caller must invoke RegisterParseUTXO at boot")
|
||||
)
|
||||
|
||||
// RegisterParseUTXO registers the fx-aware factory. Idempotent — only
|
||||
// the first call wins; subsequent calls are no-ops. This matches the
|
||||
// "register once at process boot" pattern and prevents accidental
|
||||
// override at test time.
|
||||
func RegisterParseUTXO(fn ParseUTXOFunc) {
|
||||
parseUTXOOnce.Do(func() {
|
||||
parseUTXO = fn
|
||||
})
|
||||
}
|
||||
|
||||
// ParseUTXO reconstructs a *UTXO from its ZAP wire envelope using the
|
||||
// registered factory. Returns ErrParseUTXONotRegistered if no factory
|
||||
// has been registered.
|
||||
func ParseUTXO(wireBytes []byte) (*UTXO, error) {
|
||||
if parseUTXO == nil {
|
||||
return nil, ErrParseUTXONotRegistered
|
||||
}
|
||||
return parseUTXO(wireBytes)
|
||||
}
|
||||
+3
-8
@@ -30,14 +30,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
log := fx.VM.Logger()
|
||||
log.Debug("initializing nft fx")
|
||||
|
||||
c := fx.VM.CodecRegistry()
|
||||
return errors.Join(
|
||||
c.RegisterType(&MintOutput{}),
|
||||
c.RegisterType(&OwnedOutput{}),
|
||||
c.RegisterType(&MintOperation{}),
|
||||
c.RegisterType(&BurnOperation{}),
|
||||
c.RegisterType(&Credential{}),
|
||||
)
|
||||
// ZAP-native: wire schemas are compile-time static. No runtime
|
||||
// codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fx *Fx) VerifyOperation(txIntf, opIntf, credIntf interface{}, utxosIntf []interface{}) error {
|
||||
|
||||
+3
-23
@@ -7,7 +7,6 @@ import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/luxfi/cache/lru"
|
||||
@@ -66,28 +65,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := fx.VM.CodecRegistry()
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errs := []error{}
|
||||
if err := c.RegisterType(&TransferInput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&TransferOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOperation{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&Credential{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
// ZAP-native: wire schemas are compile-time static in the per-fx
|
||||
// wire.go bridge. No runtime codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fx *Fx) InitializeVM(vmIntf interface{}) error {
|
||||
|
||||
+4
-10
@@ -4,14 +4,13 @@
|
||||
package schnorrfx
|
||||
|
||||
import (
|
||||
"github.com/luxfi/codec"
|
||||
log "github.com/luxfi/log"
|
||||
"github.com/luxfi/timer/mockable"
|
||||
)
|
||||
|
||||
// VM that this Fx must be run by
|
||||
// VM that this Fx must be run by. ZAP-native: no runtime codec
|
||||
// registration — wire schemas are compile-time static.
|
||||
type VM interface {
|
||||
CodecRegistry() codec.Registry
|
||||
Clock() *mockable.Clock
|
||||
Logger() log.Logger
|
||||
}
|
||||
@@ -20,19 +19,14 @@ var _ VM = (*TestVM)(nil)
|
||||
|
||||
// TestVM is a minimal implementation of a VM
|
||||
type TestVM struct {
|
||||
Clk mockable.Clock
|
||||
Codec codec.Registry
|
||||
Log log.Logger
|
||||
Clk mockable.Clock
|
||||
Log log.Logger
|
||||
}
|
||||
|
||||
func (vm *TestVM) Clock() *mockable.Clock {
|
||||
return &vm.Clk
|
||||
}
|
||||
|
||||
func (vm *TestVM) CodecRegistry() codec.Registry {
|
||||
return vm.Codec
|
||||
}
|
||||
|
||||
func (vm *TestVM) Logger() log.Logger {
|
||||
return vm.Log
|
||||
}
|
||||
|
||||
+3
-28
@@ -6,7 +6,6 @@ package secp256k1fx
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/luxfi/ids"
|
||||
|
||||
@@ -59,33 +58,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
|
||||
fx.recoverCache = secp256k1.NewRecoverCache(defaultCacheSize)
|
||||
|
||||
if fx.VM == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := fx.VM.CodecRegistry()
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Try to register types, but ignore duplicate registration errors
|
||||
errs := []error{}
|
||||
if err := c.RegisterType(&TransferInput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&TransferOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOperation{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&Credential{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
// ZAP-native: wire schemas are compile-time static in
|
||||
// secp256k1fx/wire.go. No runtime codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fx *Fx) InitializeVM(vmIntf interface{}) error {
|
||||
|
||||
+4
-10
@@ -4,14 +4,13 @@
|
||||
package secp256k1fx
|
||||
|
||||
import (
|
||||
"github.com/luxfi/codec"
|
||||
log "github.com/luxfi/log"
|
||||
"github.com/luxfi/timer/mockable"
|
||||
)
|
||||
|
||||
// VM that this Fx must be run by
|
||||
// VM that this Fx must be run by. ZAP-native: no runtime codec
|
||||
// registration — wire schemas are compile-time static.
|
||||
type VM interface {
|
||||
CodecRegistry() codec.Registry
|
||||
Clock() *mockable.Clock
|
||||
Logger() log.Logger
|
||||
}
|
||||
@@ -20,19 +19,14 @@ var _ VM = (*TestVM)(nil)
|
||||
|
||||
// TestVM is a minimal implementation of a VM
|
||||
type TestVM struct {
|
||||
Clk mockable.Clock
|
||||
Codec codec.Registry
|
||||
Log log.Logger
|
||||
Clk mockable.Clock
|
||||
Log log.Logger
|
||||
}
|
||||
|
||||
func (vm *TestVM) Clock() *mockable.Clock {
|
||||
return &vm.Clk
|
||||
}
|
||||
|
||||
func (vm *TestVM) CodecRegistry() codec.Registry {
|
||||
return vm.Codec
|
||||
}
|
||||
|
||||
func (vm *TestVM) Logger() log.Logger {
|
||||
return vm.Log
|
||||
}
|
||||
|
||||
+3
-23
@@ -6,7 +6,6 @@ package secp256r1fx
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/luxfi/cache/lru"
|
||||
"github.com/luxfi/crypto/hash"
|
||||
@@ -60,28 +59,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := fx.VM.CodecRegistry()
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errs := []error{}
|
||||
if err := c.RegisterType(&TransferInput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&TransferOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOperation{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&Credential{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
// ZAP-native: wire schemas are compile-time static in the per-fx
|
||||
// wire.go bridge. No runtime codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fx *Fx) InitializeVM(vmIntf interface{}) error {
|
||||
|
||||
+4
-10
@@ -4,14 +4,13 @@
|
||||
package secp256r1fx
|
||||
|
||||
import (
|
||||
"github.com/luxfi/codec"
|
||||
log "github.com/luxfi/log"
|
||||
"github.com/luxfi/timer/mockable"
|
||||
)
|
||||
|
||||
// VM that this Fx must be run by
|
||||
// VM that this Fx must be run by. ZAP-native: no runtime codec
|
||||
// registration — wire schemas are compile-time static.
|
||||
type VM interface {
|
||||
CodecRegistry() codec.Registry
|
||||
Clock() *mockable.Clock
|
||||
Logger() log.Logger
|
||||
}
|
||||
@@ -20,19 +19,14 @@ var _ VM = (*TestVM)(nil)
|
||||
|
||||
// TestVM is a minimal implementation of a VM
|
||||
type TestVM struct {
|
||||
Clk mockable.Clock
|
||||
Codec codec.Registry
|
||||
Log log.Logger
|
||||
Clk mockable.Clock
|
||||
Log log.Logger
|
||||
}
|
||||
|
||||
func (vm *TestVM) Clock() *mockable.Clock {
|
||||
return &vm.Clk
|
||||
}
|
||||
|
||||
func (vm *TestVM) CodecRegistry() codec.Registry {
|
||||
return vm.Codec
|
||||
}
|
||||
|
||||
func (vm *TestVM) Logger() log.Logger {
|
||||
return vm.Log
|
||||
}
|
||||
|
||||
+3
-23
@@ -6,7 +6,6 @@ package slhdsafx
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/luxfi/cache/lru"
|
||||
"github.com/luxfi/crypto/hash"
|
||||
@@ -66,28 +65,9 @@ func (fx *Fx) Initialize(vmIntf interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := fx.VM.CodecRegistry()
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
errs := []error{}
|
||||
if err := c.RegisterType(&TransferInput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&TransferOutput{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&MintOperation{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := c.RegisterType(&Credential{}); err != nil && !strings.Contains(err.Error(), "duplicate type registration") {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
// ZAP-native: wire schemas are compile-time static in the per-fx
|
||||
// wire.go bridge. No runtime codec registration needed.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fx *Fx) InitializeVM(vmIntf interface{}) error {
|
||||
|
||||
+4
-10
@@ -4,14 +4,13 @@
|
||||
package slhdsafx
|
||||
|
||||
import (
|
||||
"github.com/luxfi/codec"
|
||||
log "github.com/luxfi/log"
|
||||
"github.com/luxfi/timer/mockable"
|
||||
)
|
||||
|
||||
// VM that this Fx must be run by
|
||||
// VM that this Fx must be run by. ZAP-native: no runtime codec
|
||||
// registration — wire schemas are compile-time static.
|
||||
type VM interface {
|
||||
CodecRegistry() codec.Registry
|
||||
Clock() *mockable.Clock
|
||||
Logger() log.Logger
|
||||
}
|
||||
@@ -20,19 +19,14 @@ var _ VM = (*TestVM)(nil)
|
||||
|
||||
// TestVM is a minimal implementation of a VM
|
||||
type TestVM struct {
|
||||
Clk mockable.Clock
|
||||
Codec codec.Registry
|
||||
Log log.Logger
|
||||
Clk mockable.Clock
|
||||
Log log.Logger
|
||||
}
|
||||
|
||||
func (vm *TestVM) Clock() *mockable.Clock {
|
||||
return &vm.Clk
|
||||
}
|
||||
|
||||
func (vm *TestVM) CodecRegistry() codec.Registry {
|
||||
return vm.Codec
|
||||
}
|
||||
|
||||
func (vm *TestVM) Logger() log.Logger {
|
||||
return vm.Log
|
||||
}
|
||||
|
||||
+27
-20
@@ -8,7 +8,6 @@ import (
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
"github.com/luxfi/codec"
|
||||
"github.com/luxfi/crypto/secp256k1"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/runtime"
|
||||
@@ -86,9 +85,21 @@ func (out *TransferableOutput) Verify() error {
|
||||
}
|
||||
}
|
||||
|
||||
// wireBytesOrNil returns the ZAP wire envelope for a TransferableOut if
|
||||
// the inner fxs primitive implements the per-fx wire.go Bytes() bridge.
|
||||
// Returns nil when the type does not carry a wire adapter — callers must
|
||||
// not rely on a stable sort across unknown types. Every production fxs
|
||||
// primitive (secp256k1fx/mldsafx/slhdsafx/ed25519fx/secp256r1fx/schnorrfx/
|
||||
// bls12381fx/nftfx/propertyfx) satisfies this contract via wire.go.
|
||||
func wireBytesOrNil(out TransferableOut) []byte {
|
||||
if ws, ok := out.(interface{ Bytes() []byte }); ok {
|
||||
return ws.Bytes()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type innerSortTransferableOutputs struct {
|
||||
outs []*TransferableOutput
|
||||
codec codec.Manager
|
||||
outs []*TransferableOutput
|
||||
}
|
||||
|
||||
func (outs *innerSortTransferableOutputs) Less(i, j int) bool {
|
||||
@@ -105,15 +116,11 @@ func (outs *innerSortTransferableOutputs) Less(i, j int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
iBytes, err := outs.codec.Marshal(codecVersion, &iOut.Out)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
jBytes, err := outs.codec.Marshal(codecVersion, &jOut.Out)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Compare(iBytes, jBytes) == -1
|
||||
// ZAP-native canonical sort: bytes of the inner fx wire envelope.
|
||||
// The per-fx wire.go Bytes() returns the same TypeKind+ShapeKind+
|
||||
// ZAP-message envelope that hits the wire and disk — single source
|
||||
// of truth for total ordering, no separate codec marshal step.
|
||||
return bytes.Compare(wireBytesOrNil(iOut.Out), wireBytesOrNil(jOut.Out)) == -1
|
||||
}
|
||||
|
||||
func (outs *innerSortTransferableOutputs) Len() int {
|
||||
@@ -125,14 +132,15 @@ func (outs *innerSortTransferableOutputs) Swap(i, j int) {
|
||||
o[j], o[i] = o[i], o[j]
|
||||
}
|
||||
|
||||
// SortTransferableOutputs sorts output objects
|
||||
func SortTransferableOutputs(outs []*TransferableOutput, c codec.Manager) {
|
||||
sort.Sort(&innerSortTransferableOutputs{outs: outs, codec: c})
|
||||
// SortTransferableOutputs sorts output objects by (AssetID, inner-output
|
||||
// ZAP wire bytes). ZAP-native — no codec.Manager needed.
|
||||
func SortTransferableOutputs(outs []*TransferableOutput) {
|
||||
sort.Sort(&innerSortTransferableOutputs{outs: outs})
|
||||
}
|
||||
|
||||
// IsSortedTransferableOutputs returns true if output objects are sorted
|
||||
func IsSortedTransferableOutputs(outs []*TransferableOutput, c codec.Manager) bool {
|
||||
return sort.IsSorted(&innerSortTransferableOutputs{outs: outs, codec: c})
|
||||
// IsSortedTransferableOutputs returns true if output objects are sorted.
|
||||
func IsSortedTransferableOutputs(outs []*TransferableOutput) bool {
|
||||
return sort.IsSorted(&innerSortTransferableOutputs{outs: outs})
|
||||
}
|
||||
|
||||
type TransferableInput struct {
|
||||
@@ -213,7 +221,6 @@ func VerifyTx(
|
||||
feeAssetID ids.ID,
|
||||
allIns [][]*TransferableInput,
|
||||
allOuts [][]*TransferableOutput,
|
||||
c codec.Manager,
|
||||
) error {
|
||||
fc := NewFlowChecker()
|
||||
|
||||
@@ -227,7 +234,7 @@ func VerifyTx(
|
||||
}
|
||||
fc.Produce(out.AssetID(), out.Output().Amount())
|
||||
}
|
||||
if !IsSortedTransferableOutputs(outs, c) {
|
||||
if !IsSortedTransferableOutputs(outs) {
|
||||
return ErrOutputsNotSorted
|
||||
}
|
||||
}
|
||||
|
||||
+11
-13
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/luxfi/cache"
|
||||
"github.com/luxfi/cache/metercacher"
|
||||
"github.com/luxfi/codec"
|
||||
"github.com/luxfi/database"
|
||||
"github.com/luxfi/database/linkeddb"
|
||||
"github.com/luxfi/database/prefixdb"
|
||||
@@ -72,8 +71,6 @@ type UTXOWriter interface {
|
||||
}
|
||||
|
||||
type utxoState struct {
|
||||
codec codec.Manager
|
||||
|
||||
// UTXO ID -> *UTXO. If the *UTXO is nil the UTXO doesn't exist
|
||||
utxoCache cache.Cacher[ids.ID, *UTXO]
|
||||
utxoDB database.Database
|
||||
@@ -85,14 +82,15 @@ type utxoState struct {
|
||||
checksum ids.ID
|
||||
}
|
||||
|
||||
// NewUTXOState returns a UTXOState backed by ZAP-native wire bytes
|
||||
// (no codec.Manager). Caller MUST have invoked RegisterParseUTXO at
|
||||
// boot — the fxs dispatch needed to reconstruct *UTXO from wire bytes
|
||||
// lives in the consumer package to break the import cycle.
|
||||
func NewUTXOState(
|
||||
db database.Database,
|
||||
codec codec.Manager,
|
||||
trackChecksum bool,
|
||||
) (UTXOState, error) {
|
||||
s := &utxoState{
|
||||
codec: codec,
|
||||
|
||||
utxoCache: &cache.LRU[ids.ID, *UTXO]{Size: utxoCacheSize},
|
||||
utxoDB: prefixdb.New(utxoPrefix, db),
|
||||
|
||||
@@ -106,7 +104,6 @@ func NewUTXOState(
|
||||
|
||||
func NewMeteredUTXOState(
|
||||
db database.Database,
|
||||
codec codec.Manager,
|
||||
metrics metric.Registerer,
|
||||
trackChecksum bool,
|
||||
) (UTXOState, error) {
|
||||
@@ -135,8 +132,6 @@ func NewMeteredUTXOState(
|
||||
}
|
||||
|
||||
s := &utxoState{
|
||||
codec: codec,
|
||||
|
||||
utxoCache: utxoCache,
|
||||
utxoDB: prefixdb.New(utxoPrefix, db),
|
||||
|
||||
@@ -165,9 +160,10 @@ func (s *utxoState) GetUTXO(utxoID ids.ID) (*UTXO, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The key was in the database
|
||||
utxo := &UTXO{}
|
||||
if _, err := s.codec.Unmarshal(bytes, utxo); err != nil {
|
||||
// The key was in the database. Parse via the consumer-registered
|
||||
// fx-aware ParseUTXO factory (set via RegisterParseUTXO at boot).
|
||||
utxo, err := ParseUTXO(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -176,7 +172,9 @@ func (s *utxoState) GetUTXO(utxoID ids.ID) (*UTXO, error) {
|
||||
}
|
||||
|
||||
func (s *utxoState) PutUTXO(utxo *UTXO) error {
|
||||
utxoBytes, err := s.codec.Marshal(codecVersion, utxo)
|
||||
// ZAP-native: same bytes flow on the wire and to disk. No
|
||||
// separate codec.Marshal step.
|
||||
utxoBytes, err := utxo.WireBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user