fix vendor folder

This commit is contained in:
Juan Pablo Civile
2019-12-16 17:59:11 -03:00
parent 240b7f00bd
commit a60e97ace6
72 changed files with 1551 additions and 6487 deletions

View File

@@ -36,10 +36,17 @@ var (
// interface from crypto/elliptic.
type KoblitzCurve struct {
*elliptic.CurveParams
q *big.Int
// q is the value (P+1)/4 used to compute the square root of field
// elements.
q *big.Int
H int // cofactor of the curve.
halfOrder *big.Int // half the order N
// fieldB is the constant B of the curve as a fieldVal.
fieldB *fieldVal
// byteSize is simply the bit size / 8 and is provided for convenience
// since it is calculated repeatedly.
byteSize int
@@ -879,12 +886,22 @@ func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
return curve.fieldJacobianToBigAffine(qx, qy, qz)
}
// QPlus1Div4 returns the Q+1/4 constant for the curve for use in calculating
// square roots via exponention.
// QPlus1Div4 returns the (P+1)/4 constant for the curve for use in calculating
// square roots via exponentiation.
//
// DEPRECATED: The actual value returned is (P+1)/4, where as the original
// method name implies that this value is (((P+1)/4)+1)/4. This method is kept
// to maintain backwards compatibility of the API. Use Q() instead.
func (curve *KoblitzCurve) QPlus1Div4() *big.Int {
return curve.q
}
// Q returns the (P+1)/4 constant for the curve for use in calculating square
// roots via exponentiation.
func (curve *KoblitzCurve) Q() *big.Int {
return curve.q
}
var initonce sync.Once
var secp256k1 KoblitzCurve
@@ -917,6 +934,7 @@ func initS256() {
big.NewInt(1)), big.NewInt(4))
secp256k1.H = 1
secp256k1.halfOrder = new(big.Int).Rsh(secp256k1.N, 1)
secp256k1.fieldB = new(fieldVal).SetByteSlice(secp256k1.B.Bytes())
// Provided for convenience since this gets computed repeatedly.
secp256k1.byteSize = secp256k1.BitSize / 8

View File

@@ -102,6 +102,20 @@ const (
fieldPrimeWordOne = 0x3ffffbf
)
var (
// fieldQBytes is the value Q = (P+1)/4 for the secp256k1 prime P. This
// value is used to efficiently compute the square root of values in the
// field via exponentiation. The value of Q in hex is:
//
// Q = 3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c
fieldQBytes = []byte{
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0x0c,
}
)
// fieldVal implements optimized fixed-precision arithmetic over the
// secp256k1 finite field. This means all arithmetic is performed modulo
// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. It
@@ -1221,3 +1235,118 @@ func (f *fieldVal) Inverse() *fieldVal {
f.Square().Square().Square().Square().Square() // f = a^(2^256 - 4294968320)
return f.Mul(&a45) // f = a^(2^256 - 4294968275) = a^(p-2)
}
// SqrtVal computes the square root of x modulo the curve's prime, and stores
// the result in f. The square root is computed via exponentiation of x by the
// value Q = (P+1)/4 using the curve's precomputed big-endian representation of
// the Q. This method uses a modified version of square-and-multiply
// exponentiation over secp256k1 fieldVals to operate on bytes instead of bits,
// which offers better performance over both big.Int exponentiation and bit-wise
// square-and-multiply.
//
// NOTE: This method only works when P is intended to be the secp256k1 prime and
// is not constant time. The returned value is of magnitude 1, but is
// denormalized.
func (f *fieldVal) SqrtVal(x *fieldVal) *fieldVal {
// The following computation iteratively computes x^((P+1)/4) = x^Q
// using the recursive, piece-wise definition:
//
// x^n = (x^2)^(n/2) mod P if n is even
// x^n = x(x^2)^(n-1/2) mod P if n is odd
//
// Given n in its big-endian representation b_k, ..., b_0, x^n can be
// computed by defining the sequence r_k+1, ..., r_0, where:
//
// r_k+1 = 1
// r_i = (r_i+1)^2 * x^b_i for i = k, ..., 0
//
// The final value r_0 = x^n.
//
// See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more
// details.
//
// This can be further optimized, by observing that the value of Q in
// secp256k1 has the value:
//
// Q = 3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c
//
// We can unroll the typical bit-wise interpretation of the
// exponentiation algorithm above to instead operate on bytes.
// This reduces the number of comparisons by an order of magnitude,
// reducing the overhead of failed branch predictions and additional
// comparisons in this method.
//
// Since there there are only 4 unique bytes of Q, this keeps the jump
// table small without the need to handle all possible 8-bit values.
// Further, we observe that 29 of the 32 bytes are 0xff; making the
// first case handle 0xff therefore optimizes the hot path.
f.SetInt(1)
for _, b := range fieldQBytes {
switch b {
// Most common case, where all 8 bits are set.
case 0xff:
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
// First byte of Q (0x3f), where all but the top two bits are
// set. Note that this case only applies six operations, since
// the highest bit of Q resides in bit six of the first byte. We
// ignore the first two bits, since squaring for these bits will
// result in an invalid result. We forgo squaring f before the
// first multiply, since 1^2 = 1.
case 0x3f:
f.Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
// Byte 28 of Q (0xbf), where only bit 7 is unset.
case 0xbf:
f.Square().Mul(x)
f.Square()
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
f.Square().Mul(x)
// Byte 31 of Q (0x0c), where only bits 3 and 4 are set.
default:
f.Square()
f.Square()
f.Square()
f.Square()
f.Square().Mul(x)
f.Square().Mul(x)
f.Square()
f.Square()
}
}
return f
}
// Sqrt computes the square root of f modulo the curve's prime, and stores the
// result in f. The square root is computed via exponentiation of x by the value
// Q = (P+1)/4 using the curve's precomputed big-endian representation of the Q.
// This method uses a modified version of square-and-multiply exponentiation
// over secp256k1 fieldVals to operate on bytes instead of bits, which offers
// better performance over both big.Int exponentiation and bit-wise
// square-and-multiply.
//
// NOTE: This method only works when P is intended to be the secp256k1 prime and
// is not constant time. The returned value is of magnitude 1, but is
// denormalized.
func (f *fieldVal) Sqrt() *fieldVal {
return f.SqrtVal(f)
}

View File

@@ -1,63 +0,0 @@
// Copyright 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
// This file is ignored during the regular build due to the following build tag.
// It is called by go generate and used to automatically generate pre-computed
// tables used to accelerate operations.
// +build ignore
package main
import (
"bytes"
"compress/zlib"
"encoding/base64"
"fmt"
"log"
"os"
"github.com/btcsuite/btcd/btcec"
)
func main() {
fi, err := os.Create("secp256k1.go")
if err != nil {
log.Fatal(err)
}
defer fi.Close()
// Compress the serialized byte points.
serialized := btcec.S256().SerializedBytePoints()
var compressed bytes.Buffer
w := zlib.NewWriter(&compressed)
if _, err := w.Write(serialized); err != nil {
fmt.Println(err)
os.Exit(1)
}
w.Close()
// Encode the compressed byte points with base64.
encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len()))
base64.StdEncoding.Encode(encoded, compressed.Bytes())
fmt.Fprintln(fi, "// Copyright (c) 2015 The btcsuite developers")
fmt.Fprintln(fi, "// Use of this source code is governed by an ISC")
fmt.Fprintln(fi, "// license that can be found in the LICENSE file.")
fmt.Fprintln(fi)
fmt.Fprintln(fi, "package btcec")
fmt.Fprintln(fi)
fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)")
fmt.Fprintln(fi, "// DO NOT EDIT")
fmt.Fprintln(fi)
fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded))
a1, b1, a2, b2 := btcec.S256().EndomorphismVectors()
fmt.Println("The following values are the computed linearly " +
"independent vectors needed to make use of the secp256k1 " +
"endomorphism:")
fmt.Printf("a1: %x\n", a1)
fmt.Printf("b1: %x\n", b1)
fmt.Printf("a2: %x\n", a2)
fmt.Printf("b2: %x\n", b2)
}

View File

@@ -22,41 +22,40 @@ func isOdd(a *big.Int) bool {
return a.Bit(0) == 1
}
// decompressPoint decompresses a point on the given curve given the X point and
// decompressPoint decompresses a point on the secp256k1 curve given the X point and
// the solution to use.
func decompressPoint(curve *KoblitzCurve, x *big.Int, ybit bool) (*big.Int, error) {
// TODO: This will probably only work for secp256k1 due to
// optimizations.
func decompressPoint(curve *KoblitzCurve, bigX *big.Int, ybit bool) (*big.Int, error) {
var x fieldVal
x.SetByteSlice(bigX.Bytes())
// Y = +-sqrt(x^3 + B)
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
x3.Add(x3, curve.Params().B)
x3.Mod(x3, curve.Params().P)
// Compute x^3 + B mod p.
var x3 fieldVal
x3.SquareVal(&x).Mul(&x)
x3.Add(curve.fieldB).Normalize()
// Now calculate sqrt mod p of x^3 + B
// This code used to do a full sqrt based on tonelli/shanks,
// but this was replaced by the algorithms referenced in
// https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294
y := new(big.Int).Exp(x3, curve.QPlus1Div4(), curve.Params().P)
if ybit != isOdd(y) {
y.Sub(curve.Params().P, y)
var y fieldVal
y.SqrtVal(&x3).Normalize()
if ybit != y.IsOdd() {
y.Negate(1).Normalize()
}
// Check that y is a square root of x^3 + B.
y2 := new(big.Int).Mul(y, y)
y2.Mod(y2, curve.Params().P)
if y2.Cmp(x3) != 0 {
var y2 fieldVal
y2.SquareVal(&y).Normalize()
if !y2.Equals(&x3) {
return nil, fmt.Errorf("invalid square root")
}
// Verify that y-coord has expected parity.
if ybit != isOdd(y) {
if ybit != y.IsOdd() {
return nil, fmt.Errorf("ybit doesn't match oddness")
}
return y, nil
return new(big.Int).SetBytes(y.Bytes()[:]), nil
}
const (
@@ -102,6 +101,17 @@ func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *PublicKey, err err
if format == pubkeyHybrid && ybit != isOdd(pubkey.Y) {
return nil, fmt.Errorf("ybit doesn't match oddness")
}
if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, fmt.Errorf("pubkey X parameter is >= to P")
}
if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, fmt.Errorf("pubkey Y parameter is >= to P")
}
if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) {
return nil, fmt.Errorf("pubkey isn't on secp256k1 curve")
}
case PubKeyBytesLenCompressed:
// format is 0x2 | solution, <X coordinate>
// solution determines which solution of the curve we use.
@@ -115,20 +125,12 @@ func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *PublicKey, err err
if err != nil {
return nil, err
}
default: // wrong!
return nil, fmt.Errorf("invalid pub key length %d",
len(pubKeyStr))
}
if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, fmt.Errorf("pubkey X parameter is >= to P")
}
if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, fmt.Errorf("pubkey Y parameter is >= to P")
}
if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) {
return nil, fmt.Errorf("pubkey isn't on secp256k1 curve")
}
return &pubkey, nil
}

View File

@@ -276,7 +276,7 @@ func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
}
// recoverKeyFromSignature recovers a public key from the signature "sig" on the
// given message hash "msg". Based on the algorithm found in section 5.1.5 of
// given message hash "msg". Based on the algorithm found in section 4.1.6 of
// SEC 1 Ver 2.0, page 47-48 (53 and 54 in the pdf). This performs the details
// in the inner loop in Step 1. The counter provided is actually the j parameter
// of the loop * 2 - on the first iteration of j we do the R case, else the -R

View File

@@ -638,6 +638,7 @@ func NewSearchRawTransactionsCmd(address string, verbose, skip, count *int, vinE
type SendRawTransactionCmd struct {
HexTx string
AllowHighFees *bool `jsonrpcdefault:"false"`
MaxFeeRate *int32
}
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
@@ -652,6 +653,17 @@ func NewSendRawTransactionCmd(hexTx string, allowHighFees *bool) *SendRawTransac
}
}
// NewSendRawTransactionCmd returns a new instance which can be used to issue a
// sendrawtransaction JSON-RPC command to a bitcoind node.
//
// A 0 maxFeeRate indicates that a maximum fee rate won't be enforced.
func NewBitcoindSendRawTransactionCmd(hexTx string, maxFeeRate int32) *SendRawTransactionCmd {
return &SendRawTransactionCmd{
HexTx: hexTx,
MaxFeeRate: &maxFeeRate,
}
}
// SetGenerateCmd defines the setgenerate JSON-RPC command.
type SetGenerateCmd struct {
Generate bool

View File

@@ -90,28 +90,61 @@ type SoftForkDescription struct {
// Bip9SoftForkDescription describes the current state of a defined BIP0009
// version bits soft-fork.
type Bip9SoftForkDescription struct {
Status string `json:"status"`
Bit uint8 `json:"bit"`
StartTime int64 `json:"startTime"`
Timeout int64 `json:"timeout"`
Since int32 `json:"since"`
Status string `json:"status"`
Bit uint8 `json:"bit"`
StartTime1 int64 `json:"startTime"`
StartTime2 int64 `json:"start_time"`
Timeout int64 `json:"timeout"`
Since int32 `json:"since"`
}
// StartTime returns the starting time of the softfork as a Unix epoch.
func (d *Bip9SoftForkDescription) StartTime() int64 {
if d.StartTime1 != 0 {
return d.StartTime1
}
return d.StartTime2
}
// SoftForks describes the current softforks enabled by the backend. Softforks
// activated through BIP9 are grouped together separate from any other softforks
// with different activation types.
type SoftForks struct {
SoftForks []*SoftForkDescription `json:"softforks"`
Bip9SoftForks map[string]*Bip9SoftForkDescription `json:"bip9_softforks"`
}
// UnifiedSoftForks describes a softforks in a general manner, irrespective of
// its activation type. This was a format introduced by bitcoind v0.19.0
type UnifiedSoftFork struct {
Type string `json:"type"`
BIP9SoftForkDescription *Bip9SoftForkDescription `json:"bip9"`
Height int32 `json:"height"`
Active bool `json:"active"`
}
// UnifiedSoftForks describes the current softforks enabled the by the backend
// in a unified manner, i.e, softforks with different activation types are
// grouped together. This was a format introduced by bitcoind v0.19.0
type UnifiedSoftForks struct {
SoftForks map[string]*UnifiedSoftFork `json:"softforks"`
}
// GetBlockChainInfoResult models the data returned from the getblockchaininfo
// command.
type GetBlockChainInfoResult struct {
Chain string `json:"chain"`
Blocks int32 `json:"blocks"`
Headers int32 `json:"headers"`
BestBlockHash string `json:"bestblockhash"`
Difficulty float64 `json:"difficulty"`
MedianTime int64 `json:"mediantime"`
VerificationProgress float64 `json:"verificationprogress,omitempty"`
Pruned bool `json:"pruned"`
PruneHeight int32 `json:"pruneheight,omitempty"`
ChainWork string `json:"chainwork,omitempty"`
SoftForks []*SoftForkDescription `json:"softforks"`
Bip9SoftForks map[string]*Bip9SoftForkDescription `json:"bip9_softforks"`
Chain string `json:"chain"`
Blocks int32 `json:"blocks"`
Headers int32 `json:"headers"`
BestBlockHash string `json:"bestblockhash"`
Difficulty float64 `json:"difficulty"`
MedianTime int64 `json:"mediantime"`
VerificationProgress float64 `json:"verificationprogress,omitempty"`
Pruned bool `json:"pruned"`
PruneHeight int32 `json:"pruneheight,omitempty"`
ChainWork string `json:"chainwork,omitempty"`
*SoftForks
*UnifiedSoftForks
}
// GetBlockTemplateResultTx models the transactions field of the
@@ -265,6 +298,7 @@ type GetPeerInfoResult struct {
type GetRawMempoolVerboseResult struct {
Size int32 `json:"size"`
Vsize int32 `json:"vsize"`
Weight int32 `json:"weight"`
Fee float64 `json:"fee"`
Time int64 `json:"time"`
Height int64 `json:"height"`
@@ -505,6 +539,7 @@ type TxRawResult struct {
Hash string `json:"hash,omitempty"`
Size int32 `json:"size,omitempty"`
Vsize int32 `json:"vsize,omitempty"`
Weight int32 `json:"weight,omitempty"`
Version int32 `json:"version"`
LockTime uint32 `json:"locktime"`
Vin []Vin `json:"vin"`
@@ -523,6 +558,7 @@ type SearchRawTransactionsResult struct {
Hash string `json:"hash"`
Size string `json:"size"`
Vsize string `json:"vsize"`
Weight string `json:"weight"`
Version int32 `json:"version"`
LockTime uint32 `json:"locktime"`
Vin []VinPrevOut `json:"vin"`

View File

@@ -253,16 +253,15 @@ func (c *Client) GetDifficulty() (float64, error) {
// FutureGetBlockChainInfoResult is a promise to deliver the result of a
// GetBlockChainInfoAsync RPC invocation (or an applicable error).
type FutureGetBlockChainInfoResult chan *response
// Receive waits for the response promised by the future and returns chain info
// result provided by the server.
func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResult, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, err
}
type FutureGetBlockChainInfoResult struct {
client *Client
Response chan *response
}
// unmarshalPartialGetBlockChainInfoResult unmarshals the response into an
// instance of GetBlockChainInfoResult without populating the SoftForks and
// UnifiedSoftForks fields.
func unmarshalPartialGetBlockChainInfoResult(res []byte) (*btcjson.GetBlockChainInfoResult, error) {
var chainInfo btcjson.GetBlockChainInfoResult
if err := json.Unmarshal(res, &chainInfo); err != nil {
return nil, err
@@ -270,6 +269,59 @@ func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResu
return &chainInfo, nil
}
// unmarshalGetBlockChainInfoResultSoftForks properly unmarshals the softforks
// related fields into the GetBlockChainInfoResult instance.
func unmarshalGetBlockChainInfoResultSoftForks(chainInfo *btcjson.GetBlockChainInfoResult,
version BackendVersion, res []byte) error {
switch version {
// Versions of bitcoind on or after v0.19.0 use the unified format.
case BitcoindPost19:
var softForks btcjson.UnifiedSoftForks
if err := json.Unmarshal(res, &softForks); err != nil {
return err
}
chainInfo.UnifiedSoftForks = &softForks
// All other versions use the original format.
default:
var softForks btcjson.SoftForks
if err := json.Unmarshal(res, &softForks); err != nil {
return err
}
chainInfo.SoftForks = &softForks
}
return nil
}
// Receive waits for the response promised by the future and returns chain info
// result provided by the server.
func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResult, error) {
res, err := receiveFuture(r.Response)
if err != nil {
return nil, err
}
chainInfo, err := unmarshalPartialGetBlockChainInfoResult(res)
if err != nil {
return nil, err
}
// Inspect the version to determine how we'll need to parse the
// softforks from the response.
version, err := r.client.BackendVersion()
if err != nil {
return nil, err
}
err = unmarshalGetBlockChainInfoResultSoftForks(chainInfo, version, res)
if err != nil {
return nil, err
}
return chainInfo, nil
}
// GetBlockChainInfoAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function
// on the returned instance.
@@ -277,7 +329,10 @@ func (r FutureGetBlockChainInfoResult) Receive() (*btcjson.GetBlockChainInfoResu
// See GetBlockChainInfo for the blocking version and more details.
func (c *Client) GetBlockChainInfoAsync() FutureGetBlockChainInfoResult {
cmd := btcjson.NewGetBlockChainInfoCmd()
return c.sendCmd(cmd)
return FutureGetBlockChainInfoResult{
client: c,
Response: c.sendCmd(cmd),
}
}
// GetBlockChainInfo returns information related to the processing state of

View File

@@ -19,6 +19,7 @@ import (
"net"
"net/http"
"net/url"
"strings"
"sync"
"sync/atomic"
"time"
@@ -103,6 +104,22 @@ type jsonRequest struct {
responseChan chan *response
}
// BackendVersion represents the version of the backend the client is currently
// connected to.
type BackendVersion uint8
const (
// BitcoindPre19 represents a bitcoind version before 0.19.0.
BitcoindPre19 BackendVersion = iota
// BitcoindPost19 represents a bitcoind version equal to or greater than
// 0.19.0.
BitcoindPost19
// Btcd represents a catch-all btcd version.
Btcd
)
// Client represents a Bitcoin RPC client which allows easy access to the
// various RPC methods available on a Bitcoin RPC server. Each of the wrapper
// functions handle the details of converting the passed and return types to and
@@ -129,6 +146,11 @@ type Client struct {
// POST mode.
httpClient *http.Client
// backendVersion is the version of the backend the client is currently
// connected to. This should be retrieved through GetVersion.
backendVersionMu sync.Mutex
backendVersion *BackendVersion
// mtx is a mutex to protect access to connection related fields.
mtx sync.Mutex
@@ -659,6 +681,12 @@ out:
log.Infof("Reestablished connection to RPC server %s",
c.config.Host)
// Reset the version in case the backend was
// disconnected due to an upgrade.
c.backendVersionMu.Lock()
c.backendVersion = nil
c.backendVersionMu.Unlock()
// Reset the connection state and signal the reconnect
// has happened.
c.wsConn = wsConn
@@ -1332,3 +1360,84 @@ func (c *Client) Connect(tries int) error {
// All connection attempts failed, so return the last error.
return err
}
const (
// bitcoind19Str is the string representation of bitcoind v0.19.0.
bitcoind19Str = "0.19.0"
// bitcoindVersionPrefix specifies the prefix included in every bitcoind
// version exposed through GetNetworkInfo.
bitcoindVersionPrefix = "/Satoshi:"
// bitcoindVersionSuffix specifies the suffix included in every bitcoind
// version exposed through GetNetworkInfo.
bitcoindVersionSuffix = "/"
)
// parseBitcoindVersion parses the bitcoind version from its string
// representation.
func parseBitcoindVersion(version string) BackendVersion {
// Trim the version of its prefix and suffix to determine the
// appropriate version number.
version = strings.TrimPrefix(
strings.TrimSuffix(version, bitcoindVersionSuffix),
bitcoindVersionPrefix,
)
switch {
case version < bitcoind19Str:
return BitcoindPre19
default:
return BitcoindPost19
}
}
// BackendVersion retrieves the version of the backend the client is currently
// connected to.
func (c *Client) BackendVersion() (BackendVersion, error) {
c.backendVersionMu.Lock()
defer c.backendVersionMu.Unlock()
if c.backendVersion != nil {
return *c.backendVersion, nil
}
// We'll start by calling GetInfo. This method doesn't exist for
// bitcoind nodes as of v0.16.0, so we'll assume the client is connected
// to a btcd backend if it does exist.
info, err := c.GetInfo()
switch err := err.(type) {
// Parse the btcd version and cache it.
case nil:
log.Debugf("Detected btcd version: %v", info.Version)
version := Btcd
c.backendVersion = &version
return *c.backendVersion, nil
// Inspect the RPC error to ensure the method was not found, otherwise
// we actually ran into an error.
case *btcjson.RPCError:
if err.Code != btcjson.ErrRPCMethodNotFound.Code {
return 0, fmt.Errorf("unable to detect btcd version: "+
"%v", err)
}
default:
return 0, fmt.Errorf("unable to detect btcd version: %v", err)
}
// Since the GetInfo method was not found, we assume the client is
// connected to a bitcoind backend, which exposes its version through
// GetNetworkInfo.
networkInfo, err := c.GetNetworkInfo()
if err != nil {
return 0, fmt.Errorf("unable to detect bitcoind version: %v", err)
}
// Parse the bitcoind version and cache it.
log.Debugf("Detected bitcoind version: %v", networkInfo.SubVersion)
version := parseBitcoindVersion(networkInfo.SubVersion)
c.backendVersion = &version
return *c.backendVersion, nil
}

View File

@@ -244,6 +244,43 @@ func (c *Client) Ping() error {
return c.PingAsync().Receive()
}
// FutureGetNetworkInfoResult is a future promise to deliver the result of a
// GetNetworkInfoAsync RPC invocation (or an applicable error).
type FutureGetNetworkInfoResult chan *response
// Receive waits for the response promised by the future and returns data about
// the current network.
func (r FutureGetNetworkInfoResult) Receive() (*btcjson.GetNetworkInfoResult, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, err
}
// Unmarshal result as an array of getpeerinfo result objects.
var networkInfo btcjson.GetNetworkInfoResult
err = json.Unmarshal(res, &networkInfo)
if err != nil {
return nil, err
}
return &networkInfo, nil
}
// GetNetworkInfoAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See GetNetworkInfo for the blocking version and more details.
func (c *Client) GetNetworkInfoAsync() FutureGetNetworkInfoResult {
cmd := btcjson.NewGetNetworkInfoCmd()
return c.sendCmd(cmd)
}
// GetNetworkInfo returns data about the current network.
func (c *Client) GetNetworkInfo() (*btcjson.GetNetworkInfoResult, error) {
return c.GetNetworkInfoAsync().Receive()
}
// FutureGetPeerInfoResult is a future promise to deliver the result of a
// GetPeerInfoAsync RPC invocation (or an applicable error).
type FutureGetPeerInfoResult chan *response

View File

@@ -15,6 +15,12 @@ import (
"github.com/btcsuite/btcutil"
)
const (
// defaultMaxFeeRate is the default maximum fee rate in sat/KB enforced
// by bitcoind v0.19.0 or after for transaction broadcast.
defaultMaxFeeRate = btcutil.SatoshiPerBitcoin / 10
)
// SigHashType enumerates the available signature hashing types that the
// SignRawTransaction function accepts.
type SigHashType string
@@ -296,7 +302,31 @@ func (c *Client) SendRawTransactionAsync(tx *wire.MsgTx, allowHighFees bool) Fut
txHex = hex.EncodeToString(buf.Bytes())
}
cmd := btcjson.NewSendRawTransactionCmd(txHex, &allowHighFees)
// Due to differences in the sendrawtransaction API for different
// backends, we'll need to inspect our version and construct the
// appropriate request.
version, err := c.BackendVersion()
if err != nil {
return newFutureError(err)
}
var cmd *btcjson.SendRawTransactionCmd
switch version {
// Starting from bitcoind v0.19.0, the MaxFeeRate field should be used.
case BitcoindPost19:
// Using a 0 MaxFeeRate is interpreted as a maximum fee rate not
// being enforced by bitcoind.
var maxFeeRate int32
if !allowHighFees {
maxFeeRate = defaultMaxFeeRate
}
cmd = btcjson.NewBitcoindSendRawTransactionCmd(txHex, maxFeeRate)
// Otherwise, use the AllowHighFees field.
default:
cmd = btcjson.NewSendRawTransactionCmd(txHex, &allowHighFees)
}
return c.sendCmd(cmd)
}

View File

@@ -1,79 +0,0 @@
// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
//+build ignore
package main
import (
"bytes"
"io"
"log"
"os"
"strconv"
)
var (
start = []byte(`// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
// AUTOGENERATED by genalphabet.go; do not edit.
package base58
const (
// alphabet is the modified base58 alphabet used by Bitcoin.
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
alphabetIdx0 = '1'
)
var b58 = [256]byte{`)
end = []byte(`}`)
alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
tab = []byte("\t")
invalid = []byte("255")
comma = []byte(",")
space = []byte(" ")
nl = []byte("\n")
)
func write(w io.Writer, b []byte) {
_, err := w.Write(b)
if err != nil {
log.Fatal(err)
}
}
func main() {
fi, err := os.Create("alphabet.go")
if err != nil {
log.Fatal(err)
}
defer fi.Close()
write(fi, start)
write(fi, nl)
for i := byte(0); i < 32; i++ {
write(fi, tab)
for j := byte(0); j < 8; j++ {
idx := bytes.IndexByte(alphabet, i*8+j)
if idx == -1 {
write(fi, invalid)
} else {
write(fi, strconv.AppendInt(nil, int64(idx), 10))
}
write(fi, comma)
if j != 7 {
write(fi, space)
}
}
write(fi, nl)
}
write(fi, end)
write(fi, nl)
}

View File

@@ -10,18 +10,19 @@ datastore. Package bdb is licensed under the copyfree ISC license.
## Usage
This package is only a driver to the walletdb package and provides the database
type of "bdb". The only parameter the Open and Create functions take is the
database path as a string:
type of "bdb". The only parameters the Open and Create functions take is the
database path as a string, and an option for the database to not sync its
freelist to disk as a bool:
```Go
db, err := walletdb.Open("bdb", "path/to/database.db")
db, err := walletdb.Open("bdb", "path/to/database.db", true)
if err != nil {
// Handle error
}
```
```Go
db, err := walletdb.Create("bdb", "path/to/database.db")
db, err := walletdb.Create("bdb", "path/to/database.db", true)
if err != nil {
// Handle error
}

View File

@@ -339,7 +339,7 @@ func fileExists(name string) bool {
// openDB opens the database at the provided path. walletdb.ErrDbDoesNotExist
// is returned if the database doesn't exist and the create flag is not set.
func openDB(dbPath string, create bool) (walletdb.DB, error) {
func openDB(dbPath string, noFreelistSync bool, create bool) (walletdb.DB, error) {
if !create && !fileExists(dbPath) {
return nil, walletdb.ErrDbDoesNotExist
}
@@ -347,7 +347,7 @@ func openDB(dbPath string, create bool) (walletdb.DB, error) {
// Specify bbolt freelist options to reduce heap pressure in case the
// freelist grows to be very large.
options := &bbolt.Options{
NoFreelistSync: true,
NoFreelistSync: noFreelistSync,
FreelistType: bbolt.FreelistMapType,
}

View File

@@ -9,15 +9,16 @@ datastore.
Usage
This package is only a driver to the walletdb package and provides the database
type of "bdb". The only parameter the Open and Create functions take is the
database path as a string:
type of "bdb". The only parameters the Open and Create functions take is the
database path as a string, and an option for the database to not sync its
freelist to disk as a bool:
db, err := walletdb.Open("bdb", "path/to/database.db")
db, err := walletdb.Open("bdb", "path/to/database.db", true)
if err != nil {
// Handle error
}
db, err := walletdb.Create("bdb", "path/to/database.db")
db, err := walletdb.Create("bdb", "path/to/database.db", true)
if err != nil {
// Handle error
}

View File

@@ -15,41 +15,50 @@ const (
)
// parseArgs parses the arguments from the walletdb Open/Create methods.
func parseArgs(funcName string, args ...interface{}) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("invalid arguments to %s.%s -- "+
"expected database path", dbType, funcName)
func parseArgs(funcName string, args ...interface{}) (string, bool, error) {
if len(args) != 2 {
return "", false, fmt.Errorf("invalid arguments to %s.%s -- "+
"expected database path and no-freelist-sync option",
dbType, funcName)
}
dbPath, ok := args[0].(string)
if !ok {
return "", fmt.Errorf("first argument to %s.%s is invalid -- "+
"expected database path string", dbType, funcName)
return "", false, fmt.Errorf("first argument to %s.%s is "+
"invalid -- expected database path string", dbType,
funcName)
}
return dbPath, nil
noFreelistSync, ok := args[1].(bool)
if !ok {
return "", false, fmt.Errorf("second argument to %s.%s is "+
"invalid -- expected no-freelist-sync bool", dbType,
funcName)
}
return dbPath, noFreelistSync, nil
}
// openDBDriver is the callback provided during driver registration that opens
// an existing database for use.
func openDBDriver(args ...interface{}) (walletdb.DB, error) {
dbPath, err := parseArgs("Open", args...)
dbPath, noFreelistSync, err := parseArgs("Open", args...)
if err != nil {
return nil, err
}
return openDB(dbPath, false)
return openDB(dbPath, noFreelistSync, false)
}
// createDBDriver is the callback provided during driver registration that
// creates, initializes, and opens a database for use.
func createDBDriver(args ...interface{}) (walletdb.DB, error) {
dbPath, err := parseArgs("Create", args...)
dbPath, noFreelistSync, err := parseArgs("Create", args...)
if err != nil {
return nil, err
}
return openDB(dbPath, true)
return openDB(dbPath, noFreelistSync, true)
}
func init() {

View File

@@ -1,6 +1,8 @@
package lnwire
import "io"
import (
"io"
)
// CommitSig is sent by either side to stage any pending HTLC's in the
// receiver's pending set into a new commitment state. Implicitly, the new
@@ -83,3 +85,11 @@ func (c *CommitSig) MaxPayloadLength(uint32) uint32 {
// 32 + 64 + 2 + max_allowed_htlcs
return MaxMessagePayload
}
// TargetChanID returns the channel id of the link for which this message is
// intended.
//
// NOTE: Part of lnd.LinkUpdater interface.
func (c *CommitSig) TargetChanID() ChannelID {
return c.ChanID
}

View File

@@ -1,41 +1,32 @@
package lnwire
import (
"fmt"
"io"
"google.golang.org/grpc/codes"
)
// ErrorCode represents the short error code for each of the defined errors
// within the Lightning Network protocol spec.
type ErrorCode uint8
// ToGrpcCode is used to generate gRPC specific code which will be propagated
// to the ln rpc client. This code is used to have more detailed view of what
// goes wrong and also in order to have the ability pragmatically determine the
// error and take specific actions on the client side.
func (e ErrorCode) ToGrpcCode() codes.Code {
return (codes.Code)(e) + 100
}
// FundingError represents a set of errors that can be encountered and sent
// during the funding workflow.
type FundingError uint8
const (
// ErrMaxPendingChannels is returned by remote peer when the number of
// active pending channels exceeds their maximum policy limit.
ErrMaxPendingChannels ErrorCode = 1
ErrMaxPendingChannels FundingError = 1
// ErrSynchronizingChain is returned by a remote peer that receives a
// channel update or a funding request while their still syncing to the
// latest state of the blockchain.
ErrSynchronizingChain ErrorCode = 2
ErrSynchronizingChain FundingError = 2
// ErrChanTooLarge is returned by a remote peer that receives a
// FundingOpen request for a channel that is above their current
// soft-limit.
ErrChanTooLarge ErrorCode = 3
ErrChanTooLarge FundingError = 3
)
// String returns a human readable version of the target ErrorCode.
func (e ErrorCode) String() string {
// String returns a human readable version of the target FundingError.
func (e FundingError) String() string {
switch e {
case ErrMaxPendingChannels:
return "Number of pending channels exceed maximum"
@@ -48,10 +39,10 @@ func (e ErrorCode) String() string {
}
}
// Error returns the human redable version of the target ErrorCode.
// Error returns the human redable version of the target FundingError.
//
// Satisfies the Error interface.
func (e ErrorCode) Error() string {
// NOTE: Satisfies the Error interface.
func (e FundingError) Error() string {
return e.String()
}
@@ -65,8 +56,6 @@ type ErrorData []byte
// format is purposefully general in order to allow expression of a wide array
// of possible errors. Each Error message is directed at a particular open
// channel referenced by ChannelPoint.
//
// TODO(roasbeef): remove the error code
type Error struct {
// ChanID references the active channel in which the error occurred
// within. If the ChanID is all zeros, then this error applies to the
@@ -87,6 +76,18 @@ func NewError() *Error {
// interface.
var _ Message = (*Error)(nil)
// Error returns the string representation to Error.
//
// NOTE: Satisfies the error interface.
func (c *Error) Error() string {
errMsg := "non-ascii data"
if isASCII(c.Data) {
errMsg = string(c.Data)
}
return fmt.Sprintf("chan_id=%v, err=%v", c.ChanID, errMsg)
}
// Decode deserializes a serialized Error message stored in the passed
// io.Reader observing the specified protocol version.
//
@@ -125,3 +126,14 @@ func (c *Error) MaxPayloadLength(uint32) uint32 {
// 32 + 2 + 65501
return 65535
}
// isASCII is a helper method that checks whether all bytes in `data` would be
// printable ASCII characters if interpreted as a string.
func isASCII(data []byte) bool {
for _, c := range data {
if c < 32 || c > 126 {
return false
}
}
return true
}

View File

@@ -46,6 +46,25 @@ const (
// efficient network view reconciliation.
GossipQueriesOptional FeatureBit = 7
// TLVOnionPayloadRequired is a feature bit that indicates a node is
// able to decode the new TLV information included in the onion packet.
TLVOnionPayloadRequired FeatureBit = 8
// TLVOnionPayloadRequired is an optional feature bit that indicates a
// node is able to decode the new TLV information included in the onion
// packet.
TLVOnionPayloadOptional FeatureBit = 9
// StaticRemoteKeyRequired is a required feature bit that signals that
// within one's commitment transaction, the key used for the remote
// party's non-delay output should not be tweaked.
StaticRemoteKeyRequired FeatureBit = 12
// StaticRemoteKeyOptional is an optional feature bit that signals that
// within one's commitment transaction, the key used for the remote
// party's non-delay output should not be tweaked.
StaticRemoteKeyOptional FeatureBit = 13
// maxAllowedSize is a maximum allowed size of feature vector.
//
// NOTE: Within the protocol, the maximum allowed message size is 65535
@@ -76,7 +95,12 @@ var LocalFeatures = map[FeatureBit]string{
// name. All known global feature bits must be assigned a name in this mapping.
// Global features are those which are advertised to the entire network. A full
// description of these feature bits is provided in the BOLT-09 specification.
var GlobalFeatures map[FeatureBit]string
var GlobalFeatures = map[FeatureBit]string{
TLVOnionPayloadRequired: "tlv-onion",
TLVOnionPayloadOptional: "tlv-onion",
StaticRemoteKeyOptional: "static-remote-key",
StaticRemoteKeyRequired: "static-remote-key",
}
// RawFeatureVector represents a set of feature bits as defined in BOLT-09. A
// RawFeatureVector itself just stores a set of bit flags but can be used to
@@ -115,6 +139,20 @@ func (fv *RawFeatureVector) Unset(feature FeatureBit) {
// SerializeSize returns the number of bytes needed to represent feature vector
// in byte format.
func (fv *RawFeatureVector) SerializeSize() int {
// We calculate byte-length via the largest bit index.
return fv.serializeSize(8)
}
// SerializeSize32 returns the number of bytes needed to represent feature
// vector in base32 format.
func (fv *RawFeatureVector) SerializeSize32() int {
// We calculate base32-length via the largest bit index.
return fv.serializeSize(5)
}
// serializeSize returns the number of bytes required to encode the feature
// vector using at most width bits per encoded byte.
func (fv *RawFeatureVector) serializeSize(width int) int {
// Find the largest feature bit index
max := -1
for feature := range fv.features {
@@ -127,8 +165,7 @@ func (fv *RawFeatureVector) SerializeSize() int {
return 0
}
// We calculate byte-length via the largest bit index
return max/8 + 1
return max/width + 1
}
// Encode writes the feature vector in byte representation. Every feature
@@ -144,12 +181,25 @@ func (fv *RawFeatureVector) Encode(w io.Writer) error {
return err
}
return fv.encode(w, length, 8)
}
// EncodeBase32 writes the feature vector in base32 representation. Every feature
// encoded as a bit, and the bit vector is serialized using the least number of
// bytes.
func (fv *RawFeatureVector) EncodeBase32(w io.Writer) error {
length := fv.SerializeSize32()
return fv.encode(w, length, 5)
}
// encode writes the feature vector
func (fv *RawFeatureVector) encode(w io.Writer, length, width int) error {
// Generate the data and write it.
data := make([]byte, length)
for feature := range fv.features {
byteIndex := int(feature / 8)
bitIndex := feature % 8
data[length-byteIndex-1] |= 1 << bitIndex
byteIndex := int(feature) / width
bitIndex := int(feature) % width
data[length-byteIndex-1] |= 1 << uint(bitIndex)
}
_, err := w.Write(data)
@@ -168,6 +218,19 @@ func (fv *RawFeatureVector) Decode(r io.Reader) error {
}
length := binary.BigEndian.Uint16(l[:])
return fv.decode(r, int(length), 8)
}
// DecodeBase32 reads the feature vector from its base32 representation. Every
// feature encoded as a bit, and the bit vector is serialized using the least
// number of bytes.
func (fv *RawFeatureVector) DecodeBase32(r io.Reader, length int) error {
return fv.decode(r, length, 5)
}
// decode reads a feature vector from the next length bytes of the io.Reader,
// assuming each byte has width feature bits encoded per byte.
func (fv *RawFeatureVector) decode(r io.Reader, length, width int) error {
// Read the feature vector data.
data := make([]byte, length)
if _, err := io.ReadFull(r, data); err != nil {
@@ -175,10 +238,10 @@ func (fv *RawFeatureVector) Decode(r io.Reader) error {
}
// Set feature bits from parsed data.
bitsNumber := len(data) * 8
bitsNumber := len(data) * width
for i := 0; i < bitsNumber; i++ {
byteIndex := uint16(i / 8)
bitIndex := uint(i % 8)
byteIndex := int(i / width)
bitIndex := uint(i % width)
if (data[length-byteIndex-1]>>bitIndex)&1 == 1 {
fv.Set(FeatureBit(i))
}

View File

@@ -117,12 +117,6 @@ func WriteElement(w io.Writer, element interface{}) error {
if _, err := w.Write(b[:]); err != nil {
return err
}
case ErrorCode:
var b [2]byte
binary.BigEndian.PutUint16(b[:], uint16(e))
if _, err := w.Write(b[:]); err != nil {
return err
}
case MilliSatoshi:
var b [8]byte
binary.BigEndian.PutUint64(b[:], uint64(e))
@@ -506,12 +500,6 @@ func ReadElement(r io.Reader, element interface{}) error {
return err
}
*e = ChanUpdateChanFlags(b[0])
case *ErrorCode:
var b [2]byte
if _, err := io.ReadFull(r, b[:]); err != nil {
return err
}
*e = ErrorCode(binary.BigEndian.Uint16(b[:]))
case *uint32:
var b [4]byte
if _, err := io.ReadFull(r, b[:]); err != nil {

View File

@@ -10,11 +10,6 @@ import (
"unicode/utf8"
)
var (
startPort uint16 = 1024
endPort uint16 = 49151
)
// ErrUnknownAddrType is an error returned if we encounter an unknown address type
// when parsing addresses.
type ErrUnknownAddrType struct {

View File

@@ -46,7 +46,7 @@ const (
FlagUpdate FailCode = 0x1000
)
// FailCode specifies the precise reason that an upstream HTLC was cancelled.
// FailCode specifies the precise reason that an upstream HTLC was canceled.
// Each UpdateFailHTLC message carries a FailCode which is to be passed
// backwards, encrypted at each step back to the source of the HTLC within the
// route.
@@ -55,29 +55,29 @@ type FailCode uint16
// The currently defined onion failure types within this current version of the
// Lightning protocol.
const (
CodeNone FailCode = 0
CodeInvalidRealm = FlagBadOnion | 1
CodeTemporaryNodeFailure = FlagNode | 2
CodePermanentNodeFailure = FlagPerm | FlagNode | 2
CodeRequiredNodeFeatureMissing = FlagPerm | FlagNode | 3
CodeInvalidOnionVersion = FlagBadOnion | FlagPerm | 4
CodeInvalidOnionHmac = FlagBadOnion | FlagPerm | 5
CodeInvalidOnionKey = FlagBadOnion | FlagPerm | 6
CodeTemporaryChannelFailure = FlagUpdate | 7
CodePermanentChannelFailure = FlagPerm | 8
CodeRequiredChannelFeatureMissing = FlagPerm | 9
CodeUnknownNextPeer = FlagPerm | 10
CodeAmountBelowMinimum = FlagUpdate | 11
CodeFeeInsufficient = FlagUpdate | 12
CodeIncorrectCltvExpiry = FlagUpdate | 13
CodeExpiryTooSoon = FlagUpdate | 14
CodeChannelDisabled = FlagUpdate | 20
CodeUnknownPaymentHash = FlagPerm | 15
CodeIncorrectPaymentAmount = FlagPerm | 16
CodeFinalExpiryTooSoon FailCode = 17
CodeFinalIncorrectCltvExpiry FailCode = 18
CodeFinalIncorrectHtlcAmount FailCode = 19
CodeExpiryTooFar FailCode = 21
CodeNone FailCode = 0
CodeInvalidRealm = FlagBadOnion | 1
CodeTemporaryNodeFailure = FlagNode | 2
CodePermanentNodeFailure = FlagPerm | FlagNode | 2
CodeRequiredNodeFeatureMissing = FlagPerm | FlagNode | 3
CodeInvalidOnionVersion = FlagBadOnion | FlagPerm | 4
CodeInvalidOnionHmac = FlagBadOnion | FlagPerm | 5
CodeInvalidOnionKey = FlagBadOnion | FlagPerm | 6
CodeTemporaryChannelFailure = FlagUpdate | 7
CodePermanentChannelFailure = FlagPerm | 8
CodeRequiredChannelFeatureMissing = FlagPerm | 9
CodeUnknownNextPeer = FlagPerm | 10
CodeAmountBelowMinimum = FlagUpdate | 11
CodeFeeInsufficient = FlagUpdate | 12
CodeIncorrectCltvExpiry = FlagUpdate | 13
CodeExpiryTooSoon = FlagUpdate | 14
CodeChannelDisabled = FlagUpdate | 20
CodeIncorrectOrUnknownPaymentDetails = FlagPerm | 15
CodeIncorrectPaymentAmount = FlagPerm | 16
CodeFinalExpiryTooSoon FailCode = 17
CodeFinalIncorrectCltvExpiry FailCode = 18
CodeFinalIncorrectHtlcAmount FailCode = 19
CodeExpiryTooFar FailCode = 21
)
// String returns the string representation of the failure code.
@@ -134,8 +134,8 @@ func (c FailCode) String() string {
case CodeChannelDisabled:
return "ChannelDisabled"
case CodeUnknownPaymentHash:
return "UnknownPaymentHash"
case CodeIncorrectOrUnknownPaymentDetails:
return "IncorrectOrUnknownPaymentDetails"
case CodeFinalExpiryTooSoon:
return "FinalExpiryTooSoon"
@@ -317,7 +317,7 @@ func (f *FailIncorrectPaymentAmount) Error() string {
return f.Code().String()
}
// FailUnknownPaymentHash is returned for two reasons:
// FailIncorrectDetails is returned for two reasons:
//
// 1) if the payment hash has already been paid, the final node MAY treat the
// payment hash as unknown, or may succeed in accepting the HTLC. If the
@@ -330,42 +330,56 @@ func (f *FailIncorrectPaymentAmount) Error() string {
// gross overpayment.
//
// NOTE: May only be returned by the final node in the path.
type FailUnknownPaymentHash struct {
type FailIncorrectDetails struct {
// amount is the value of the extended HTLC.
amount MilliSatoshi
// height is the block height when the htlc was received.
height uint32
}
// NewFailUnknownPaymentHash makes a new instance of the FailUnknownPaymentHash
// error bound to the specified HTLC amount.
func NewFailUnknownPaymentHash(amt MilliSatoshi) *FailUnknownPaymentHash {
return &FailUnknownPaymentHash{
// NewFailIncorrectDetails makes a new instance of the FailIncorrectDetails
// error bound to the specified HTLC amount and acceptance height.
func NewFailIncorrectDetails(amt MilliSatoshi,
height uint32) *FailIncorrectDetails {
return &FailIncorrectDetails{
amount: amt,
height: height,
}
}
// Amount is the value of the extended HTLC.
func (f *FailUnknownPaymentHash) Amount() MilliSatoshi {
func (f *FailIncorrectDetails) Amount() MilliSatoshi {
return f.amount
}
// Height is the block height when the htlc was received.
func (f *FailIncorrectDetails) Height() uint32 {
return f.height
}
// Code returns the failure unique code.
//
// NOTE: Part of the FailureMessage interface.
func (f *FailUnknownPaymentHash) Code() FailCode {
return CodeUnknownPaymentHash
func (f *FailIncorrectDetails) Code() FailCode {
return CodeIncorrectOrUnknownPaymentDetails
}
// Returns a human readable string describing the target FailureMessage.
//
// NOTE: Implements the error interface.
func (f *FailUnknownPaymentHash) Error() string {
return fmt.Sprintf("UnknownPaymentHash(amt=%v)", f.amount)
func (f *FailIncorrectDetails) Error() string {
return fmt.Sprintf(
"%v(amt=%v, height=%v)", CodeIncorrectOrUnknownPaymentDetails,
f.amount, f.height,
)
}
// Decode decodes the failure from bytes stream.
//
// NOTE: Part of the Serializable interface.
func (f *FailUnknownPaymentHash) Decode(r io.Reader, pver uint32) error {
func (f *FailIncorrectDetails) Decode(r io.Reader, pver uint32) error {
err := ReadElement(r, &f.amount)
switch {
// This is an optional tack on that was added later in the protocol. As
@@ -379,14 +393,25 @@ func (f *FailUnknownPaymentHash) Decode(r io.Reader, pver uint32) error {
return err
}
// At a later stage, the height field was also tacked on. We need to
// check for io.EOF here as well.
err = ReadElement(r, &f.height)
switch {
case err == io.EOF:
return nil
case err != nil:
return err
}
return nil
}
// Encode writes the failure in bytes stream.
//
// NOTE: Part of the Serializable interface.
func (f *FailUnknownPaymentHash) Encode(w io.Writer, pver uint32) error {
return WriteElement(w, f.amount)
func (f *FailIncorrectDetails) Encode(w io.Writer, pver uint32) error {
return WriteElements(w, f.amount, f.height)
}
// FailFinalExpiryTooSoon is returned if the cltv_expiry is too low, the final
@@ -1113,10 +1138,16 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) {
dataReader := bytes.NewReader(failureData)
return DecodeFailureMessage(dataReader, pver)
}
// DecodeFailureMessage decodes just the failure message, ignoring any padding
// that may be present at the end.
func DecodeFailureMessage(r io.Reader, pver uint32) (FailureMessage, error) {
// Once we have the failure data, we can obtain the failure code from
// the first two bytes of the buffer.
var codeBytes [2]byte
if _, err := io.ReadFull(dataReader, codeBytes[:]); err != nil {
if _, err := io.ReadFull(r, codeBytes[:]); err != nil {
return nil, fmt.Errorf("unable to read failure code: %v", err)
}
failCode := FailCode(binary.BigEndian.Uint16(codeBytes[:]))
@@ -1132,10 +1163,9 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) {
// well.
switch f := failure.(type) {
case Serializable:
if err := f.Decode(dataReader, pver); err != nil {
if err := f.Decode(r, pver); err != nil {
return nil, fmt.Errorf("unable to decode error "+
"update (type=%T, len_bytes=%v, bytes=%x): %v",
failure, failureLength, failureData[:], err)
"update (type=%T): %v", failure, err)
}
}
@@ -1147,26 +1177,11 @@ func DecodeFailure(r io.Reader, pver uint32) (FailureMessage, error) {
func EncodeFailure(w io.Writer, failure FailureMessage, pver uint32) error {
var failureMessageBuffer bytes.Buffer
// First, we'll write out the error code itself into the failure
// buffer.
var codeBytes [2]byte
code := uint16(failure.Code())
binary.BigEndian.PutUint16(codeBytes[:], code)
_, err := failureMessageBuffer.Write(codeBytes[:])
err := EncodeFailureMessage(&failureMessageBuffer, failure, pver)
if err != nil {
return err
}
// Next, some message have an additional message payload, if this is
// one of those types, then we'll also encode the error payload as
// well.
switch failure := failure.(type) {
case Serializable:
if err := failure.Encode(&failureMessageBuffer, pver); err != nil {
return err
}
}
// The combined size of this message must be below the max allowed
// failure message length.
failureMessage := failureMessageBuffer.Bytes()
@@ -1187,6 +1202,32 @@ func EncodeFailure(w io.Writer, failure FailureMessage, pver uint32) error {
)
}
// EncodeFailureMessage encodes just the failure message without adding a length
// and padding the message for the onion protocol.
func EncodeFailureMessage(w io.Writer, failure FailureMessage, pver uint32) error {
// First, we'll write out the error code itself into the failure
// buffer.
var codeBytes [2]byte
code := uint16(failure.Code())
binary.BigEndian.PutUint16(codeBytes[:], code)
_, err := w.Write(codeBytes[:])
if err != nil {
return err
}
// Next, some message have an additional message payload, if this is
// one of those types, then we'll also encode the error payload as
// well.
switch failure := failure.(type) {
case Serializable:
if err := failure.Encode(w, pver); err != nil {
return err
}
}
return nil
}
// makeEmptyOnionError creates a new empty onion error of the proper concrete
// type based on the passed failure code.
func makeEmptyOnionError(code FailCode) (FailureMessage, error) {
@@ -1212,8 +1253,8 @@ func makeEmptyOnionError(code FailCode) (FailureMessage, error) {
case CodeUnknownNextPeer:
return &FailUnknownNextPeer{}, nil
case CodeUnknownPaymentHash:
return &FailUnknownPaymentHash{}, nil
case CodeIncorrectOrUnknownPaymentDetails:
return &FailIncorrectDetails{}, nil
case CodeIncorrectPaymentAmount:
return &FailIncorrectPaymentAmount{}, nil

View File

@@ -81,3 +81,11 @@ func (c *RevokeAndAck) MaxPayloadLength(uint32) uint32 {
// 32 + 32 + 33
return 97
}
// TargetChanID returns the channel id of the link for which this message is
// intended.
//
// NOTE: Part of lnd.LinkUpdater interface.
func (c *RevokeAndAck) TargetChanID() ChannelID {
return c.ChanID
}

View File

@@ -1,6 +1,8 @@
package lnwire
import "io"
import (
"io"
)
// OnionPacketSize is the size of the serialized Sphinx onion packet included
// in each UpdateAddHTLC message. The breakdown of the onion packet is as
@@ -107,3 +109,11 @@ func (c *UpdateAddHTLC) MaxPayloadLength(uint32) uint32 {
// 1450
return 32 + 8 + 4 + 8 + 32 + 1366
}
// TargetChanID returns the channel id of the link for which this message is
// intended.
//
// NOTE: Part of lnd.LinkUpdater interface.
func (c *UpdateAddHTLC) TargetChanID() ChannelID {
return c.ChanID
}

View File

@@ -1,6 +1,8 @@
package lnwire
import "io"
import (
"io"
)
// OpaqueReason is an opaque encrypted byte slice that encodes the exact
// failure reason and additional some supplemental data. The contents of this
@@ -83,3 +85,11 @@ func (c *UpdateFailHTLC) MaxPayloadLength(uint32) uint32 {
return length
}
// TargetChanID returns the channel id of the link for which this message is
// intended.
//
// NOTE: Part of lnd.LinkUpdater interface.
func (c *UpdateFailHTLC) TargetChanID() ChannelID {
return c.ChanID
}

View File

@@ -73,3 +73,11 @@ func (c *UpdateFailMalformedHTLC) MaxPayloadLength(uint32) uint32 {
// 32 + 8 + 32 + 2
return 74
}
// TargetChanID returns the channel id of the link for which this message is
// intended.
//
// NOTE: Part of lnd.LinkUpdater interface.
func (c *UpdateFailMalformedHTLC) TargetChanID() ChannelID {
return c.ChanID
}

View File

@@ -68,3 +68,11 @@ func (c *UpdateFee) MaxPayloadLength(uint32) uint32 {
// 32 + 4
return 36
}
// TargetChanID returns the channel id of the link for which this message is
// intended.
//
// NOTE: Part of lnd.LinkUpdater interface.
func (c *UpdateFee) TargetChanID() ChannelID {
return c.ChanID
}

View File

@@ -1,6 +1,8 @@
package lnwire
import "io"
import (
"io"
)
// UpdateFulfillHTLC is sent by Alice to Bob when she wishes to settle a
// particular HTLC referenced by its HTLCKey within a specific active channel
@@ -76,3 +78,11 @@ func (c *UpdateFulfillHTLC) MaxPayloadLength(uint32) uint32 {
// 32 + 8 + 32
return 72
}
// TargetChanID returns the channel id of the link for which this message is
// intended.
//
// NOTE: Part of lnd.LinkUpdater interface.
func (c *UpdateFulfillHTLC) TargetChanID() ChannelID {
return c.ChanID
}

View File

@@ -3,6 +3,7 @@ package zpay32
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"strings"
"time"
@@ -67,6 +68,24 @@ const (
// fieldTypeC contains an optional requested final CLTV delta.
fieldTypeC = 24
// fieldType9 contains one or more bytes for signaling features
// supported or required by the receiver.
fieldType9 = 5
// maxInvoiceLength is the maximum total length an invoice can have.
// This is chosen to be the maximum number of bytes that can fit into a
// single QR code: https://en.wikipedia.org/wiki/QR_code#Storage
maxInvoiceLength = 7089
)
var (
// InvoiceFeatures holds the set of all known feature bits that are
// exposed as BOLT 11 features.
InvoiceFeatures = map[lnwire.FeatureBit]string{}
// ErrInvoiceTooLarge is returned when an invoice exceeds maxInvoiceLength.
ErrInvoiceTooLarge = errors.New("invoice is too large")
)
// MessageSigner is passed to the Encode method to provide a signature
@@ -146,6 +165,10 @@ type Invoice struct {
//
// NOTE: This is optional.
RouteHints [][]HopHint
// Features represents an optional field used to signal optional or
// required support for features by the receiver.
Features *lnwire.FeatureVector
}
// Amount is a functional option that allows callers of NewInvoice to set the
@@ -249,6 +272,12 @@ func NewInvoice(net *chaincfg.Params, paymentHash [32]byte,
func Decode(invoice string, net *chaincfg.Params) (*Invoice, error) {
decodedInvoice := Invoice{}
// Before bech32 decoding the invoice, make sure that it is not too large.
// This is done as an anti-DoS measure since bech32 decoding is expensive.
if len(invoice) > maxInvoiceLength {
return nil, ErrInvoiceTooLarge
}
// Decode the invoice using the modified bech32 decoder.
hrp, data, err := decodeBech32(invoice)
if err != nil {
@@ -453,6 +482,12 @@ func (invoice *Invoice) Encode(signer MessageSigner) (string, error) {
return "", err
}
// Before returning, check that the bech32 encoded string is not greater
// than our largest supported invoice size.
if len(b32) > maxInvoiceLength {
return "", ErrInvoiceTooLarge
}
return b32, nil
}
@@ -504,21 +539,6 @@ func validateInvoice(invoice *Invoice) error {
return fmt.Errorf("neither description nor description hash set")
}
// We'll restrict invoices to include up to 20 different private route
// hints. We do this to avoid overly large invoices.
if len(invoice.RouteHints) > 20 {
return fmt.Errorf("too many private routes: %d",
len(invoice.RouteHints))
}
// Each route hint can have at most 20 hops.
for i, routeHint := range invoice.RouteHints {
if len(routeHint) > 20 {
return fmt.Errorf("route hint %d has too many extra "+
"hops: %d", i, len(routeHint))
}
}
// Check that we support the field lengths.
if len(invoice.PaymentHash) != 32 {
return fmt.Errorf("unsupported payment hash length: %d",
@@ -663,6 +683,14 @@ func parseTaggedFields(invoice *Invoice, fields []byte, net *chaincfg.Params) er
}
invoice.RouteHints = append(invoice.RouteHints, routeHint)
case fieldType9:
if invoice.Features != nil {
// We skip the field if we have already seen a
// supported one.
continue
}
invoice.Features, err = parseFeatures(base32Data)
default:
// Ignore unknown type.
}
@@ -848,6 +876,7 @@ func parseRouteHint(data []byte) ([]HopHint, error) {
return nil, err
}
// Check that base256Data is a multiple of hopHintLen.
if len(base256Data)%hopHintLen != 0 {
return nil, fmt.Errorf("expected length multiple of %d bytes, "+
"got %d", hopHintLen, len(base256Data))
@@ -874,6 +903,25 @@ func parseRouteHint(data []byte) ([]HopHint, error) {
return routeHint, nil
}
// parseFeatures decodes any feature bits directly from the base32
// representation.
func parseFeatures(data []byte) (*lnwire.FeatureVector, error) {
rawFeatures := lnwire.NewRawFeatureVector()
err := rawFeatures.DecodeBase32(bytes.NewReader(data), len(data))
if err != nil {
return nil, err
}
fv := lnwire.NewFeatureVector(rawFeatures, InvoiceFeatures)
unknownFeatures := fv.UnknownRequiredFeatures()
if len(unknownFeatures) > 0 {
return nil, fmt.Errorf("invoice contains unknown required "+
"features: %v", unknownFeatures)
}
return fv, nil
}
// writeTaggedFields writes the non-nil tagged fields of the Invoice to the
// base32 buffer.
func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
@@ -1011,7 +1059,7 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
pubKeyBase32, err := bech32.ConvertBits(
invoice.Destination.SerializeCompressed(), 8, 5, true)
if err != nil {
return nil
return err
}
if len(pubKeyBase32) != pubKeyBase32Len {
@@ -1024,6 +1072,18 @@ func writeTaggedFields(bufferBase32 *bytes.Buffer, invoice *Invoice) error {
return err
}
}
if invoice.Features != nil && invoice.Features.SerializeSize32() > 0 {
var b bytes.Buffer
err := invoice.Features.RawFeatureVector.EncodeBase32(&b)
if err != nil {
return err
}
err = writeTaggedField(bufferBase32, fieldType9, b.Bytes())
if err != nil {
return err
}
}
return nil
}

View File

@@ -1,189 +0,0 @@
//+build ignore
// compression_generate.go is meant to run with go generate. It will use
// go/{importer,types} to track down all the RR struct types. Then for each type
// it will look to see if there are (compressible) names, if so it will add that
// type to compressionLenHelperType and comressionLenSearchType which "fake" the
// compression so that Len() is fast.
package main
import (
"bytes"
"fmt"
"go/format"
"go/importer"
"go/types"
"log"
"os"
)
var packageHdr = `
// *** DO NOT MODIFY ***
// AUTOGENERATED BY go generate from compress_generate.go
package dns
`
// getTypeStruct will take a type and the package scope, and return the
// (innermost) struct if the type is considered a RR type (currently defined as
// those structs beginning with a RR_Header, could be redefined as implementing
// the RR interface). The bool return value indicates if embedded structs were
// resolved.
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
st, ok := t.Underlying().(*types.Struct)
if !ok {
return nil, false
}
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
return st, false
}
if st.Field(0).Anonymous() {
st, _ := getTypeStruct(st.Field(0).Type(), scope)
return st, true
}
return nil, false
}
func main() {
// Import and type-check the package
pkg, err := importer.Default().Import("github.com/miekg/dns")
fatalIfErr(err)
scope := pkg.Scope()
var domainTypes []string // Types that have a domain name in them (either compressible or not).
var cdomainTypes []string // Types that have a compressible domain name in them (subset of domainType)
Names:
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
continue
}
st, _ := getTypeStruct(o.Type(), scope)
if st == nil {
continue
}
if name == "PrivateRR" {
continue
}
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
log.Fatalf("Constant Type%s does not exist.", o.Name())
}
for i := 1; i < st.NumFields(); i++ {
if _, ok := st.Field(i).Type().(*types.Slice); ok {
if st.Tag(i) == `dns:"domain-name"` {
domainTypes = append(domainTypes, o.Name())
continue Names
}
if st.Tag(i) == `dns:"cdomain-name"` {
cdomainTypes = append(cdomainTypes, o.Name())
domainTypes = append(domainTypes, o.Name())
continue Names
}
continue
}
switch {
case st.Tag(i) == `dns:"domain-name"`:
domainTypes = append(domainTypes, o.Name())
continue Names
case st.Tag(i) == `dns:"cdomain-name"`:
cdomainTypes = append(cdomainTypes, o.Name())
domainTypes = append(domainTypes, o.Name())
continue Names
}
}
}
b := &bytes.Buffer{}
b.WriteString(packageHdr)
// compressionLenHelperType - all types that have domain-name/cdomain-name can be used for compressing names
fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR) {\n")
fmt.Fprint(b, "switch x := r.(type) {\n")
for _, name := range domainTypes {
o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope)
fmt.Fprintf(b, "case *%s:\n", name)
for i := 1; i < st.NumFields(); i++ {
out := func(s string) { fmt.Fprintf(b, "compressionLenHelper(c, x.%s)\n", st.Field(i).Name()) }
if _, ok := st.Field(i).Type().(*types.Slice); ok {
switch st.Tag(i) {
case `dns:"domain-name"`:
fallthrough
case `dns:"cdomain-name"`:
// For HIP we need to slice over the elements in this slice.
fmt.Fprintf(b, `for i := range x.%s {
compressionLenHelper(c, x.%s[i])
}
`, st.Field(i).Name(), st.Field(i).Name())
}
continue
}
switch {
case st.Tag(i) == `dns:"cdomain-name"`:
fallthrough
case st.Tag(i) == `dns:"domain-name"`:
out(st.Field(i).Name())
}
}
}
fmt.Fprintln(b, "}\n}\n\n")
// compressionLenSearchType - search cdomain-tags types for compressible names.
fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool) {\n")
fmt.Fprint(b, "switch x := r.(type) {\n")
for _, name := range cdomainTypes {
o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope)
fmt.Fprintf(b, "case *%s:\n", name)
j := 1
for i := 1; i < st.NumFields(); i++ {
out := func(s string, j int) {
fmt.Fprintf(b, "k%d, ok%d := compressionLenSearch(c, x.%s)\n", j, j, st.Field(i).Name())
}
// There are no slice types with names that can be compressed.
switch {
case st.Tag(i) == `dns:"cdomain-name"`:
out(st.Field(i).Name(), j)
j++
}
}
k := "k1"
ok := "ok1"
for i := 2; i < j; i++ {
k += fmt.Sprintf(" + k%d", i)
ok += fmt.Sprintf(" && ok%d", i)
}
fmt.Fprintf(b, "return %s, %s\n", k, ok)
}
fmt.Fprintln(b, "}\nreturn 0, false\n}\n\n")
// gofmt
res, err := format.Source(b.Bytes())
if err != nil {
b.WriteTo(os.Stderr)
log.Fatal(err)
}
f, err := os.Create("zcompress.go")
fatalIfErr(err)
defer f.Close()
f.Write(res)
}
func fatalIfErr(err error) {
if err != nil {
log.Fatal(err)
}
}

View File

@@ -1,349 +0,0 @@
//+build ignore
// msg_generate.go is meant to run with go generate. It will use
// go/{importer,types} to track down all the RR struct types. Then for each type
// it will generate pack/unpack methods based on the struct tags. The generated source is
// written to zmsg.go, and is meant to be checked into git.
package main
import (
"bytes"
"fmt"
"go/format"
"go/importer"
"go/types"
"log"
"os"
"strings"
)
var packageHdr = `
// *** DO NOT MODIFY ***
// AUTOGENERATED BY go generate from msg_generate.go
package dns
`
// getTypeStruct will take a type and the package scope, and return the
// (innermost) struct if the type is considered a RR type (currently defined as
// those structs beginning with a RR_Header, could be redefined as implementing
// the RR interface). The bool return value indicates if embedded structs were
// resolved.
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
st, ok := t.Underlying().(*types.Struct)
if !ok {
return nil, false
}
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
return st, false
}
if st.Field(0).Anonymous() {
st, _ := getTypeStruct(st.Field(0).Type(), scope)
return st, true
}
return nil, false
}
func main() {
// Import and type-check the package
pkg, err := importer.Default().Import("github.com/miekg/dns")
fatalIfErr(err)
scope := pkg.Scope()
// Collect actual types (*X)
var namedTypes []string
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
continue
}
if st, _ := getTypeStruct(o.Type(), scope); st == nil {
continue
}
if name == "PrivateRR" {
continue
}
// Check if corresponding TypeX exists
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
log.Fatalf("Constant Type%s does not exist.", o.Name())
}
namedTypes = append(namedTypes, o.Name())
}
b := &bytes.Buffer{}
b.WriteString(packageHdr)
fmt.Fprint(b, "// pack*() functions\n\n")
for _, name := range namedTypes {
o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope)
fmt.Fprintf(b, "func (rr *%s) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {\n", name)
fmt.Fprint(b, `off, err := rr.Hdr.pack(msg, off, compression, compress)
if err != nil {
return off, err
}
headerEnd := off
`)
for i := 1; i < st.NumFields(); i++ {
o := func(s string) {
fmt.Fprintf(b, s, st.Field(i).Name())
fmt.Fprint(b, `if err != nil {
return off, err
}
`)
}
if _, ok := st.Field(i).Type().(*types.Slice); ok {
switch st.Tag(i) {
case `dns:"-"`: // ignored
case `dns:"txt"`:
o("off, err = packStringTxt(rr.%s, msg, off)\n")
case `dns:"opt"`:
o("off, err = packDataOpt(rr.%s, msg, off)\n")
case `dns:"nsec"`:
o("off, err = packDataNsec(rr.%s, msg, off)\n")
case `dns:"domain-name"`:
o("off, err = packDataDomainNames(rr.%s, msg, off, compression, compress)\n")
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
continue
}
switch {
case st.Tag(i) == `dns:"-"`: // ignored
case st.Tag(i) == `dns:"cdomain-name"`:
o("off, err = PackDomainName(rr.%s, msg, off, compression, compress)\n")
case st.Tag(i) == `dns:"domain-name"`:
o("off, err = PackDomainName(rr.%s, msg, off, compression, false)\n")
case st.Tag(i) == `dns:"a"`:
o("off, err = packDataA(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"aaaa"`:
o("off, err = packDataAAAA(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"uint48"`:
o("off, err = packUint48(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"txt"`:
o("off, err = packString(rr.%s, msg, off)\n")
case strings.HasPrefix(st.Tag(i), `dns:"size-base32`): // size-base32 can be packed just like base32
fallthrough
case st.Tag(i) == `dns:"base32"`:
o("off, err = packStringBase32(rr.%s, msg, off)\n")
case strings.HasPrefix(st.Tag(i), `dns:"size-base64`): // size-base64 can be packed just like base64
fallthrough
case st.Tag(i) == `dns:"base64"`:
o("off, err = packStringBase64(rr.%s, msg, off)\n")
case strings.HasPrefix(st.Tag(i), `dns:"size-hex:SaltLength`):
// directly write instead of using o() so we get the error check in the correct place
field := st.Field(i).Name()
fmt.Fprintf(b, `// Only pack salt if value is not "-", i.e. empty
if rr.%s != "-" {
off, err = packStringHex(rr.%s, msg, off)
if err != nil {
return off, err
}
}
`, field, field)
continue
case strings.HasPrefix(st.Tag(i), `dns:"size-hex`): // size-hex can be packed just like hex
fallthrough
case st.Tag(i) == `dns:"hex"`:
o("off, err = packStringHex(rr.%s, msg, off)\n")
case st.Tag(i) == `dns:"octet"`:
o("off, err = packStringOctet(rr.%s, msg, off)\n")
case st.Tag(i) == "":
switch st.Field(i).Type().(*types.Basic).Kind() {
case types.Uint8:
o("off, err = packUint8(rr.%s, msg, off)\n")
case types.Uint16:
o("off, err = packUint16(rr.%s, msg, off)\n")
case types.Uint32:
o("off, err = packUint32(rr.%s, msg, off)\n")
case types.Uint64:
o("off, err = packUint64(rr.%s, msg, off)\n")
case types.String:
o("off, err = packString(rr.%s, msg, off)\n")
default:
log.Fatalln(name, st.Field(i).Name())
}
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
}
// We have packed everything, only now we know the rdlength of this RR
fmt.Fprintln(b, "rr.Header().Rdlength = uint16(off-headerEnd)")
fmt.Fprintln(b, "return off, nil }\n")
}
fmt.Fprint(b, "// unpack*() functions\n\n")
for _, name := range namedTypes {
o := scope.Lookup(name)
st, _ := getTypeStruct(o.Type(), scope)
fmt.Fprintf(b, "func unpack%s(h RR_Header, msg []byte, off int) (RR, int, error) {\n", name)
fmt.Fprintf(b, "rr := new(%s)\n", name)
fmt.Fprint(b, "rr.Hdr = h\n")
fmt.Fprint(b, `if noRdata(h) {
return rr, off, nil
}
var err error
rdStart := off
_ = rdStart
`)
for i := 1; i < st.NumFields(); i++ {
o := func(s string) {
fmt.Fprintf(b, s, st.Field(i).Name())
fmt.Fprint(b, `if err != nil {
return rr, off, err
}
`)
}
// size-* are special, because they reference a struct member we should use for the length.
if strings.HasPrefix(st.Tag(i), `dns:"size-`) {
structMember := structMember(st.Tag(i))
structTag := structTag(st.Tag(i))
switch structTag {
case "hex":
fmt.Fprintf(b, "rr.%s, off, err = unpackStringHex(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember)
case "base32":
fmt.Fprintf(b, "rr.%s, off, err = unpackStringBase32(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember)
case "base64":
fmt.Fprintf(b, "rr.%s, off, err = unpackStringBase64(msg, off, off + int(rr.%s))\n", st.Field(i).Name(), structMember)
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
fmt.Fprint(b, `if err != nil {
return rr, off, err
}
`)
continue
}
if _, ok := st.Field(i).Type().(*types.Slice); ok {
switch st.Tag(i) {
case `dns:"-"`: // ignored
case `dns:"txt"`:
o("rr.%s, off, err = unpackStringTxt(msg, off)\n")
case `dns:"opt"`:
o("rr.%s, off, err = unpackDataOpt(msg, off)\n")
case `dns:"nsec"`:
o("rr.%s, off, err = unpackDataNsec(msg, off)\n")
case `dns:"domain-name"`:
o("rr.%s, off, err = unpackDataDomainNames(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
continue
}
switch st.Tag(i) {
case `dns:"-"`: // ignored
case `dns:"cdomain-name"`:
fallthrough
case `dns:"domain-name"`:
o("rr.%s, off, err = UnpackDomainName(msg, off)\n")
case `dns:"a"`:
o("rr.%s, off, err = unpackDataA(msg, off)\n")
case `dns:"aaaa"`:
o("rr.%s, off, err = unpackDataAAAA(msg, off)\n")
case `dns:"uint48"`:
o("rr.%s, off, err = unpackUint48(msg, off)\n")
case `dns:"txt"`:
o("rr.%s, off, err = unpackString(msg, off)\n")
case `dns:"base32"`:
o("rr.%s, off, err = unpackStringBase32(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"base64"`:
o("rr.%s, off, err = unpackStringBase64(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"hex"`:
o("rr.%s, off, err = unpackStringHex(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
case `dns:"octet"`:
o("rr.%s, off, err = unpackStringOctet(msg, off)\n")
case "":
switch st.Field(i).Type().(*types.Basic).Kind() {
case types.Uint8:
o("rr.%s, off, err = unpackUint8(msg, off)\n")
case types.Uint16:
o("rr.%s, off, err = unpackUint16(msg, off)\n")
case types.Uint32:
o("rr.%s, off, err = unpackUint32(msg, off)\n")
case types.Uint64:
o("rr.%s, off, err = unpackUint64(msg, off)\n")
case types.String:
o("rr.%s, off, err = unpackString(msg, off)\n")
default:
log.Fatalln(name, st.Field(i).Name())
}
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
// If we've hit len(msg) we return without error.
if i < st.NumFields()-1 {
fmt.Fprintf(b, `if off == len(msg) {
return rr, off, nil
}
`)
}
}
fmt.Fprintf(b, "return rr, off, err }\n\n")
}
// Generate typeToUnpack map
fmt.Fprintln(b, "var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){")
for _, name := range namedTypes {
if name == "RFC3597" {
continue
}
fmt.Fprintf(b, "Type%s: unpack%s,\n", name, name)
}
fmt.Fprintln(b, "}\n")
// gofmt
res, err := format.Source(b.Bytes())
if err != nil {
b.WriteTo(os.Stderr)
log.Fatal(err)
}
// write result
f, err := os.Create("zmsg.go")
fatalIfErr(err)
defer f.Close()
f.Write(res)
}
// structMember will take a tag like dns:"size-base32:SaltLength" and return the last part of this string.
func structMember(s string) string {
fields := strings.Split(s, ":")
if len(fields) == 0 {
return ""
}
f := fields[len(fields)-1]
// f should have a closing "
if len(f) > 1 {
return f[:len(f)-1]
}
return f
}
// structTag will take a tag like dns:"size-base32:SaltLength" and return base32.
func structTag(s string) string {
fields := strings.Split(s, ":")
if len(fields) < 2 {
return ""
}
return fields[1][len("\"size-"):]
}
func fatalIfErr(err error) {
if err != nil {
log.Fatal(err)
}
}

View File

@@ -1,271 +0,0 @@
//+build ignore
// types_generate.go is meant to run with go generate. It will use
// go/{importer,types} to track down all the RR struct types. Then for each type
// it will generate conversion tables (TypeToRR and TypeToString) and banal
// methods (len, Header, copy) based on the struct tags. The generated source is
// written to ztypes.go, and is meant to be checked into git.
package main
import (
"bytes"
"fmt"
"go/format"
"go/importer"
"go/types"
"log"
"os"
"strings"
"text/template"
)
var skipLen = map[string]struct{}{
"NSEC": {},
"NSEC3": {},
"OPT": {},
"CSYNC": {},
}
var packageHdr = `
// *** DO NOT MODIFY ***
// AUTOGENERATED BY go generate from types_generate.go
package dns
import (
"encoding/base64"
"net"
)
`
var TypeToRR = template.Must(template.New("TypeToRR").Parse(`
// TypeToRR is a map of constructors for each RR type.
var TypeToRR = map[uint16]func() RR{
{{range .}}{{if ne . "RFC3597"}} Type{{.}}: func() RR { return new({{.}}) },
{{end}}{{end}} }
`))
var typeToString = template.Must(template.New("typeToString").Parse(`
// TypeToString is a map of strings for each RR type.
var TypeToString = map[uint16]string{
{{range .}}{{if ne . "NSAPPTR"}} Type{{.}}: "{{.}}",
{{end}}{{end}} TypeNSAPPTR: "NSAP-PTR",
}
`))
var headerFunc = template.Must(template.New("headerFunc").Parse(`
{{range .}} func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr }
{{end}}
`))
// getTypeStruct will take a type and the package scope, and return the
// (innermost) struct if the type is considered a RR type (currently defined as
// those structs beginning with a RR_Header, could be redefined as implementing
// the RR interface). The bool return value indicates if embedded structs were
// resolved.
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
st, ok := t.Underlying().(*types.Struct)
if !ok {
return nil, false
}
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
return st, false
}
if st.Field(0).Anonymous() {
st, _ := getTypeStruct(st.Field(0).Type(), scope)
return st, true
}
return nil, false
}
func main() {
// Import and type-check the package
pkg, err := importer.Default().Import("github.com/miekg/dns")
fatalIfErr(err)
scope := pkg.Scope()
// Collect constants like TypeX
var numberedTypes []string
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
continue
}
b, ok := o.Type().(*types.Basic)
if !ok || b.Kind() != types.Uint16 {
continue
}
if !strings.HasPrefix(o.Name(), "Type") {
continue
}
name := strings.TrimPrefix(o.Name(), "Type")
if name == "PrivateRR" {
continue
}
numberedTypes = append(numberedTypes, name)
}
// Collect actual types (*X)
var namedTypes []string
for _, name := range scope.Names() {
o := scope.Lookup(name)
if o == nil || !o.Exported() {
continue
}
if st, _ := getTypeStruct(o.Type(), scope); st == nil {
continue
}
if name == "PrivateRR" {
continue
}
// Check if corresponding TypeX exists
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
log.Fatalf("Constant Type%s does not exist.", o.Name())
}
namedTypes = append(namedTypes, o.Name())
}
b := &bytes.Buffer{}
b.WriteString(packageHdr)
// Generate TypeToRR
fatalIfErr(TypeToRR.Execute(b, namedTypes))
// Generate typeToString
fatalIfErr(typeToString.Execute(b, numberedTypes))
// Generate headerFunc
fatalIfErr(headerFunc.Execute(b, namedTypes))
// Generate len()
fmt.Fprint(b, "// len() functions\n")
for _, name := range namedTypes {
if _, ok := skipLen[name]; ok {
continue
}
o := scope.Lookup(name)
st, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded {
continue
}
fmt.Fprintf(b, "func (rr *%s) len() int {\n", name)
fmt.Fprintf(b, "l := rr.Hdr.len()\n")
for i := 1; i < st.NumFields(); i++ {
o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) }
if _, ok := st.Field(i).Type().(*types.Slice); ok {
switch st.Tag(i) {
case `dns:"-"`:
// ignored
case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
o("for _, x := range rr.%s { l += len(x) + 1 }\n")
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
continue
}
switch {
case st.Tag(i) == `dns:"-"`:
// ignored
case st.Tag(i) == `dns:"cdomain-name"`, st.Tag(i) == `dns:"domain-name"`:
o("l += len(rr.%s) + 1\n")
case st.Tag(i) == `dns:"octet"`:
o("l += len(rr.%s)\n")
case strings.HasPrefix(st.Tag(i), `dns:"size-base64`):
fallthrough
case st.Tag(i) == `dns:"base64"`:
o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
case strings.HasPrefix(st.Tag(i), `dns:"size-hex`):
fallthrough
case st.Tag(i) == `dns:"hex"`:
o("l += len(rr.%s)/2 + 1\n")
case st.Tag(i) == `dns:"a"`:
o("l += net.IPv4len // %s\n")
case st.Tag(i) == `dns:"aaaa"`:
o("l += net.IPv6len // %s\n")
case st.Tag(i) == `dns:"txt"`:
o("for _, t := range rr.%s { l += len(t) + 1 }\n")
case st.Tag(i) == `dns:"uint48"`:
o("l += 6 // %s\n")
case st.Tag(i) == "":
switch st.Field(i).Type().(*types.Basic).Kind() {
case types.Uint8:
o("l++ // %s\n")
case types.Uint16:
o("l += 2 // %s\n")
case types.Uint32:
o("l += 4 // %s\n")
case types.Uint64:
o("l += 8 // %s\n")
case types.String:
o("l += len(rr.%s) + 1\n")
default:
log.Fatalln(name, st.Field(i).Name())
}
default:
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
}
}
fmt.Fprintf(b, "return l }\n")
}
// Generate copy()
fmt.Fprint(b, "// copy() functions\n")
for _, name := range namedTypes {
o := scope.Lookup(name)
st, isEmbedded := getTypeStruct(o.Type(), scope)
if isEmbedded {
continue
}
fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
fields := []string{"*rr.Hdr.copyHeader()"}
for i := 1; i < st.NumFields(); i++ {
f := st.Field(i).Name()
if sl, ok := st.Field(i).Type().(*types.Slice); ok {
t := sl.Underlying().String()
t = strings.TrimPrefix(t, "[]")
if strings.Contains(t, ".") {
splits := strings.Split(t, ".")
t = splits[len(splits)-1]
}
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
f, t, f, f, f)
fields = append(fields, f)
continue
}
if st.Field(i).Type().String() == "net.IP" {
fields = append(fields, "copyIP(rr."+f+")")
continue
}
fields = append(fields, "rr."+f)
}
fmt.Fprintf(b, "return &%s{%s}\n", name, strings.Join(fields, ","))
fmt.Fprintf(b, "}\n")
}
// gofmt
res, err := format.Source(b.Bytes())
if err != nil {
b.WriteTo(os.Stderr)
log.Fatal(err)
}
// write result
f, err := os.Create("ztypes.go")
fatalIfErr(err)
defer f.Close()
f.Write(res)
}
func fatalIfErr(err error) {
if err != nil {
log.Fatal(err)
}
}

54
vendor/github.com/muun/libwallet/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,54 @@
Microsoft Reference Source License (Ms-RSL)
===========================================
This license governs use of the accompanying software. If you use the software,
you accept this license. If you do not accept the license, do not use the
software.
1. Definitions
--------------
The terms "reproduce", "reproduction" and "distribution" have the same meaning
here as under U.S. copyright law.
"You" means the licensee of the software.
"Your company" means the company you worked for when you downloaded the
software.
"Reference use" means use of the software within your company as a reference, in
read only form, for the sole purposes of debugging your products, maintaining
your products, or enhancing the interoperability of your products with the
software, and specifically excludes the right to distribute the software outside
of your company.
Licensed patents" means any Licensor patent claims which read directly on the
software as distributed by the Licensor under this license.
2. Grant of Rights
------------------
(A) Copyright Grant - Subject to the terms of this license, the Licensor grants
you a non-transferable, non-exclusive, worldwide, royalty-free copyright license
to reproduce the software for reference use.
(B) Patent Grant - Subject to the terms of this license, the Licensor grants you
a non-transferable, non-exclusive, worldwide, royalty-free patent license under
licensed patents for reference use.
3. Limitations
--------------
(A) No Trademark License - This license does not grant you any rights to use the
Licensor's name, logo, or trademarks.
(B) If you begin patent litigation against the Licensor over patents that you
think may apply to the software (including a cross-claim or counterclaim in a
lawsuit), your license to the software ends automatically.
(C) The software is licensed "as-is." You bear the risk of using it. The
Licensor gives no express warranties, guarantees or conditions. You may have
additional consumer rights under your local laws which this license cannot
change. To the extent permitted under your local laws, the Licensor excludes the
implied warranties of merchantability, fitness for a particular purpose and
non-infringement.

View File

@@ -24,7 +24,6 @@ func CreateAddressV2(userKey, muunKey *HDPublicKey) (MuunAddress, error) {
address: address.String(),
version: addressV2,
derivationPath: userKey.Path,
redeemScript: script,
}, nil
}

View File

@@ -24,7 +24,6 @@ func CreateAddressV3(userKey, muunKey *HDPublicKey) (MuunAddress, error) {
address: address.EncodeAddress(),
version: addressV3,
derivationPath: userKey.Path,
redeemScript: redeemScript,
}, nil
}
@@ -48,7 +47,6 @@ func addUserSignatureInputV3(input Input, index int, tx *wire.MsgTx, privateKey
return nil, errors.Errorf("muun signature must be present")
}
witnessScript, err := createWitnessScriptV3(privateKey.PublicKey(), muunKey)
if err != nil {
return nil, err
@@ -77,7 +75,7 @@ func signInputV3(input Input, index int, tx *wire.MsgTx, userKey *HDPublicKey, m
redeemScript, err := createRedeemScriptV3(userKey, muunKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to build reedem script for signing")
return nil, errors.Wrapf(err, "failed to build reedem script for signing")
}
return signNonNativeSegwitInput(input, index, tx, signingKey, redeemScript, witnessScript)

71
vendor/github.com/muun/libwallet/V4.go generated vendored Normal file
View File

@@ -0,0 +1,71 @@
package libwallet
import (
"crypto/sha256"
"github.com/btcsuite/btcutil"
"github.com/pkg/errors"
"github.com/btcsuite/btcd/wire"
)
func CreateAddressV4(userKey, muunKey *HDPublicKey) (MuunAddress, error) {
witnessScript, err := createWitnessScriptV4(userKey, muunKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to generate witness script v4")
}
witnessScript256 := sha256.Sum256(witnessScript)
address, err := btcutil.NewAddressWitnessScriptHash(witnessScript256[:], userKey.Network.network)
if err != nil {
return nil, err
}
return &muunAddress{
address: address.EncodeAddress(),
version: addressV4,
derivationPath: userKey.Path,
}, nil
}
func createWitnessScriptV4(userKey, muunKey *HDPublicKey) ([]byte, error) {
// createRedeemScriptV2 creates a valid script for V2, V3 and V4 schemes
return createRedeemScriptV2(userKey, muunKey)
}
func addUserSignatureInputV4(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey, muunKey *HDPublicKey) (*wire.TxIn, error) {
if len(input.MuunSignature()) == 0 {
return nil, errors.Errorf("muun signature must be present")
}
witnessScript, err := createWitnessScriptV4(privateKey.PublicKey(), muunKey)
if err != nil {
return nil, err
}
sig, err := signInputV4(input, index, tx, privateKey.PublicKey(), muunKey, privateKey)
if err != nil {
return nil, err
}
zeroByteArray := []byte{}
txInput := tx.TxIn[index]
txInput.Witness = wire.TxWitness{zeroByteArray, sig, input.MuunSignature(), witnessScript}
return txInput, nil
}
func signInputV4(input Input, index int, tx *wire.MsgTx, userKey *HDPublicKey, muunKey *HDPublicKey,
signingKey *HDPrivateKey) ([]byte, error) {
witnessScript, err := createWitnessScriptV4(userKey, muunKey)
if err != nil {
return nil, err
}
return signNativeSegwitInput(input, index, tx, signingKey, witnessScript)
}

View File

@@ -13,20 +13,27 @@ import (
"github.com/pkg/errors"
)
// These constants are here for clients usage.
const (
AddressVersionSwapsV1 = 101
AddressVersionSwapsV2 = 102
)
type AddressVersion int
const (
addressV1 AddressVersion = 1
addressV2 AddressVersion = 2
addressV3 AddressVersion = 3
addressSubmarineSwap AddressVersion = 101
addressV1 AddressVersion = 1
addressV2 AddressVersion = 2
addressV3 AddressVersion = 3
addressV4 AddressVersion = 4
addressSubmarineSwapV1 AddressVersion = AddressVersionSwapsV1
addressSubmarineSwapV2 AddressVersion = AddressVersionSwapsV2
)
type muunAddress struct {
version AddressVersion
derivationPath string
address string
redeemScript []byte
}
func newMuunAddress(version AddressVersion, userPublicKey, muunPublicKey *HDPublicKey) (MuunAddress, error) {
@@ -41,8 +48,12 @@ func newMuunAddress(version AddressVersion, userPublicKey, muunPublicKey *HDPubl
return CreateAddressV2(userPublicKey, muunPublicKey)
case addressV3:
return CreateAddressV3(userPublicKey, muunPublicKey)
case addressSubmarineSwap:
return CreateAddressSubmarineSwap(userPublicKey)
case addressV4:
return CreateAddressV4(userPublicKey, muunPublicKey)
case addressSubmarineSwapV1:
return nil, errors.Errorf("can't manually create a submarine swap v1 address")
case addressSubmarineSwapV2:
return nil, errors.Errorf("can't manually create a submarine swap v2 address")
}
return nil, errors.Errorf("unknown version %v", version)
@@ -60,10 +71,6 @@ func (a *muunAddress) Address() string {
return a.address
}
func (a *muunAddress) RedeemScript() []byte {
return a.redeemScript
}
// MuunPaymentURI is muun's uri struct
type MuunPaymentURI struct {
Address string
@@ -127,7 +134,7 @@ func GetPaymentURI(address string, network *Network) (*MuunPaymentURI, error) {
invoice, err := ParseInvoice(queryValues["lightning"][0], network)
if err == nil {
return &MuunPaymentURI{Invoice:invoice}, nil
return &MuunPaymentURI{Invoice: invoice}, nil
}
}
@@ -240,9 +247,7 @@ func getAddressFromScript(script []byte, network *Network) (string, error) {
func normalizeAddress(rawAddress string) string {
newAddress := rawAddress
if strings.Contains(newAddress, muunScheme) {
newAddress = strings.Replace(newAddress, muunScheme, bitcoinScheme, 1)
}
newAddress = strings.Replace(newAddress, muunScheme, bitcoinScheme, 1)
if !strings.Contains(newAddress, bitcoinScheme) {
newAddress = bitcoinScheme + rawAddress

View File

@@ -55,22 +55,6 @@ func (m *Output) XXX_DiscardUnknown() {
var xxx_messageInfo_Output proto.InternalMessageInfo
const Default_Output_Amount uint64 = 0
func (m *Output) GetAmount() uint64 {
if m != nil && m.Amount != nil {
return *m.Amount
}
return Default_Output_Amount
}
func (m *Output) GetScript() []byte {
if m != nil {
return m.Script
}
return nil
}
type PaymentDetails struct {
Network *string `protobuf:"bytes,1,opt,name=network,def=main" json:"network,omitempty"`
Outputs []*Output `protobuf:"bytes,2,rep,name=outputs" json:"outputs,omitempty"`
@@ -153,13 +137,6 @@ func (m *PaymentDetails) GetPaymentUrl() string {
return ""
}
func (m *PaymentDetails) GetMerchantData() []byte {
if m != nil {
return m.MerchantData
}
return nil
}
type PaymentRequest struct {
PaymentDetailsVersion *uint32 `protobuf:"varint,1,opt,name=payment_details_version,json=paymentDetailsVersion,def=1" json:"payment_details_version,omitempty"`
PkiType *string `protobuf:"bytes,2,opt,name=pki_type,json=pkiType,def=none" json:"pki_type,omitempty"`
@@ -213,26 +190,6 @@ func (m *PaymentRequest) GetPkiType() string {
return Default_PaymentRequest_PkiType
}
func (m *PaymentRequest) GetPkiData() []byte {
if m != nil {
return m.PkiData
}
return nil
}
func (m *PaymentRequest) GetSerializedPaymentDetails() []byte {
if m != nil {
return m.SerializedPaymentDetails
}
return nil
}
func (m *PaymentRequest) GetSignature() []byte {
if m != nil {
return m.Signature
}
return nil
}
type X509Certificates struct {
Certificate [][]byte `protobuf:"bytes,1,rep,name=certificate" json:"certificate,omitempty"`
@@ -308,12 +265,6 @@ func (m *Payment) XXX_DiscardUnknown() {
var xxx_messageInfo_Payment proto.InternalMessageInfo
func (m *Payment) GetMerchantData() []byte {
if m != nil {
return m.MerchantData
}
return nil
}
func (m *Payment) GetTransactions() [][]byte {
if m != nil {
@@ -369,13 +320,6 @@ func (m *PaymentACK) XXX_DiscardUnknown() {
var xxx_messageInfo_PaymentACK proto.InternalMessageInfo
func (m *PaymentACK) GetPayment() *Payment {
if m != nil {
return m.Payment
}
return nil
}
func (m *PaymentACK) GetMemo() string {
if m != nil && m.Memo != nil {
return *m.Memo

View File

@@ -3,10 +3,11 @@ module github.com/muun/libwallet
go 1.12
require (
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3
github.com/btcsuite/btcd v0.20.1-beta
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d
github.com/go-errors/errors v1.0.1
github.com/golang/protobuf v1.3.2
github.com/lightningnetwork/lnd v0.7.1-beta-rc2
github.com/lightningnetwork/lnd v0.8.0-beta
github.com/pkg/errors v0.8.1
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7
)

View File

@@ -1,6 +1,6 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
git.schwanenlied.me/yawning/bsaes.git v0.0.0-20180720073208-c0276d75487e/go.mod h1:BWqTsj8PgcPriQJGl7el20J/7TuT1d/hSyFDXMEpoEo=
github.com/NebulousLabs/fastrand v0.0.0-20180208210444-3cf7173006a0/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ=
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ=
github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82/go.mod h1:GbuBk21JqF+driLX3XtJYNZjGa45YDoa9IqCTzNSfEc=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk=
@@ -10,25 +10,22 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/btcsuite/btcd v0.0.0-20180823030728-d81d8877b8f3/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
github.com/btcsuite/btcd v0.0.0-20181130015935-7d2daa5bfef2/go.mod h1:Jr9bmNVGZ7TH2Ux1QuP0ec+yGgh0gE9FIlkzQiI5bR0=
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 h1:A/EVblehb75cUgXA5njHPn0kLAsykn6mJGz7rnmW5W0=
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.0-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcwallet v0.0.0-20180904010540-284e2e0e696e33d5be388f7f3d9a26db703e0c06/go.mod h1:/d7QHZsfUAruXuBhyPITqoYOmJ+nq35qPsJjz/aSpCg=
github.com/btcsuite/btcwallet v0.0.0-20190313032608-acf3b04b0273/go.mod h1:mkOYY8/psBiL5E+Wb0V7M0o+N7NXi2SZJz6+RKkncIc=
github.com/btcsuite/btcwallet v0.0.0-20190319010515-89ab2044f962/go.mod h1:qMi4jGpAO6YRsd81RYDG7o5pBIGqN9faCioJdagLu64=
github.com/btcsuite/btcwallet v0.0.0-20190712034938-7a3a3e82cbb6/go.mod h1:sXVxjjP5YeWqWsiQbQDXvAw6J6Qvr8swu7MONoNaF9k=
github.com/btcsuite/btcwallet v0.10.0/go.mod h1:4TqBEuceheGNdeLNrelliLHJzmXauMM2vtWfuy1pFiM=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU=
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0/go.mod h1:UwQE78yCerZ313EXZwEiu3jNAtfXj2n2+c8RWiE/WNA=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.0/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk=
github.com/btcsuite/btcwallet/walletdb v1.1.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk=
github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY=
github.com/btcsuite/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:QcFA8DZHtuIAdYKCq/BzELOaznRsCvwf4zTPmaYwaig=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc=
@@ -40,12 +37,12 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v0.0.0-20180223184059-7ee3ded59d4835e10f3e7d0f7603c42aa5e83820/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@@ -57,11 +54,11 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v0.0.0-20180821051752-b27b920f9e71/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v0.0.0-20170724004829-f2862b476edc/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
@@ -71,11 +68,11 @@ github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad/go.mod h1:QPH04
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/juju/clock v0.0.0-20180808021310-bab88fc67299/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=
github.com/juju/version v0.0.0-20180108022336-b64dbd566305/go.mod h1:kE8gK5X0CImdr7qpSKl3xB2PmpySSmfj7zVbkZFs81U=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
@@ -87,18 +84,13 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lightninglabs/gozmq v0.0.0-20180324010646-462a8a753885/go.mod h1:KUh15naRlx/TmUMFS/p4JJrCrE6F7RGF7rsnvuu45E4=
github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
github.com/lightninglabs/neutrino v0.0.0-20181017011010-4d6069299130/go.mod h1:KJq43Fu9ceitbJsSXMILcT4mGDNI/crKmPIkDOZXFyM=
github.com/lightninglabs/neutrino v0.0.0-20190213031021-ae4583a89cfb/go.mod h1:g6cMQd+hfAU8pQTJAdjm6/EQREhupyd22f+CL0qYFOE=
github.com/lightninglabs/neutrino v0.0.0-20190313035638-e1ad4c33fb18/go.mod h1:v6tz6jbuAubTrRpX8ke2KH9sJxml8KlPQTKgo9mAp1Q=
github.com/lightninglabs/neutrino v0.0.0-20190725230401-ddf667a8b5c4/go.mod h1:vzLU75ll8qbRJIzW5dvK/UXtR9c2FecJ6VNOM8chyVM=
github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9/go.mod h1:Sooe/CoCqa85JxqHV+IBR2HW+6t2Cv+36awSmoccswM=
github.com/lightningnetwork/lnd v0.7.1-beta-rc2 h1:N0AuHo4wI6TogabvOfpwg1LkR3RxGCvqYq0Wb7GL+ck=
github.com/lightningnetwork/lnd v0.7.1-beta-rc2/go.mod h1:ODASBFcJwVlb4aqO3m090whpP2kfA9zEvmG/pj+fOfg=
github.com/lightninglabs/neutrino v0.10.0/go.mod h1:C3KhCMk1Mcx3j8v0qRVWM1Ow6rIJSvSPnUAq00ZNAfk=
github.com/lightningnetwork/lightning-onion v0.0.0-20190909101754-850081b08b6a/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
github.com/lightningnetwork/lnd v0.8.0-beta h1:HmmhSRTq48qobqQF8YLqNa8eKU8dDBNbWWpr2VzycJM=
github.com/lightningnetwork/lnd v0.8.0-beta/go.mod h1:nq06y2BDv7vwWeMmwgB7P3pT7/Uj7sGf5FzHISVD6t4=
github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms=
github.com/lightningnetwork/lnd/ticker v1.0.0/go.mod h1:iaLXJiVgI1sPANIF2qYYUJXjoksPNvGNYowB8aRbpX0=
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -123,19 +115,16 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S068ZqfrO6S8HsoJq2bF3ETfTL+kt4tInY=
github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
@@ -144,7 +133,6 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180821023952-922f4815f713/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -156,16 +144,15 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180821140842-3b58ed4ad339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -173,18 +160,16 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk=
gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA=
gopkg.in/macaroon.v2 v2.0.0/go.mod h1:+I6LnTMkm/uV5ew/0nsulNjL16SK4+C8yDmRUzHR17I=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -39,9 +39,9 @@ func NewHDPrivateKeyFromBytes(rawKey, chainCode []byte, network *Network) (*HDPr
// NewHDPrivateKeyFromString creates an HD priv key from a base58-encoded string
// If the parsed key is public, it returns an error
func NewHDPrivateKeyFromString(str, path string) (*HDPrivateKey, error) {
func NewHDPrivateKeyFromString(str, path string, network *Network) (*HDPrivateKey, error) {
key, network, err := keyFromString(str)
key, _, err := keyFromString(str)
if err != nil {
return nil, err
}

View File

@@ -18,9 +18,9 @@ type HDPublicKey struct {
// NewHDPublicKeyFromString creates an HD pub key from a base58-encoded string
// If the parsed key is private, it returns an error
func NewHDPublicKeyFromString(str, path string) (*HDPublicKey, error) {
func NewHDPublicKeyFromString(str, path string, network *Network) (*HDPublicKey, error) {
key, network, err := keyFromString(str)
key, _, err := keyFromString(str)
if err != nil {
return nil, err
}

View File

@@ -27,7 +27,7 @@ func ParseInvoice(invoice string, network *Network) (*Invoice, error) {
if strings.HasPrefix(strings.ToLower(invoice), lightningScheme) {
// Remove lightning scheme from rawInvoice
invoice = invoice[len(lightningScheme):len(invoice)]
invoice = invoice[len(lightningScheme):]
}
parsedInvoice, err := zpay32.Decode(invoice, network.network)

View File

@@ -64,7 +64,7 @@ func KeyEncrypt(key *HDPrivateKey, passphrase string) (string, error) {
}
// KeyDecrypt decrypts a key encrypted with KeyEncrypt
func KeyDecrypt(value, passphrase string) (*DecryptedKey, error) {
func KeyDecrypt(value, passphrase string, network *Network) (*DecryptedKey, error) {
elements := strings.Split(value, seperator)
@@ -126,7 +126,7 @@ func KeyDecrypt(value, passphrase string) (*DecryptedKey, error) {
encodedPrivateKey := string(decryptedBytes[:])
path := string(pathBytes[:])
privateKey, err := NewHDPrivateKeyFromString(encodedPrivateKey, path)
privateKey, err := NewHDPrivateKeyFromString(encodedPrivateKey, path, network)
if err != nil {
return nil, errors.New("KeyCrypter: failed to decode pk: " + err.Error())
}

View File

@@ -25,19 +25,29 @@ type Outpoint interface {
Amount() int64
}
type InputSubmarineSwap interface {
type InputSubmarineSwapV1 interface {
RefundAddress() string
PaymentHash256() []byte
ServerPublicKey() []byte
LockTime() int64
}
type InputSubmarineSwapV2 interface {
PaymentHash256() []byte
UserPublicKey() []byte
MuunPublicKey() []byte
ServerPublicKey() []byte
BlocksForExpiration() int64
ServerSignature() []byte
}
type Input interface {
OutPoint() Outpoint
Address() MuunAddress
UserSignature() []byte
MuunSignature() []byte
SubmarineSwap() InputSubmarineSwap
SubmarineSwapV1() InputSubmarineSwapV1
SubmarineSwapV2() InputSubmarineSwapV2
}
type PartiallySignedTransaction struct {
@@ -93,8 +103,12 @@ func (p *PartiallySignedTransaction) Sign(key *HDPrivateKey, muunKey *HDPublicKe
txIn, err = addUserSignatureInputV2(input, i, p.tx, derivedKey, derivedMuunKey)
case addressV3:
txIn, err = addUserSignatureInputV3(input, i, p.tx, derivedKey, derivedMuunKey)
case addressSubmarineSwap:
txIn, err = addUserSignatureInputSubmarineSwap(input, i, p.tx, derivedKey, derivedMuunKey)
case addressV4:
txIn, err = addUserSignatureInputV4(input, i, p.tx, derivedKey, derivedMuunKey)
case addressSubmarineSwapV1:
txIn, err = addUserSignatureInputSubmarineSwapV1(input, i, p.tx, derivedKey, derivedMuunKey)
case addressSubmarineSwapV2:
txIn, err = addUserSignatureInputSubmarineSwapV2(input, i, p.tx, derivedKey, derivedMuunKey)
default:
return nil, errors.Errorf("cant sign transaction of version %v", input.Address().Version())
}
@@ -141,9 +155,13 @@ func (p *PartiallySignedTransaction) MuunSignatureForInput(index int, userKey *H
return signInputV2(input, index, p.tx, derivedUserKey, derivedMuunKey.PublicKey(), derivedMuunKey)
case addressV3:
return signInputV3(input, index, p.tx, derivedUserKey, derivedMuunKey.PublicKey(), derivedMuunKey)
case addressSubmarineSwap:
return nil, errors.New("cant sign arbitrary submarine swap inputs")
case addressV4:
return signInputV4(input, index, p.tx, derivedUserKey, derivedMuunKey.PublicKey(), derivedMuunKey)
case addressSubmarineSwapV1:
return nil, errors.New("cant sign arbitrary submarine swap v1 inputs")
case addressSubmarineSwapV2:
return nil, errors.New("cant sign arbitrary submarine swap v2 inputs")
}
return nil, errors.New("unknown address scheme")
}
}

View File

@@ -1,7 +1,7 @@
package libwallet
import (
hash "golang.org/x/crypto/ripemd160"
hash "golang.org/x/crypto/ripemd160" //lint:ignore SA1019 using deprecated hash function for compatibility
)
func ripemd160(data []byte) []byte {

View File

@@ -8,6 +8,22 @@ import (
"github.com/pkg/errors"
)
func signNativeSegwitInput(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey, witnessScript []byte) ([]byte, error) {
privKey, err := privateKey.key.ECPrivKey()
if err != nil {
return nil, errors.Wrapf(err, "failed to produce EC priv key for signing")
}
sigHashes := txscript.NewTxSigHashes(tx)
sig, err := txscript.RawTxInWitnessSignature(tx, sigHashes, index, input.OutPoint().Amount(), witnessScript, txscript.SigHashAll, privKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to sign V4 input")
}
return sig, nil
}
func createNonNativeSegwitRedeemScript(witnessScript []byte) ([]byte, error) {
witnessScriptHash := sha256.Sum256(witnessScript)

View File

@@ -1,14 +1,7 @@
package libwallet
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/pkg/errors"
"github.com/go-errors/errors"
)
type SubmarineSwap interface {
@@ -26,190 +19,33 @@ type SubmarineSwapReceiver interface {
}
type SubmarineSwapFundingOutput interface {
ScriptVersion() int64
OutputAddress() string
OutputAmount() int64
ConfirmationsNeeded() int
UserLockTime() int64
UserRefundAddress() MuunAddress
ServerPaymentHashInHex() string
ServerPublicKeyInHex() string
UserLockTime() int64
// v1 only
UserRefundAddress() MuunAddress
// v2 only
ExpirationInBlocks() int64
UserPublicKey() *HDPublicKey
MuunPublicKey() *HDPublicKey
}
func CreateAddressSubmarineSwap(publicKey *HDPublicKey) (MuunAddress, error) {
pubkey, err := btcutil.NewAddressPubKey(publicKey.Raw(), publicKey.Network.network)
if err != nil {
return nil, err
func ValidateSubmarineSwap(rawInvoice string, userPublicKey *HDPublicKey, muunPublicKey *HDPublicKey, swap SubmarineSwap, originalExpirationInBlocks int64, network *Network) error {
switch AddressVersion(swap.FundingOutput().ScriptVersion()) {
case addressSubmarineSwapV1:
return ValidateSubmarineSwapV1(rawInvoice, userPublicKey, muunPublicKey, swap, network)
case addressSubmarineSwapV2:
return ValidateSubmarineSwapV2(rawInvoice, userPublicKey, muunPublicKey, swap, originalExpirationInBlocks, network)
}
pubkeyHash := pubkey.AddressPubKeyHash()
address := pubkeyHash.String()
return &muunAddress{address: address, version: addressSubmarineSwap, derivationPath: publicKey.Path}, nil
}
func addUserSignatureInputSubmarineSwap(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey,
muunKey *HDPublicKey) (*wire.TxIn, error) {
submarineSwap := input.SubmarineSwap()
if submarineSwap == nil {
return nil, errors.Errorf("submarine swap data is nil for ss input")
}
witnessScript, err := createWitnessScriptSubmarineSwap(submarineSwap.RefundAddress(),
submarineSwap.PaymentHash256(),
submarineSwap.ServerPublicKey(),
submarineSwap.LockTime(),
privateKey.Network)
if err != nil {
return nil, err
}
redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript)
if err != nil {
return nil, errors.Wrapf(err, "failed to build reedem script for signing")
}
sig, err := signNonNativeSegwitInput(input, index, tx, privateKey, redeemScript, witnessScript)
if err != nil {
return nil, err
}
txInput := tx.TxIn[index]
txInput.Witness = wire.TxWitness{sig, privateKey.PublicKey().Raw(), witnessScript}
return txInput, nil
}
func createRedeemScriptSubmarineSwapForUser(publicKey *HDPublicKey) {
}
func createWitnessScriptSubmarineSwap(refundAddress string, paymentHash []byte, swapServerPubKey []byte, lockTime int64, network *Network) ([]byte, error) {
// It turns out that the payment hash present in an invoice is just the SHA256 of the
// payment preimage, so we still have to do a pass of RIPEMD160 before pushing it to the
// script
paymentHash160 := ripemd160(paymentHash)
decodedRefundAddress, err := btcutil.DecodeAddress(refundAddress, network.network)
if err != nil {
return nil, errors.Wrapf(err, "refund address is invalid")
}
refundAddressHash := decodedRefundAddress.ScriptAddress()
builder := txscript.NewScriptBuilder()
builder.AddOp(txscript.OP_DUP)
// Condition to decide which branch to follow:
builder.AddOp(txscript.OP_HASH160).
AddData(paymentHash160).
AddOp(txscript.OP_EQUAL)
// SubmarineSwap service spending script, for successful LN payments:
builder.AddOp(txscript.OP_IF).
AddOp(txscript.OP_DROP).
AddData(swapServerPubKey)
// User spending script, for failed LN payments:
builder.AddOp(txscript.OP_ELSE).
AddInt64(lockTime).
AddOp(txscript.OP_CHECKLOCKTIMEVERIFY).
AddOp(txscript.OP_DROP).
AddOp(txscript.OP_DUP).
AddOp(txscript.OP_HASH160).
AddData(refundAddressHash).
AddOp(txscript.OP_EQUALVERIFY)
// Final verification for both branches:
builder.AddOp(txscript.OP_ENDIF).
AddOp(txscript.OP_CHECKSIG)
return builder.Script()
}
func ValidateSubmarineSwap(rawInvoice string, userPublicKey *HDPublicKey, muunPublicKey *HDPublicKey, swap SubmarineSwap, network *Network) error {
invoice, err := ParseInvoice(rawInvoice, network)
if err != nil {
return errors.Wrapf(err, "failed to decode invoice")
}
// Check the payment hash matches
serverPaymentHash, err := hex.DecodeString(swap.FundingOutput().ServerPaymentHashInHex())
if err != nil {
return errors.Wrapf(err, "server payment hash is not valid hex")
}
if !bytes.Equal(invoice.PaymentHash[:], serverPaymentHash) {
return errors.Errorf("payment hash doesn't match %v != %v", invoice.PaymentHash, swap.FundingOutput().ServerPaymentHashInHex())
}
// TODO: check that timelock is acceptable
// Validate that the refund address is one we can derive
swapRefundAddress := swap.FundingOutput().UserRefundAddress()
derivedUserKey, err := userPublicKey.DeriveTo(swapRefundAddress.DerivationPath())
if err != nil {
return errors.Wrapf(err, "failed to derive user key")
}
derivedMuunKey, err := muunPublicKey.DeriveTo(swapRefundAddress.DerivationPath())
if err != nil {
return errors.Wrapf(err, "failed to derive muun key")
}
refundAddress, err := newMuunAddress(AddressVersion(swapRefundAddress.Version()), derivedUserKey, derivedMuunKey)
if err != nil {
return errors.Wrapf(err, "failed to generate refund address")
}
if refundAddress.Address() != swapRefundAddress.Address() {
return errors.Errorf("refund address doesn't match generated (%v != %v)", swapRefundAddress.Address(), refundAddress.Address())
}
// Check the swap's witness script is a valid swap script
serverPubKey, err := hex.DecodeString(swap.FundingOutput().ServerPublicKeyInHex())
if err != nil {
return errors.Wrapf(err, "server pub key is not hex")
}
witnessScript, err := createWitnessScriptSubmarineSwap(
swapRefundAddress.Address(),
serverPaymentHash,
serverPubKey,
swap.FundingOutput().UserLockTime(),
network)
if err != nil {
return errors.Wrapf(err, "failed to compute witness script")
}
redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript)
if err != nil {
return errors.Wrapf(err, "failed to build redeem script")
}
address, err := btcutil.NewAddressScriptHash(redeemScript, network.network)
if err != nil {
return errors.Wrapf(err, "failed to build address for swap script")
}
if address.EncodeAddress() != swap.FundingOutput().OutputAddress() {
return errors.Errorf("address for swap script mismatch (%v != %v)", address.EncodeAddress(), swap.FundingOutput().OutputAddress())
}
if len(swap.PreimageInHex()) > 0 {
preimage, err := hex.DecodeString(swap.PreimageInHex())
if err != nil {
return errors.Wrapf(err, "preimagehex is not actually hex 🤔")
}
calculatedPaymentHash := sha256.Sum256(preimage)
if !bytes.Equal(invoice.PaymentHash[:], calculatedPaymentHash[:]) {
return errors.Errorf("payment hash doesn't match preimage (%v != hash(%v)", invoice.PaymentHash, swap.PreimageInHex())
}
}
return nil
return errors.Errorf("unknown swap version %v", swap.FundingOutput().ScriptVersion())
}

180
vendor/github.com/muun/libwallet/submarineSwapV1.go generated vendored Normal file
View File

@@ -0,0 +1,180 @@
package libwallet
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/pkg/errors"
)
func addUserSignatureInputSubmarineSwapV1(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey,
muunKey *HDPublicKey) (*wire.TxIn, error) {
submarineSwap := input.SubmarineSwapV1()
if submarineSwap == nil {
return nil, errors.Errorf("submarine swap data is nil for ss input")
}
witnessScript, err := createWitnessScriptSubmarineSwapV1(submarineSwap.RefundAddress(),
submarineSwap.PaymentHash256(),
submarineSwap.ServerPublicKey(),
submarineSwap.LockTime(),
privateKey.Network)
if err != nil {
return nil, err
}
redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript)
if err != nil {
return nil, errors.Wrapf(err, "failed to build reedem script for signing")
}
sig, err := signNonNativeSegwitInput(input, index, tx, privateKey, redeemScript, witnessScript)
if err != nil {
return nil, err
}
txInput := tx.TxIn[index]
txInput.Witness = wire.TxWitness{sig, privateKey.PublicKey().Raw(), witnessScript}
return txInput, nil
}
//lint:ignore U1000 unused function for consistency with other schemes
func createRedeemScriptSubmarineSwapForUser(publicKey *HDPublicKey) {
}
func createWitnessScriptSubmarineSwapV1(refundAddress string, paymentHash []byte, swapServerPubKey []byte, lockTime int64, network *Network) ([]byte, error) {
// It turns out that the payment hash present in an invoice is just the SHA256 of the
// payment preimage, so we still have to do a pass of RIPEMD160 before pushing it to the
// script
paymentHash160 := ripemd160(paymentHash)
decodedRefundAddress, err := btcutil.DecodeAddress(refundAddress, network.network)
if err != nil {
return nil, errors.Wrapf(err, "refund address is invalid")
}
refundAddressHash := decodedRefundAddress.ScriptAddress()
builder := txscript.NewScriptBuilder()
builder.AddOp(txscript.OP_DUP)
// Condition to decide which branch to follow:
builder.AddOp(txscript.OP_HASH160).
AddData(paymentHash160).
AddOp(txscript.OP_EQUAL)
// SubmarineSwap service spending script, for successful LN payments:
builder.AddOp(txscript.OP_IF).
AddOp(txscript.OP_DROP).
AddData(swapServerPubKey)
// User spending script, for failed LN payments:
builder.AddOp(txscript.OP_ELSE).
AddInt64(lockTime).
AddOp(txscript.OP_CHECKLOCKTIMEVERIFY).
AddOp(txscript.OP_DROP).
AddOp(txscript.OP_DUP).
AddOp(txscript.OP_HASH160).
AddData(refundAddressHash).
AddOp(txscript.OP_EQUALVERIFY)
// Final verification for both branches:
builder.AddOp(txscript.OP_ENDIF).
AddOp(txscript.OP_CHECKSIG)
return builder.Script()
}
func ValidateSubmarineSwapV1(rawInvoice string, userPublicKey *HDPublicKey, muunPublicKey *HDPublicKey, swap SubmarineSwap, network *Network) error {
invoice, err := ParseInvoice(rawInvoice, network)
if err != nil {
return errors.Wrapf(err, "failed to decode invoice")
}
// Check the payment hash matches
serverPaymentHash, err := hex.DecodeString(swap.FundingOutput().ServerPaymentHashInHex())
if err != nil {
return errors.Wrapf(err, "server payment hash is not valid hex")
}
if !bytes.Equal(invoice.PaymentHash[:], serverPaymentHash) {
return errors.Errorf("payment hash doesn't match %v != %v", invoice.PaymentHash, swap.FundingOutput().ServerPaymentHashInHex())
}
// TODO: check that timelock is acceptable
// Validate that the refund address is one we can derive
swapRefundAddress := swap.FundingOutput().UserRefundAddress()
derivedUserKey, err := userPublicKey.DeriveTo(swapRefundAddress.DerivationPath())
if err != nil {
return errors.Wrapf(err, "failed to derive user key")
}
derivedMuunKey, err := muunPublicKey.DeriveTo(swapRefundAddress.DerivationPath())
if err != nil {
return errors.Wrapf(err, "failed to derive muun key")
}
refundAddress, err := newMuunAddress(AddressVersion(swapRefundAddress.Version()), derivedUserKey, derivedMuunKey)
if err != nil {
return errors.Wrapf(err, "failed to generate refund address")
}
if refundAddress.Address() != swapRefundAddress.Address() {
return errors.Errorf("refund address doesn't match generated (%v != %v)", swapRefundAddress.Address(), refundAddress.Address())
}
// Check the swap's witness script is a valid swap script
serverPubKey, err := hex.DecodeString(swap.FundingOutput().ServerPublicKeyInHex())
if err != nil {
return errors.Wrapf(err, "server pub key is not hex")
}
witnessScript, err := createWitnessScriptSubmarineSwapV1(
swapRefundAddress.Address(),
serverPaymentHash,
serverPubKey,
swap.FundingOutput().UserLockTime(),
network)
if err != nil {
return errors.Wrapf(err, "failed to compute witness script")
}
redeemScript, err := createNonNativeSegwitRedeemScript(witnessScript)
if err != nil {
return errors.Wrapf(err, "failed to build redeem script")
}
address, err := btcutil.NewAddressScriptHash(redeemScript, network.network)
if err != nil {
return errors.Wrapf(err, "failed to build address for swap script")
}
if address.EncodeAddress() != swap.FundingOutput().OutputAddress() {
return errors.Errorf("address for swap script mismatch (%v != %v)", address.EncodeAddress(), swap.FundingOutput().OutputAddress())
}
if len(swap.PreimageInHex()) > 0 {
preimage, err := hex.DecodeString(swap.PreimageInHex())
if err != nil {
return errors.Wrapf(err, "preimagehex is not actually hex 🤔")
}
calculatedPaymentHash := sha256.Sum256(preimage)
if !bytes.Equal(invoice.PaymentHash[:], calculatedPaymentHash[:]) {
return errors.Errorf("payment hash doesn't match preimage (%v != hash(%v)", invoice.PaymentHash, swap.PreimageInHex())
}
}
return nil
}

231
vendor/github.com/muun/libwallet/submarineSwapV2.go generated vendored Normal file
View File

@@ -0,0 +1,231 @@
package libwallet
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/pkg/errors"
)
func addUserSignatureInputSubmarineSwapV2(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey,
muunKey *HDPublicKey) (*wire.TxIn, error) {
submarineSwap := input.SubmarineSwapV2()
if submarineSwap == nil {
return nil, errors.Errorf("submarine swap data is nil for ss input")
}
if len(submarineSwap.ServerSignature()) == 0 {
return nil, errors.Errorf("Swap server must provide signature")
}
witnessScript, err := createWitnessScriptSubmarineSwapV2(
submarineSwap.PaymentHash256(),
submarineSwap.UserPublicKey(),
submarineSwap.MuunPublicKey(),
submarineSwap.ServerPublicKey(),
submarineSwap.BlocksForExpiration())
if err != nil {
return nil, err
}
sig, err := signNativeSegwitInput(input, index, tx, privateKey, witnessScript)
if err != nil {
return nil, err
}
txInput := tx.TxIn[index]
txInput.Witness = wire.TxWitness{
sig,
submarineSwap.ServerSignature(),
witnessScript,
}
return txInput, nil
}
func createWitnessScriptSubmarineSwapV2(paymentHash, userPubKey, muunPubKey, swapServerPubKey []byte, blocksForExpiration int64) ([]byte, error) {
// It turns out that the payment hash present in an invoice is just the SHA256 of the
// payment preimage, so we still have to do a pass of RIPEMD160 before pushing it to the
// script
paymentHash160 := ripemd160(paymentHash)
muunPublicKeyHash160 := btcutil.Hash160(muunPubKey)
// Equivalent miniscript (http://bitcoin.sipa.be/miniscript/):
// or(
// and(pk(userPublicKey), pk(swapServerPublicKey)),
// or(
// and(pk(swapServerPublicKey), hash160(swapPaymentHash160)),
// and(pk(userPublicKey), and(pk(muunPublicKey), older(numBlocksForExpiration)))
// )
// )
//
// However, we differ in that the size of the script was heavily optimized for spending the
// first two branches (the collaborative close and the unilateral close by swapper), which
// are the most probable to be used.
builder := txscript.NewScriptBuilder().
// Push the user public key to the second position of the stack
AddData(userPubKey).
AddOp(txscript.OP_SWAP).
// Check whether the first stack item was a valid swap server signature
AddData(swapServerPubKey).
AddOp(txscript.OP_CHECKSIG).
// If the swap server signature was correct
AddOp(txscript.OP_IF).
AddOp(txscript.OP_SWAP).
// Check whether the second stack item was the payment preimage
AddOp(txscript.OP_DUP).
AddOp(txscript.OP_HASH160).
AddData(paymentHash160).
AddOp(txscript.OP_EQUAL).
// If the preimage was correct
AddOp(txscript.OP_IF).
// We are done, leave just one true-ish item in the stack (there're 2
// remaining items)
AddOp(txscript.OP_DROP).
// If the second stack item wasn't a valid payment preimage
AddOp(txscript.OP_ELSE).
// Validate that the second stack item was a valid user signature
AddOp(txscript.OP_SWAP).
AddOp(txscript.OP_CHECKSIG).
AddOp(txscript.OP_ENDIF).
// If the first stack item wasn't a valid server signature
AddOp(txscript.OP_ELSE).
// Validate that the blockchain height is big enough
AddInt64(blocksForExpiration).
AddOp(txscript.OP_CHECKSEQUENCEVERIFY).
AddOp(txscript.OP_DROP).
// Validate that the second stack item was a valid user signature
AddOp(txscript.OP_CHECKSIGVERIFY).
// Validate that the third stack item was the muun public key
AddOp(txscript.OP_DUP).
AddOp(txscript.OP_HASH160).
AddData(muunPublicKeyHash160).
AddOp(txscript.OP_EQUALVERIFY).
// Notice that instead of directly pushing the public key here and checking the
// signature P2PK-style, we pushed the hash of the public key, and require an
// extra stack item with the actual public key, verifying the signature and
// public key P2PKH-style.
//
// This trick reduces the on-chain footprint of the muun key from 33 bytes to
// 20 bytes for the collaborative, and swap server's non-collaborative branches,
// which are the most frequent ones.
// Validate that the fourth stack item was a valid server signature
AddOp(txscript.OP_CHECKSIG).
AddOp(txscript.OP_ENDIF)
return builder.Script()
}
func ValidateSubmarineSwapV2(rawInvoice string, userPublicKey *HDPublicKey, muunPublicKey *HDPublicKey, swap SubmarineSwap, originalExpirationInBlocks int64, network *Network) error {
fundingOutput := swap.FundingOutput()
invoice, err := ParseInvoice(rawInvoice, network)
if err != nil {
return errors.Wrapf(err, "failed to decode invoice")
}
// Check the payment hash matches
serverPaymentHash, err := hex.DecodeString(fundingOutput.ServerPaymentHashInHex())
if err != nil {
return errors.Wrapf(err, "server payment hash is not valid hex")
}
if !bytes.Equal(invoice.PaymentHash[:], serverPaymentHash) {
return errors.Errorf("payment hash doesn't match %v != %v", invoice.PaymentHash, fundingOutput.ServerPaymentHashInHex())
}
destination, err := hex.DecodeString(swap.Receiver().PublicKey())
if err != nil {
return errors.Wrapf(err, "destination is not valid hex")
}
if !bytes.Equal(invoice.Destination[:], destination) {
return errors.Errorf("destination doesnt match %v != %v", invoice.Destination, swap.Receiver().PublicKey())
}
if fundingOutput.ExpirationInBlocks() != originalExpirationInBlocks {
return errors.Errorf("expiration in blocks doesnt match %v != %v", originalExpirationInBlocks, fundingOutput.ExpirationInBlocks())
}
// Validate that we can derive the addresses involved
derivationPath := fundingOutput.UserPublicKey().Path
derivedUserKey, err := userPublicKey.DeriveTo(derivationPath)
if err != nil {
return errors.Wrapf(err, "failed to derive user key")
}
if !bytes.Equal(derivedUserKey.Raw(), fundingOutput.UserPublicKey().Raw()) {
return errors.Errorf("user pub keys dont match %v != %v", derivedUserKey.String(), fundingOutput.UserPublicKey().String())
}
derivedMuunKey, err := muunPublicKey.DeriveTo(derivationPath)
if err != nil {
return errors.Wrapf(err, "failed to derive muun key")
}
if !bytes.Equal(derivedMuunKey.Raw(), fundingOutput.MuunPublicKey().Raw()) {
return errors.Errorf("muun pub keys dont match %v != %v", derivedMuunKey.String(), fundingOutput.MuunPublicKey().String())
}
// Check the swap's witness script is a valid swap script
serverPubKey, err := hex.DecodeString(swap.FundingOutput().ServerPublicKeyInHex())
if err != nil {
return errors.Wrapf(err, "server pub key is not hex")
}
witnessScript, err := createWitnessScriptSubmarineSwapV2(
serverPaymentHash,
derivedUserKey.Raw(),
derivedMuunKey.Raw(),
serverPubKey,
swap.FundingOutput().ExpirationInBlocks())
if err != nil {
return errors.Wrapf(err, "failed to compute witness script")
}
witnessScriptHash := sha256.Sum256(witnessScript)
address, err := btcutil.NewAddressWitnessScriptHash(witnessScriptHash[:], network.network)
if err != nil {
return errors.Wrapf(err, "failed to build address for swap script")
}
if address.EncodeAddress() != swap.FundingOutput().OutputAddress() {
return errors.Errorf("address for swap script mismatch (%v != %v)", address.EncodeAddress(), swap.FundingOutput().OutputAddress())
}
if len(swap.PreimageInHex()) > 0 {
preimage, err := hex.DecodeString(swap.PreimageInHex())
if err != nil {
return errors.Wrapf(err, "preimagehex is not actually hex 🤔")
}
calculatedPaymentHash := sha256.Sum256(preimage)
if !bytes.Equal(invoice.PaymentHash[:], calculatedPaymentHash[:]) {
return errors.Errorf("payment hash doesn't match preimage (%v != hash(%v)", invoice.PaymentHash, swap.PreimageInHex())
}
}
return nil
}