github.com/ava-labs/avalanchego@v1.11.11/vms/components/avax/addresses.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package avax
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  
    10  	"github.com/ava-labs/avalanchego/ids"
    11  	"github.com/ava-labs/avalanchego/snow"
    12  	"github.com/ava-labs/avalanchego/utils/constants"
    13  	"github.com/ava-labs/avalanchego/utils/formatting/address"
    14  	"github.com/ava-labs/avalanchego/utils/set"
    15  )
    16  
    17  var (
    18  	_ AddressManager = (*addressManager)(nil)
    19  
    20  	ErrMismatchedChainIDs = errors.New("mismatched chainIDs")
    21  )
    22  
    23  type AddressManager interface {
    24  	// ParseLocalAddress takes in an address for this chain and produces the ID
    25  	ParseLocalAddress(addrStr string) (ids.ShortID, error)
    26  
    27  	// ParseAddress takes in an address and produces the ID of the chain it's
    28  	// for and the ID of the address
    29  	ParseAddress(addrStr string) (ids.ID, ids.ShortID, error)
    30  
    31  	// FormatLocalAddress takes in a raw address and produces the formatted
    32  	// address for this chain
    33  	FormatLocalAddress(addr ids.ShortID) (string, error)
    34  
    35  	// FormatAddress takes in a chainID and a raw address and produces the
    36  	// formatted address for that chain
    37  	FormatAddress(chainID ids.ID, addr ids.ShortID) (string, error)
    38  }
    39  
    40  type addressManager struct {
    41  	ctx *snow.Context
    42  }
    43  
    44  func NewAddressManager(ctx *snow.Context) AddressManager {
    45  	return &addressManager{
    46  		ctx: ctx,
    47  	}
    48  }
    49  
    50  func (a *addressManager) ParseLocalAddress(addrStr string) (ids.ShortID, error) {
    51  	chainID, addr, err := a.ParseAddress(addrStr)
    52  	if err != nil {
    53  		return ids.ShortID{}, err
    54  	}
    55  	if chainID != a.ctx.ChainID {
    56  		return ids.ShortID{}, fmt.Errorf(
    57  			"%w: expected %q but got %q",
    58  			ErrMismatchedChainIDs,
    59  			a.ctx.ChainID,
    60  			chainID,
    61  		)
    62  	}
    63  	return addr, nil
    64  }
    65  
    66  func (a *addressManager) ParseAddress(addrStr string) (ids.ID, ids.ShortID, error) {
    67  	chainIDAlias, hrp, addrBytes, err := address.Parse(addrStr)
    68  	if err != nil {
    69  		return ids.Empty, ids.ShortID{}, err
    70  	}
    71  
    72  	chainID, err := a.ctx.BCLookup.Lookup(chainIDAlias)
    73  	if err != nil {
    74  		return ids.Empty, ids.ShortID{}, err
    75  	}
    76  
    77  	expectedHRP := constants.GetHRP(a.ctx.NetworkID)
    78  	if hrp != expectedHRP {
    79  		return ids.Empty, ids.ShortID{}, fmt.Errorf(
    80  			"expected hrp %q but got %q",
    81  			expectedHRP,
    82  			hrp,
    83  		)
    84  	}
    85  
    86  	addr, err := ids.ToShortID(addrBytes)
    87  	if err != nil {
    88  		return ids.Empty, ids.ShortID{}, err
    89  	}
    90  	return chainID, addr, nil
    91  }
    92  
    93  func (a *addressManager) FormatLocalAddress(addr ids.ShortID) (string, error) {
    94  	return a.FormatAddress(a.ctx.ChainID, addr)
    95  }
    96  
    97  func (a *addressManager) FormatAddress(chainID ids.ID, addr ids.ShortID) (string, error) {
    98  	chainIDAlias, err := a.ctx.BCLookup.PrimaryAlias(chainID)
    99  	if err != nil {
   100  		return "", err
   101  	}
   102  	hrp := constants.GetHRP(a.ctx.NetworkID)
   103  	return address.Format(chainIDAlias, hrp, addr.Bytes())
   104  }
   105  
   106  func ParseLocalAddresses(a AddressManager, addrStrs []string) (set.Set[ids.ShortID], error) {
   107  	addrs := make(set.Set[ids.ShortID], len(addrStrs))
   108  	for _, addrStr := range addrStrs {
   109  		addr, err := a.ParseLocalAddress(addrStr)
   110  		if err != nil {
   111  			return nil, fmt.Errorf("couldn't parse address %q: %w", addrStr, err)
   112  		}
   113  		addrs.Add(addr)
   114  	}
   115  	return addrs, nil
   116  }
   117  
   118  // ParseServiceAddress get address ID from address string, being it either localized (using address manager,
   119  // doing also components validations), or not localized.
   120  // If both attempts fail, reports error from localized address parsing
   121  func ParseServiceAddress(a AddressManager, addrStr string) (ids.ShortID, error) {
   122  	addr, err := ids.ShortFromString(addrStr)
   123  	if err == nil {
   124  		return addr, nil
   125  	}
   126  
   127  	addr, err = a.ParseLocalAddress(addrStr)
   128  	if err != nil {
   129  		return addr, fmt.Errorf("couldn't parse address %q: %w", addrStr, err)
   130  	}
   131  	return addr, nil
   132  }
   133  
   134  // ParseServiceAddresses get addresses IDs from addresses strings, being them either localized or not
   135  func ParseServiceAddresses(a AddressManager, addrStrs []string) (set.Set[ids.ShortID], error) {
   136  	addrs := set.NewSet[ids.ShortID](len(addrStrs))
   137  	for _, addrStr := range addrStrs {
   138  		addr, err := ParseServiceAddress(a, addrStr)
   139  		if err != nil {
   140  			return nil, err
   141  		}
   142  		addrs.Add(addr)
   143  	}
   144  	return addrs, nil
   145  }