From 6a1d8d06820d126bbbbcd124fabf14d457840fb3 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 12 Aug 2016 15:29:38 -0700 Subject: [PATCH] lnwallet: add a BtcWallet implementation of WalletController This commit adds the first concrete implementation of the WalletController interface: BtcWallet. This implementation is simply a series of wrapper functions are the base btcwallet struct. Additionally, for ease of use both the BlockChain IO and Signer interface are also implemented by BtcWallet. Finally a new WalletDriver implementation has been implemented, and will be register by the init() method within this new package. --- lnwallet/btcwallet/blockchain.go | 55 +++++ lnwallet/btcwallet/btcwallet.go | 380 +++++++++++++++++++++++++++++++ lnwallet/btcwallet/config.go | 94 ++++++++ lnwallet/btcwallet/driver.go | 45 ++++ lnwallet/btcwallet/signer.go | 174 ++++++++++++++ lnwallet/config.go | 67 +----- 6 files changed, 759 insertions(+), 56 deletions(-) create mode 100644 lnwallet/btcwallet/blockchain.go create mode 100644 lnwallet/btcwallet/btcwallet.go create mode 100644 lnwallet/btcwallet/config.go create mode 100644 lnwallet/btcwallet/driver.go create mode 100644 lnwallet/btcwallet/signer.go diff --git a/lnwallet/btcwallet/blockchain.go b/lnwallet/btcwallet/blockchain.go new file mode 100644 index 000000000..bc6237ec1 --- /dev/null +++ b/lnwallet/btcwallet/blockchain.go @@ -0,0 +1,55 @@ +package btcwallet + +import ( + "encoding/hex" + + "github.com/roasbeef/btcd/wire" +) + +// GetCurrentHeight returns the current height of the known block within the +// main chain. +// +// This method is a part of the lnwallet.BlockChainIO interface. +func (b *BtcWallet) GetCurrentHeight() (int32, error) { + _, height, err := b.rpc.GetBestBlock() + if err != nil { + return 0, err + } + + return height, nil +} + +// GetTxOut returns the original output referenced by the passed outpoint. +// +// This method is a part of the lnwallet.BlockChainIO interface. +func (b *BtcWallet) GetUtxo(txid *wire.ShaHash, index uint32) (*wire.TxOut, error) { + txout, err := b.rpc.GetTxOut(txid, index, false) + if err != nil { + return nil, err + } + + pkScript, err := hex.DecodeString(txout.ScriptPubKey.Hex) + if err != nil { + return nil, err + } + + return &wire.TxOut{ + // Sadly, gettxout returns the output value in BTC + // instead of satoshis. + Value: int64(txout.Value) * 1e8, + PkScript: pkScript, + }, nil +} + +// GetTransaction returns the full transaction identified by the passed +// transaction ID. +// +// This method is a part of the lnwallet.BlockChainIO interface. +func (b *BtcWallet) GetTransaction(txid *wire.ShaHash) (*wire.MsgTx, error) { + tx, err := b.rpc.GetRawTransaction(txid) + if err != nil { + return nil, err + } + + return tx.MsgTx(), nil +} diff --git a/lnwallet/btcwallet/btcwallet.go b/lnwallet/btcwallet/btcwallet.go new file mode 100644 index 000000000..29b9f9338 --- /dev/null +++ b/lnwallet/btcwallet/btcwallet.go @@ -0,0 +1,380 @@ +package btcwallet + +import ( + "encoding/hex" + "fmt" + "math" + "sync" + + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/roasbeef/btcd/btcec" + "github.com/roasbeef/btcd/chaincfg" + "github.com/roasbeef/btcd/txscript" + "github.com/roasbeef/btcd/wire" + "github.com/roasbeef/btcutil" + "github.com/roasbeef/btcwallet/chain" + "github.com/roasbeef/btcwallet/waddrmgr" + base "github.com/roasbeef/btcwallet/wallet" + "github.com/roasbeef/btcwallet/walletdb" +) + +const ( + defaultAccount = uint32(waddrmgr.DefaultAccountNum) +) + +var ( + lnNamespace = []byte("ln") + rootKey = []byte("ln-root") +) + +// BtcWallet is an implementation of the lnwallet.WalletController interface +// backed by an active instance of btcwallet. At the time of the writing of +// this documentation, this implementation requires a full btcd node to +// operate. +type BtcWallet struct { + // wallet is an active instance of btcwallet. + wallet *base.Wallet + + // rpc is an an active RPC connection to btcd full-node. + rpc *chain.RPCClient + + // lnNamespace is a namespace within btcwallet's walletdb used to store + // persistent state required by the WalletController interface but not + // natively supported by btcwallet. + lnNamespace walletdb.Namespace + + netParams *chaincfg.Params + + // utxoCache is a cache used to speed up repeated calls to + // FetchInputInfo. + utxoCache map[wire.OutPoint]*wire.TxOut + cacheMtx sync.RWMutex +} + +// A compile time check to ensure that BtcWallet implements the +// WalletController interface. +var _ lnwallet.WalletController = (*BtcWallet)(nil) + +// New returns a new fully initialized instance of BtcWallet given a valid +// confirguration struct. +func New(cfg *Config) (*BtcWallet, error) { + // Ensure the wallet exists or create it when the create flag is set. + netDir := networkDir(cfg.DataDir, cfg.NetParams) + + var pubPass []byte + if cfg.PublicPass == nil { + pubPass = defaultPubPassphrase + } else { + pubPass = cfg.PublicPass + } + + loader := base.NewLoader(cfg.NetParams, netDir) + walletExists, err := loader.WalletExists() + if err != nil { + return nil, err + } + + var wallet *base.Wallet + if !walletExists { + // Wallet has never been created, perform initial set up. + wallet, err = loader.CreateNewWallet(pubPass, cfg.PrivatePass, + cfg.HdSeed) + if err != nil { + return nil, err + } + } else { + // Wallet has been created and been initialized at this point, open it + // along with all the required DB namepsaces, and the DB itself. + wallet, err = loader.OpenExistingWallet(pubPass, false) + if err != nil { + return nil, err + } + } + + if err := wallet.Manager.Unlock(cfg.PrivatePass); err != nil { + return nil, err + } + + // Create a special websockets rpc client for btcd which will be used + // by the wallet for notifications, calls, etc. + rpcc, err := chain.NewRPCClient(cfg.NetParams, cfg.RpcHost, + cfg.RpcUser, cfg.RpcPass, cfg.CACert, false, 20) + if err != nil { + return nil, err + } + + db := wallet.Database() + walletNamespace, err := db.Namespace(lnNamespace) + if err != nil { + return nil, err + } + + return &BtcWallet{ + wallet: wallet, + rpc: rpcc, + lnNamespace: walletNamespace, + netParams: cfg.NetParams, + utxoCache: make(map[wire.OutPoint]*wire.TxOut), + }, nil +} + +// Start initializes the underlying rpc connection, the wallet itself, and +// begins syncing to the current available blockchain state. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) Start() error { + // Establish an RPC connection in additino to starting the goroutines + // in the underlying wallet. + if err := b.rpc.Start(); err != nil { + return err + } + + // Start the underlying btcwallet core. + b.wallet.Start() + + // Pass the rpc client into the wallet so it can sync up to the + // current main chain. + b.wallet.SynchronizeRPC(b.rpc) + + return nil +} + +// Stop signals the wallet for shutdown. Shutdown may entail closing +// any active sockets, database handles, stopping goroutines, etc. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) Stop() error { + b.wallet.Stop() + + b.wallet.WaitForShutdown() + + b.rpc.Shutdown() + + return nil +} + +// ConfirmedBalance returns the sum of all the wallet's unspent outputs that +// have at least confs confirmations. If confs is set to zero, then all unspent +// outputs, including those currently in the mempool will be included in the +// final sum. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) ConfirmedBalance(confs int32, witness bool) (btcutil.Amount, error) { + var balance btcutil.Amount + + if witness { + witnessOutputs, err := b.ListUnspentWitness(confs) + if err != nil { + return 0, err + } + + for _, witnessOutput := range witnessOutputs { + balance += witnessOutput.Value + } + } else { + outputSum, err := b.wallet.CalculateBalance(confs) + if err != nil { + return 0, err + } + + balance = outputSum + } + + return balance, nil +} + +// NewAddress returns the next external or internal address for the wallet +// dicatated by the value of the `change` paramter. If change is true, then an +// internal address will be returned, otherwise an external address should be +// returned. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) NewAddress(t lnwallet.AddressType, change bool) (btcutil.Address, error) { + var addrType waddrmgr.AddressType + + switch t { + case lnwallet.WitnessPubKey: + addrType = waddrmgr.WitnessPubKey + case lnwallet.NestedWitnessPubKey: + addrType = waddrmgr.NestedWitnessPubKey + case lnwallet.PubKeyHash: + addrType = waddrmgr.PubKeyHash + default: + return nil, fmt.Errorf("unknown address type") + } + + if change { + return b.wallet.NewAddress(defaultAccount, addrType) + } else { + return b.wallet.NewChangeAddress(defaultAccount, addrType) + } +} + +// GetPrivKey retrives the underlying private key associated with the passed +// address. If the we're unable to locate the proper private key, then a +// non-nil error will be returned. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) GetPrivKey(a btcutil.Address) (*btcec.PrivateKey, error) { + // Using the ID address, request the private key coresponding to the + // address from the wallet's address manager. + walletAddr, err := b.wallet.Manager.Address(a) + if err != nil { + return nil, err + } + + return walletAddr.(waddrmgr.ManagedPubKeyAddress).PrivKey() +} + +// NewRawKey retrieves the next key within our HD key-chain for use within as a +// multi-sig key within the funding transaction, or within the commitment +// transaction's outputs. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) NewRawKey() (*btcec.PublicKey, error) { + nextAddr, err := b.wallet.Manager.NextExternalAddresses(defaultAccount, + 1, waddrmgr.WitnessPubKey) + if err != nil { + return nil, err + } + + pkAddr := nextAddr[0].(waddrmgr.ManagedPubKeyAddress) + + return pkAddr.PubKey(), nil +} + +// FetchRootKey returns a root key which is meanted to be used as an initial +// seed/salt to generate any Lightning specific secrets. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) FetchRootKey() (*btcec.PrivateKey, error) { + // Fetch the root address hash from the database, this is persisted + // locally within the database, then used to obtain the key from the + // wallet based on the address hash. + var rootAddrHash []byte + if err := b.lnNamespace.Update(func(tx walletdb.Tx) error { + rootBucket := tx.RootBucket() + + rootAddrHash = rootBucket.Get(rootKey) + return nil + }); err != nil { + return nil, err + } + + if rootAddrHash == nil { + // Otherwise, we need to generate a fresh address from the + // wallet, then stores it's hash160 within the database so we + // can look up the exact key later. + rootAddr, err := b.wallet.Manager.NextExternalAddresses(defaultAccount, + 1, waddrmgr.WitnessPubKey) + if err != nil { + return nil, err + } + + if err := b.lnNamespace.Update(func(tx walletdb.Tx) error { + rootBucket := tx.RootBucket() + + rootAddrHash = rootAddr[0].Address().ScriptAddress() + if err := rootBucket.Put(rootKey, rootAddrHash); err != nil { + return err + } + + return nil + }); err != nil { + return nil, err + } + } + + // With the root address hash obtained, generate the corresponding + // address, then retrieve the managed address from the wallet which + // will allow us to obtain the private key. + rootAddr, err := btcutil.NewAddressWitnessPubKeyHash(rootAddrHash, + b.netParams) + if err != nil { + return nil, err + } + walletAddr, err := b.wallet.Manager.Address(rootAddr) + if err != nil { + return nil, err + } + + return walletAddr.(waddrmgr.ManagedPubKeyAddress).PrivKey() +} + +// SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying out to +// the specified outputs. In the case the wallet has insufficient funds, or the +// outputs are non-standard, a non-nil error will be be returned. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut) (*wire.ShaHash, error) { + return b.wallet.SendOutputs(outputs, defaultAccount, 1) +} + +// LockOutpoint marks an outpoint as locked meaning it will no longer be deemed +// as eligible for coin selection. Locking outputs are utilized in order to +// avoid race conditions when selecting inputs for usage when funding a +// channel. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) LockOutpoint(o wire.OutPoint) { + b.wallet.LockOutpoint(o) +} + +// UnlockOutpoint unlocks an previously locked output, marking it eligible for +// coin seleciton. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) UnlockOutpoint(o wire.OutPoint) { + b.wallet.UnlockOutpoint(o) +} + +// ListUnspentWitness returns a slice of all the unspent outputs the wallet +// controls which pay to witness programs either directly or indirectly. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) ListUnspentWitness(minConfs int32) ([]*lnwallet.Utxo, error) { + // First, grab all the unfiltered currently unspent outputs. + maxConfs := int32(math.MaxInt32) + unspentOutputs, err := b.wallet.ListUnspent(minConfs, maxConfs, nil) + if err != nil { + return nil, err + } + + // Next, we'll run through all the regular outputs, only saving those + // which are p2wkh outputs or a p2wsh output nested within a p2sh output. + witnessOutputs := make([]*lnwallet.Utxo, 0, len(unspentOutputs)) + for _, output := range unspentOutputs { + pkScript, err := hex.DecodeString(output.ScriptPubKey) + if err != nil { + return nil, err + } + + // TODO(roasbeef): this assumes all p2sh outputs returned by + // the wallet are nested p2sh... + if txscript.IsPayToWitnessPubKeyHash(pkScript) || + txscript.IsPayToScriptHash(pkScript) { + txid, err := wire.NewShaHashFromStr(output.TxID) + if err != nil { + return nil, err + } + + utxo := &lnwallet.Utxo{ + Value: btcutil.Amount(output.Amount * 1e8), + OutPoint: wire.OutPoint{ + Hash: *txid, + Index: output.Vout, + }, + } + witnessOutputs = append(witnessOutputs, utxo) + } + + } + + return witnessOutputs, nil +} + +// PublishTransaction performs cursory validation (dust checks, etc), then +// finally broadcasts the passed transaction to the Bitcoin network. +func (b *BtcWallet) PublishTransaction(tx *wire.MsgTx) error { + return b.wallet.PublishTransaction(tx) +} diff --git a/lnwallet/btcwallet/config.go b/lnwallet/btcwallet/config.go new file mode 100644 index 000000000..5b19eafbb --- /dev/null +++ b/lnwallet/btcwallet/config.go @@ -0,0 +1,94 @@ +package btcwallet + +import ( + "path/filepath" + + "github.com/roasbeef/btcd/chaincfg" + "github.com/roasbeef/btcd/wire" + "github.com/roasbeef/btcutil" + _ "github.com/roasbeef/btcwallet/walletdb/bdb" +) + +var ( + lnwalletHomeDir = btcutil.AppDataDir("lnwallet", false) + defaultDataDir = lnwalletHomeDir + + defaultLogFilename = "lnwallet.log" + defaultLogDirname = "logs" + defaultLogDir = filepath.Join(lnwalletHomeDir, defaultLogDirname) + + btcdHomeDir = btcutil.AppDataDir("btcd", false) + btcdHomedirCAFile = filepath.Join(btcdHomeDir, "rpc.cert") + defaultRPCKeyFile = filepath.Join(lnwalletHomeDir, "rpc.key") + defaultRPCCertFile = filepath.Join(lnwalletHomeDir, "rpc.cert") + + // defaultPubPassphrase is the default public wallet passphrase which is + // used when the user indicates they do not want additional protection + // provided by having all public data in the wallet encrypted by a + // passphrase only known to them. + defaultPubPassphrase = []byte("public") + + walletDbName = "lnwallet.db" +) + +// Config is a struct which houses configuration paramters which modify the +// instance of BtcWallet generated by the New() function. +type Config struct { + // DataDir is the name of the directory where the wallet's persistent + // state should be sotred. + DataDir string + + // LogDir is the name of the directory which should be used to store + // generated log files. + LogDir string + + // DebugLevel is a string representing the level of verbosity the + // logger should use. + DebugLevel string + + // RpcHost is the host and port to use to reach the rpc sever. + RpcHost string // localhost:18334 + + // RpcUser is the username which should be used to authentiate with the + // rpc server. + RpcUser string + + // RpcPass is the password which should be used to authenticate the + // connection with the RPC server. + RpcPass string + + // RpcNoTLS denotes if a TLS connection should be attempted when + // connecting to the RPC server. + RpcNoTLS bool + + // RPCCert directory where the TLS certificate of the RPC sever is + // stored. If the RpcNoTLS is false, then this value will be unused. + RPCCert string + RPCKey string + + // CACert is the raw RPC cert for btcd. + CACert []byte + + PrivatePass []byte + PublicPass []byte + HdSeed []byte + + NetParams *chaincfg.Params +} + +// networkDir returns the directory name of a network directory to hold wallet +// files. +func networkDir(dataDir string, chainParams *chaincfg.Params) string { + netname := chainParams.Name + + // For now, we must always name the testnet data directory as "testnet" + // and not "testnet3" or any other version, as the chaincfg testnet3 + // paramaters will likely be switched to being named "testnet3" in the + // future. This is done to future proof that change, and an upgrade + // plan to move the testnet3 data directory can be worked out later. + if chainParams.Net == wire.TestNet3 { + netname = "testnet" + } + + return filepath.Join(dataDir, netname) +} diff --git a/lnwallet/btcwallet/driver.go b/lnwallet/btcwallet/driver.go new file mode 100644 index 000000000..828633eda --- /dev/null +++ b/lnwallet/btcwallet/driver.go @@ -0,0 +1,45 @@ +package btcwallet + +import ( + "fmt" + + "github.com/lightningnetwork/lnd/lnwallet" +) + +const ( + walletType = "btcwallet" +) + +// createNewWallet creates a new instance of BtcWallet given the proper list of +// initialization parameters. This function is the factory function required to +// properly create an instance of the lnwallet.WalletDriver struct for +// BtcWallet. +func createNewWallet(args ...interface{}) (lnwallet.WalletController, error) { + if len(args) != 1 { + return nil, fmt.Errorf("incorrect number of arguments to .New(...), "+ + "expected 1, instead passed %v", len(args)) + } + + config, ok := args[0].(*Config) + if !ok { + return nil, fmt.Errorf("first argument to btcdnotifier.New is " + + "incorrect, expected a *btcrpcclient.ConnConfig") + } + + return New(config) +} + +// init registers a driver for the BtcWallet concrete implementation of the +// lnwallet.WalletController interface. +func init() { + // Register the driver. + driver := &lnwallet.WalletDriver{ + WalletType: walletType, + New: createNewWallet, + } + + if err := lnwallet.RegisterWallet(driver); err != nil { + panic(fmt.Sprintf("failed to register wallet driver '%s': %v", + walletType, err)) + } +} diff --git a/lnwallet/btcwallet/signer.go b/lnwallet/btcwallet/signer.go new file mode 100644 index 000000000..67bd394d5 --- /dev/null +++ b/lnwallet/btcwallet/signer.go @@ -0,0 +1,174 @@ +package btcwallet + +import ( + "fmt" + + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/roasbeef/btcd/txscript" + "github.com/roasbeef/btcd/wire" + "github.com/roasbeef/btcutil" + "github.com/roasbeef/btcwallet/waddrmgr" +) + +// FetchInputInfo queries for the WalletController's knowledge of the passed +// outpoint. If the base wallet determines this output is under its control, +// then the original txout should be returned. Otherwise, a non-nil error value +// of ErrNotMine should be returned instead. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) FetchInputInfo(prevOut *wire.OutPoint) (*wire.TxOut, error) { + var ( + err error + output *wire.TxOut + ) + + // First check to see if the output is already within the utxo cache. + // If so we can return directly saving usk a disk access. + b.cacheMtx.RLock() + if output, ok := b.utxoCache[*prevOut]; ok { + b.cacheMtx.RUnlock() + return output, nil + } + b.cacheMtx.RUnlock() + + // Otherwse, we manually look up the output within the tx store. + txDetail, err := b.wallet.TxStore.TxDetails(&prevOut.Hash) + if err != nil { + return nil, err + } else if txDetail == nil { + return nil, lnwallet.ErrNotMine + } + + output = txDetail.TxRecord.MsgTx.TxOut[prevOut.Index] + + b.cacheMtx.Lock() + b.utxoCache[*prevOut] = output + b.cacheMtx.Unlock() + + return output, nil +} + +// fetchOutputKey attempts to fetch the managed address corresponding to the +// passed output script. This function is used to look up the proper key which +// should be used to sign a specified input. +func (b *BtcWallet) fetchOutputAddr(script []byte) (waddrmgr.ManagedAddress, error) { + _, addrs, _, err := txscript.ExtractPkScriptAddrs(script, b.netParams) + if err != nil { + return nil, err + } + + // If the case of a multi-sig output, several address may be extracted. + // Therefore, we simply select the key for the first address we know + // of. + for _, addr := range addrs { + wAddr, err := b.wallet.Manager.Address(addr) + if err == nil { + return wAddr, nil + } + } + + // TODO(roasbeef): use the errors.wrap package + return nil, fmt.Errorf("address not found") +} + +// SignOutputRaw generates a signature for the passed transaction according to +// the data within the passed SignDescriptor. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) SignOutputRaw(tx *wire.MsgTx, signDesc *lnwallet.SignDescriptor) ([]byte, error) { + redeemScript := signDesc.RedeemScript + walletAddr, err := b.fetchOutputAddr(redeemScript) + if err != nil { + return nil, err + } + + privKey, err := walletAddr.(waddrmgr.ManagedPubKeyAddress).PrivKey() + if err != nil { + return nil, err + } + + amt := signDesc.Output.Value + sig, err := txscript.RawTxInWitnessSignature(tx, signDesc.SigHashes, 0, + amt, redeemScript, txscript.SigHashAll, privKey) + if err != nil { + return nil, err + } + + // Chop off the sighash flag at the end of the signature. + return sig[:len(sig)-1], nil +} + +// ComputeInputScript generates a complete InputIndex for the passed +// transaction with the signature as defined within the passed SignDescriptor. +// This method is capable of generating the proper input script for both +// regular p2wkh output and p2wkh outputs nested within a regualr p2sh output. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx, + signDesc *lnwallet.SignDescriptor) (*lnwallet.InputScript, error) { + + outputScript := signDesc.Output.PkScript + walletAddr, err := b.fetchOutputAddr(outputScript) + if err != nil { + return nil, nil + } + + pka := walletAddr.(waddrmgr.ManagedPubKeyAddress) + privKey, err := pka.PrivKey() + if err != nil { + return nil, err + } + + var witnessProgram []byte + inputScript := &lnwallet.InputScript{} + + // If we're spending p2wkh output nested within a p2sh output, then + // we'll need to attach a sigScript in addition to witness data. + switch { + case pka.IsNestedWitness(): + pubKey := privKey.PubKey() + pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed()) + + // Next, we'll generate a valid sigScript that'll allow us to + // spend the p2sh output. The sigScript will contain only a + // single push of the p2wkh witness program corresponding to + // the matching public key of this address. + p2wkhAddr, err := btcutil.NewAddressWitnessPubKeyHash(pubKeyHash, + b.netParams) + if err != nil { + return nil, err + } + witnessProgram, err = txscript.PayToAddrScript(p2wkhAddr) + if err != nil { + return nil, err + } + + bldr := txscript.NewScriptBuilder() + bldr.AddData(witnessProgram) + sigScript, err := bldr.Script() + if err != nil { + return nil, err + } + + inputScript.ScriptSig = sigScript + // Otherwise, this is a regular p2wkh output, so we include the + // witness program itself as the subscript to generate the proper + // sighash digest. As part of the new sighash digest algorithm, the + // p2wkh witness program will be expanded into a regular p2kh + // script. + default: + witnessProgram = outputScript + } + + // Generate a valid witness stack for the input. + witnessScript, err := txscript.WitnessScript(tx, signDesc.SigHashes, + signDesc.InputIndex, signDesc.Output.Value, witnessProgram, + txscript.SigHashAll, privKey, true) + if err != nil { + return nil, err + } + + inputScript.Witness = witnessScript + + return inputScript, nil +} diff --git a/lnwallet/config.go b/lnwallet/config.go index 8547c1c82..f579fde55 100644 --- a/lnwallet/config.go +++ b/lnwallet/config.go @@ -1,60 +1,15 @@ package lnwallet -import ( - "path/filepath" - - "github.com/roasbeef/btcd/chaincfg" - "github.com/roasbeef/btcutil" -) - -var ( - // TODO(roasbeef): lnwallet config file - lnwalletHomeDir = btcutil.AppDataDir("lnwallet", false) - defaultDataDir = lnwalletHomeDir - - defaultLogFilename = "lnwallet.log" - defaultLogDirname = "logs" - defaultLogDir = filepath.Join(lnwalletHomeDir, defaultLogDirname) - - btcdHomeDir = btcutil.AppDataDir("btcd", false) - btcdHomedirCAFile = filepath.Join(btcdHomeDir, "rpc.cert") - defaultRPCKeyFile = filepath.Join(lnwalletHomeDir, "rpc.key") - defaultRPCCertFile = filepath.Join(lnwalletHomeDir, "rpc.cert") - - // defaultPubPassphrase is the default public wallet passphrase which is - // used when the user indicates they do not want additional protection - // provided by having all public data in the wallet encrypted by a - // passphrase only known to them. - defaultPubPassphrase = []byte("public") - - walletDbName = "lnwallet.db" -) - -// Config... +// Config.. type Config struct { - DataDir string - LogDir string - - DebugLevel string - - RpcHost string // localhost:18334 - RpcUser string - RpcPass string - RpcNoTLS bool - - RPCCert string - RPCKey string - - CACert []byte - - PrivatePass []byte - PublicPass []byte - HdSeed []byte - - // Which bitcoin network are we using? - NetParams *chaincfg.Params -} - -// setDefaults... -func setDefaults(confg *Config) { + // default csv time + // default cltv time + // default wait for funding time + // default wait for closure time + // min amount to accept channel + // min fee imformation + // * or possibly interface to predict fees + // max htlcs in flight? + // possible secret derivation functions + // }