lnd.xprv/lndc/lnadr.go

192 lines
4.6 KiB
Go

package lndc
import (
"bytes"
"encoding/binary"
"encoding/hex"
"fmt"
"net"
"strings"
"github.com/roasbeef/btcd/btcec"
"github.com/roasbeef/btcd/chaincfg"
"github.com/roasbeef/btcutil"
)
// lnAddr...
// TODO(roasbeef): revamp
type LNAdr struct {
LnID [16]byte // redundant because adr contains it
PubKey *btcec.PublicKey
Base58Adr btcutil.Address // Base58 encoded address (1XXX...)
NetAddr *net.TCPAddr // IP address
name string // human readable name? Not a thing yet.
host string // internet host this ID is reachable at. also not a thing
endorsement []byte // a sig confirming the name? Not implemented
net *chaincfg.Params
}
// newLnAdr....
func NewLnAdr(addr *net.TCPAddr, pubkey *btcec.PublicKey,
net *chaincfg.Params) (*LNAdr, error) {
hash160 := btcutil.Hash160(pubkey.SerializeCompressed())
pkh, err := btcutil.NewAddressPubKeyHash(hash160, net)
if err != nil {
return nil, err
}
return &LNAdr{
PubKey: pubkey,
Base58Adr: pkh,
NetAddr: addr,
net: net,
}, nil
}
// newLnAddr...
func LnAddrFromString(encodedAddr string, netParams *chaincfg.Params) (*LNAdr, error) {
// The format of an lnaddr is "<pubkey or pkh>@host"
idHost := strings.Split(encodedAddr, "@")
if len(idHost) != 2 {
return nil, fmt.Errorf("invalid format for lnaddr string: %v", encodedAddr)
}
// Attempt to resolve the IP address, this handles parsing IPv6 zones,
// and such.
ipAddr, err := net.ResolveTCPAddr("tcp", idHost[1])
if err != nil {
return nil, err
}
addr := &LNAdr{NetAddr: ipAddr, net: netParams}
idLen := len(idHost[0])
switch {
// Is the ID a hex-encoded compressed public key?
case idLen > 65 && idLen < 69:
pubkeyBytes, err := hex.DecodeString(idHost[0])
if err != nil {
return nil, err
}
addr.PubKey, err = btcec.ParsePubKey(pubkeyBytes, btcec.S256())
if err != nil {
return nil, err
}
// got pubey, populate address from pubkey
pkh := btcutil.Hash160(addr.PubKey.SerializeCompressed())
addr.Base58Adr, err = btcutil.NewAddressPubKeyHash(pkh,
netParams)
if err != nil {
return nil, err
}
// Is the ID a string encoded bitcoin address?
case idLen > 33 && idLen < 37:
addr.Base58Adr, err = btcutil.DecodeAddress(idHost[0],
netParams)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("invalid address %s", idHost[0])
}
// Finally, populate the lnid from the address.
copy(addr.LnID[:], addr.Base58Adr.ScriptAddress())
return addr, nil
}
// Deserialize an LNId from byte slice (on disk)
// Note that this does not check any internal consistency, because on local
// storage there's no point. Check separately if needed.
// Also, old and probably needs to be changed / updated
func (l *LNAdr) Deserialize(s []byte) error {
b := bytes.NewBuffer(s)
// Fail if on-disk LNId too short
if b.Len() < 24 { // 24 is min lenght
return fmt.Errorf("can't read LNId - too short")
}
// read indicator of pubkey or pubkeyhash
x, err := b.ReadByte()
if err != nil {
return err
}
if x == 0xb0 { // for pubkey storage
// read 33 bytes of pubkey
l.PubKey, err = btcec.ParsePubKey(b.Next(33), btcec.S256())
if err != nil {
return err
}
l.Base58Adr, err = btcutil.NewAddressPubKeyHash(
btcutil.Hash160(l.PubKey.SerializeCompressed()),
&chaincfg.TestNet3Params)
if err != nil {
return err
}
} else if x == 0xa0 { // for pubkeyhash storage
l.Base58Adr, err = btcutil.NewAddressPubKeyHash(
b.Next(20), &chaincfg.TestNet3Params)
if err != nil {
return err
}
} else {
return fmt.Errorf("Unknown lnid indicator byte %x", x)
}
var nameLen, hostLen, endorseLen uint8
// read name length
err = binary.Read(b, binary.BigEndian, &nameLen)
if err != nil {
return err
}
// if name non-zero, read name
if nameLen > 0 {
l.name = string(b.Next(int(nameLen)))
}
// read host length
err = binary.Read(b, binary.BigEndian, &hostLen)
if err != nil {
return err
}
// if host non-zero, read host
if hostLen > 0 {
l.host = string(b.Next(int(hostLen)))
}
// read endorsement length
err = binary.Read(b, binary.BigEndian, &endorseLen)
if err != nil {
return err
}
// if endorsement non-zero, read endorsement
if endorseLen > 0 {
l.endorsement = b.Next(int(endorseLen))
}
return nil
}
// String...
func (l *LNAdr) String() string {
var encodedId []byte
if l.Base58Adr != nil {
encodedId = l.Base58Adr.ScriptAddress()
} else {
pubKey := l.PubKey.SerializeCompressed()
pkh, _ := btcutil.NewAddressPubKeyHash(pubKey, l.net)
encodedId = pkh.ScriptAddress()
}
return fmt.Sprintf("%v@%v", hex.EncodeToString(encodedId), l.NetAddr)
}