2016-01-17 21:45:07 +03:00
|
|
|
package lndc
|
|
|
|
|
|
|
|
import (
|
2016-01-19 11:05:02 +03:00
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
2016-01-17 21:45:07 +03:00
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"strings"
|
|
|
|
|
2016-05-15 17:17:44 +03:00
|
|
|
"github.com/roasbeef/btcd/btcec"
|
|
|
|
"github.com/roasbeef/btcd/chaincfg"
|
|
|
|
"github.com/roasbeef/btcutil"
|
2016-01-17 21:45:07 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// lnAddr...
|
2016-06-21 07:45:55 +03:00
|
|
|
// TODO(roasbeef): revamp
|
2016-01-17 21:45:07 +03:00
|
|
|
type LNAdr struct {
|
2016-01-19 11:05:02 +03:00
|
|
|
LnID [16]byte // redundant because adr contains it
|
2016-01-17 21:45:07 +03:00
|
|
|
PubKey *btcec.PublicKey
|
|
|
|
|
2016-01-19 11:05:02 +03:00
|
|
|
Base58Adr btcutil.Address // Base58 encoded address (1XXX...)
|
|
|
|
NetAddr *net.TCPAddr // IP address
|
2016-01-17 21:45:07 +03:00
|
|
|
|
|
|
|
name string // human readable name? Not a thing yet.
|
2016-01-19 11:05:02 +03:00
|
|
|
host string // internet host this ID is reachable at. also not a thing
|
2016-01-17 21:45:07 +03:00
|
|
|
endorsement []byte // a sig confirming the name? Not implemented
|
2016-07-17 04:00:52 +03:00
|
|
|
|
|
|
|
net *chaincfg.Params
|
2016-01-17 21:45:07 +03:00
|
|
|
}
|
|
|
|
|
2016-07-17 04:00:52 +03:00
|
|
|
// 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
|
2016-01-17 21:45:07 +03:00
|
|
|
}
|
|
|
|
|
2016-07-17 04:00:52 +03:00
|
|
|
return &LNAdr{
|
|
|
|
PubKey: pubkey,
|
|
|
|
Base58Adr: pkh,
|
|
|
|
NetAddr: addr,
|
|
|
|
net: net,
|
|
|
|
}, nil
|
2016-01-17 21:45:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// newLnAddr...
|
2016-07-17 04:00:52 +03:00
|
|
|
func LnAddrFromString(encodedAddr string, netParams *chaincfg.Params) (*LNAdr, error) {
|
2016-01-17 21:45:07 +03:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2016-07-17 04:00:52 +03:00
|
|
|
addr := &LNAdr{NetAddr: ipAddr, net: netParams}
|
2016-01-17 21:45:07 +03:00
|
|
|
|
|
|
|
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())
|
2016-01-19 11:05:02 +03:00
|
|
|
addr.Base58Adr, err = btcutil.NewAddressPubKeyHash(pkh,
|
2016-07-17 04:00:52 +03:00
|
|
|
netParams)
|
2016-01-17 21:45:07 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Is the ID a string encoded bitcoin address?
|
|
|
|
case idLen > 33 && idLen < 37:
|
2016-01-19 11:05:02 +03:00
|
|
|
addr.Base58Adr, err = btcutil.DecodeAddress(idHost[0],
|
2016-07-17 04:00:52 +03:00
|
|
|
netParams)
|
2016-01-17 21:45:07 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("invalid address %s", idHost[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, populate the lnid from the address.
|
2016-01-19 11:05:02 +03:00
|
|
|
copy(addr.LnID[:], addr.Base58Adr.ScriptAddress())
|
2016-01-17 21:45:07 +03:00
|
|
|
|
|
|
|
return addr, nil
|
|
|
|
}
|
2016-01-19 11:05:02 +03:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2016-07-17 04:00:52 +03:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|