channeldb: create new channeldb package, update lnwallet to use new API
* Initial draft of brain dump of chandler. Nothing yet set in stone. * Will most likely move the storage of all structs to a more “column” oriented approach. Such that, small updates like incrementing the total satoshi sent don’t result in the entire struct being serialized and written. * Some skeleton structs for other possible data we might want to store are also included. * Seem valuable to record as much data as possible for record keeping, visualization, debugging, etc. Will need to set up a time+space+dirty cache to ensure performance isn’t impacted too much.
This commit is contained in:
1 parent
d7a1c5d337
commit
4fdb2763e6
13 files changed
+194
-131
No files matched your search
+3
-2
@@ -27,11 +27,11 @@ type LightningChannel struct {
|
||||
// commitment update, plus some other meta-data...Or just use OP_RETURN
|
||||
// to help out?
|
||||
// currently going for: nSequence/nLockTime overloading
|
||||
channelDB *ChannelDB
|
||||
channelDB *channeldb.DB
|
||||
|
||||
// stateMtx protects concurrent access to the state struct.
|
||||
stateMtx sync.RWMutex
|
||||
channelState OpenChannelState
|
||||
channelState channeldb.OpenChannel
|
||||
|
||||
// TODO(roasbeef): create and embed 'Service' interface w/ below?
|
||||
started int32
|
||||
@@ -44,6 +44,7 @@ type LightningChannel struct {
|
||||
// newLightningChannel...
|
||||
func newLightningChannel(wallet *LightningWallet, events *chainntnfs.ChainNotifier,
|
||||
chanDB *ChannelDB, state OpenChannelState) (*LightningChannel, error) {
|
||||
chanDB *channeldb.DB, state channeldb.OpenChannel) (*LightningChannel, error) {
|
||||
|
||||
return &LightningChannel{
|
||||
wallet: wallet,
|
||||
|
||||
@@ -1,419 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"li.lan/labs/plasma/shachain"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
)
|
||||
|
||||
var (
|
||||
// Namespace bucket keys.
|
||||
lightningNamespaceKey = []byte("ln-wallet")
|
||||
waddrmgrNamespaceKey = []byte("waddrmgr")
|
||||
wtxmgrNamespaceKey = []byte("wtxmgr")
|
||||
|
||||
openChannelBucket = []byte("o")
|
||||
closedChannelBucket = []byte("c")
|
||||
activeChanKey = []byte("a")
|
||||
|
||||
endian = binary.BigEndian
|
||||
)
|
||||
|
||||
// ChannelDB...
|
||||
// TODO(roasbeef): CHECKSUMS, REDUNDANCY, etc etc.
|
||||
type ChannelDB struct {
|
||||
// TODO(roasbeef): caching, etc?
|
||||
addrmgr *waddrmgr.Manager
|
||||
|
||||
namespace walletdb.Namespace
|
||||
}
|
||||
|
||||
// PutOpenChannel...
|
||||
func (c *ChannelDB) PutOpenChannel(channel *OpenChannelState) error {
|
||||
return c.namespace.Update(func(tx walletdb.Tx) error {
|
||||
// Get the bucket dedicated to storing the meta-data for open
|
||||
// channels.
|
||||
rootBucket := tx.RootBucket()
|
||||
openChanBucket, err := rootBucket.CreateBucketIfNotExists(openChannelBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return dbPutOpenChannel(openChanBucket, channel, c.addrmgr)
|
||||
})
|
||||
}
|
||||
|
||||
// GetOpenChannel...
|
||||
// TODO(roasbeef): assumes only 1 active channel per-node
|
||||
func (c *ChannelDB) FetchOpenChannel(nodeID [32]byte) (*OpenChannelState, error) {
|
||||
var channel *OpenChannelState
|
||||
|
||||
dbErr := c.namespace.View(func(tx walletdb.Tx) error {
|
||||
// Get the bucket dedicated to storing the meta-data for open
|
||||
// channels.
|
||||
rootBucket := tx.RootBucket()
|
||||
openChanBucket := rootBucket.Bucket(openChannelBucket)
|
||||
if openChannelBucket == nil {
|
||||
return fmt.Errorf("open channel bucket does not exist")
|
||||
}
|
||||
|
||||
oChannel, err := dbGetOpenChannel(openChanBucket, nodeID, c.addrmgr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
channel = oChannel
|
||||
return nil
|
||||
})
|
||||
|
||||
return channel, dbErr
|
||||
}
|
||||
|
||||
// dbPutChannel...
|
||||
func dbPutOpenChannel(activeChanBucket walletdb.Bucket, channel *OpenChannelState,
|
||||
addrmgr *waddrmgr.Manager) error {
|
||||
|
||||
// Generate a serialized version of the open channel. The addrmgr is
|
||||
// required in order to encrypt densitive data.
|
||||
var b bytes.Buffer
|
||||
if err := channel.Encode(&b, addrmgr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Grab the bucket dedicated to storing data related to this particular
|
||||
// node.
|
||||
nodeBucket, err := activeChanBucket.CreateBucketIfNotExists(channel.TheirLNID[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nodeBucket.Put(activeChanKey, b.Bytes())
|
||||
}
|
||||
|
||||
// dbPutChannel...
|
||||
func dbGetOpenChannel(bucket walletdb.Bucket, nodeID [32]byte,
|
||||
addrmgr *waddrmgr.Manager) (*OpenChannelState, error) {
|
||||
|
||||
// Grab the bucket dedicated to storing data related to this particular
|
||||
// node.
|
||||
nodeBucket := bucket.Bucket(nodeID[:])
|
||||
if nodeBucket == nil {
|
||||
return nil, fmt.Errorf("channel bucket for node does not exist")
|
||||
}
|
||||
|
||||
serializedChannel := nodeBucket.Get(activeChanKey)
|
||||
if serializedChannel == nil {
|
||||
// TODO(roasbeef): make proper in error.go
|
||||
return nil, fmt.Errorf("node has no open channels")
|
||||
}
|
||||
|
||||
// Decode the serialized channel state, using the addrmgr to decrypt
|
||||
// sensitive information.
|
||||
channel := &OpenChannelState{}
|
||||
reader := bytes.NewReader(serializedChannel)
|
||||
if err := channel.Decode(reader, addrmgr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return channel, nil
|
||||
}
|
||||
|
||||
// NewChannelDB...
|
||||
// TODO(roasbeef): re-visit this dependancy...
|
||||
func NewChannelDB(addrmgr *waddrmgr.Manager, namespace walletdb.Namespace) *ChannelDB {
|
||||
// TODO(roasbeef): create buckets if not created?
|
||||
return &ChannelDB{addrmgr, namespace}
|
||||
}
|
||||
|
||||
// OpenChannelState...
|
||||
// TODO(roasbeef): store only the essentials? optimize space...
|
||||
// TODO(roasbeef): switch to "column store"
|
||||
type OpenChannelState struct {
|
||||
// Hash? or Their current pubKey?
|
||||
// TODO(roasbeef): switch to Tadge's LNId
|
||||
TheirLNID [wire.HashSize]byte
|
||||
|
||||
// The ID of a channel is the txid of the funding transaction.
|
||||
ChanID [wire.HashSize]byte
|
||||
|
||||
MinFeePerKb btcutil.Amount
|
||||
// Our reserve. Assume symmetric reserve amounts. Only needed if the
|
||||
// funding type is CLTV.
|
||||
//ReserveAmount btcutil.Amount
|
||||
|
||||
// Keys for both sides to be used for the commitment transactions.
|
||||
OurCommitKey *btcec.PrivateKey
|
||||
TheirCommitKey *btcec.PublicKey
|
||||
|
||||
// Tracking total channel capacity, and the amount of funds allocated
|
||||
// to each side.
|
||||
Capacity btcutil.Amount
|
||||
OurBalance btcutil.Amount
|
||||
TheirBalance btcutil.Amount
|
||||
|
||||
// Commitment transactions for both sides (they're asymmetric). Also
|
||||
// their signature which lets us spend our version of the commitment
|
||||
// transaction.
|
||||
TheirCommitTx *wire.MsgTx
|
||||
OurCommitTx *wire.MsgTx // TODO(roasbeef): store hash instead?
|
||||
TheirCommitSig []byte // TODO(roasbeef): fixed length?, same w/ redeem
|
||||
|
||||
// The final funding transaction. Kept wallet-related records.
|
||||
FundingTx *wire.MsgTx
|
||||
|
||||
MultiSigKey *btcec.PrivateKey
|
||||
FundingRedeemScript []byte
|
||||
|
||||
// Current revocation for their commitment transaction. However, since
|
||||
// this is the hash, and not the pre-image, we can't yet verify that
|
||||
// it's actually in the chain.
|
||||
TheirCurrentRevocation [wire.HashSize]byte
|
||||
TheirShaChain *shachain.HyperShaChain
|
||||
OurShaChain *shachain.HyperShaChain
|
||||
|
||||
// Final delivery address
|
||||
OurDeliveryAddress btcutil.Address
|
||||
TheirDeliveryAddress btcutil.Address
|
||||
|
||||
// In blocks
|
||||
CsvDelay uint32
|
||||
|
||||
// TODO(roasbeef): track fees, other stats?
|
||||
NumUpdates uint64
|
||||
TotalSatoshisSent uint64
|
||||
TotalSatoshisReceived uint64
|
||||
CreationTime time.Time
|
||||
}
|
||||
|
||||
// Encode...
|
||||
// TODO(roasbeef): checksum
|
||||
func (o *OpenChannelState) Encode(b io.Writer, addrManager *waddrmgr.Manager) error {
|
||||
if _, err := b.Write(o.TheirLNID[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.Write(o.ChanID[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(b, endian, uint64(o.MinFeePerKb)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encryptedPriv, err := addrManager.Encrypt(waddrmgr.CKTPrivate,
|
||||
o.OurCommitKey.Serialize())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.Write(encryptedPriv); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.Write(o.TheirCommitKey.SerializeCompressed()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(b, endian, uint64(o.Capacity)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(b, endian, uint64(o.OurBalance)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(b, endian, uint64(o.TheirBalance)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := o.TheirCommitTx.Serialize(b); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.OurCommitTx.Serialize(b); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.Write(o.TheirCommitSig[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := o.FundingTx.Serialize(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encryptedPriv, err = addrManager.Encrypt(waddrmgr.CKTPrivate,
|
||||
o.MultiSigKey.Serialize())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.Write(encryptedPriv); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.Write(o.FundingRedeemScript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := b.Write(o.TheirCurrentRevocation[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(roasbeef): serialize shachains
|
||||
|
||||
if _, err := b.Write([]byte(o.OurDeliveryAddress.EncodeAddress())); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.Write([]byte(o.TheirDeliveryAddress.EncodeAddress())); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(b, endian, o.CsvDelay); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(b, endian, o.NumUpdates); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(b, endian, o.TotalSatoshisSent); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(b, endian, o.TotalSatoshisReceived); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(b, endian, o.CreationTime.Unix()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode...
|
||||
func (o *OpenChannelState) Decode(b io.Reader, addrManager *waddrmgr.Manager) error {
|
||||
var scratch [8]byte
|
||||
|
||||
if _, err := b.Read(o.TheirLNID[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := b.Read(o.ChanID[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := b.Read(scratch[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.MinFeePerKb = btcutil.Amount(endian.Uint64(scratch[:]))
|
||||
|
||||
// nonce + serPrivKey + mac
|
||||
var encryptedPriv [24 + 32 + 16]byte
|
||||
if _, err := b.Read(encryptedPriv[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
decryptedPriv, err := addrManager.Decrypt(waddrmgr.CKTPrivate, encryptedPriv[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.OurCommitKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), decryptedPriv)
|
||||
|
||||
var serPubKey [33]byte
|
||||
if _, err := b.Read(serPubKey[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.TheirCommitKey, err = btcec.ParsePubKey(serPubKey[:], btcec.S256())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := b.Read(scratch[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.Capacity = btcutil.Amount(endian.Uint64(scratch[:]))
|
||||
if _, err := b.Read(scratch[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.OurBalance = btcutil.Amount(endian.Uint64(scratch[:]))
|
||||
if _, err := b.Read(scratch[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.TheirBalance = btcutil.Amount(endian.Uint64(scratch[:]))
|
||||
|
||||
o.TheirCommitTx = wire.NewMsgTx()
|
||||
if err := o.TheirCommitTx.Deserialize(b); err != nil {
|
||||
return err
|
||||
}
|
||||
o.OurCommitTx = wire.NewMsgTx()
|
||||
if err := o.OurCommitTx.Deserialize(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var sig [64]byte
|
||||
if _, err := b.Read(sig[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.TheirCommitSig = sig[:]
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.FundingTx = wire.NewMsgTx()
|
||||
if err := o.FundingTx.Deserialize(b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := b.Read(encryptedPriv[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
decryptedPriv, err = addrManager.Decrypt(waddrmgr.CKTPrivate, encryptedPriv[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.MultiSigKey, _ = btcec.PrivKeyFromBytes(btcec.S256(), decryptedPriv)
|
||||
|
||||
var redeemScript [71]byte
|
||||
if _, err := b.Read(redeemScript[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.FundingRedeemScript = redeemScript[:]
|
||||
|
||||
if _, err := b.Read(o.TheirCurrentRevocation[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var addr [34]byte
|
||||
if _, err := b.Read(addr[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.OurDeliveryAddress, err = btcutil.DecodeAddress(string(addr[:]), ActiveNetParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := b.Read(addr[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
o.TheirDeliveryAddress, err = btcutil.DecodeAddress(string(addr[:]), ActiveNetParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(b, endian, &o.CsvDelay); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(b, endian, &o.NumUpdates); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(b, endian, &o.TotalSatoshisSent); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(b, endian, &o.TotalSatoshisReceived); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var unix int64
|
||||
if err := binary.Read(b, endian, &unix); err != nil {
|
||||
return err
|
||||
}
|
||||
o.CreationTime = time.Unix(unix, 0)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
)
|
||||
|
||||
var (
|
||||
sig = bytes.Repeat([]byte{1}, 64)
|
||||
key = [wire.HashSize]byte{
|
||||
0x81, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
|
||||
0x68, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
|
||||
0xd, 0xe7, 0x93, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
|
||||
0x1e, 0xb, 0x4c, 0xf9, 0x9e, 0xc5, 0x8c, 0xe9,
|
||||
}
|
||||
id = [wire.HashSize]byte{
|
||||
0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
|
||||
0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
|
||||
0x2d, 0xe7, 0x93, 0xe4, 0xb7, 0x25, 0xb8, 0x4d,
|
||||
0x1f, 0xb, 0x4c, 0xf9, 0x9e, 0xc5, 0x8c, 0xe9,
|
||||
}
|
||||
testTx = &wire.MsgTx{
|
||||
Version: 1,
|
||||
TxIn: []*wire.TxIn{
|
||||
&wire.TxIn{
|
||||
PreviousOutPoint: wire.OutPoint{
|
||||
Hash: wire.ShaHash{},
|
||||
Index: 0xffffffff,
|
||||
},
|
||||
SignatureScript: []byte{0x04, 0x31, 0xdc, 0x00, 0x1b, 0x01, 0x62},
|
||||
Sequence: 0xffffffff,
|
||||
},
|
||||
},
|
||||
TxOut: []*wire.TxOut{
|
||||
&wire.TxOut{
|
||||
Value: 5000000000,
|
||||
PkScript: []byte{
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
|
||||
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
|
||||
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
|
||||
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
|
||||
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
|
||||
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
||||
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
|
||||
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
|
||||
0xa6, // 65-byte signature
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
},
|
||||
LockTime: 5,
|
||||
}
|
||||
)
|
||||
|
||||
// createDbNamespace creates a new wallet database at the provided path and
|
||||
// returns it along with the address manager namespace.
|
||||
func createDbNamespace(dbPath string) (walletdb.DB, walletdb.Namespace, error) {
|
||||
db, err := walletdb.Create("bdb", dbPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
namespace, err := db.Namespace(waddrmgrNamespaceKey)
|
||||
if err != nil {
|
||||
db.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return db, namespace, nil
|
||||
}
|
||||
|
||||
// setupManager creates a new address manager and returns a teardown function
|
||||
// that should be invoked to ensure it is closed and removed upon completion.
|
||||
func createTestManager(t *testing.T) (tearDownFunc func(), mgr *waddrmgr.Manager) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a new manager in a temp directory.
|
||||
dirName, err := ioutil.TempDir("", "mgrtest")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create db temp dir: %v", err)
|
||||
}
|
||||
dbPath := filepath.Join(dirName, "mgrtest.db")
|
||||
db, namespace, err := createDbNamespace(dbPath)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(dirName)
|
||||
t.Fatalf("createDbNamespace: unexpected error: %v", err)
|
||||
}
|
||||
mgr, err = waddrmgr.Create(namespace, key[:], []byte("test"),
|
||||
[]byte("test"), ActiveNetParams, nil)
|
||||
if err != nil {
|
||||
db.Close()
|
||||
_ = os.RemoveAll(dirName)
|
||||
t.Fatalf("Failed to create Manager: %v", err)
|
||||
}
|
||||
tearDownFunc = func() {
|
||||
mgr.Close()
|
||||
db.Close()
|
||||
_ = os.RemoveAll(dirName)
|
||||
}
|
||||
if err := mgr.Unlock([]byte("test")); err != nil {
|
||||
t.Fatalf("unable to unlock mgr: %v", err)
|
||||
}
|
||||
return tearDownFunc, mgr
|
||||
}
|
||||
|
||||
func TestOpenChannelStateEncodeDecode(t *testing.T) {
|
||||
teardown, manager := createTestManager(t)
|
||||
defer teardown()
|
||||
|
||||
privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), testWalletPrivKey)
|
||||
addr, err := btcutil.NewAddressPubKey(pubKey.SerializeCompressed(), ActiveNetParams)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create delivery address")
|
||||
}
|
||||
|
||||
script, err := txscript.MultiSigScript([]*btcutil.AddressPubKey{addr, addr}, 2)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create redeemScript")
|
||||
}
|
||||
|
||||
state := OpenChannelState{
|
||||
TheirLNID: id,
|
||||
ChanID: id,
|
||||
MinFeePerKb: btcutil.Amount(5000),
|
||||
OurCommitKey: privKey,
|
||||
TheirCommitKey: pubKey,
|
||||
Capacity: btcutil.Amount(10000),
|
||||
OurBalance: btcutil.Amount(3000),
|
||||
TheirBalance: btcutil.Amount(7000),
|
||||
TheirCommitTx: testTx,
|
||||
OurCommitTx: testTx,
|
||||
TheirCommitSig: sig,
|
||||
FundingTx: testTx,
|
||||
MultiSigKey: privKey,
|
||||
FundingRedeemScript: script,
|
||||
TheirCurrentRevocation: id,
|
||||
OurDeliveryAddress: addr,
|
||||
TheirDeliveryAddress: addr,
|
||||
CsvDelay: 5,
|
||||
NumUpdates: 1,
|
||||
TotalSatoshisSent: 1,
|
||||
TotalSatoshisReceived: 2,
|
||||
CreationTime: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
if err := state.Encode(&b, manager); err != nil {
|
||||
t.Fatalf("unable to encode channel state: %v", err)
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(b.Bytes())
|
||||
newState := &OpenChannelState{}
|
||||
if err := newState.Decode(reader, manager); err != nil {
|
||||
t.Fatalf("unable to decode channel state: %v", err)
|
||||
}
|
||||
|
||||
// The decoded channel state should be identical to what we stored
|
||||
// above.
|
||||
if !bytes.Equal(state.TheirLNID[:], newState.TheirLNID[:]) {
|
||||
t.Fatalf("their id doesn't match")
|
||||
}
|
||||
if !bytes.Equal(state.ChanID[:], newState.ChanID[:]) {
|
||||
t.Fatalf("chan id's don't match")
|
||||
}
|
||||
if state.MinFeePerKb != newState.MinFeePerKb {
|
||||
t.Fatalf("fee/kb doens't match")
|
||||
}
|
||||
|
||||
if !bytes.Equal(state.OurCommitKey.Serialize(),
|
||||
newState.OurCommitKey.Serialize()) {
|
||||
t.Fatalf("our commit key dont't match")
|
||||
}
|
||||
if !bytes.Equal(state.TheirCommitKey.SerializeCompressed(),
|
||||
newState.TheirCommitKey.SerializeCompressed()) {
|
||||
t.Fatalf("their commit key dont't match")
|
||||
}
|
||||
|
||||
if state.Capacity != newState.Capacity {
|
||||
t.Fatalf("capacity doesn't match")
|
||||
}
|
||||
if state.OurBalance != newState.OurBalance {
|
||||
t.Fatalf("our balance doesn't match")
|
||||
}
|
||||
if state.TheirBalance != newState.TheirBalance {
|
||||
t.Fatalf("their balance doesn't match")
|
||||
}
|
||||
|
||||
var b1, b2 bytes.Buffer
|
||||
if err := state.TheirCommitTx.Serialize(&b1); err != nil {
|
||||
t.Fatalf("unable to serialize transaction")
|
||||
}
|
||||
if err := newState.TheirCommitTx.Serialize(&b2); err != nil {
|
||||
t.Fatalf("unable to serialize transaction")
|
||||
}
|
||||
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
|
||||
t.Fatalf("theirCommitTx doesn't match")
|
||||
}
|
||||
|
||||
b1.Reset()
|
||||
b2.Reset()
|
||||
|
||||
if err := state.OurCommitTx.Serialize(&b1); err != nil {
|
||||
t.Fatalf("unable to serialize transaction")
|
||||
}
|
||||
if err := newState.OurCommitTx.Serialize(&b2); err != nil {
|
||||
t.Fatalf("unable to serialize transaction")
|
||||
}
|
||||
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
|
||||
t.Fatalf("ourCommitTx doesn't match")
|
||||
}
|
||||
|
||||
if !bytes.Equal(state.TheirCommitSig, newState.TheirCommitSig) {
|
||||
t.Fatalf("theirCommitSig doesn't match")
|
||||
}
|
||||
|
||||
b1.Reset()
|
||||
b2.Reset()
|
||||
|
||||
if err := state.FundingTx.Serialize(&b1); err != nil {
|
||||
t.Fatalf("unable to serialize transaction")
|
||||
}
|
||||
if err := newState.FundingTx.Serialize(&b2); err != nil {
|
||||
t.Fatalf("unable to serialize transaction")
|
||||
}
|
||||
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
|
||||
t.Fatalf("funding tx doesn't match")
|
||||
}
|
||||
|
||||
if !bytes.Equal(state.MultiSigKey.Serialize(),
|
||||
newState.MultiSigKey.Serialize()) {
|
||||
t.Fatalf("multisig key doesn't match")
|
||||
}
|
||||
if !bytes.Equal(state.FundingRedeemScript, newState.FundingRedeemScript) {
|
||||
t.Fatalf("redeem script doesn't match")
|
||||
}
|
||||
|
||||
if state.OurDeliveryAddress.EncodeAddress() != newState.OurDeliveryAddress.EncodeAddress() {
|
||||
t.Fatalf("our delivery address doesn't match")
|
||||
}
|
||||
if state.TheirDeliveryAddress.EncodeAddress() != newState.TheirDeliveryAddress.EncodeAddress() {
|
||||
t.Fatalf("their delivery address doesn't match")
|
||||
}
|
||||
|
||||
if state.NumUpdates != newState.NumUpdates {
|
||||
t.Fatalf("num updates doesn't match: %v vs %v",
|
||||
state.NumUpdates, newState.NumUpdates)
|
||||
}
|
||||
if state.CsvDelay != newState.CsvDelay {
|
||||
t.Fatalf("csv delay doesn't match: %v vs %v",
|
||||
state.CsvDelay, newState.CsvDelay)
|
||||
}
|
||||
if state.TotalSatoshisSent != newState.TotalSatoshisSent {
|
||||
t.Fatalf("satoshis sent doesn't match: %v vs %v",
|
||||
state.TotalSatoshisSent, newState.TotalSatoshisSent)
|
||||
}
|
||||
if state.TotalSatoshisReceived != newState.TotalSatoshisReceived {
|
||||
t.Fatalf("satoshis received doesn't match")
|
||||
}
|
||||
|
||||
if state.CreationTime.Unix() != newState.CreationTime.Unix() {
|
||||
t.Fatalf("creation time doesn't match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenChannelStateEncodeDecodeCorruption(t *testing.T) {
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package lnwallet
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"li.lan/labs/plasma/channeldb"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
@@ -64,7 +66,7 @@ type ChannelReservation struct {
|
||||
ourContribution *ChannelContribution
|
||||
theirContribution *ChannelContribution
|
||||
|
||||
partialState *OpenChannelState
|
||||
partialState *channeldb.OpenChannel
|
||||
|
||||
// The ID of this reservation, used to uniquely track the reservation
|
||||
// throughout its lifetime.
|
||||
@@ -90,7 +92,7 @@ func newChannelReservation(t FundingType, fundingAmt btcutil.Amount,
|
||||
theirContribution: &ChannelContribution{
|
||||
FundingAmount: fundingAmt,
|
||||
},
|
||||
partialState: &OpenChannelState{
|
||||
partialState: &channeldb.OpenChannel{
|
||||
// TODO(roasbeef): assumes balanced symmetric channels.
|
||||
Capacity: fundingAmt * 2,
|
||||
OurBalance: fundingAmt,
|
||||
|
||||
+11
-2
@@ -1,6 +1,7 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -9,6 +10,7 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"li.lan/labs/plasma/channeldb"
|
||||
"li.lan/labs/plasma/shachain"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
@@ -34,7 +36,14 @@ var (
|
||||
"create funding transaction")
|
||||
|
||||
// Which bitcoin network are we using?
|
||||
// TODO(roasbeef): config
|
||||
ActiveNetParams = &chaincfg.TestNet3Params
|
||||
// Namespace bucket keys.
|
||||
lightningNamespaceKey = []byte("ln-wallet")
|
||||
waddrmgrNamespaceKey = []byte("waddrmgr")
|
||||
wtxmgrNamespaceKey = []byte("wtxmgr")
|
||||
|
||||
endian = binary.BigEndian
|
||||
)
|
||||
|
||||
type FundingType uint16
|
||||
@@ -137,7 +146,7 @@ type LightningWallet struct {
|
||||
|
||||
// A wrapper around a namespace within boltdb reserved for ln-based
|
||||
// wallet meta-data.
|
||||
channelDB *ChannelDB
|
||||
channelDB *channeldb.DB
|
||||
|
||||
wallet *btcwallet.Wallet
|
||||
rpc *chain.Client
|
||||
@@ -210,7 +219,7 @@ func NewLightningWallet(privWalletPass, pubWalletPass, hdSeed []byte, dataDir st
|
||||
return &LightningWallet{
|
||||
DB: db,
|
||||
wallet: wallet,
|
||||
channelDB: NewChannelDB(wallet.Manager, lnNamespace),
|
||||
channelDB: channeldb.New(wallet.Manager, lnNamespace),
|
||||
msgChan: make(chan interface{}, msgBufferSize),
|
||||
// TODO(roasbeef): make this atomic.Uint32 instead? Which is
|
||||
// faster, locks or CAS? I'm guessing CAS because assembly:
|
||||
|
||||
@@ -591,10 +591,7 @@ func clearWalletState(w *LightningWallet) error {
|
||||
w.nextFundingID = 0
|
||||
w.fundingLimbo = make(map[uint64]*ChannelReservation)
|
||||
w.wallet.ResetLockedOutpoints()
|
||||
return w.channelDB.namespace.Update(func(tx walletdb.Tx) error {
|
||||
rootBucket := tx.RootBucket()
|
||||
return rootBucket.DeleteBucket(openChannelBucket)
|
||||
})
|
||||
return w.channelDB.Wipe()
|
||||
}
|
||||
|
||||
// TODO(roasbeef): why is wallet so slow to create+open?
|
||||
|
||||
Reference in new issue
Block a user