mirror of
https://github.com/luxfi/proto.git
synced 2026-10-30 15:21:09 +00:00
proto required luxfi/node and luxfi/node required proto, with no replace directive on either side. The cycle was not load-bearing: most of it was proto reaching into the node for packages proto already owns — p/warp, p/txs, p/signer, p/stakeable, p/security, x/txs — which now name themselves. Two were real. The UTXO components moved here, where the chains that use them already live, and the node is the only other caller, so that dependency now runs one way. And p/config held the node's chain manager to queue a chain the P-Chain had accepted a CreateChainTx for; it calls one method, so it declares one method. A P-Chain that imports the node to describe QueueChainCreation is what made two modules require each other. Dropping the requirement dropped a registration with it: lux.ParseUTXO is a registry filled by an init, which the node used to link in on proto's behalf. The packages that call it now say so themselves. Co-authored-by: Hanzo Dev <[email protected]>
155 lines
4.2 KiB
Go
155 lines
4.2 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package lux
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/runtime"
|
|
|
|
"github.com/luxfi/address"
|
|
"github.com/luxfi/constants"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/math/set"
|
|
)
|
|
|
|
var (
|
|
_ AddressManager = (*addressManager)(nil)
|
|
|
|
ErrMismatchedChainIDs = errors.New("mismatched chainIDs")
|
|
)
|
|
|
|
// BCLookup provides blockchain alias lookup
|
|
type BCLookup interface {
|
|
Lookup(string) (ids.ID, error)
|
|
PrimaryAlias(ids.ID) (string, error)
|
|
}
|
|
|
|
type AddressManager interface {
|
|
// ParseLocalAddress takes in an address for this chain and produces the ID
|
|
ParseLocalAddress(addrStr string) (ids.ShortID, error)
|
|
|
|
// ParseAddress takes in an address and produces the ID of the chain it's
|
|
// for and the ID of the address
|
|
ParseAddress(addrStr string) (ids.ID, ids.ShortID, error)
|
|
|
|
// FormatLocalAddress takes in a raw address and produces the formatted
|
|
// address for this chain
|
|
FormatLocalAddress(addr ids.ShortID) (string, error)
|
|
|
|
// FormatAddress takes in a chainID and a raw address and produces the
|
|
// formatted address for that chain
|
|
FormatAddress(chainID ids.ID, addr ids.ShortID) (string, error)
|
|
}
|
|
|
|
type addressManager struct {
|
|
rt *runtime.Runtime
|
|
}
|
|
|
|
func NewAddressManager(rt *runtime.Runtime) AddressManager {
|
|
return &addressManager{
|
|
rt: rt,
|
|
}
|
|
}
|
|
|
|
func (a *addressManager) ParseLocalAddress(addrStr string) (ids.ShortID, error) {
|
|
chainID, addr, err := a.ParseAddress(addrStr)
|
|
if err != nil {
|
|
return ids.ShortID{}, err
|
|
}
|
|
expectedChainID := a.rt.ChainID
|
|
if chainID != expectedChainID {
|
|
return ids.ShortID{}, fmt.Errorf(
|
|
"%w: expected %q but got %q",
|
|
ErrMismatchedChainIDs,
|
|
expectedChainID,
|
|
chainID,
|
|
)
|
|
}
|
|
return addr, nil
|
|
}
|
|
|
|
func (a *addressManager) ParseAddress(addrStr string) (ids.ID, ids.ShortID, error) {
|
|
chainIDAlias, hrp, addrBytes, err := address.Parse(addrStr)
|
|
if err != nil {
|
|
return ids.Empty, ids.ShortID{}, err
|
|
}
|
|
|
|
// Try to parse chainIDAlias as an ID directly since Runtime doesn't have BCLookup
|
|
chainID, err := ids.FromString(chainIDAlias)
|
|
if err != nil {
|
|
return ids.ID{}, ids.ShortID{}, fmt.Errorf("failed to parse chain ID %q: %w", chainIDAlias, err)
|
|
}
|
|
|
|
networkID := a.rt.NetworkID
|
|
expectedHRP := constants.GetHRP(networkID)
|
|
if hrp != expectedHRP {
|
|
return ids.Empty, ids.ShortID{}, fmt.Errorf(
|
|
"expected hrp %q but got %q",
|
|
expectedHRP,
|
|
hrp,
|
|
)
|
|
}
|
|
|
|
addr, err := ids.ToShortID(addrBytes)
|
|
if err != nil {
|
|
return ids.Empty, ids.ShortID{}, err
|
|
}
|
|
return chainID, addr, nil
|
|
}
|
|
|
|
func (a *addressManager) FormatLocalAddress(addr ids.ShortID) (string, error) {
|
|
chainID := a.rt.ChainID
|
|
return a.FormatAddress(chainID, addr)
|
|
}
|
|
|
|
func (a *addressManager) FormatAddress(chainID ids.ID, addr ids.ShortID) (string, error) {
|
|
// Use ChainID directly - Runtime doesn't have BCLookup
|
|
chainIDAlias := chainID.String()
|
|
hrp := constants.GetHRP(a.rt.NetworkID)
|
|
return address.Format(chainIDAlias, hrp, addr.Bytes())
|
|
}
|
|
|
|
func ParseLocalAddresses(a AddressManager, addrStrs []string) (set.Set[ids.ShortID], error) {
|
|
addrs := make(set.Set[ids.ShortID], len(addrStrs))
|
|
for _, addrStr := range addrStrs {
|
|
addr, err := a.ParseLocalAddress(addrStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("couldn't parse address %q: %w", addrStr, err)
|
|
}
|
|
addrs.Add(addr)
|
|
}
|
|
return addrs, nil
|
|
}
|
|
|
|
// ParseServiceAddress get address ID from address string, being it either localized (using address manager,
|
|
// doing also components validations), or not localized.
|
|
// If both attempts fail, reports error from localized address parsing
|
|
func ParseServiceAddress(a AddressManager, addrStr string) (ids.ShortID, error) {
|
|
addr, err := ids.ShortFromString(addrStr)
|
|
if err == nil {
|
|
return addr, nil
|
|
}
|
|
|
|
addr, err = a.ParseLocalAddress(addrStr)
|
|
if err != nil {
|
|
return addr, fmt.Errorf("couldn't parse address %q: %w", addrStr, err)
|
|
}
|
|
return addr, nil
|
|
}
|
|
|
|
// ParseServiceAddress get addresses IDs from addresses strings, being them either localized or not
|
|
func ParseServiceAddresses(a AddressManager, addrStrs []string) (set.Set[ids.ShortID], error) {
|
|
addrs := set.NewSet[ids.ShortID](len(addrStrs))
|
|
for _, addrStr := range addrStrs {
|
|
addr, err := ParseServiceAddress(a, addrStr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
addrs.Add(addr)
|
|
}
|
|
return addrs, nil
|
|
}
|