Files
zeekay 7cf87b230b node-unified is the node
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.
2026-09-07 16:15:25 -07:00

144 lines
4.0 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package common
import (
"context"
"maps"
"slices"
"sync"
"github.com/luxfi/database"
"github.com/luxfi/ids"
lux "github.com/luxfi/utxo"
)
var (
_ UTXOs = (*utxos)(nil)
_ ChainUTXOs = (*chainUTXOs)(nil)
)
type UTXOs interface {
AddUTXO(ctx context.Context, sourceChainID, destinationChainID ids.ID, utxo *lux.UTXO) error
RemoveUTXO(ctx context.Context, sourceChainID, destinationChainID, utxoID ids.ID) error
UTXOs(ctx context.Context, sourceChainID, destinationChainID ids.ID) ([]*lux.UTXO, error)
GetUTXO(ctx context.Context, sourceChainID, destinationChainID, utxoID ids.ID) (*lux.UTXO, error)
}
type ChainUTXOs interface {
AddUTXO(ctx context.Context, destinationChainID ids.ID, utxo *lux.UTXO) error
RemoveUTXO(ctx context.Context, sourceChainID, utxoID ids.ID) error
UTXOs(ctx context.Context, sourceChainID ids.ID) ([]*lux.UTXO, error)
GetUTXO(ctx context.Context, sourceChainID, utxoID ids.ID) (*lux.UTXO, error)
}
func NewUTXOs() UTXOs {
return &utxos{
sourceToDestToUTXOIDToUTXO: make(map[ids.ID]map[ids.ID]map[ids.ID]*lux.UTXO),
}
}
func NewChainUTXOs(chainID ids.ID, utxos UTXOs) ChainUTXOs {
return &chainUTXOs{
utxos: utxos,
chainID: chainID,
}
}
type utxos struct {
lock sync.RWMutex
// sourceChainID -> destinationChainID -> utxoID -> utxo
sourceToDestToUTXOIDToUTXO map[ids.ID]map[ids.ID]map[ids.ID]*lux.UTXO
}
func (u *utxos) AddUTXO(_ context.Context, sourceChainID, destinationChainID ids.ID, utxo *lux.UTXO) error {
u.lock.Lock()
defer u.lock.Unlock()
destToUTXOIDToUTXO, ok := u.sourceToDestToUTXOIDToUTXO[sourceChainID]
if !ok {
destToUTXOIDToUTXO = make(map[ids.ID]map[ids.ID]*lux.UTXO)
u.sourceToDestToUTXOIDToUTXO[sourceChainID] = destToUTXOIDToUTXO
}
utxoIDToUTXO, ok := destToUTXOIDToUTXO[destinationChainID]
if !ok {
utxoIDToUTXO = make(map[ids.ID]*lux.UTXO)
destToUTXOIDToUTXO[destinationChainID] = utxoIDToUTXO
}
utxoIDToUTXO[utxo.InputID()] = utxo
return nil
}
func (u *utxos) RemoveUTXO(_ context.Context, sourceChainID, destinationChainID, utxoID ids.ID) error {
u.lock.Lock()
defer u.lock.Unlock()
destToUTXOIDToUTXO := u.sourceToDestToUTXOIDToUTXO[sourceChainID]
utxoIDToUTXO := destToUTXOIDToUTXO[destinationChainID]
_, ok := utxoIDToUTXO[utxoID]
if !ok {
return nil
}
delete(utxoIDToUTXO, utxoID)
if len(utxoIDToUTXO) != 0 {
return nil
}
delete(destToUTXOIDToUTXO, destinationChainID)
if len(destToUTXOIDToUTXO) != 0 {
return nil
}
delete(u.sourceToDestToUTXOIDToUTXO, sourceChainID)
return nil
}
func (u *utxos) UTXOs(_ context.Context, sourceChainID, destinationChainID ids.ID) ([]*lux.UTXO, error) {
u.lock.RLock()
defer u.lock.RUnlock()
destToUTXOIDToUTXO := u.sourceToDestToUTXOIDToUTXO[sourceChainID]
utxoIDToUTXO := destToUTXOIDToUTXO[destinationChainID]
return slices.Collect(maps.Values(utxoIDToUTXO)), nil
}
func (u *utxos) GetUTXO(_ context.Context, sourceChainID, destinationChainID, utxoID ids.ID) (*lux.UTXO, error) {
u.lock.RLock()
defer u.lock.RUnlock()
destToUTXOIDToUTXO := u.sourceToDestToUTXOIDToUTXO[sourceChainID]
utxoIDToUTXO := destToUTXOIDToUTXO[destinationChainID]
utxo, ok := utxoIDToUTXO[utxoID]
if !ok {
return nil, database.ErrNotFound
}
return utxo, nil
}
type chainUTXOs struct {
utxos UTXOs
chainID ids.ID
}
func (c *chainUTXOs) AddUTXO(ctx context.Context, destinationChainID ids.ID, utxo *lux.UTXO) error {
return c.utxos.AddUTXO(ctx, c.chainID, destinationChainID, utxo)
}
func (c *chainUTXOs) RemoveUTXO(ctx context.Context, sourceChainID, utxoID ids.ID) error {
return c.utxos.RemoveUTXO(ctx, sourceChainID, c.chainID, utxoID)
}
func (c *chainUTXOs) UTXOs(ctx context.Context, sourceChainID ids.ID) ([]*lux.UTXO, error) {
return c.utxos.UTXOs(ctx, sourceChainID, c.chainID)
}
func (c *chainUTXOs) GetUTXO(ctx context.Context, sourceChainID, utxoID ids.ID) (*lux.UTXO, error) {
return c.utxos.GetUTXO(ctx, sourceChainID, c.chainID, utxoID)
}