This commit is contained in:
Oliver Gugger 2021-04-26 15:39:32 +02:00
parent 7af677a467
commit f460060692
No known key found for this signature in database
GPG key ID: 8E4256593F177720
34 changed files with 1841 additions and 336 deletions

2
.gitignore vendored
View file

@ -2,3 +2,5 @@
/poold
cmd/pool/pool
cmd/poold/poold
pool.wasm

View file

@ -90,6 +90,9 @@ release:
$(VERSION_CHECK)
./scripts/release.sh build-release "$(VERSION_TAG)" "$(BUILD_SYSTEM)" "" "$(RELEASE_LDFLAGS)"
build-wasm:
GOOS=js GOARCH=wasm go build -trimpath -ldflags="$(LDFLAGS)" -tags=appengine -v -o pool.wasm $(PKG)/cmd/poold
scratch: build
# =======

View file

@ -6,8 +6,8 @@ import (
"io"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/account"
"go.etcd.io/bbolt"
)
var (
@ -28,8 +28,8 @@ func getAccountKey(account *account.Account) []byte {
// AddAccount adds a record for the account to the database.
func (db *DB) AddAccount(account *account.Account) error {
return db.Update(func(tx *bbolt.Tx) error {
accounts, err := getBucket(tx, accountBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
accounts, err := getWriteBucket(tx, accountBucketKey)
if err != nil {
return err
}
@ -43,8 +43,8 @@ func (db *DB) AddAccount(account *account.Account) error {
func (db *DB) UpdateAccount(acct *account.Account,
modifiers ...account.Modifier) error {
err := db.Update(func(tx *bbolt.Tx) error {
accounts, err := getBucket(tx, accountBucketKey)
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
accounts, err := getWriteBucket(tx, accountBucketKey)
if err != nil {
return err
}
@ -65,7 +65,7 @@ func (db *DB) UpdateAccount(acct *account.Account,
// updateAccount reads an account from the src bucket, applies the given
// modifiers to it, and store it back into dst bucket.
func updateAccount(src, dst *bbolt.Bucket, accountKey []byte,
func updateAccount(src, dst walletdb.ReadWriteBucket, accountKey []byte,
modifiers []account.Modifier) (*account.Account, error) {
dbAccount, err := readAccount(src, accountKey)
@ -84,8 +84,8 @@ func updateAccount(src, dst *bbolt.Bucket, accountKey []byte,
// ErrAccountNotFound if it's not found.
func (db *DB) Account(traderKey *btcec.PublicKey) (*account.Account, error) {
var acct *account.Account
err := db.View(func(tx *bbolt.Tx) error {
accounts, err := getBucket(tx, accountBucketKey)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
accounts, err := getReadBucket(tx, accountBucketKey)
if err != nil {
return err
}
@ -105,8 +105,8 @@ func (db *DB) Account(traderKey *btcec.PublicKey) (*account.Account, error) {
// Accounts retrieves all known accounts from the database.
func (db *DB) Accounts() ([]*account.Account, error) {
var res []*account.Account
err := db.View(func(tx *bbolt.Tx) error {
accounts, err := getBucket(tx, accountBucketKey)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
accounts, err := getReadBucket(tx, accountBucketKey)
if err != nil {
return err
}
@ -133,7 +133,7 @@ func (db *DB) Accounts() ([]*account.Account, error) {
return res, nil
}
func storeAccount(targetBucket *bbolt.Bucket, a *account.Account) error {
func storeAccount(targetBucket walletdb.ReadWriteBucket, a *account.Account) error {
accountKey := getAccountKey(a)
var accountBuf bytes.Buffer
@ -144,7 +144,7 @@ func storeAccount(targetBucket *bbolt.Bucket, a *account.Account) error {
return targetBucket.Put(accountKey, accountBuf.Bytes())
}
func readAccount(sourceBucket *bbolt.Bucket,
func readAccount(sourceBucket walletdb.ReadBucket,
accountKey []byte) (*account.Account, error) {
accountBytes := sourceBucket.Get(accountKey)

View file

@ -3,9 +3,9 @@ package clientdb
import (
"fmt"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/account"
"github.com/lightninglabs/pool/order"
"go.etcd.io/bbolt"
)
var (
@ -48,28 +48,28 @@ func (db *DB) StorePendingBatch(batch *order.Batch, orders []order.Nonce,
}
// Wrap the whole batch update in a single update transaction.
return db.Update(func(tx *bbolt.Tx) error {
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
// Before updating the set of orders and accounts, we'll first
// delete the buckets containing any existing staged updates.
// This is to done to handle the case where the first version of
// a batch updated an order/account, but its second version
// didn't. Without this, our state would become desynchronized
// with the auction.
bucket, err := getBucket(tx, batchBucketKey)
bucket, err := getWriteBucket(tx, batchBucketKey)
if err != nil {
return err
}
err = bucket.DeleteBucket(pendingBatchAccountsBucketKey)
if err != nil && err != bbolt.ErrBucketNotFound {
err = bucket.DeleteNestedBucket(pendingBatchAccountsBucketKey)
if err != nil && err != walletdb.ErrBucketNotFound {
return err
}
err = bucket.DeleteBucket(pendingBatchOrdersBucketKey)
if err != nil && err != bbolt.ErrBucketNotFound {
err = bucket.DeleteNestedBucket(pendingBatchOrdersBucketKey)
if err != nil && err != walletdb.ErrBucketNotFound {
return err
}
// Update orders first.
ordersBucket, err := getBucket(tx, ordersBucketKey)
ordersBucket, err := getWriteBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -94,7 +94,7 @@ func (db *DB) StorePendingBatch(batch *order.Batch, orders []order.Nonce,
}
// Then update the accounts.
accountsBucket, err := getBucket(tx, accountBucketKey)
accountsBucket, err := getWriteBucket(tx, accountBucketKey)
if err != nil {
return err
}
@ -142,7 +142,7 @@ func (db *DB) StorePendingBatch(batch *order.Batch, orders []order.Nonce,
// If there isn't one, account.ErrNoPendingBatch is returned.
func (db *DB) PendingBatchSnapshot() (*LocalBatchSnapshot, error) {
var batchSnapshot *LocalBatchSnapshot
err := db.View(func(tx *bbolt.Tx) error {
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
var err error
batchSnapshot, err = fetchPendingBatchSnapshot(tx)
return err
@ -152,8 +152,8 @@ func (db *DB) PendingBatchSnapshot() (*LocalBatchSnapshot, error) {
// pendingBatchID retrieves the stored pending batch ID within a database
// transaction.
func pendingBatchID(tx *bbolt.Tx) (order.BatchID, error) {
bucket, err := getBucket(tx, batchBucketKey)
func pendingBatchID(tx walletdb.ReadTx) (order.BatchID, error) {
bucket, err := getReadBucket(tx, batchBucketKey)
if err != nil {
return zeroBatchID, err
}
@ -172,8 +172,8 @@ func pendingBatchID(tx *bbolt.Tx) (order.BatchID, error) {
// without applying its staged updates to accounts and orders. If no pending
// batch exists, this acts as a no-op.
func (db *DB) DeletePendingBatch() error {
return db.Update(func(tx *bbolt.Tx) error {
bucket, err := getBucket(tx, batchBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
bucket, err := getWriteBucket(tx, batchBucketKey)
if err != nil {
return err
}
@ -181,12 +181,12 @@ func (db *DB) DeletePendingBatch() error {
if err := bucket.Delete(pendingBatchIDKey); err != nil {
return err
}
err = bucket.DeleteBucket(pendingBatchAccountsBucketKey)
if err != nil && err != bbolt.ErrBucketNotFound {
err = bucket.DeleteNestedBucket(pendingBatchAccountsBucketKey)
if err != nil && err != walletdb.ErrBucketNotFound {
return err
}
err = bucket.DeleteBucket(pendingBatchOrdersBucketKey)
if err != nil && err != bbolt.ErrBucketNotFound {
err = bucket.DeleteNestedBucket(pendingBatchOrdersBucketKey)
if err != nil && err != walletdb.ErrBucketNotFound {
return err
}
@ -200,7 +200,7 @@ func (db *DB) DeletePendingBatch() error {
// modifications necessary, and allowing a trader to participate in a new batch.
// If a pending batch is not found, account.ErrNoPendingBatch is returned.
func (db *DB) MarkBatchComplete() error {
return db.Update(func(tx *bbolt.Tx) error {
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
pendingID, err := pendingBatchID(tx)
if err != nil {
return err
@ -215,8 +215,8 @@ func (db *DB) MarkBatchComplete() error {
// applyBatchUpdates applies the staged updates for any accounts and orders that
// participated in the latest pending batch.
func applyBatchUpdates(tx *bbolt.Tx) error {
bucket, err := getBucket(tx, batchBucketKey)
func applyBatchUpdates(tx walletdb.ReadWriteTx) error {
bucket, err := getWriteBucket(tx, batchBucketKey)
if err != nil {
return err
}
@ -230,7 +230,7 @@ func applyBatchUpdates(tx *bbolt.Tx) error {
if err != nil {
return err
}
accounts, err := getBucket(tx, accountBucketKey)
accounts, err := getWriteBucket(tx, accountBucketKey)
if err != nil {
return err
}
@ -248,7 +248,7 @@ func applyBatchUpdates(tx *bbolt.Tx) error {
// Once we've updated all of the accounts, we can remove the pending
// updates as they've been committed.
if err := bucket.DeleteBucket(pendingBatchAccountsBucketKey); err != nil {
if err := bucket.DeleteNestedBucket(pendingBatchAccountsBucketKey); err != nil {
return err
}
@ -259,7 +259,7 @@ func applyBatchUpdates(tx *bbolt.Tx) error {
if err != nil {
return err
}
orders, err := getBucket(tx, ordersBucketKey)
orders, err := getWriteBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -278,7 +278,7 @@ func applyBatchUpdates(tx *bbolt.Tx) error {
// Once again, remove the pending order updates as they've been
// committed.
if err := bucket.DeleteBucket(pendingBatchOrdersBucketKey); err != nil {
if err := bucket.DeleteNestedBucket(pendingBatchOrdersBucketKey); err != nil {
return err
}

View file

@ -7,11 +7,11 @@ import (
"io"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/account"
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/terms"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"go.etcd.io/bbolt"
)
// batch-snapshot-bucket
@ -137,7 +137,7 @@ func NewSnapshot(batch *order.Batch, ourOrders []order.Order,
// participated in.
func (db *DB) GetLocalBatchSnapshots() ([]*LocalBatchSnapshot, error) {
var snapshots []*LocalBatchSnapshot
err := db.View(func(tx *bbolt.Tx) error {
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
var err error
snapshots, err = db.fetchLocalBatchSnapshots(tx)
return err
@ -154,8 +154,8 @@ func (db *DB) GetLocalBatchSnapshot(id order.BatchID) (
*LocalBatchSnapshot, error) {
var snapshot *LocalBatchSnapshot
err := db.View(func(tx *bbolt.Tx) error {
_, seqBucket, indexBucket, err := getSnapshotBuckets(tx)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
_, seqBucket, indexBucket, err := getSnapshotReadBuckets(tx)
if err != nil {
return err
}
@ -165,7 +165,7 @@ func (db *DB) GetLocalBatchSnapshot(id order.BatchID) (
return fmt.Errorf("snapshot of batch %x not found",
id[:])
}
rootOrderBucket, err := getBucket(tx, ordersBucketKey)
rootOrderBucket, err := getReadBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -182,14 +182,14 @@ func (db *DB) GetLocalBatchSnapshot(id order.BatchID) (
return snapshot, nil
}
func (db *DB) fetchLocalBatchSnapshots(tx *bbolt.Tx) ([]*LocalBatchSnapshot,
error) {
func (db *DB) fetchLocalBatchSnapshots(
tx walletdb.ReadTx) ([]*LocalBatchSnapshot, error) {
_, seqBucket, _, err := getSnapshotBuckets(tx)
_, seqBucket, _, err := getSnapshotReadBuckets(tx)
if err != nil {
return nil, err
}
rootOrderBucket, err := getBucket(tx, ordersBucketKey)
rootOrderBucket, err := getReadBucket(tx, ordersBucketKey)
if err != nil {
return nil, err
}
@ -216,10 +216,10 @@ func (db *DB) fetchLocalBatchSnapshots(tx *bbolt.Tx) ([]*LocalBatchSnapshot,
return snapshots, nil
}
func fetchLocalBatchSnapshot(seqBucket *bbolt.Bucket, seqNum []byte,
rootOrderBucket *bbolt.Bucket) (*LocalBatchSnapshot, error) {
func fetchLocalBatchSnapshot(seqBucket walletdb.ReadBucket, seqNum []byte,
rootOrderBucket walletdb.ReadBucket) (*LocalBatchSnapshot, error) {
snapshotBucket, err := getNestedBucket(seqBucket, seqNum, false)
snapshotBucket, err := getNestedReadBucket(seqBucket, seqNum)
if err != nil {
return nil, err
}
@ -241,8 +241,8 @@ func fetchLocalBatchSnapshot(seqBucket *bbolt.Bucket, seqNum []byte,
// The snapshot doesn't contain all the order information needed, so
// we'll retrieve the missing data.
for nonce, o := range batchSnapshot.Orders {
orderBucket, err := getNestedBucket(
rootOrderBucket, nonce[:], false,
orderBucket, err := getNestedReadBucket(
rootOrderBucket, nonce[:],
)
if err != nil {
return nil, ErrNoOrder
@ -299,10 +299,10 @@ func fetchLocalBatchSnapshot(seqBucket *bbolt.Bucket, seqNum []byte,
return batchSnapshot, nil
}
func storePendingBatchSnapshot(tx *bbolt.Tx,
func storePendingBatchSnapshot(tx walletdb.ReadWriteTx,
snapshot *LocalBatchSnapshot) error {
topBucket, err := getBucket(tx, batchSnapshotBucketKey)
topBucket, err := getWriteBucket(tx, batchSnapshotBucketKey)
if err != nil {
return err
}
@ -319,8 +319,8 @@ func storePendingBatchSnapshot(tx *bbolt.Tx,
// fetchPendingBatchSnapshot retrieves the currently pending batch snapshot from
// the database or returns the account.ErrNoPendingBatch error if none exists.
func fetchPendingBatchSnapshot(tx *bbolt.Tx) (*LocalBatchSnapshot, error) {
topBucket, err := getBucket(tx, batchSnapshotBucketKey)
func fetchPendingBatchSnapshot(tx walletdb.ReadTx) (*LocalBatchSnapshot, error) {
topBucket, err := getReadBucket(tx, batchSnapshotBucketKey)
if err != nil {
return nil, err
}
@ -335,8 +335,8 @@ func fetchPendingBatchSnapshot(tx *bbolt.Tx) (*LocalBatchSnapshot, error) {
// finalizeBatchSnapshot moves the pending batch snapshot into the sub-bucket
// indexed by sequence numbers.
func finalizeBatchSnapshot(tx *bbolt.Tx, batchID order.BatchID) error {
topBucket, seqBucket, indexBucket, err := getSnapshotBuckets(tx)
func finalizeBatchSnapshot(tx walletdb.ReadWriteTx, batchID order.BatchID) error {
topBucket, seqBucket, indexBucket, err := getSnapshotWriteBuckets(tx)
if err != nil {
return err
}
@ -379,10 +379,37 @@ func finalizeBatchSnapshot(tx *bbolt.Tx, batchID order.BatchID) error {
return nil
}
func getSnapshotBuckets(tx *bbolt.Tx) (*bbolt.Bucket, *bbolt.Bucket,
*bbolt.Bucket, error) {
func getSnapshotReadBuckets(tx walletdb.ReadTx) (walletdb.ReadBucket,
walletdb.ReadBucket, walletdb.ReadBucket, error) {
topBucket, err := getBucket(tx, batchSnapshotBucketKey)
topBucket, err := getReadBucket(tx, batchSnapshotBucketKey)
if err != nil {
return nil, nil, nil, err
}
// Get the sub-buckets. We expect them to be created at DB init, so we
// don't attempt to create them if non-existent.
seqBucket, err := getNestedReadBucket(
topBucket, batchSnapshotSeqBucketKey,
)
if err != nil {
return nil, nil, nil, err
}
indexBucket, err := getNestedReadBucket(
topBucket, batchSnapshotBatchIDIndexBucketKey,
)
if err != nil {
return nil, nil, nil, err
}
return topBucket, seqBucket, indexBucket, nil
}
func getSnapshotWriteBuckets(tx walletdb.ReadWriteTx) (walletdb.ReadWriteBucket,
walletdb.ReadWriteBucket, walletdb.ReadWriteBucket, error) {
topBucket, err := getWriteBucket(tx, batchSnapshotBucketKey)
if err != nil {
return nil, nil, nil, err
}
@ -695,8 +722,8 @@ func deserializeMatchedOrder(r io.Reader) (order.Nonce,
}
// deletePendingSnapshot deletes the pending batch snapshot.
func deletePendingSnapshot(tx *bbolt.Tx) error {
topBucket, err := getBucket(tx, batchSnapshotBucketKey)
func deletePendingSnapshot(tx walletdb.ReadWriteTx) error {
topBucket, err := getWriteBucket(tx, batchSnapshotBucketKey)
if err != nil {
return err
}

View file

@ -8,12 +8,12 @@ import (
"testing"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/davecgh/go-spew/spew"
"github.com/lightninglabs/pool/account"
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/terms"
"github.com/stretchr/testify/require"
"go.etcd.io/bbolt"
)
var (
@ -207,7 +207,7 @@ func TestGetLocalBatchSnapshots(t *testing.T) {
// Store the same batch 10 times, only changing the batch ID each time.
for i := 0; i < 10; i++ {
i := i
err := store.Update(func(tx *bbolt.Tx) error {
err := walletdb.Update(store, func(tx walletdb.ReadWriteTx) error {
testSnapshot.BatchID[0] = byte(i)
err := storePendingBatchSnapshot(tx, testSnapshot)
if err != nil {
@ -235,14 +235,14 @@ func TestGetLocalBatchSnapshots(t *testing.T) {
// Store and delete a pending snapshot, and make sure all other batches are
// still there.
testSnapshot.BatchID[0] = byte(99)
err = store.Update(func(tx *bbolt.Tx) error {
err = walletdb.Update(store, func(tx walletdb.ReadWriteTx) error {
return storePendingBatchSnapshot(tx, testSnapshot)
})
if err != nil {
t.Fatal(err)
}
err = store.Update(deletePendingSnapshot)
err = walletdb.Update(store, deletePendingSnapshot)
if err != nil {
t.Fatal(err)
}

View file

@ -8,11 +8,11 @@ import (
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/account"
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/terms"
"github.com/lightningnetwork/lnd/keychain"
"go.etcd.io/bbolt"
)
var (
@ -396,18 +396,18 @@ func TestDeletePendingBatch(t *testing.T) {
assertPendingBatch := func(exists bool) {
t.Helper()
err := db.View(func(tx *bbolt.Tx) error {
root := tx.Bucket(batchBucketKey)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
root := tx.ReadBucket(batchBucketKey)
if (root.Get(pendingBatchIDKey) != nil) != exists {
return fmt.Errorf("found unexpected key %v",
string(pendingBatchIDKey))
}
if (root.Bucket(pendingBatchAccountsBucketKey) != nil) != exists {
if (root.NestedReadBucket(pendingBatchAccountsBucketKey) != nil) != exists {
return fmt.Errorf("found unexpected bucket %v",
string(pendingBatchAccountsBucketKey))
}
if (root.Bucket(pendingBatchOrdersBucketKey) != nil) != exists {
if (root.NestedReadBucket(pendingBatchOrdersBucketKey) != nil) != exists {
return fmt.Errorf("found unexpected bucket %v",
string(pendingBatchOrdersBucketKey))
}

View file

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/account"
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/terms"
@ -17,7 +18,6 @@ import (
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire"
"go.etcd.io/bbolt"
)
var (
@ -272,8 +272,8 @@ func ReadElement(r io.Reader, element interface{}) error { // nolint:gocyclo
// getAdditionalDataBucket returns the bucket for additional data of a database
// object located at mainKey.
func getAdditionalDataBucket(parentBucket *bbolt.Bucket,
mainKey []byte, createBucket bool) (*bbolt.Bucket, error) {
func getAdditionalDataBucket(parentBucket walletdb.ReadWriteBucket,
mainKey []byte, createBucket bool) (walletdb.ReadWriteBucket, error) {
keyLen := len(mainKey) + len(additionalDataSuffix)
additionalDataKey := make([]byte, keyLen)
@ -286,10 +286,21 @@ func getAdditionalDataBucket(parentBucket *bbolt.Bucket,
return parentBucket.CreateBucketIfNotExists(additionalDataKey)
}
return parentBucket.Bucket(additionalDataKey), nil
return parentBucket.NestedReadWriteBucket(additionalDataKey), nil
}
func writeAdditionalValue(targetBucket *bbolt.Bucket, valueKey []byte,
func getAdditionalDataReadBucket(parentBucket walletdb.ReadBucket,
mainKey []byte) (walletdb.ReadBucket, error) {
keyLen := len(mainKey) + len(additionalDataSuffix)
additionalDataKey := make([]byte, keyLen)
copy(additionalDataKey, mainKey)
copy(additionalDataKey[len(mainKey):], additionalDataSuffix)
return parentBucket.NestedReadBucket(additionalDataKey), nil
}
func writeAdditionalValue(targetBucket walletdb.ReadWriteBucket, valueKey []byte,
value interface{}) error {
var valueBuf bytes.Buffer
@ -300,7 +311,7 @@ func writeAdditionalValue(targetBucket *bbolt.Bucket, valueKey []byte,
return targetBucket.Put(valueKey, valueBuf.Bytes())
}
func readAdditionalValue(sourceBucket *bbolt.Bucket, valueKey []byte,
func readAdditionalValue(sourceBucket walletdb.ReadBucket, valueKey []byte,
valueTarget interface{}, defaultValue interface{}) error {
// First of all, check that the valueTarget is a pointer to the same

View file

@ -4,9 +4,9 @@ import (
"testing"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/account"
"github.com/stretchr/testify/require"
"go.etcd.io/bbolt"
)
var (
@ -48,9 +48,9 @@ func TestAdditionalData(t *testing.T) {
// Now try to read the additional value that does not exist yet. We
// should instead get back the default value.
myAdditionalValue := uint32(0)
require.NoError(t, db.DB.View(func(tx *bbolt.Tx) error {
subBucket, err := getAdditionalDataBucket(
tx.Bucket(accountBucketKey), accountKey, false,
require.NoError(t, walletdb.View(db, func(tx walletdb.ReadTx) error {
subBucket, err := getAdditionalDataReadBucket(
tx.ReadBucket(accountBucketKey), accountKey,
)
if err != nil {
return err
@ -63,9 +63,9 @@ func TestAdditionalData(t *testing.T) {
require.Equal(t, additionalDataTestDefaultValue, myAdditionalValue)
// Write the additional into the sub bucket of the account now.
require.NoError(t, db.DB.Update(func(tx *bbolt.Tx) error {
require.NoError(t, walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
subBucket, err := getAdditionalDataBucket(
tx.Bucket(accountBucketKey), accountKey, true,
tx.ReadWriteBucket(accountBucketKey), accountKey, true,
)
if err != nil {
return err
@ -78,9 +78,9 @@ func TestAdditionalData(t *testing.T) {
// Read the additional info again, now we shouldn't get the default
// value anymore.
require.NoError(t, db.DB.View(func(tx *bbolt.Tx) error {
subBucket, err := getAdditionalDataBucket(
tx.Bucket(accountBucketKey), accountKey, false,
require.NoError(t, walletdb.View(db, func(tx walletdb.ReadTx) error {
subBucket, err := getAdditionalDataReadBucket(
tx.ReadBucket(accountBucketKey), accountKey,
)
if err != nil {
return err
@ -96,9 +96,9 @@ func TestAdditionalData(t *testing.T) {
// accidentally when using the readAdditionalValue function.
// Read the additional info again, now we shouldn't get the default
// value anymore.
require.Error(t, db.DB.View(func(tx *bbolt.Tx) error {
subBucket, err := getAdditionalDataBucket(
tx.Bucket(accountBucketKey), accountKey, false,
require.Error(t, walletdb.View(db, func(tx walletdb.ReadTx) error {
subBucket, err := getAdditionalDataReadBucket(
tx.ReadBucket(accountBucketKey), accountKey,
)
if err != nil {
return err

View file

@ -2,22 +2,18 @@ package clientdb
import (
"encoding/binary"
"fmt"
"os"
"path/filepath"
"time"
"go.etcd.io/bbolt"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightningnetwork/lnd/lnrpc"
)
const (
// DBFilename is the default filename of the client database.
DBFilename = "pool.db"
// dbFilePermission is the default permission the client database file
// is created with.
dbFilePermission = 0600
// DefaultPoolDBTimeout is the default maximum time we wait for the
// Pool bbolt database to be opened. If the database is already opened
// by another process, the unique lock cannot be obtained. With the
@ -34,23 +30,22 @@ var (
// DB is a bolt-backed persistent store.
type DB struct {
*bbolt.DB
walletdb.DB
}
// New creates a new bolt database that can be found at the given directory.
func New(dir, fileName string) (*DB, error) {
firstInit := false
path := filepath.Join(dir, fileName)
// If the database file does not exist yet, create its directory.
if !fileExists(path) {
if err := os.MkdirAll(dir, 0700); err != nil {
return nil, err
}
firstInit = true
// Detect first init of database for JS.
dbExists, err := isExistingDB(dir, path)
if err != nil {
return nil, err
}
db, err := initDB(path, firstInit)
log.Debugf("Database %s exists: %v", path, dbExists)
db, err := initDB(path, !dbExists)
if err != nil {
return nil, err
}
@ -75,24 +70,26 @@ func fileExists(path string) bool {
}
// initDB initializes all of the required top-level buckets for the database.
func initDB(filepath string, firstInit bool) (*bbolt.DB, error) {
db, err := bbolt.Open(filepath, dbFilePermission, &bbolt.Options{
Timeout: DefaultPoolDBTimeout,
})
if err == bbolt.ErrTimeout {
return nil, fmt.Errorf("error while trying to open %s: timed "+
"out after %v when trying to obtain exclusive lock - "+
"make sure no other pool daemon process (standalone "+
"or embedded in lightning-terminal) is running",
filepath, DefaultPoolDBTimeout)
}
if err != nil {
return nil, err
func initDB(filepath string, firstInit bool) (walletdb.DB, error) {
var (
db walletdb.DB
err error
)
if !lnrpc.FileExists(filepath) {
db, err = walletdb.Create(dbDriver, filepath, false, time.Second)
if err != nil {
return nil, err
}
} else {
db, err = walletdb.Open(dbDriver, filepath, false, time.Second)
if err != nil {
return nil, err
}
}
err = db.Update(func(tx *bbolt.Tx) error {
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
if firstInit {
metadataBucket, err := tx.CreateBucketIfNotExists(
metadataBucket, err := tx.CreateTopLevelBucket(
metadataBucketKey,
)
if err != nil {
@ -107,27 +104,27 @@ func initDB(filepath string, firstInit bool) (*bbolt.DB, error) {
}
}
_, err = tx.CreateBucketIfNotExists(accountBucketKey)
_, err = tx.CreateTopLevelBucket(accountBucketKey)
if err != nil {
return err
}
_, err = tx.CreateBucketIfNotExists(ordersBucketKey)
_, err = tx.CreateTopLevelBucket(ordersBucketKey)
if err != nil {
return err
}
_, err = tx.CreateBucketIfNotExists(sidecarsBucketKey)
_, err = tx.CreateTopLevelBucket(sidecarsBucketKey)
if err != nil {
return err
}
_, err = tx.CreateBucketIfNotExists(batchBucketKey)
_, err = tx.CreateTopLevelBucket(batchBucketKey)
if err != nil {
return err
}
_, err = tx.CreateBucketIfNotExists(eventBucketKey)
_, err = tx.CreateTopLevelBucket(eventBucketKey)
if err != nil {
return err
}
snapshotBucket, err := tx.CreateBucketIfNotExists(
snapshotBucket, err := tx.CreateTopLevelBucket(
batchSnapshotBucketKey,
)
if err != nil {

20
clientdb/driver.go Normal file
View file

@ -0,0 +1,20 @@
// +build !wasm
package clientdb
const (
dbDriver = "bdb"
)
func isExistingDB(dir, path string) (bool, error) {
// If the database file does not exist yet, create its directory.
if !fileExists(path) {
if err := os.MkdirAll(dir, 0700); err != nil {
return false, err
}
return false, nil
}
return true, nil
}

512
clientdb/driver_js.go Normal file
View file

@ -0,0 +1,512 @@
package clientdb
import (
"encoding/base64"
"errors"
"fmt"
"io"
"strings"
"syscall/js"
"github.com/btcsuite/btcwallet/walletdb"
)
const (
dbDriver = "localStorage"
)
var (
errNotSupported = fmt.Errorf("not supported")
)
func init() {
// Register the driver.
driver := walletdb.Driver{
DbType: dbDriver,
Create: openDB,
Open: openDB,
}
if err := walletdb.RegisterDriver(driver); err != nil {
panic(fmt.Sprintf("Failed to regiser database driver '%s': %v",
dbDriver, err))
}
}
func isExistingDB(_, _ string) (bool, error) {
ok := DetectStorage()
if !ok {
return false, ErrLocalStorageNotSupported
}
_, err := getDBVersion(&transaction{path: string(metadataBucketKey)})
if err == ErrDBVersionNotFound {
return false, nil
} else if err != nil {
return false, err
}
return true, nil
}
// 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(...interface{}) (walletdb.DB, error) {
ok := DetectStorage()
if !ok {
return nil, ErrLocalStorageNotSupported
}
return &db{}, nil
}
type transaction struct {
path string
}
func (tx *transaction) subKey(key []byte) string {
return strings.Join([]string{tx.path, string(key)}, "/")
}
func (tx *transaction) ReadBucket(key []byte) walletdb.ReadBucket {
log.Debugf("ReadBucket(%s)", string(key))
return tx.ReadWriteBucket(key)
}
func (tx *transaction) ReadWriteBucket(key []byte) walletdb.ReadWriteBucket {
log.Debugf("ReadWriteBucket(%s)", string(key))
return &transaction{path: string(key)}
}
func (tx *transaction) CreateTopLevelBucket(
key []byte) (walletdb.ReadWriteBucket, error) {
return tx.ReadWriteBucket(key), nil
}
func (tx *transaction) DeleteTopLevelBucket([]byte) error {
return fmt.Errorf("not supported")
}
// Commit commits all changes that have been made through the root bucket and
// all of its sub-buckets to persistent storage.
//
// This function is part of the walletdb.ReadWriteTx interface implementation.
func (tx *transaction) Commit() error {
return nil
}
// Rollback undoes all changes that have been made to the root bucket and all of
// its sub-buckets.
//
// This function is part of the walletdb.ReadTx interface implementation.
func (tx *transaction) Rollback() error {
return nil
}
// OnCommit takes a function closure that will be executed when the transaction
// successfully gets committed.
//
// This function is part of the walletdb.ReadWriteTx interface implementation.
func (tx *transaction) OnCommit(f func()) {
f()
}
// NestedReadWriteBucket retrieves a nested bucket with the given key. Returns
// nil if the bucket does not exist.
//
// This function is part of the walletdb.ReadWriteBucket interface implementation.
func (tx *transaction) NestedReadWriteBucket(key []byte) walletdb.ReadWriteBucket {
log.Debugf("NestedReadWriteBucket(%s)", string(key))
return &transaction{path: tx.subKey(key)}
}
func (tx *transaction) NestedReadBucket(key []byte) walletdb.ReadBucket {
log.Debugf("NestedReadBucket(%s)", string(key))
return tx.NestedReadWriteBucket(key)
}
// CreateBucket creates and returns a new nested bucket with the given key.
// Returns ErrBucketExists if the bucket already exists, ErrBucketNameRequired
// if the key is empty, or ErrIncompatibleValue if the key value is otherwise
// invalid.
//
// This function is part of the walletdb.ReadWriteBucket interface implementation.
func (tx *transaction) CreateBucket(key []byte) (walletdb.ReadWriteBucket, error) {
log.Debugf("CreateBucket(%s)", string(key))
return tx.NestedReadWriteBucket(key), nil
}
// CreateBucketIfNotExists creates and returns a new nested bucket with the
// given key if it does not already exist. Returns ErrBucketNameRequired if the
// key is empty or ErrIncompatibleValue if the key value is otherwise invalid.
//
// This function is part of the walletdb.ReadWriteBucket interface implementation.
func (tx *transaction) CreateBucketIfNotExists(
key []byte) (walletdb.ReadWriteBucket, error) {
log.Debugf("CreateBucketIfNotExists(%s)", string(key))
return tx.NestedReadWriteBucket(key), nil
}
// DeleteNestedBucket removes a nested bucket with the given key. Returns
// ErrTxNotWritable if attempted against a read-only transaction and
// ErrBucketNotFound if the specified bucket does not exist.
//
// This function is part of the walletdb.ReadWriteBucket interface implementation.
func (tx *transaction) DeleteNestedBucket([]byte) error {
return errNotSupported
}
// ForEach invokes the passed function with every key/value pair in the bucket.
// This includes nested buckets, in which case the value is nil, but it does not
// include the key/value pairs within those nested buckets.
//
// NOTE: The values returned by this function are only valid during a
// transaction. Attempting to access them after a transaction has ended will
// likely result in an access violation.
//
// This function is part of the walletdb.ReadBucket interface implementation.
func (tx *transaction) ForEach(fn func(k, v []byte) error) error {
return ForEach(tx.path, func(key, valueBase64 string) error {
value, err := base64.StdEncoding.DecodeString(valueBase64)
if err != nil {
return err
}
return fn([]byte(key), value)
})
}
func (tx *transaction) ForEachBucket(fn func(k []byte) error) error {
return errNotSupported
}
// Put saves the specified key/value pair to the bucket. Keys that do not
// already exist are added and keys that already exist are overwritten. Returns
// ErrTxNotWritable if attempted against a read-only transaction.
//
// This function is part of the walletdb.ReadWriteBucket interface implementation.
func (tx *transaction) Put(key, value []byte) error {
fullKey := tx.subKey(key)
log.Debugf("Put(%s, %s)", fullKey, string(value))
return SetItem(fullKey, base64.StdEncoding.EncodeToString(value))
}
// Get returns the value for the given key. Returns nil if the key does
// not exist in this bucket (or nested buckets).
//
// NOTE: The value returned by this function is only valid during a
// transaction. Attempting to access it after a transaction has ended
// will likely result in an access violation.
//
// This function is part of the walletdb.ReadBucket interface implementation.
func (tx *transaction) Get(key []byte) []byte {
fullKey := tx.subKey(key)
log.Debugf("Get(%s)", fullKey)
valueBase64, err := GetItem(fullKey)
if err != nil {
return nil
}
value, err := base64.StdEncoding.DecodeString(valueBase64)
if err != nil {
return nil
}
return value
}
// Delete removes the specified key from the bucket. Deleting a key that does
// not exist does not return an error. Returns ErrTxNotWritable if attempted
// against a read-only transaction.
//
// This function is part of the walletdb.ReadWriteBucket interface implementation.
func (tx *transaction) Delete(key []byte) error {
fullKey := tx.subKey(key)
log.Debugf("Delete(%s)", fullKey)
return RemoveItem(fullKey)
}
func (tx *transaction) ReadCursor() walletdb.ReadCursor {
return nil
}
// ReadWriteCursor returns a new cursor, allowing for iteration over the bucket's
// key/value pairs and nested buckets in forward or backward order.
//
// This function is part of the walletdb.ReadWriteBucket interface implementation.
func (tx *transaction) ReadWriteCursor() walletdb.ReadWriteCursor {
return nil
}
// Tx returns the bucket's transaction.
//
// This function is part of the walletdb.ReadWriteBucket interface implementation.
func (tx *transaction) Tx() walletdb.ReadWriteTx {
return tx
}
// NextSequence returns an autoincrementing integer for the bucket.
func (tx *transaction) NextSequence() (uint64, error) {
return 0, errNotSupported
}
// SetSequence updates the sequence number for the bucket.
func (tx *transaction) SetSequence(uint64) error {
return errNotSupported
}
// Sequence returns the current integer for the bucket without incrementing it.
func (tx *transaction) Sequence() uint64 {
return 0
}
// db represents a collection of namespaces which are persisted and implements
// the walletdb.Db interface. All database access is performed through
// transactions which are obtained through the specific Namespace.
type db struct {
}
// Enforce db implements the walletdb.Db interface.
var _ walletdb.DB = (*db)(nil)
func (db *db) beginTx() (*transaction, error) {
return &transaction{}, nil
}
func (db *db) BeginReadTx() (walletdb.ReadTx, error) {
return db.beginTx()
}
func (db *db) BeginReadWriteTx() (walletdb.ReadWriteTx, error) {
return db.beginTx()
}
// Copy writes a copy of the database to the provided writer. This call will
// start a read-only transaction to perform all operations.
//
// This function is part of the walletdb.Db interface implementation.
func (db *db) Copy(io.Writer) error {
return errNotSupported
}
// Close cleanly shuts down the database and syncs all data.
//
// This function is part of the walletdb.Db interface implementation.
func (db *db) Close() error {
return nil
}
// Batch is similar to the package-level Update method, but it will attempt to
// optismitcally combine the invocation of several transaction functions into a
// single db write transaction.
//
// This function is part of the walletdb.Db interface implementation.
func (db *db) Batch(f func(tx walletdb.ReadWriteTx) error) error {
tx, err := db.BeginReadWriteTx()
if err != nil {
return err
}
return f(tx)
}
var localStorage js.Value
// ErrLocalStorageNotSupported is returned if localStorage is not supported.
var ErrLocalStorageNotSupported = errors.New("localStorage does not appear " +
"to be supported/enabled in this browser")
// ItemNotFoundError is returned if an item with the given key does not exist in
// localStorage.
type ItemNotFoundError struct {
msg string
}
// Error implements the error interface.
func (e ItemNotFoundError) Error() string {
return e.msg
}
func newItemNotFoundError(format string, args ...interface{}) ItemNotFoundError {
return ItemNotFoundError{
msg: fmt.Sprintf(format, args...),
}
}
// DetectStorage detects and (re)initializes the localStorage.
func DetectStorage() (ok bool) {
defer func() {
if r := recover(); r != nil {
log.Debugf("Recovered from panic in DetectStorage: %v",
r)
localStorage = js.Undefined()
ok = false
}
}()
localStorage = js.Global().Get("localStorage")
if localStorage.IsUndefined() {
log.Debugf("Value is undefined")
return false
}
// Cf. https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
// https://gist.github.com/paulirish/5558557
x := "__storage_test__"
localStorage.Set(x, x)
obj := localStorage.Get(x)
if obj.IsUndefined() {
log.Debugf("Storage test return value nil")
localStorage = js.Undefined()
return false
}
localStorage.Call("removeItem", x)
return true
}
// SetItem saves the given item in localStorage under the given key.
func SetItem(key, item string) (err error) {
if localStorage.IsUndefined() {
return ErrLocalStorageNotSupported
}
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("could not use local "+
"storage: %v", r)
}
}
}()
localStorage.Call("setItem", key, item)
return nil
}
// GetItem finds and returns the item identified by key. If there is no item in
// localStorage with the given key, GetItem will return an ItemNotFoundError.
func GetItem(key string) (s string, err error) {
if localStorage.IsUndefined() {
return "", ErrLocalStorageNotSupported
}
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("could not use local "+
"storage: %v", r)
}
s = ""
}
}()
item := localStorage.Call("getItem", key)
if item.IsUndefined() {
err = newItemNotFoundError(
"Could not find an item with the given key: %s", key)
} else {
s = item.String()
}
return s, err
}
// Key finds and returns the key associated with the given item. If the item is
// not in localStorage, Key will return an ItemNotFoundError.
func Key(item string) (s string, err error) {
if localStorage.IsUndefined() {
return "", ErrLocalStorageNotSupported
}
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("could not use local "+
"storage: %v", r)
}
s = ""
}
}()
key := localStorage.Call("key", item)
if key.IsUndefined() {
err = newItemNotFoundError(
"Could not find a key for the given item: %s", item)
} else {
s = key.String()
}
return s, err
}
// RemoveItem removes the item with the given key from localStorage.
func RemoveItem(key string) (err error) {
if localStorage.IsUndefined() {
return ErrLocalStorageNotSupported
}
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("could not use local "+
"storage: %v", r)
}
}
}()
localStorage.Call("removeItem", key)
return nil
}
// Length returns the number of items currently in localStorage.
func Length() (l int, err error) {
if localStorage.IsUndefined() {
return 0, ErrLocalStorageNotSupported
}
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("could not use local "+
"storage: %v", r)
}
l = 0
}
}()
length := localStorage.Get("length")
return length.Int(), nil
}
func ForEach(prefix string, f func(key, value string) error) error {
length, err := Length()
if err != nil {
return err
}
for i := 0; i < length; i++ {
strKey, err := Key(fmt.Sprintf("%d", i))
if err != nil {
return err
}
if !strings.HasPrefix(strKey, prefix) {
continue
}
value, err := GetItem(strKey)
if err != nil {
return err
}
err = f(strKey, value)
if err != nil {
return err
}
}
return nil
}

View file

@ -7,8 +7,8 @@ import (
"sort"
"time"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/event"
"go.etcd.io/bbolt"
)
var (
@ -64,7 +64,7 @@ func (db *DB) AllEvents(evtType event.Type) ([]event.Event, error) {
// events that match the given predicate.
func (db *DB) getEvents(predicate event.Predicate) ([]event.Event, error) {
var events []event.Event
err := db.View(func(tx *bbolt.Tx) error {
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
var err error
events, err = getEventsTX(tx, predicate)
return err
@ -78,11 +78,11 @@ func (db *DB) getEvents(predicate event.Predicate) ([]event.Event, error) {
// getEventsTX retrieves all events that match the given predicate from the main
// event bucket within the given database transaction.
func getEventsTX(tx *bbolt.Tx, predicate event.Predicate) ([]event.Event,
func getEventsTX(tx walletdb.ReadTx, predicate event.Predicate) ([]event.Event,
error) {
events := make([]event.Event, 0, eventsAllocSize)
eventBucket := tx.Bucket(eventBucketKey)
eventBucket := tx.ReadBucket(eventBucketKey)
err := eventBucket.ForEach(func(k, v []byte) error {
// There shouldn't be any other keys below the main
// event bucket so we fail hard if a key doesn't match
@ -133,7 +133,7 @@ func getEventsTX(tx *bbolt.Tx, predicate event.Predicate) ([]event.Event,
// storeEventTX stores a single event both in the main events bucket (ensuring
// the uniqueness of its timestamp in the process) and a reference to it in the
// "owner"'s bucket under an event reference sub bucket.
func storeEventTX(ownerBucket *bbolt.Bucket, evt event.Event) error {
func storeEventTX(ownerBucket walletdb.ReadWriteBucket, evt event.Event) error {
// For convenience, the event is allowed to be nil, in case no update
// really happened.
if evt == nil {
@ -141,7 +141,7 @@ func storeEventTX(ownerBucket *bbolt.Bucket, evt event.Event) error {
}
// First of all, write the event to the global event bucket.
evtBucket := ownerBucket.Tx().Bucket(eventBucketKey)
evtBucket := ownerBucket.Tx().ReadWriteBucket(eventBucketKey)
err := event.StoreEvent(evtBucket, evt)
if err != nil {
return err

View file

@ -5,10 +5,10 @@ import (
"testing"
"time"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/event"
"github.com/lightninglabs/pool/order"
"github.com/stretchr/testify/require"
"go.etcd.io/bbolt"
)
// TestOrderEvents tests that storing and updating orders creates the correct
@ -117,10 +117,10 @@ func assertOrderCreateEvent(t *testing.T, store *DB, o order.Nonce) {
func getOrderEventTimestamps(store *DB, o order.Nonce, evtType event.Type) (
map[time.Time]struct{}, error) {
orderEventTimestamps := make(map[time.Time]struct{})
err := store.DB.View(func(tx *bbolt.Tx) error {
ordersBucket := tx.Bucket(ordersBucketKey)
orderBucket := ordersBucket.Bucket(o[:])
eventBucket := orderBucket.Bucket(eventRefSubBucket)
err := walletdb.View(store, func(tx walletdb.ReadTx) error {
ordersBucket := tx.ReadBucket(ordersBucketKey)
orderBucket := ordersBucket.NestedReadBucket(o[:])
eventBucket := orderBucket.NestedReadBucket(eventRefSubBucket)
return eventBucket.ForEach(func(k, v []byte) error {
// Only look at keys with correct length.
if len(k) != event.TimestampLength {

View file

@ -5,15 +5,15 @@ import (
"errors"
"fmt"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/btcsuite/btcwallet/wtxmgr"
"github.com/lightninglabs/pool/clientdb/migrations"
"go.etcd.io/bbolt"
)
// migration is a function which takes a prior outdated version of the database
// instance and mutates the key/bucket structure to arrive at a more up-to-date
// version of the database.
type migration func(tx *bbolt.Tx) error
type migration func(tx walletdb.ReadWriteTx) error
var (
// metadataBucketKey stores all the metadata concerning the state of the
@ -34,6 +34,8 @@ var (
// ErrDBReversion is returned when detecting an attempt to revert to a
// prior database version.
ErrDBReversion = errors.New("cannot revert to prior version")
ErrDBVersionNotFound = errors.New("database version not found")
// dbVersions is storing all versions of database. If current version
// of database don't match with latest version this list will be used
@ -47,24 +49,38 @@ var (
)
// getDBVersion retrieves the current database version.
func getDBVersion(bucket *bbolt.Bucket) (uint32, error) {
func getDBVersion(bucket walletdb.ReadBucket) (uint32, error) {
versionBytes := bucket.Get(dbVersionKey)
if versionBytes == nil {
return 0, errors.New("database version not found")
return 0, ErrDBVersionNotFound
}
return byteOrder.Uint32(versionBytes), nil
}
// setDBVersion updates the current database version.
func setDBVersion(bucket *bbolt.Bucket, version uint32) error {
func setDBVersion(bucket walletdb.ReadWriteBucket, version uint32) error {
var b [4]byte
byteOrder.PutUint32(b[:], version)
return bucket.Put(dbVersionKey, b[:])
}
// getBucket retrieves the bucket with the given key.
func getBucket(tx *bbolt.Tx, key []byte) (*bbolt.Bucket, error) {
bucket := tx.Bucket(key)
// getWriteBucket retrieves the bucket with the given key in write mode.
func getWriteBucket(tx walletdb.ReadWriteTx,
key []byte) (walletdb.ReadWriteBucket, error) {
bucket := tx.ReadWriteBucket(key)
if bucket == nil {
return nil, fmt.Errorf("bucket \"%v\" does not exist",
string(key))
}
return bucket, nil
}
// getReadBucket retrieves the bucket with the given key in read mode.
func getReadBucket(tx walletdb.ReadTx,
key []byte) (walletdb.ReadBucket, error) {
bucket := tx.ReadBucket(key)
if bucket == nil {
return nil, fmt.Errorf("bucket \"%v\" does not exist",
string(key))
@ -75,10 +91,10 @@ func getBucket(tx *bbolt.Tx, key []byte) (*bbolt.Bucket, error) {
// getNestedBucket retrieves the nested bucket with the given key found within
// the given bucket. If the bucket does not exist and `create` is true, then the
// bucket is created.
func getNestedBucket(bucket *bbolt.Bucket, key []byte,
create bool) (*bbolt.Bucket, error) {
func getNestedBucket(bucket walletdb.ReadWriteBucket, key []byte,
create bool) (walletdb.ReadWriteBucket, error) {
nestedBucket := bucket.Bucket(key)
nestedBucket := bucket.NestedReadWriteBucket(key)
if nestedBucket == nil && create {
return bucket.CreateBucketIfNotExists(key)
}
@ -89,13 +105,24 @@ func getNestedBucket(bucket *bbolt.Bucket, key []byte,
return nestedBucket, nil
}
func getNestedReadBucket(bucket walletdb.ReadBucket,
key []byte) (walletdb.ReadBucket, error) {
nestedBucket := bucket.NestedReadBucket(key)
if nestedBucket == nil {
return nil, fmt.Errorf("nested bucket \"%v\" does not exist",
string(key))
}
return nestedBucket, nil
}
// syncVersions function is used for safe db version synchronization. It
// applies migration functions to the current database and recovers the
// previous state of db if at least one error/panic appeared during migration.
func syncVersions(db *bbolt.DB) error {
func syncVersions(db walletdb.DB) error {
var currentVersion uint32
err := db.View(func(tx *bbolt.Tx) error {
metadata, err := getBucket(tx, metadataBucketKey)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
metadata, err := getReadBucket(tx, metadataBucketKey)
if err != nil {
return err
}
@ -131,7 +158,7 @@ func syncVersions(db *bbolt.DB) error {
// Otherwise we execute the migrations serially within a single database
// transaction to ensure the migration is atomic.
return db.Update(func(tx *bbolt.Tx) error {
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
for v := currentVersion; v < latestDBVersion; v++ {
log.Infof("Applying migration #%v", v+1)
@ -142,7 +169,7 @@ func syncVersions(db *bbolt.DB) error {
}
}
metadata, err := getBucket(tx, metadataBucketKey)
metadata, err := getWriteBucket(tx, metadataBucketKey)
if err != nil {
return err
}
@ -152,7 +179,7 @@ func syncVersions(db *bbolt.DB) error {
// storeRandomLockID generates a random lock ID backed by the system's CSPRNG
// and stores it under the metadata bucket.
func storeRandomLockID(metadata *bbolt.Bucket) error {
func storeRandomLockID(metadata walletdb.ReadWriteBucket) error {
var lockID wtxmgr.LockID
if _, err := rand.Read(lockID[:]); err != nil {
return err
@ -164,8 +191,8 @@ func storeRandomLockID(metadata *bbolt.Bucket) error {
// backing lnd node's wallet.
func (db *DB) LockID() (wtxmgr.LockID, error) {
var lockID wtxmgr.LockID
err := db.View(func(tx *bbolt.Tx) error {
metadata, err := getBucket(tx, metadataBucketKey)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
metadata, err := getReadBucket(tx, metadataBucketKey)
if err != nil {
return err
}

View file

@ -6,8 +6,8 @@ import (
"fmt"
"time"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/event"
"go.etcd.io/bbolt"
)
var (
@ -35,7 +35,7 @@ var (
// AddInitialOrderTimestamps creates an "order created" timestamp for each of
// the existing orders. This will only be executed once, when the main event
// bucket is created for the first time.
func AddInitialOrderTimestamps(tx *bbolt.Tx) error {
func AddInitialOrderTimestamps(tx walletdb.ReadWriteTx) error {
// We back date all existing orders to the beginning of the year of hell
// to signal this isn't the real timestamp it was created at but
// something we added later.
@ -44,7 +44,7 @@ func AddInitialOrderTimestamps(tx *bbolt.Tx) error {
).UnixNano()
// First, we'll grab our main order bucket key.
ordersBucket := tx.Bucket(ordersBucketKey)
ordersBucket := tx.ReadWriteBucket(ordersBucketKey)
if ordersBucket == nil {
return fmt.Errorf("bucket \"%v\" does not exist",
string(ordersBucketKey))
@ -69,7 +69,7 @@ func AddInitialOrderTimestamps(tx *bbolt.Tx) error {
// creation event for that order.
var nonce [32]byte
copy(nonce[:], nonceBytes)
orderBucket := ordersBucket.Bucket(nonce[:])
orderBucket := ordersBucket.NestedReadWriteBucket(nonce[:])
if orderBucket == nil {
return fmt.Errorf("order bucket not found")
}
@ -83,7 +83,7 @@ func AddInitialOrderTimestamps(tx *bbolt.Tx) error {
// With the key encoded, we'll then encode the event into our
// buffer, then write it out to disk.
evtBucket := tx.Bucket(eventBucketKey)
evtBucket := tx.ReadWriteBucket(eventBucketKey)
var eventBuf bytes.Buffer
if err := eventBuf.WriteByte(eventType); err != nil {
return err
@ -107,7 +107,7 @@ func AddInitialOrderTimestamps(tx *bbolt.Tx) error {
// Because we can't modify the order bucket in the ForEach above
// directly, we need to insert the references outside of the callback.
for nonce, ts := range eventRefs {
orderBucket := ordersBucket.Bucket(nonce[:])
orderBucket := ordersBucket.NestedReadWriteBucket(nonce[:])
if orderBucket == nil {
return fmt.Errorf("order bucket not found")
}

View file

@ -7,11 +7,11 @@ import (
"io"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/event"
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/sidecar"
"github.com/lightningnetwork/lnd/tlv"
"go.etcd.io/bbolt"
)
const (
@ -80,8 +80,8 @@ type orderCallback func(nonce order.Nonce, rawOrder []byte,
//
// NOTE: This is part of the Store interface.
func (db *DB) SubmitOrder(newOrder order.Order) error {
return db.Update(func(tx *bbolt.Tx) error {
rootBucket, err := getBucket(tx, ordersBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
rootBucket, err := getWriteBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -152,8 +152,8 @@ func (db *DB) SubmitOrder(newOrder order.Order) error {
//
// NOTE: This is part of the Store interface.
func (db *DB) UpdateOrder(nonce order.Nonce, modifiers ...order.Modifier) error {
return db.Update(func(tx *bbolt.Tx) error {
rootBucket, err := getBucket(tx, ordersBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
rootBucket, err := getWriteBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -175,8 +175,8 @@ func (db *DB) UpdateOrders(nonces []order.Nonce,
// Read and update the orders in one single transaction that they are
// updated atomically.
return db.Update(func(tx *bbolt.Tx) error {
rootBucket, err := getBucket(tx, ordersBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
rootBucket, err := getWriteBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -225,8 +225,8 @@ func (db *DB) GetOrder(nonce order.Nonce) (order.Order, error) {
return nil
}
)
err = db.View(func(tx *bbolt.Tx) error {
rootBucket, err := getBucket(tx, ordersBucketKey)
err = walletdb.View(db, func(tx walletdb.ReadTx) error {
rootBucket, err := getReadBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -265,9 +265,9 @@ func (db *DB) GetOrders() ([]order.Order, error) {
return nil
}
)
err := db.View(func(tx *bbolt.Tx) error {
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
// First, we'll grab our main order bucket key.
rootBucket, err := getBucket(tx, ordersBucketKey)
rootBucket, err := getReadBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -295,7 +295,7 @@ func (db *DB) GetOrders() ([]order.Order, error) {
// storeOrderTX saves a byte serialized order in its specific sub bucket within
// the root orders bucket.
func storeOrderTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
func storeOrderTX(rootBucket walletdb.ReadWriteBucket, nonce order.Nonce,
orderBytes []byte, evt event.Event) error {
// From the root bucket, we'll make a new sub order bucket using
@ -317,7 +317,7 @@ func storeOrderTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
// storeOrderMinNoderTierTX saves the current node tier for a given order to
// the proper bucket.
func storeOrderMinNoderTierTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
func storeOrderMinNoderTierTX(rootBucket walletdb.ReadWriteBucket, nonce order.Nonce,
minNodeTier order.NodeTier) error {
orderBucket, err := rootBucket.CreateBucketIfNotExists(nonce[:])
@ -335,7 +335,7 @@ func storeOrderMinNoderTierTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
// storeOrderMinUnitsMatchTX saves the order's minimum units match within the
// order's root bucket.
func storeOrderMinUnitsMatchTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
func storeOrderMinUnitsMatchTX(rootBucket walletdb.ReadWriteBucket, nonce order.Nonce,
minUnitsMatch order.SupplyUnit) error {
// From the root bucket, we'll make a new sub order bucket using
@ -356,7 +356,7 @@ func storeOrderMinUnitsMatchTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
// storeOrderTlvTX saves the order's additional information as a tlv stream
// within the order's root bucket.
func storeOrderTlvTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
func storeOrderTlvTX(rootBucket walletdb.ReadWriteBucket, nonce order.Nonce,
o order.Order) error {
orderBucket, err := rootBucket.CreateBucketIfNotExists(nonce[:])
@ -374,11 +374,11 @@ func storeOrderTlvTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
// fetchOrderTX fetches the binary data of one order specified by its nonce from
// the root orders bucket.
func fetchOrderTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
func fetchOrderTX(rootBucket walletdb.ReadBucket, nonce order.Nonce,
callback orderCallback) error {
// Get the main order bucket next.
orderBucket := rootBucket.Bucket(nonce[:])
orderBucket := rootBucket.NestedReadBucket(nonce[:])
if orderBucket == nil {
return ErrNoOrder
}
@ -431,7 +431,7 @@ func fetchOrderTX(rootBucket *bbolt.Bucket, nonce order.Nonce,
// update should be written to a staging area instead of being applied to the
// original order directly. Do not use this function for applying the staged
// changes to the final bucket but use copyOrder instead.
func updateOrder(ordersBucket, dst *bbolt.Bucket, nonce order.Nonce,
func updateOrder(ordersBucket, dst walletdb.ReadWriteBucket, nonce order.Nonce,
modifiers []order.Modifier) (order.Order, error) {
var (
@ -484,7 +484,7 @@ func updateOrder(ordersBucket, dst *bbolt.Bucket, nonce order.Nonce,
// reference to the order in the main order bucket, even if the
// destination bucket is the pending orders bucket.
evt := NewUpdatedEvent(prevState, o)
orderBucket := ordersBucket.Bucket(nonce[:])
orderBucket := ordersBucket.NestedReadWriteBucket(nonce[:])
if orderBucket == nil {
return nil, ErrNoOrder
}
@ -522,7 +522,7 @@ func updateOrder(ordersBucket, dst *bbolt.Bucket, nonce order.Nonce,
// copyOrder copies a single order from the source to destination bucket. No
// event references are copied, only the order itself.
func copyOrder(src, dst *bbolt.Bucket, nonce order.Nonce) error {
func copyOrder(src, dst walletdb.ReadWriteBucket, nonce order.Nonce) error {
var (
o order.Order
orderBytes []byte

View file

@ -5,11 +5,11 @@ import (
"io"
"time"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/auctioneerrpc"
"github.com/lightninglabs/pool/event"
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/poolrpc"
"go.etcd.io/bbolt"
)
// OrderEvent is the main interface for order specific events.
@ -317,18 +317,18 @@ var _ OrderEvent = (*MatchEvent)(nil)
// reference keys in the order bucket.
func (db *DB) GetOrderEvents(o order.Nonce) ([]event.Event, error) {
var events []event.Event
err := db.View(func(tx *bbolt.Tx) error {
ordersBucket, err := getBucket(tx, ordersBucketKey)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
ordersBucket, err := getReadBucket(tx, ordersBucketKey)
if err != nil {
return err
}
orderBucket := ordersBucket.Bucket(o[:])
orderBucket := ordersBucket.NestedReadBucket(o[:])
if orderBucket == nil {
return ErrNoOrder
}
eventSubBucket := orderBucket.Bucket(eventRefSubBucket)
eventSubBucket := orderBucket.NestedReadBucket(eventRefSubBucket)
if eventSubBucket == nil {
return fmt.Errorf("order event sub bucket not found")
}
@ -388,8 +388,8 @@ func (db *DB) StoreOrderEvents(events []OrderEvent) error {
}
event.MakeUniqueTimestamps(baseEvents)
return db.Update(func(tx *bbolt.Tx) error {
ordersBucket, err := getBucket(tx, ordersBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
ordersBucket, err := getWriteBucket(tx, ordersBucketKey)
if err != nil {
return err
}
@ -398,7 +398,7 @@ func (db *DB) StoreOrderEvents(events []OrderEvent) error {
// up the individual order bucket in each iteration.
for _, evt := range events {
nonce := evt.Nonce()
orderBucket := ordersBucket.Bucket(nonce[:])
orderBucket := ordersBucket.NestedReadWriteBucket(nonce[:])
if orderBucket == nil {
return ErrNoOrder
}

View file

@ -6,9 +6,9 @@ import (
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/sidecar"
"go.etcd.io/bbolt"
)
var (
@ -60,8 +60,8 @@ func (db *DB) AddSidecar(ticket *sidecar.Ticket) error {
return err
}
return db.Update(func(tx *bbolt.Tx) error {
sidecarBucket, err := getBucket(tx, sidecarsBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
sidecarBucket, err := getWriteBucket(tx, sidecarsBucketKey)
if err != nil {
return err
}
@ -92,8 +92,8 @@ func (db *DB) AddSidecarWithBid(ticket *sidecar.Ticket, bid *order.Bid) error {
bidNonce := bid.Nonce()
copy(ticket.Order.BidNonce[:], bidNonce[:])
return db.Update(func(tx *bbolt.Tx) error {
sidecarBucket, err := getBucket(tx, sidecarsBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
sidecarBucket, err := getWriteBucket(tx, sidecarsBucketKey)
if err != nil {
return err
}
@ -126,8 +126,8 @@ func (db *DB) UpdateSidecar(ticket *sidecar.Ticket) error {
return err
}
return db.Update(func(tx *bbolt.Tx) error {
sidecarBucket, err := getBucket(tx, sidecarsBucketKey)
return walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
sidecarBucket, err := getWriteBucket(tx, sidecarsBucketKey)
if err != nil {
return err
}
@ -154,8 +154,8 @@ func (db *DB) Sidecar(id [8]byte,
}
var s *sidecar.Ticket
err = db.View(func(tx *bbolt.Tx) error {
sidecarBucket, err := getBucket(tx, sidecarsBucketKey)
err = walletdb.View(db, func(tx walletdb.ReadTx) error {
sidecarBucket, err := getReadBucket(tx, sidecarsBucketKey)
if err != nil {
return err
}
@ -175,13 +175,13 @@ func (db *DB) Sidecar(id [8]byte,
func (db *DB) SidecarBidTemplate(ticket *sidecar.Ticket) (*order.Bid, error) {
var bid *order.Bid
err := db.View(func(tx *bbolt.Tx) error {
sidecarBucket, err := getBucket(tx, sidecarsBucketKey)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
sidecarBucket, err := getReadBucket(tx, sidecarsBucketKey)
if err != nil {
return err
}
bidBucket := sidecarBucket.Bucket(bidTemplateBucket)
bidBucket := sidecarBucket.NestedReadBucket(bidTemplateBucket)
if bidBucket == nil {
return err
}
@ -199,8 +199,8 @@ func (db *DB) SidecarBidTemplate(ticket *sidecar.Ticket) (*order.Bid, error) {
// Sidecars retrieves all known sidecars from the database.
func (db *DB) Sidecars() ([]*sidecar.Ticket, error) {
var res []*sidecar.Ticket
err := db.View(func(tx *bbolt.Tx) error {
sidecarBucket, err := getBucket(tx, sidecarsBucketKey)
err := walletdb.View(db, func(tx walletdb.ReadTx) error {
sidecarBucket, err := getReadBucket(tx, sidecarsBucketKey)
if err != nil {
return err
}
@ -227,7 +227,7 @@ func (db *DB) Sidecars() ([]*sidecar.Ticket, error) {
return res, nil
}
func storeSidecar(targetBucket *bbolt.Bucket, key []byte,
func storeSidecar(targetBucket walletdb.ReadWriteBucket, key []byte,
ticket *sidecar.Ticket) error {
var sidecarBuf bytes.Buffer
@ -240,7 +240,7 @@ func storeSidecar(targetBucket *bbolt.Bucket, key []byte,
return targetBucket.Put(key, sidecarBuf.Bytes())
}
func readSidecar(sourceBucket *bbolt.Bucket, id []byte) (*sidecar.Ticket,
func readSidecar(sourceBucket walletdb.ReadBucket, id []byte) (*sidecar.Ticket,
error) {
sidecarBytes := sourceBucket.Get(id)
@ -251,7 +251,9 @@ func readSidecar(sourceBucket *bbolt.Bucket, id []byte) (*sidecar.Ticket,
return sidecar.DeserializeTicket(bytes.NewReader(sidecarBytes))
}
func storeBidTemplate(bidBucket *bbolt.Bucket, bid *order.Bid, ticketNonce order.Nonce) error {
func storeBidTemplate(bidBucket walletdb.ReadWriteBucket, bid *order.Bid,
ticketNonce order.Nonce) error {
var w bytes.Buffer
if err := SerializeOrder(bid, &w); err != nil {
return err
@ -273,7 +275,7 @@ func storeBidTemplate(bidBucket *bbolt.Bucket, bid *order.Bid, ticketNonce order
return storeOrderMinNoderTierTX(bidBucket, ticketNonce, bid.MinNodeTier)
}
func readBidTemplate(bidBucket *bbolt.Bucket,
func readBidTemplate(bidBucket walletdb.ReadBucket,
ticketNonce order.Nonce) (*order.Bid, error) {
var (

View file

@ -12,7 +12,6 @@ import (
"github.com/lightninglabs/pool/order"
"github.com/lightninglabs/pool/poolrpc"
"github.com/lightninglabs/pool/terms"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/urfave/cli"
)
@ -233,7 +232,7 @@ func getPoolDB(ctx *cli.Context) (*clientdb.DB, error) {
clientdb.DBFilename,
)
if ctx.IsSet("db") {
fullDbPath = lncfg.CleanAndExpandPath(ctx.String("db"))
fullDbPath = pool.CleanAndExpandPath(ctx.String("db"))
}
db, err := clientdb.New(path.Dir(fullDbPath), path.Base(fullDbPath))

View file

@ -19,7 +19,6 @@ import (
"github.com/lightninglabs/protobuf-hex-display/json"
"github.com/lightninglabs/protobuf-hex-display/jsonpb"
"github.com/lightninglabs/protobuf-hex-display/proto"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/urfave/cli"
"google.golang.org/grpc"
@ -208,11 +207,11 @@ func extractPathArgs(ctx *cli.Context) (string, string, error) {
// We'll now fetch the basedir so we can make a decision on how to
// properly read the cert and macaroon. This will either be the default,
// or will have been overwritten by the end user.
baseDir := lncfg.CleanAndExpandPath(ctx.GlobalString(baseDirFlag.Name))
tlsCertPath := lncfg.CleanAndExpandPath(ctx.GlobalString(
baseDir := pool.CleanAndExpandPath(ctx.GlobalString(baseDirFlag.Name))
tlsCertPath := pool.CleanAndExpandPath(ctx.GlobalString(
tlsCertFlag.Name,
))
macPath := lncfg.CleanAndExpandPath(ctx.GlobalString(
macPath := pool.CleanAndExpandPath(ctx.GlobalString(
macaroonPathFlag.Name,
))

View file

@ -6,13 +6,15 @@ import (
"fmt"
"net"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/cert"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
@ -42,6 +44,11 @@ var (
defaultMinBackoff = 5 * time.Second
defaultMaxBackoff = 1 * time.Minute
// DefaultAutogenValidity is the default validity of a self-signed
// certificate. The value corresponds to 14 months
// (14 months * 30 days * 24 hours).
DefaultAutogenValidity = 14 * 30 * 24 * time.Hour
// DefaultTLSCertFilename is the default file name for the autogenerated
// TLS certificate.
DefaultTLSCertFilename = "tls.cert"
@ -105,6 +112,9 @@ type LndConfig struct {
MacaroonPath string `long:"macaroonpath" description:"The full path to the single macaroon to use, either the admin.macaroon or a custom baked one. Cannot be specified at the same time as macaroondir. A custom macaroon must contain ALL permissions required for all subservers to work, otherwise permission errors will occur."`
TLSPath string `long:"tlspath" description:"Path to lnd tls certificate"`
ConnectMailbox string `long:"connectmailbox" description:"Use the mailbox with the given address to connect to lnd instead"`
MailboxPassword string `long:"mailboxpassword" description:"The password for connecting to the mailbox"`
}
type Config struct {
@ -193,11 +203,11 @@ func DefaultConfig() Config {
// Validate cleans up paths in the config provided and validates it.
func Validate(cfg *Config) error {
// Cleanup any paths before we use them.
cfg.BaseDir = lncfg.CleanAndExpandPath(cfg.BaseDir)
cfg.LogDir = lncfg.CleanAndExpandPath(cfg.LogDir)
cfg.TLSCertPath = lncfg.CleanAndExpandPath(cfg.TLSCertPath)
cfg.TLSKeyPath = lncfg.CleanAndExpandPath(cfg.TLSKeyPath)
cfg.MacaroonPath = lncfg.CleanAndExpandPath(cfg.MacaroonPath)
cfg.BaseDir = CleanAndExpandPath(cfg.BaseDir)
cfg.LogDir = CleanAndExpandPath(cfg.LogDir)
cfg.TLSCertPath = CleanAndExpandPath(cfg.TLSCertPath)
cfg.TLSKeyPath = CleanAndExpandPath(cfg.TLSKeyPath)
cfg.MacaroonPath = CleanAndExpandPath(cfg.MacaroonPath)
// Since our pool directory overrides our log and TLS dir values, make
// sure that they are not set when base dir is set. We hard here rather
@ -260,12 +270,14 @@ func Validate(cfg *Config) error {
}
// If either of these directories do not exist, create them.
if err := os.MkdirAll(cfg.BaseDir, os.ModePerm); err != nil {
return err
}
if runtime.GOOS != "js" {
if err := os.MkdirAll(cfg.BaseDir, os.ModePerm); err != nil {
return err
}
if err := os.MkdirAll(cfg.LogDir, os.ModePerm); err != nil {
return err
if err := os.MkdirAll(cfg.LogDir, os.ModePerm); err != nil {
return err
}
}
// Make sure only one of the macaroon options is used.
@ -281,12 +293,12 @@ func Validate(cfg *Config) error {
// macaroondir is used, we use the admin macaroon located in
// that directory.
cfg.Lnd.MacaroonPath = path.Join(
lncfg.CleanAndExpandPath(cfg.Lnd.MacaroonDir),
CleanAndExpandPath(cfg.Lnd.MacaroonDir),
defaultLndMacaroon,
)
case cfg.Lnd.MacaroonPath != "":
cfg.Lnd.MacaroonPath = lncfg.CleanAndExpandPath(
cfg.Lnd.MacaroonPath = CleanAndExpandPath(
cfg.Lnd.MacaroonPath,
)
@ -370,7 +382,7 @@ func loadCertWithCreate(cfg *Config) (tls.Certificate, *x509.Certificate,
defaultSelfSignedOrganization, cfg.TLSCertPath,
cfg.TLSKeyPath, cfg.TLSExtraIPs,
cfg.TLSExtraDomains, cfg.TLSDisableAutofill,
cert.DefaultAutogenValidity,
DefaultAutogenValidity,
)
if err != nil {
return tls.Certificate{}, nil, err
@ -380,3 +392,29 @@ func loadCertWithCreate(cfg *Config) (tls.Certificate, *x509.Certificate,
return cert.LoadCert(cfg.TLSCertPath, cfg.TLSKeyPath)
}
// CleanAndExpandPath expands environment variables and leading ~ in the
// passed path, cleans the result, and returns it.
// This function is taken from https://github.com/btcsuite/btcd
func CleanAndExpandPath(path string) string {
if path == "" {
return ""
}
// Expand initial ~ to OS specific home directory.
if strings.HasPrefix(path, "~") {
var homeDir string
u, err := user.Current()
if err == nil {
homeDir = u.HomeDir
} else {
homeDir = os.Getenv("HOME")
}
path = strings.Replace(path, "~", homeDir, 1)
}
// NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%,
// but the variables can still be expanded via POSIX-style $VARIABLE.
return filepath.Clean(os.ExpandEnv(path))
}

View file

@ -8,7 +8,7 @@ import (
"sort"
"time"
"go.etcd.io/bbolt"
"github.com/btcsuite/btcwallet/walletdb"
)
const (
@ -96,7 +96,7 @@ type Predicate func(time.Time, Type) bool
// function should be called first to ensure the timestamps are already unique
// among themselves. If no "gap" in the timestamps can be found after 1000 tries
// an error is returned.
func StoreEvent(bucket *bbolt.Bucket, event Event) error {
func StoreEvent(bucket walletdb.ReadWriteBucket, event Event) error {
// We use a fixed length array as our buffer so we don't allocate new
// memory for each try.
var tsScratchSpace [TimestampLength]byte

15
go.mod
View file

@ -5,9 +5,11 @@ go 1.14
require (
github.com/btcsuite/btcd v0.21.0-beta.0.20210429225535-ce697fe7e82b
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
github.com/btcsuite/btcwallet v0.12.0
github.com/btcsuite/btcutil v1.0.3-0.20210514234026-faeebcb9abbe
github.com/btcsuite/btcwallet v0.12.1-0.20210518235050-c31e1497759c
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210518235050-c31e1497759c // indirect
github.com/btcsuite/btcwallet/walletdb v1.3.5
github.com/btcsuite/btcwallet/wtxmgr v1.3.0
github.com/davecgh/go-spew v1.1.1
github.com/golang/protobuf v1.4.3
@ -33,3 +35,12 @@ replace github.com/lightninglabs/pool/auctioneerrpc => ./auctioneerrpc
// Fix incompatibility of etcd go.mod package.
// See https://github.com/etcd-io/etcd/issues/11154
replace go.etcd.io/etcd => go.etcd.io/etcd v0.5.0-alpha.5.0.20201125193152-8a03d2e9614b
replace github.com/lightningnetwork/lnd => ../../lightningnetwork/lnd
replace github.com/lightningnetwork/lnd/healthcheck => ../../lightningnetwork/lnd/healthcheck
replace github.com/lightningnetwork/lnd/kvdb => ../../lightningnetwork/lnd/kvdb
replace github.com/lightningnetwork/lnd/cert => ../../lightningnetwork/lnd/cert
replace github.com/lightninglabs/lndclient => ../lndclient

133
go.sum
View file

@ -8,7 +8,6 @@ github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e h1:n+DcnTNkQ
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 h1:MG93+PZYs9PyEsj/n5/haQu2gK0h4tUtSy9ejtMwWa0=
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 h1:2be4ykKKov3M1yISM2E8gnGXZ/N2SsPawfnGiXxaYEU=
github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
@ -27,44 +26,44 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.20.1-beta.0.20200513120220-b470eee47728/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btcd v0.20.1-beta.0.20200730232343-1db1b6f8217f/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
github.com/btcsuite/btcd v0.21.0-beta.0.20201208033208-6bd4c64a54fa/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs=
github.com/btcsuite/btcd v0.21.0-beta.0.20210426180113-7eba688b65e5/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
github.com/btcsuite/btcd v0.21.0-beta.0.20210426180113-7eba688b65e5/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
github.com/btcsuite/btcd v0.21.0-beta.0.20210429225535-ce697fe7e82b h1:+BMyRYlNCozjv6zGhnyHExB6JquAIYZRwsc5bxPEXrI=
github.com/btcsuite/btcd v0.21.0-beta.0.20210429225535-ce697fe7e82b/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
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-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ=
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
github.com/btcsuite/btcutil/psbt v1.0.2/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ=
github.com/btcsuite/btcutil/psbt v1.0.3-0.20200826194809-5f93e33af2b0/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ=
github.com/btcsuite/btcutil/psbt v1.0.3-0.20201208143702-a53e38424cce h1:3PRwz+js0AMMV1fHRrCdQ55akoomx4Q3ulozHC3BDDY=
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
github.com/btcsuite/btcutil v1.0.3-0.20210514234026-faeebcb9abbe h1:SdSUcRKxJEWfRCfZryp2YKn632Lh6UoTBfLi+cv1GNo=
github.com/btcsuite/btcutil v1.0.3-0.20210514234026-faeebcb9abbe/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
github.com/btcsuite/btcutil/psbt v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ=
github.com/btcsuite/btcwallet v0.11.1-0.20200814001439-1d31f4ea6fc5/go.mod h1:YkEbJaCyN6yncq5gEp2xG0OKDwus2QxGCEXTNF27w5I=
github.com/btcsuite/btcwallet v0.11.1-0.20200904022754-2c5947a45222/go.mod h1:owv9oZqM0HnUW+ByF7VqOgfs2eb0ooiePW/+Tl/i/Nk=
github.com/btcsuite/btcwallet v0.11.1-0.20201207233335-415f37ff11a1/go.mod h1:P1U4LKSB/bhFQdOM7ab1XqNoBGFyFAe7eKObEBD9mIo=
github.com/btcsuite/btcwallet v0.12.0 h1:0kT0rDN8vNcAvuHp2qUS/hLsfa0VUn2dNQ2GvM9ozBA=
github.com/btcsuite/btcutil/psbt v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ=
github.com/btcsuite/btcutil/psbt v1.0.3-0.20210514234026-faeebcb9abbe h1:+zkzfj2bGHMOuxxf8xG3d5mDvd7phT7IyVv+8sQizqc=
github.com/btcsuite/btcutil/psbt v1.0.3-0.20210514234026-faeebcb9abbe/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ=
github.com/btcsuite/btcwallet v0.12.0/go.mod h1:f1HuBGov5+OTp40Gh1vA+tvF6d7bbuLFTceJMRB7fXw=
github.com/btcsuite/btcwallet v0.12.1-0.20210518235050-c31e1497759c h1:iCyE00LfXe92XqdTU4zCPvUZhm8VQZUT3WwPrEesNBQ=
github.com/btcsuite/btcwallet v0.12.1-0.20210518235050-c31e1497759c/go.mod h1:f1HuBGov5+OTp40Gh1vA+tvF6d7bbuLFTceJMRB7fXw=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.1-0.20210329233242-e0607006dce6 h1:mO7NxcfgLe75paLDHx+LWNG5BskiDQigHnSVT2KvNZA=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.1-0.20210329233242-e0607006dce6 h1:mO7NxcfgLe75paLDHx+LWNG5BskiDQigHnSVT2KvNZA=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.1-0.20210329233242-e0607006dce6/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.1-0.20210329233242-e0607006dce6/go.mod h1:VufDts7bd/zs3GV13f/lXc/0lXrPnvxD/NvmpG/FEKU=
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0 h1:2VsfS0sBedcM5KmDzRMT3+b6xobqWveZGvjb+jFez5w=
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/wallet/txsizes v1.0.1-0.20210329233242-e0607006dce6 h1:n9SLPLz2PRg2X+lnWxioxTmtAa2ZqjR8EwL/tZD7BAY=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210329233242-e0607006dce6/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
github.com/btcsuite/btcwallet/walletdb v1.0.0/go.mod h1:bZTy9RyYZh9fLnSua+/CD48TJtYJSHjjYcSaszuxCCk=
github.com/btcsuite/btcwallet/walletdb v1.2.0/go.mod h1:9cwc1Yyg4uvd4ZdfdoMnALji+V9gfWSMfxEdLdR5Vwc=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210329233242-e0607006dce6/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210518235050-c31e1497759c h1:m7dBYDQC0cHyH3WKJPNph3P5bealrqQzrcGhECypj6s=
github.com/btcsuite/btcwallet/wallet/txsizes v1.0.1-0.20210518235050-c31e1497759c/go.mod h1:pauEU8UuMFiThe5PB3EO+gO5kx87Me5NvdQDsTuq6cs=
github.com/btcsuite/btcwallet/walletdb v1.3.2/go.mod h1:GZCMPNpUu5KE3ASoVd+k06p/1OW8OwNGCCaNWRto2cQ=
github.com/btcsuite/btcwallet/walletdb v1.3.3/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
github.com/btcsuite/btcwallet/walletdb v1.3.4/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
github.com/btcsuite/btcwallet/walletdb v1.3.5-0.20210513043850-3a2f12e3a954/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
github.com/btcsuite/btcwallet/walletdb v1.3.5 h1:SoxUPLgJUkyO1XqON6X7x+rjHJoIpRQov8o8X6gNoz8=
github.com/btcsuite/btcwallet/walletdb v1.3.5/go.mod h1:oJDxAEUHVtnmIIBaa22wSBPTVcs6hUp5NKWmI8xDwwU=
github.com/btcsuite/btcwallet/wtxmgr v1.0.0/go.mod h1:vc4gBprll6BP0UJ+AIGDaySoc7MdAmZf8kelfNb8CFY=
github.com/btcsuite/btcwallet/wtxmgr v1.2.0/go.mod h1:h8hkcKUE3X7lMPzTUoGnNiw5g7VhGrKEW3KpR2r0VnY=
github.com/btcsuite/btcwallet/wtxmgr v1.3.0 h1:lrZaZXGJjDedYTV7s5UgU9xBe8+N+cIDW7BYwI/B8Fs=
github.com/btcsuite/btcwallet/wtxmgr v1.3.0/go.mod h1:awQsh1n/0ZrEQ+JZgWvHeo153ubzEisf/FyNtwI0dDk=
@ -82,10 +81,11 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.22+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@ -107,7 +107,7 @@ github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@ -125,14 +125,31 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
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=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@ -146,13 +163,22 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -168,10 +194,13 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@ -182,6 +211,7 @@ github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4G
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc=
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad h1:heFfj7z0pGsNCekUlsFhO2jstxO4b5iQ665LjwM5mDc=
@ -220,6 +250,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec h1:n1NeQ3SgUHyISrjFFoO5dR748Is8dBL9qpaTNfphQrs=
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@ -228,37 +260,25 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lightninglabs/aperture v0.1.6-beta h1:bhpK4O9xa0YUBFQfkfg/h/3sMAY+AOMxi9YUjg6/l/E=
github.com/lightninglabs/aperture v0.1.6-beta/go.mod h1:9xl4mx778ZAzrB87nLHMqk+XQcSz8Dx/DypjWzGN1xo=
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc=
github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
github.com/lightninglabs/lndclient v0.11.0-4/go.mod h1:8/cTKNwgL87NX123gmlv3Xh6p1a7pvzu+40Un3PhHiI=
github.com/lightninglabs/lndclient v0.12.0-8 h1:ZnX8wp0atNsBNGNIs+MYvLDRRnoia63RPflD9OfeonQ=
github.com/lightninglabs/lndclient v0.12.0-8/go.mod h1:L0R2VOaLxMylGbxgnfiZGc0hMDIIgj91cfgwGuFz9kU=
github.com/lightninglabs/neutrino v0.11.0/go.mod h1:CuhF0iuzg9Sp2HO6ZgXgayviFTn1QHdSTJlMncK80wg=
github.com/lightninglabs/neutrino v0.11.1-0.20200316235139-bffc52e8f200/go.mod h1:MlZmoKa7CJP3eR1s5yB7Rm5aSyadpKkxqAwLQmog7N0=
github.com/lightninglabs/neutrino v0.11.1-0.20201210023533-e1978372d15e/go.mod h1:KDWfQDKp+CFBxO1t2NRmWuagTY2sYIjpHB1k5vrojTI=
github.com/lightninglabs/neutrino v0.12.1 h1:9umzk5kKNc/l3bAyak8ClSRP1qSulnjc6kppLYDnuqk=
github.com/lightninglabs/neutrino v0.12.1/go.mod h1:GlKninWpRBbL7b8G0oQ36/8downfnFwKsr0hbRA6E/E=
github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI=
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display h1:RZJ8H4ueU/aQ9pFtx5wqsuD3B/DezrewJeVwDKKYY8E=
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display h1:RZJ8H4ueU/aQ9pFtx5wqsuD3B/DezrewJeVwDKKYY8E=
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display/go.mod h1:2oKOBU042GKFHrdbgGiKax4xVrFiZu51lhacUZQ9MnE=
github.com/lightninglabs/protobuf-hex-display v1.4.3-hex-display/go.mod h1:2oKOBU042GKFHrdbgGiKax4xVrFiZu51lhacUZQ9MnE=
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea h1:oCj48NQ8u7Vz+MmzHqt0db6mxcFZo3Ho7M5gCJauY/k=
github.com/lightningnetwork/lightning-onion v1.0.2-0.20200501022730-3c8c8d0b89ea/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4=
github.com/lightningnetwork/lnd v0.11.0-beta/go.mod h1:CzArvT7NFDLhVyW06+NJWSuWFmE6Ea+AjjA3txUBqTM=
github.com/lightningnetwork/lnd v0.11.1-beta/go.mod h1:PGIgxy8aH70Li33YVYkHSaCM8m8LjEevk5h1Dpldrr4=
github.com/lightningnetwork/lnd v0.12.0-beta/go.mod h1:2GyP1IG1kXV5Af/LOCxnXfux1OP3fAGr8zptS5PB2YI=
github.com/lightningnetwork/lnd v0.13.0-beta.rc2 h1:Pg1Qa0LPwOJXYt/vr3NYZwnn/RiwERxeTkZj39x7A1E=
github.com/lightningnetwork/lnd v0.13.0-beta.rc2/go.mod h1:uPP8n+uTsMC7WDpO6tosvVwI2B51wgHptMzWDXcwq2M=
github.com/lightningnetwork/lnd/cert v1.0.2/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo=
github.com/lightningnetwork/lnd/cert v1.0.3 h1:/K2gjzLgVI8we2IIPKc0ztWTEa85uds5sWXi1K6mOT0=
github.com/lightningnetwork/lnd/cert v1.0.3/go.mod h1:3MWXVLLPI0Mg0XETm9fT4N9Vyy/8qQLmaM5589bEggM=
github.com/lightningnetwork/lnd/clock v1.0.1 h1:QQod8+m3KgqHdvVMV+2DRNNZS1GRFir8mHZYA+Z2hFo=
github.com/lightningnetwork/lnd/clock v1.0.1/go.mod h1:KnQudQ6w0IAMZi1SgvecLZQZ43ra2vpDNj7H/aasemg=
github.com/lightningnetwork/lnd/healthcheck v1.0.0 h1:0Cj8aiFB1OANsUuW9P0OlheSPcZEB38rUQXankr8ZpU=
github.com/lightningnetwork/lnd/healthcheck v1.0.0/go.mod h1:u92p1JGFJNMSkMvztKEwmt1P3TRnLeJBXZ3M85xkU1E=
github.com/lightningnetwork/lnd/kvdb v1.0.0 h1:k5nubbfAPYqu4HXySPgKddYVPSVOcuNZtDAiyx8H7rQ=
github.com/lightningnetwork/lnd/kvdb v1.0.0/go.mod h1:NMZdCUmFmS6dezJo1uSUM7GRjKTVksQrIfinoyKIGAI=
github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms=
github.com/lightningnetwork/lnd/queue v1.0.4 h1:8Dq3vxAFSACPy+pKN88oPFhuCpCoAAChPBwa4BJxH4k=
github.com/lightningnetwork/lnd/queue v1.0.4/go.mod h1:YTkTVZCxz8tAYreH27EO3s8572ODumWrNdYW2E/YKxg=
@ -268,7 +288,12 @@ github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oa
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/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
@ -283,7 +308,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
@ -297,22 +322,24 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
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/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@ -322,9 +349,11 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -337,12 +366,16 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc h1:yUaosFVTJwnltaHbSNC3i82I92quFs+OFPRl8kNMVwo=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02 h1:tcJ6OjwOMvExLlzrAVZute09ocAGa7KqOON60++Gz4E=
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=
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
@ -354,6 +387,7 @@ go.etcd.io/etcd v0.5.0-alpha.5.0.20201125193152-8a03d2e9614b h1:PLwvCoe5rvpuo9Un
go.etcd.io/etcd v0.5.0-alpha.5.0.20201125193152-8a03d2e9614b/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@ -407,7 +441,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -422,16 +455,24 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83 h1:kHSDPqCtsHZOg0nVylfTo20DDhE9gG4Y0jn7hKQ0QAM=
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/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/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2 h1:+DCIGbF/swA92ohVg0//6X2IVY3KZs6p9mix0ziNYJM=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -504,6 +545,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

62
index.html Normal file
View file

@ -0,0 +1,62 @@
<!doctype html>
<!--
Copyright 2018 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<html>
<head>
<meta charset="utf-8">
<title>Go wasm</title>
</head>
<body>
<!--
Add the following polyfill for Microsoft Edge 17/18 support:
<script src="https://cdn.jsdelivr.net/npm/text-encoding@0.7.0/lib/encoding.min.js"></script>
(see https://caniuse.com/#feat=textencoder)
-->
<script src="wasm_exec.js"></script>
<script>
if (!WebAssembly.instantiateStreaming) { // polyfill
WebAssembly.instantiateStreaming = async (resp, importObject) => {
const source = await (await resp).arrayBuffer();
return await WebAssembly.instantiate(source, importObject);
};
}
const go = new Go();
let mod, inst;
WebAssembly.instantiateStreaming(fetch('pool.wasm'), go.importObject).then((result) => {
mod = result.module;
inst = result.instance;
document.getElementById('runButton').disabled = false;
}).catch((err) => {
console.error(err);
});
async function run() {
console.clear();
let password = document.getElementById('password').value;
go.argv = [
'poold',
'--debuglevel=debug',
'--insecure',
'--network=regtest',
'--fakeauth',
'--auctionserver=localhost:12009',
'--lnd.connectmailbox=localhost:12080',
'--lnd.mailboxpassword', password,
];
await go.run(inst);
inst = await WebAssembly.instantiate(mod, go.importObject); // reset instance
}
</script>
<label for="password">Password: </label>
<input id="password" type="text" size="50" maxlength="255">
<button onClick="run();" id="runButton" disabled>Run</button>
</body>
</html>

61
lnd.go Normal file
View file

@ -0,0 +1,61 @@
// +build !js
package pool
import (
"context"
"path"
"github.com/lightninglabs/lndclient"
"github.com/lightningnetwork/lnd/lnrpc"
)
// getLnd returns an instance of the lnd services proxy.
func getLnd(network string, cfg *LndConfig) (*lndclient.GrpcLndServices,
lnrpc.LightningClient, error) {
// We'll want to wait for lnd to be fully synced to its chain backend.
// The call to NewLndServices will block until the sync is completed.
// But we still want to be able to shutdown the daemon if the user
// decides to not wait. For that we can pass down a context that we
// cancel on shutdown.
ctxc, cancel := context.WithCancel(context.Background())
defer cancel()
// Make sure the context is canceled if the user requests shutdown.
go func() {
select {
// Client requests shutdown, cancel the wait.
case <-interceptor.ShutdownChannel():
cancel()
// The check was completed and the above defer canceled the
// context. We can just exit the goroutine, nothing more to do.
case <-ctxc.Done():
}
}()
services, err := lndclient.NewLndServices(&lndclient.LndServicesConfig{
LndAddress: cfg.Host,
Network: lndclient.Network(network),
CustomMacaroonPath: cfg.MacaroonPath,
TLSPath: cfg.TLSPath,
CheckVersion: minimalCompatibleVersion,
BlockUntilChainSynced: true,
BlockUntilUnlocked: true,
CallerCtx: ctxc,
})
if err != nil {
return nil, nil, err
}
basicClient, err := lndclient.NewBasicClient(
cfg.Host, cfg.TLSPath, path.Dir(cfg.MacaroonPath), network,
lndclient.MacFilename(path.Base(cfg.MacaroonPath)),
)
if err != nil {
return nil, nil, err
}
return services, basicClient, nil
}

58
lnd_js.go Normal file
View file

@ -0,0 +1,58 @@
package pool
import (
"context"
"crypto/sha512"
"strings"
"github.com/btcsuite/btcd/btcec"
"github.com/lightninglabs/lndclient"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/mailbox"
"google.golang.org/grpc"
)
// getLnd returns an instance of the lnd services proxy.
func getLnd(network string, cfg *LndConfig) (*lndclient.GrpcLndServices,
lnrpc.LightningClient, error) {
conn, err := mailboxClientConnection(cfg)
if err != nil {
return nil, nil, err
}
services, err := lndclient.NewLndServicesFromAuthConn(
lndclient.Network(network), conn, 0,
)
return services, lnrpc.NewLightningClient(conn), err
}
func mailboxClientConnection(cfg *LndConfig) (*grpc.ClientConn, error) {
words := strings.Split(cfg.MailboxPassword, " ")
var mnemonicWords [mailbox.NumPasswordWords]string
copy(mnemonicWords[:], words)
password := mailbox.PasswordMnemonicToEntropy(mnemonicWords)
sid := sha512.Sum512(password[:])
receiveSID := mailbox.GetSID(sid, true)
sendSID := mailbox.GetSID(sid, false)
privKey, err := btcec.NewPrivateKey(btcec.S256())
if err != nil {
return nil, err
}
ecdh := &keychain.PrivKeyECDH{PrivKey: privKey}
transportConn := mailbox.NewClientConn(receiveSID, sendSID)
noiseConn := mailbox.NewNoiseConn(ecdh, nil)
dialOpts := []grpc.DialOption{
grpc.WithContextDialer(transportConn.Dial),
grpc.WithTransportCredentials(noiseConn),
grpc.WithPerRPCCredentials(noiseConn),
}
ctx := context.Background()
return grpc.DialContext(ctx, cfg.ConnectMailbox, dialOpts...)
}

View file

@ -1,3 +1,5 @@
// +build !js
package pool
import (

34
macaroons_js.go Normal file
View file

@ -0,0 +1,34 @@
package pool
import (
"context"
"google.golang.org/grpc"
)
func (s *Server) startMacaroonService() error {
return nil
}
func (s *Server) stopMacaroonService() error {
return nil
}
// macaroonInterceptor creates macaroon security interceptors.
func (s *Server) macaroonInterceptor() (grpc.UnaryServerInterceptor,
grpc.StreamServerInterceptor, error) {
return noopUnaryInterceptor, noopStreamInterceptor, nil
}
func noopUnaryInterceptor(ctx context.Context, req interface{},
_ *grpc.UnaryServerInfo, h grpc.UnaryHandler) (interface{}, error) {
return h(ctx, req)
}
func noopStreamInterceptor(srv interface{}, ss grpc.ServerStream,
_ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
return handler(srv, ss)
}

View file

@ -30,7 +30,6 @@ import (
"github.com/lightninglabs/pool/sidecar"
"github.com/lightninglabs/pool/terms"
"github.com/lightningnetwork/lnd/chanbackup"
lndFunding "github.com/lightningnetwork/lnd/funding"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
@ -41,6 +40,8 @@ const (
// getInfoTimeout is the maximum time we allow for the initial getInfo
// call to the connected lnd node.
getInfoTimeout = 5 * time.Second
MaxBtcFundingAmount = btcutil.Amount(1<<24) - 1
)
// rpcServer implements the gRPC server on the client side and answers RPC calls
@ -1094,7 +1095,7 @@ func (s *rpcServer) validateOrder(order order.Order, acct *account.Account,
// Now that we now how large the order is, ensure that if it's a
// wumbo-sized order, then the backing lnd node is advertising wumbo
// support.
if order.Details().Amt > lndFunding.MaxBtcFundingAmount && !s.wumboSupported {
if order.Details().Amt > MaxBtcFundingAmount && !s.wumboSupported {
return fmt.Errorf("%v is wumbo sized, but "+
"lnd node isn't signalling wumbo", order.Details().Amt)
}

28
run.go
View file

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/lightningnetwork/lnd/build"
"github.com/lightningnetwork/lnd/signal"
@ -28,12 +29,14 @@ func Run(cfg *Config) error {
}
// Initialize logging at the default logging level.
err = logWriter.InitLogRotator(
filepath.Join(cfg.LogDir, DefaultLogFilename),
cfg.MaxLogFileSize, cfg.MaxLogFiles,
)
if err != nil {
return err
if runtime.GOOS != "js" {
err := logWriter.InitLogRotator(
filepath.Join(cfg.LogDir, DefaultLogFilename),
cfg.MaxLogFileSize, cfg.MaxLogFiles,
)
if err != nil {
return err
}
}
err = build.ParseAndSetDebugLevels(cfg.DebugLevel, logWriter)
if err != nil {
@ -41,10 +44,21 @@ func Run(cfg *Config) error {
}
trader := NewServer(cfg)
err = trader.Start()
if runtime.GOOS == "js" {
services, basicClient, err := getLnd(cfg.Network, cfg.Lnd)
if err != nil {
return fmt.Errorf("unable to connect to lnd: %v", err)
}
err = trader.StartAsSubserver(basicClient, services)
} else {
err = trader.Start()
}
if err != nil {
return fmt.Errorf("unable to start server: %v", err)
}
<-shutdownInterceptor.ShutdownChannel()
return trader.Stop()
}

View file

@ -9,7 +9,6 @@ import (
"fmt"
"net"
"net/http"
"path"
"strings"
"sync"
"sync/atomic"
@ -115,8 +114,14 @@ func (s *Server) Start() error {
}
}()
// Connect to lnd now. As there're some other lower-level operations we
// may need access to, we'll also make a connection for a
// "basic client".
//
// TODO(roasbeef): more granular macaroons, can ask user to make just
// what we need
var err error
s.lndServices, err = getLnd(s.cfg.Network, s.cfg.Lnd)
s.lndServices, s.lndClient, err = getLnd(s.cfg.Network, s.cfg.Lnd)
if err != nil {
return err
}
@ -125,20 +130,6 @@ func (s *Server) Start() error {
return nil
}
// As there're some other lower-level operations we may need access to,
// we'll also make a connection for a "basic client".
//
// TODO(roasbeef): more granular macaroons, can ask user to make just
// what we need
s.lndClient, err = lndclient.NewBasicClient(
s.cfg.Lnd.Host, s.cfg.Lnd.TLSPath,
path.Dir(s.cfg.Lnd.MacaroonPath), s.cfg.Network,
lndclient.MacFilename(path.Base(s.cfg.Lnd.MacaroonPath)),
)
if err != nil {
return err
}
// Start the macaroon service and let it create its default macaroon in
// case it doesn't exist yet.
if err := s.startMacaroonService(); err != nil {
@ -590,41 +581,6 @@ func (s *Server) Stop() error {
return nil
}
// getLnd returns an instance of the lnd services proxy.
func getLnd(network string, cfg *LndConfig) (*lndclient.GrpcLndServices, error) {
// We'll want to wait for lnd to be fully synced to its chain backend.
// The call to NewLndServices will block until the sync is completed.
// But we still want to be able to shutdown the daemon if the user
// decides to not wait. For that we can pass down a context that we
// cancel on shutdown.
ctxc, cancel := context.WithCancel(context.Background())
defer cancel()
// Make sure the context is canceled if the user requests shutdown.
go func() {
select {
// Client requests shutdown, cancel the wait.
case <-interceptor.ShutdownChannel():
cancel()
// The check was completed and the above defer canceled the
// context. We can just exit the goroutine, nothing more to do.
case <-ctxc.Done():
}
}()
return lndclient.NewLndServices(&lndclient.LndServicesConfig{
LndAddress: cfg.Host,
Network: lndclient.Network(network),
CustomMacaroonPath: cfg.MacaroonPath,
TLSPath: cfg.TLSPath,
CheckVersion: minimalCompatibleVersion,
BlockUntilChainSynced: true,
BlockUntilUnlocked: true,
CallerCtx: ctxc,
})
}
// Interceptor is the interface a client side gRPC interceptor has to implement.
type Interceptor interface {
// UnaryInterceptor intercepts normal, non-streaming requests from the

626
wasm_exec.js Normal file
View file

@ -0,0 +1,626 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
(() => {
// Map multiple JavaScript environments to a single common API,
// preferring web standards over Node.js API.
//
// Environments considered:
// - Browsers
// - Node.js
// - Electron
// - Parcel
// - Webpack
if (typeof global !== "undefined") {
// global already exists
} else if (typeof window !== "undefined") {
window.global = window;
} else if (typeof self !== "undefined") {
self.global = self;
} else {
throw new Error("cannot export Go (neither global, window nor self is defined)");
}
if (!global.require && typeof require !== "undefined") {
global.require = require;
}
if (!global.fs && global.require) {
const fs = require("fs");
if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) {
global.fs = fs;
}
}
const enosys = () => {
const err = new Error("not implemented");
err.code = "ENOSYS";
return err;
};
if (!global.fs) {
let outputBuf = "";
global.fs = {
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
writeSync(fd, buf) {
outputBuf += decoder.decode(buf);
const nl = outputBuf.lastIndexOf("\n");
if (nl != -1) {
console.log(outputBuf.substr(0, nl));
outputBuf = outputBuf.substr(nl + 1);
}
return buf.length;
},
write(fd, buf, offset, length, position, callback) {
if (offset !== 0 || length !== buf.length || position !== null) {
callback(enosys());
return;
}
const n = this.writeSync(fd, buf);
callback(null, n);
},
chmod(path, mode, callback) { callback(enosys()); },
chown(path, uid, gid, callback) { callback(enosys()); },
close(fd, callback) { callback(enosys()); },
fchmod(fd, mode, callback) { callback(enosys()); },
fchown(fd, uid, gid, callback) { callback(enosys()); },
fstat(fd, callback) { callback(enosys()); },
fsync(fd, callback) { callback(null); },
ftruncate(fd, length, callback) { callback(enosys()); },
lchown(path, uid, gid, callback) { callback(enosys()); },
link(path, link, callback) { callback(enosys()); },
lstat(path, callback) { callback(enosys()); },
mkdir(path, perm, callback) { callback(enosys()); },
open(path, flags, mode, callback) { callback(enosys()); },
read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
readdir(path, callback) { callback(enosys()); },
readlink(path, callback) { callback(enosys()); },
rename(from, to, callback) { callback(enosys()); },
rmdir(path, callback) { callback(enosys()); },
stat(path, callback) { callback(enosys()); },
symlink(path, link, callback) { callback(enosys()); },
truncate(path, length, callback) { callback(enosys()); },
unlink(path, callback) { callback(enosys()); },
utimes(path, atime, mtime, callback) { callback(enosys()); },
};
}
if (!global.process) {
global.process = {
getuid() { return -1; },
getgid() { return -1; },
geteuid() { return -1; },
getegid() { return -1; },
getgroups() { throw enosys(); },
pid: -1,
ppid: -1,
umask() { throw enosys(); },
cwd() { throw enosys(); },
chdir() { throw enosys(); },
}
}
if (!global.crypto && global.require) {
const nodeCrypto = require("crypto");
global.crypto = {
getRandomValues(b) {
nodeCrypto.randomFillSync(b);
},
};
}
if (!global.crypto) {
throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
}
if (!global.performance) {
global.performance = {
now() {
const [sec, nsec] = process.hrtime();
return sec * 1000 + nsec / 1000000;
},
};
}
if (!global.TextEncoder && global.require) {
global.TextEncoder = require("util").TextEncoder;
}
if (!global.TextEncoder) {
throw new Error("global.TextEncoder is not available, polyfill required");
}
if (!global.TextDecoder && global.require) {
global.TextDecoder = require("util").TextDecoder;
}
if (!global.TextDecoder) {
throw new Error("global.TextDecoder is not available, polyfill required");
}
// End of polyfills for common API.
const encoder = new TextEncoder("utf-8");
const decoder = new TextDecoder("utf-8");
global.Go = class {
constructor() {
this.argv = ["js"];
this.env = {};
this.exit = (code) => {
if (code !== 0) {
console.warn("exit code:", code);
}
};
this._exitPromise = new Promise((resolve) => {
this._resolveExitPromise = resolve;
});
this._pendingEvent = null;
this._scheduledTimeouts = new Map();
this._nextCallbackTimeoutID = 1;
const setInt64 = (addr, v) => {
this.mem.setUint32(addr + 0, v, true);
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
}
const getInt64 = (addr) => {
const low = this.mem.getUint32(addr + 0, true);
const high = this.mem.getInt32(addr + 4, true);
return low + high * 4294967296;
}
const loadValue = (addr) => {
const f = this.mem.getFloat64(addr, true);
if (f === 0) {
return undefined;
}
if (!isNaN(f)) {
return f;
}
const id = this.mem.getUint32(addr, true);
return this._values[id];
}
const storeValue = (addr, v) => {
const nanHead = 0x7FF80000;
if (typeof v === "number" && v !== 0) {
if (isNaN(v)) {
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 0, true);
return;
}
this.mem.setFloat64(addr, v, true);
return;
}
if (v === undefined) {
this.mem.setFloat64(addr, 0, true);
return;
}
let id = this._ids.get(v);
if (id === undefined) {
id = this._idPool.pop();
if (id === undefined) {
id = this._values.length;
}
this._values[id] = v;
this._goRefCounts[id] = 0;
this._ids.set(v, id);
}
this._goRefCounts[id]++;
let typeFlag = 0;
switch (typeof v) {
case "object":
if (v !== null) {
typeFlag = 1;
}
break;
case "string":
typeFlag = 2;
break;
case "symbol":
typeFlag = 3;
break;
case "function":
typeFlag = 4;
break;
}
this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
this.mem.setUint32(addr, id, true);
}
const loadSlice = (addr) => {
const array = getInt64(addr + 0);
const len = getInt64(addr + 8);
return new Uint8Array(this._inst.exports.mem.buffer, array, len);
}
const loadSliceOfValues = (addr) => {
const array = getInt64(addr + 0);
const len = getInt64(addr + 8);
const a = new Array(len);
for (let i = 0; i < len; i++) {
a[i] = loadValue(array + i * 8);
}
return a;
}
const loadString = (addr) => {
const saddr = getInt64(addr + 0);
const len = getInt64(addr + 8);
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
}
const timeOrigin = Date.now() - performance.now();
this.importObject = {
go: {
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
// This changes the SP, thus we have to update the SP used by the imported function.
// func wasmExit(code int32)
"runtime.wasmExit": (sp) => {
sp >>>= 0;
const code = this.mem.getInt32(sp + 8, true);
this.exited = true;
delete this._inst;
delete this._values;
delete this._goRefCounts;
delete this._ids;
delete this._idPool;
this.exit(code);
},
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
"runtime.wasmWrite": (sp) => {
sp >>>= 0;
const fd = getInt64(sp + 8);
const p = getInt64(sp + 16);
const n = this.mem.getInt32(sp + 24, true);
fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
},
// func resetMemoryDataView()
"runtime.resetMemoryDataView": (sp) => {
sp >>>= 0;
this.mem = new DataView(this._inst.exports.mem.buffer);
},
// func nanotime1() int64
"runtime.nanotime1": (sp) => {
sp >>>= 0;
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
},
// func walltime1() (sec int64, nsec int32)
"runtime.walltime1": (sp) => {
sp >>>= 0;
const msec = (new Date).getTime();
setInt64(sp + 8, msec / 1000);
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
},
// func scheduleTimeoutEvent(delay int64) int32
"runtime.scheduleTimeoutEvent": (sp) => {
sp >>>= 0;
const id = this._nextCallbackTimeoutID;
this._nextCallbackTimeoutID++;
this._scheduledTimeouts.set(id, setTimeout(
() => {
this._resume();
while (this._scheduledTimeouts.has(id)) {
// for some reason Go failed to register the timeout event, log and try again
// (temporary workaround for https://github.com/golang/go/issues/28975)
console.warn("scheduleTimeoutEvent: missed timeout event");
this._resume();
}
},
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
));
this.mem.setInt32(sp + 16, id, true);
},
// func clearTimeoutEvent(id int32)
"runtime.clearTimeoutEvent": (sp) => {
sp >>>= 0;
const id = this.mem.getInt32(sp + 8, true);
clearTimeout(this._scheduledTimeouts.get(id));
this._scheduledTimeouts.delete(id);
},
// func getRandomData(r []byte)
"runtime.getRandomData": (sp) => {
sp >>>= 0;
crypto.getRandomValues(loadSlice(sp + 8));
},
// func finalizeRef(v ref)
"syscall/js.finalizeRef": (sp) => {
sp >>>= 0;
const id = this.mem.getUint32(sp + 8, true);
this._goRefCounts[id]--;
if (this._goRefCounts[id] === 0) {
const v = this._values[id];
this._values[id] = null;
this._ids.delete(v);
this._idPool.push(id);
}
},
// func stringVal(value string) ref
"syscall/js.stringVal": (sp) => {
sp >>>= 0;
storeValue(sp + 24, loadString(sp + 8));
},
// func valueGet(v ref, p string) ref
"syscall/js.valueGet": (sp) => {
sp >>>= 0;
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 32, result);
},
// func valueSet(v ref, p string, x ref)
"syscall/js.valueSet": (sp) => {
sp >>>= 0;
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
},
// func valueDelete(v ref, p string)
"syscall/js.valueDelete": (sp) => {
sp >>>= 0;
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
},
// func valueIndex(v ref, i int) ref
"syscall/js.valueIndex": (sp) => {
sp >>>= 0;
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
},
// valueSetIndex(v ref, i int, x ref)
"syscall/js.valueSetIndex": (sp) => {
sp >>>= 0;
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
},
// func valueCall(v ref, m string, args []ref) (ref, bool)
"syscall/js.valueCall": (sp) => {
sp >>>= 0;
try {
const v = loadValue(sp + 8);
const m = Reflect.get(v, loadString(sp + 16));
const args = loadSliceOfValues(sp + 32);
const result = Reflect.apply(m, v, args);
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 56, result);
this.mem.setUint8(sp + 64, 1);
} catch (err) {
storeValue(sp + 56, err);
this.mem.setUint8(sp + 64, 0);
}
},
// func valueInvoke(v ref, args []ref) (ref, bool)
"syscall/js.valueInvoke": (sp) => {
sp >>>= 0;
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
const result = Reflect.apply(v, undefined, args);
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 40, result);
this.mem.setUint8(sp + 48, 1);
} catch (err) {
storeValue(sp + 40, err);
this.mem.setUint8(sp + 48, 0);
}
},
// func valueNew(v ref, args []ref) (ref, bool)
"syscall/js.valueNew": (sp) => {
sp >>>= 0;
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
const result = Reflect.construct(v, args);
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 40, result);
this.mem.setUint8(sp + 48, 1);
} catch (err) {
storeValue(sp + 40, err);
this.mem.setUint8(sp + 48, 0);
}
},
// func valueLength(v ref) int
"syscall/js.valueLength": (sp) => {
sp >>>= 0;
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
},
// valuePrepareString(v ref) (ref, int)
"syscall/js.valuePrepareString": (sp) => {
sp >>>= 0;
const str = encoder.encode(String(loadValue(sp + 8)));
storeValue(sp + 16, str);
setInt64(sp + 24, str.length);
},
// valueLoadString(v ref, b []byte)
"syscall/js.valueLoadString": (sp) => {
sp >>>= 0;
const str = loadValue(sp + 8);
loadSlice(sp + 16).set(str);
},
// func valueInstanceOf(v ref, t ref) bool
"syscall/js.valueInstanceOf": (sp) => {
sp >>>= 0;
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
},
// func copyBytesToGo(dst []byte, src ref) (int, bool)
"syscall/js.copyBytesToGo": (sp) => {
sp >>>= 0;
const dst = loadSlice(sp + 8);
const src = loadValue(sp + 32);
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
this.mem.setUint8(sp + 48, 0);
return;
}
const toCopy = src.subarray(0, dst.length);
dst.set(toCopy);
setInt64(sp + 40, toCopy.length);
this.mem.setUint8(sp + 48, 1);
},
// func copyBytesToJS(dst ref, src []byte) (int, bool)
"syscall/js.copyBytesToJS": (sp) => {
sp >>>= 0;
const dst = loadValue(sp + 8);
const src = loadSlice(sp + 16);
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
this.mem.setUint8(sp + 48, 0);
return;
}
const toCopy = src.subarray(0, dst.length);
dst.set(toCopy);
setInt64(sp + 40, toCopy.length);
this.mem.setUint8(sp + 48, 1);
},
"debug": (value) => {
console.log(value);
},
}
};
}
async run(instance) {
if (!(instance instanceof WebAssembly.Instance)) {
throw new Error("Go.run: WebAssembly.Instance expected");
}
this._inst = instance;
this.mem = new DataView(this._inst.exports.mem.buffer);
this._values = [ // JS values that Go currently has references to, indexed by reference id
NaN,
0,
null,
true,
false,
global,
this,
];
this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
this._ids = new Map([ // mapping from JS values to reference ids
[0, 1],
[null, 2],
[true, 3],
[false, 4],
[global, 5],
[this, 6],
]);
this._idPool = []; // unused ids that have been garbage collected
this.exited = false; // whether the Go program has exited
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
let offset = 4096;
const strPtr = (str) => {
const ptr = offset;
const bytes = encoder.encode(str + "\0");
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
offset += bytes.length;
if (offset % 8 !== 0) {
offset += 8 - (offset % 8);
}
return ptr;
};
const argc = this.argv.length;
const argvPtrs = [];
this.argv.forEach((arg) => {
argvPtrs.push(strPtr(arg));
});
argvPtrs.push(0);
const keys = Object.keys(this.env).sort();
keys.forEach((key) => {
argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
});
argvPtrs.push(0);
const argv = offset;
argvPtrs.forEach((ptr) => {
this.mem.setUint32(offset, ptr, true);
this.mem.setUint32(offset + 4, 0, true);
offset += 8;
});
this._inst.exports.run(argc, argv);
if (this.exited) {
this._resolveExitPromise();
}
await this._exitPromise;
}
_resume() {
if (this.exited) {
throw new Error("Go program has already exited");
}
this._inst.exports.resume();
if (this.exited) {
this._resolveExitPromise();
}
}
_makeFuncWrapper(id) {
const go = this;
return function () {
const event = { id: id, this: this, args: arguments };
go._pendingEvent = event;
go._resume();
return event.result;
};
}
}
if (
typeof module !== "undefined" &&
global.require &&
global.require.main === module &&
global.process &&
global.process.versions &&
!global.process.versions.electron
) {
if (process.argv.length < 3) {
console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
process.exit(1);
}
const go = new Go();
go.argv = process.argv.slice(2);
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
process.on("exit", (code) => { // Node.js exits if no event handler is pending
if (code === 0 && !go.exited) {
// deadlock, make Go print error and stack traces
go._pendingEvent = { id: 0 };
go._resume();
}
});
return go.run(result.instance);
}).catch((err) => {
console.error(err);
process.exit(1);
});
}
})();