make votingpool tests compile and pass

This commit is contained in:
Josh Rickmar 2017-01-19 15:24:57 -05:00 committed by Olaoluwa Osuntokun
parent f143d095d6
commit 1075ad3fa0
10 changed files with 1145 additions and 629 deletions

View file

@ -11,7 +11,8 @@ import (
"testing" "testing"
"github.com/btcsuite/btclog" "github.com/btcsuite/btclog"
"github.com/roasbeef/btcwallet/waddrmgr" "github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/walletdb"
) )
func init() { func init() {
@ -39,8 +40,8 @@ func TstCheckError(t *testing.T, testName string, gotErr error, wantErrCode Erro
// TstRunWithManagerUnlocked calls the given callback with the manager unlocked, // TstRunWithManagerUnlocked calls the given callback with the manager unlocked,
// and locks it again before returning. // and locks it again before returning.
func TstRunWithManagerUnlocked(t *testing.T, mgr *waddrmgr.Manager, callback func()) { func TstRunWithManagerUnlocked(t *testing.T, mgr *waddrmgr.Manager, addrmgrNs walletdb.ReadBucket, callback func()) {
if err := mgr.Unlock(privPassphrase); err != nil { if err := mgr.Unlock(addrmgrNs, privPassphrase); err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer mgr.Lock() defer mgr.Lock()

View file

@ -13,24 +13,24 @@ import (
) )
func TestPutUsedAddrHash(t *testing.T) { func TestPutUsedAddrHash(t *testing.T) {
tearDown, _, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dummyHash := bytes.Repeat([]byte{0x09}, 10) dummyHash := bytes.Repeat([]byte{0x09}, 10)
err := pool.namespace.Update( err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
func(tx walletdb.Tx) error { ns, _ := TstRWNamespaces(tx)
return putUsedAddrHash(tx, pool.ID, 0, 0, 0, dummyHash) return putUsedAddrHash(ns, pool.ID, 0, 0, 0, dummyHash)
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
var storedHash []byte var storedHash []byte
err = pool.namespace.View( err = walletdb.View(db, func(tx walletdb.ReadTx) error {
func(tx walletdb.Tx) error { ns, _ := TstRNamespaces(tx)
storedHash = getUsedAddrHash(tx, pool.ID, 0, 0, 0) storedHash = getUsedAddrHash(ns, pool.ID, 0, 0, 0)
return nil return nil
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -40,42 +40,52 @@ func TestPutUsedAddrHash(t *testing.T) {
} }
func TestGetMaxUsedIdx(t *testing.T) { func TestGetMaxUsedIdx(t *testing.T) {
tearDown, _, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
var err error err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
pool.namespace.Update( ns, _ := TstRWNamespaces(tx)
func(tx walletdb.Tx) error { for i, idx := range []int{0, 7, 9, 3001, 41, 500, 6} {
for i, idx := range []int{0, 7, 9, 3001, 41, 500, 6} { dummyHash := bytes.Repeat([]byte{byte(i)}, 10)
dummyHash := bytes.Repeat([]byte{byte(i)}, 10) err := putUsedAddrHash(ns, pool.ID, 0, 0, Index(idx), dummyHash)
err = putUsedAddrHash(tx, pool.ID, 0, 0, Index(idx), dummyHash) if err != nil {
if err != nil { return err
t.Fatal(err)
}
} }
return nil }
}) return nil
})
if err != nil {
t.Fatal(err)
}
var maxIdx Index var maxIdx Index
pool.namespace.View( err = walletdb.View(db, func(tx walletdb.ReadTx) error {
func(tx walletdb.Tx) error { ns, _ := TstRNamespaces(tx)
maxIdx, err = getMaxUsedIdx(tx, pool.ID, 0, 0) var err error
if err != nil { maxIdx, err = getMaxUsedIdx(ns, pool.ID, 0, 0)
t.Fatal(err) return err
} })
return nil if err != nil {
}) t.Fatal(err)
}
if maxIdx != Index(3001) { if maxIdx != Index(3001) {
t.Fatalf("Wrong max idx; got %d, want %d", maxIdx, Index(3001)) t.Fatalf("Wrong max idx; got %d, want %d", maxIdx, Index(3001))
} }
} }
func TestWithdrawalSerialization(t *testing.T) { func TestWithdrawalSerialization(t *testing.T) {
tearDown, _, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
roundID := uint32(0) roundID := uint32(0)
wi := createAndFulfillWithdrawalRequests(t, pool, roundID) wi := createAndFulfillWithdrawalRequests(t, dbtx, pool, roundID)
serialized, err := serializeWithdrawal(wi.requests, wi.startAddress, wi.lastSeriesID, serialized, err := serializeWithdrawal(wi.requests, wi.startAddress, wi.lastSeriesID,
wi.changeStart, wi.dustThreshold, wi.status) wi.changeStart, wi.dustThreshold, wi.status)
@ -84,8 +94,8 @@ func TestWithdrawalSerialization(t *testing.T) {
} }
var wInfo *withdrawalInfo var wInfo *withdrawalInfo
TstRunWithManagerUnlocked(t, pool.Manager(), func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
wInfo, err = deserializeWithdrawal(pool, serialized) wInfo, err = deserializeWithdrawal(pool, ns, addrmgrNs, serialized)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -115,26 +125,26 @@ func TestWithdrawalSerialization(t *testing.T) {
} }
func TestPutAndGetWithdrawal(t *testing.T) { func TestPutAndGetWithdrawal(t *testing.T) {
tearDown, _, pool := TstCreatePool(t) tearDown, db, _ := TstCreatePool(t)
defer tearDown() defer tearDown()
serialized := bytes.Repeat([]byte{1}, 10) serialized := bytes.Repeat([]byte{1}, 10)
poolID := []byte{0x00} poolID := []byte{0x00}
roundID := uint32(0) roundID := uint32(0)
err := pool.namespace.Update( err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
func(tx walletdb.Tx) error { ns, _ := TstRWNamespaces(tx)
return putWithdrawal(tx, poolID, roundID, serialized) return putWithdrawal(ns, poolID, roundID, serialized)
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
var retrieved []byte var retrieved []byte
err = pool.namespace.View( err = walletdb.View(db, func(tx walletdb.ReadTx) error {
func(tx walletdb.Tx) error { ns, _ := TstRNamespaces(tx)
retrieved = getWithdrawal(tx, poolID, roundID) retrieved = getWithdrawal(ns, poolID, roundID)
return nil return nil
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -40,13 +40,13 @@ var (
fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1} fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
) )
func createWaddrmgr(ns walletdb.Namespace, params *chaincfg.Params) (*waddrmgr.Manager, error) { func createWaddrmgr(ns walletdb.ReadWriteBucket, params *chaincfg.Params) (*waddrmgr.Manager, error) {
err := waddrmgr.Create(ns, seed, pubPassphrase, privPassphrase, params, err := waddrmgr.Create(ns, seed, pubPassphrase, privPassphrase, params,
fastScrypt) fastScrypt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return waddrmgr.Open(ns, pubPassphrase, params, nil) return waddrmgr.Open(ns, pubPassphrase, params)
} }
func ExampleCreate() { func ExampleCreate() {
@ -59,8 +59,15 @@ func ExampleCreate() {
} }
defer dbTearDown() defer dbTearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
fmt.Println(err)
return
}
defer dbtx.Commit()
// Create a new walletdb namespace for the address manager. // Create a new walletdb namespace for the address manager.
mgrNamespace, err := db.Namespace([]byte("waddrmgr")) mgrNamespace, err := dbtx.CreateTopLevelBucket([]byte("waddrmgr"))
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
@ -74,7 +81,7 @@ func ExampleCreate() {
} }
// Create a walletdb namespace for votingpools. // Create a walletdb namespace for votingpools.
vpNamespace, err := db.Namespace([]byte("votingpool")) vpNamespace, err := dbtx.CreateTopLevelBucket([]byte("votingpool"))
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
@ -96,41 +103,43 @@ func ExampleCreate() {
func Example_depositAddress() { func Example_depositAddress() {
// Create the address manager and votingpool DB namespace. See the example // Create the address manager and votingpool DB namespace. See the example
// for the Create() function for more info on how this is done. // for the Create() function for more info on how this is done.
mgr, vpNamespace, tearDownFunc, err := exampleCreateMgrAndDBNamespace() teardown, db, mgr := exampleCreateDBAndMgr()
if err != nil { defer teardown()
fmt.Println(err)
return
}
defer tearDownFunc()
// Create the voting pool. err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
pool, err := votingpool.Create(vpNamespace, mgr, []byte{0x00}) ns := votingpoolNamespace(tx)
if err != nil {
fmt.Println(err)
return
}
// Create a 2-of-3 series. // Create the voting pool.
seriesID := uint32(1) pool, err := votingpool.Create(ns, mgr, []byte{0x00})
requiredSignatures := uint32(2) if err != nil {
pubKeys := []string{ return err
"xpub661MyMwAqRbcFDDrR5jY7LqsRioFDwg3cLjc7tML3RRcfYyhXqqgCH5SqMSQdpQ1Xh8EtVwcfm8psD8zXKPcRaCVSY4GCqbb3aMEs27GitE", }
"xpub661MyMwAqRbcGsxyD8hTmJFtpmwoZhy4NBBVxzvFU8tDXD2ME49A6JjQCYgbpSUpHGP1q4S2S1Pxv2EqTjwfERS5pc9Q2yeLkPFzSgRpjs9",
"xpub661MyMwAqRbcEbc4uYVXvQQpH9L3YuZLZ1gxCmj59yAhNy33vXxbXadmRpx5YZEupNSqWRrR7PqU6duS2FiVCGEiugBEa5zuEAjsyLJjKCh",
}
err = pool.CreateSeries(votingpool.CurrentVersion, seriesID, requiredSignatures, pubKeys)
if err != nil {
fmt.Println(err)
return
}
// Create a deposit address. // Create a 2-of-3 series.
addr, err := pool.DepositScriptAddress(seriesID, votingpool.Branch(0), votingpool.Index(1)) seriesID := uint32(1)
requiredSignatures := uint32(2)
pubKeys := []string{
"xpub661MyMwAqRbcFDDrR5jY7LqsRioFDwg3cLjc7tML3RRcfYyhXqqgCH5SqMSQdpQ1Xh8EtVwcfm8psD8zXKPcRaCVSY4GCqbb3aMEs27GitE",
"xpub661MyMwAqRbcGsxyD8hTmJFtpmwoZhy4NBBVxzvFU8tDXD2ME49A6JjQCYgbpSUpHGP1q4S2S1Pxv2EqTjwfERS5pc9Q2yeLkPFzSgRpjs9",
"xpub661MyMwAqRbcEbc4uYVXvQQpH9L3YuZLZ1gxCmj59yAhNy33vXxbXadmRpx5YZEupNSqWRrR7PqU6duS2FiVCGEiugBEa5zuEAjsyLJjKCh",
}
err = pool.CreateSeries(ns, votingpool.CurrentVersion, seriesID, requiredSignatures, pubKeys)
if err != nil {
return err
}
// Create a deposit address.
addr, err := pool.DepositScriptAddress(seriesID, votingpool.Branch(0), votingpool.Index(1))
if err != nil {
return err
}
fmt.Println("Generated deposit address:", addr.EncodeAddress())
return nil
})
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
fmt.Println("Generated deposit address:", addr.EncodeAddress())
// Output: // Output:
// Generated deposit address: 3QTzpc9d3tTbNLJLB7xwt87nWM38boAhAw // Generated deposit address: 3QTzpc9d3tTbNLJLB7xwt87nWM38boAhAw
@ -141,30 +150,27 @@ func Example_depositAddress() {
func Example_empowerSeries() { func Example_empowerSeries() {
// Create the address manager and votingpool DB namespace. See the example // Create the address manager and votingpool DB namespace. See the example
// for the Create() function for more info on how this is done. // for the Create() function for more info on how this is done.
mgr, vpNamespace, tearDownFunc, err := exampleCreateMgrAndDBNamespace() teardown, db, mgr := exampleCreateDBAndMgr()
if err != nil { defer teardown()
fmt.Println(err)
return
}
defer tearDownFunc()
// Create a pool and a series. See the DepositAddress example for more info // Create a pool and a series. See the DepositAddress example for more info
// on how this is done. // on how this is done.
pool, seriesID, err := exampleCreatePoolAndSeries(mgr, vpNamespace) pool, seriesID := exampleCreatePoolAndSeries(db, mgr)
if err != nil {
fmt.Println(err)
return
}
// Now empower the series with one of its private keys. Notice that in order err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
// to do that we need to unlock the address manager. ns := votingpoolNamespace(tx)
if err := mgr.Unlock(privPassphrase); err != nil { addrmgrNs := addrmgrNamespace(tx)
fmt.Println(err)
return // Now empower the series with one of its private keys. Notice that in order
} // to do that we need to unlock the address manager.
defer mgr.Lock() err := mgr.Unlock(addrmgrNs, privPassphrase)
privKey := "xprv9s21ZrQH143K2j9PK4CXkCu8sgxkpUxCF7p1KVwiV5tdnkeYzJXReUkxz5iB2FUzTXC1L15abCDG4RMxSYT5zhm67uvsnLYxuDhZfoFcB6a" if err != nil {
err = pool.EmpowerSeries(seriesID, privKey) return err
}
defer mgr.Lock()
privKey := "xprv9s21ZrQH143K2j9PK4CXkCu8sgxkpUxCF7p1KVwiV5tdnkeYzJXReUkxz5iB2FUzTXC1L15abCDG4RMxSYT5zhm67uvsnLYxuDhZfoFcB6a"
return pool.EmpowerSeries(ns, seriesID, privKey)
})
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
@ -178,70 +184,67 @@ func Example_empowerSeries() {
func Example_startWithdrawal() { func Example_startWithdrawal() {
// Create the address manager and votingpool DB namespace. See the example // Create the address manager and votingpool DB namespace. See the example
// for the Create() function for more info on how this is done. // for the Create() function for more info on how this is done.
mgr, vpNamespace, tearDownFunc, err := exampleCreateMgrAndDBNamespace() teardown, db, mgr := exampleCreateDBAndMgr()
if err != nil { defer teardown()
fmt.Println(err)
return
}
defer tearDownFunc()
// Create a pool and a series. See the DepositAddress example for more info // Create a pool and a series. See the DepositAddress example for more info
// on how this is done. // on how this is done.
pool, seriesID, err := exampleCreatePoolAndSeries(mgr, vpNamespace) pool, seriesID := exampleCreatePoolAndSeries(db, mgr)
if err != nil {
fmt.Println(err)
return
}
// Unlock the manager err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
if err := mgr.Unlock(privPassphrase); err != nil { ns := votingpoolNamespace(tx)
fmt.Println(err) addrmgrNs := addrmgrNamespace(tx)
return txmgrNs := txmgrNamespace(tx)
}
defer mgr.Lock()
addr, _ := btcutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams()) // Create the transaction store for later use.
pkScript, _ := txscript.PayToAddrScript(addr) txstore := exampleCreateTxStore(txmgrNs)
requests := []votingpool.OutputRequest{
{ // Unlock the manager
PkScript: pkScript, err := mgr.Unlock(addrmgrNs, privPassphrase)
Address: addr, if err != nil {
Amount: 1e6, return err
Server: "server-id", }
Transaction: 123}, defer mgr.Lock()
}
changeStart, err := pool.ChangeAddress(seriesID, votingpool.Index(0)) addr, _ := btcutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams())
pkScript, _ := txscript.PayToAddrScript(addr)
requests := []votingpool.OutputRequest{
{
PkScript: pkScript,
Address: addr,
Amount: 1e6,
Server: "server-id",
Transaction: 123,
},
}
changeStart, err := pool.ChangeAddress(seriesID, votingpool.Index(0))
if err != nil {
return err
}
// This is only needed because we have not used any deposit addresses from
// the series, and we cannot create a WithdrawalAddress for an unused
// branch/idx pair.
err = pool.EnsureUsedAddr(ns, addrmgrNs, seriesID, votingpool.Branch(1), votingpool.Index(0))
if err != nil {
return err
}
startAddr, err := pool.WithdrawalAddress(ns, addrmgrNs, seriesID, votingpool.Branch(1), votingpool.Index(0))
if err != nil {
return err
}
lastSeriesID := seriesID
dustThreshold := btcutil.Amount(1e4)
currentBlock := int32(19432)
roundID := uint32(0)
_, err = pool.StartWithdrawal(ns, addrmgrNs,
roundID, requests, *startAddr, lastSeriesID, *changeStart, txstore, txmgrNs, currentBlock,
dustThreshold)
return err
})
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
// This is only needed because we have not used any deposit addresses from
// the series, and we cannot create a WithdrawalAddress for an unused
// branch/idx pair.
if err = pool.EnsureUsedAddr(seriesID, votingpool.Branch(1), votingpool.Index(0)); err != nil {
fmt.Println(err)
return
}
startAddr, err := pool.WithdrawalAddress(seriesID, votingpool.Branch(1), votingpool.Index(0))
if err != nil {
fmt.Println(err)
return
}
lastSeriesID := seriesID
dustThreshold := btcutil.Amount(1e4)
currentBlock := int32(19432)
roundID := uint32(0)
txstore, tearDownFunc, err := exampleCreateTxStore()
if err != nil {
fmt.Println(err)
return
}
_, err = pool.StartWithdrawal(
roundID, requests, *startAddr, lastSeriesID, *changeStart, txstore, currentBlock,
dustThreshold)
if err != nil {
fmt.Println(err)
}
// Output: // Output:
// //
@ -263,86 +266,99 @@ func createWalletDB() (walletdb.DB, func(), error) {
return db, dbTearDown, nil return db, dbTearDown, nil
} }
func exampleCreateMgrAndDBNamespace() (*waddrmgr.Manager, walletdb.Namespace, func(), error) { var (
addrmgrNamespaceKey = []byte("addrmgr")
txmgrNamespaceKey = []byte("txmgr")
votingpoolNamespaceKey = []byte("votingpool")
)
func addrmgrNamespace(dbtx walletdb.ReadWriteTx) walletdb.ReadWriteBucket {
return dbtx.ReadWriteBucket(addrmgrNamespaceKey)
}
func txmgrNamespace(dbtx walletdb.ReadWriteTx) walletdb.ReadWriteBucket {
return dbtx.ReadWriteBucket(txmgrNamespaceKey)
}
func votingpoolNamespace(dbtx walletdb.ReadWriteTx) walletdb.ReadWriteBucket {
return dbtx.ReadWriteBucket(votingpoolNamespaceKey)
}
func exampleCreateDBAndMgr() (teardown func(), db walletdb.DB, mgr *waddrmgr.Manager) {
db, dbTearDown, err := createWalletDB() db, dbTearDown, err := createWalletDB()
if err != nil { if err != nil {
return nil, nil, nil, err panic(err)
} }
// Create a new walletdb namespace for the address manager. // Create a new walletdb namespace for the address manager.
mgrNamespace, err := db.Namespace([]byte("waddrmgr")) err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs, err := tx.CreateTopLevelBucket(addrmgrNamespaceKey)
if err != nil {
return err
}
_, err = tx.CreateTopLevelBucket(votingpoolNamespaceKey)
if err != nil {
return err
}
_, err = tx.CreateTopLevelBucket(txmgrNamespaceKey)
if err != nil {
return err
}
// Create the address manager
mgr, err = createWaddrmgr(addrmgrNs, &chaincfg.MainNetParams)
return err
})
if err != nil { if err != nil {
dbTearDown() dbTearDown()
return nil, nil, nil, err panic(err)
} }
// Create the address manager teardown = func() {
mgr, err := createWaddrmgr(mgrNamespace, &chaincfg.MainNetParams)
if err != nil {
dbTearDown()
return nil, nil, nil, err
}
tearDownFunc := func() {
mgr.Close() mgr.Close()
dbTearDown() dbTearDown()
} }
// Create a walletdb namespace for votingpools. return teardown, db, mgr
vpNamespace, err := db.Namespace([]byte("votingpool"))
if err != nil {
tearDownFunc()
return nil, nil, nil, err
}
return mgr, vpNamespace, tearDownFunc, nil
} }
func exampleCreatePoolAndSeries(mgr *waddrmgr.Manager, vpNamespace walletdb.Namespace) ( func exampleCreatePoolAndSeries(db walletdb.DB, mgr *waddrmgr.Manager) (pool *votingpool.Pool, seriesID uint32) {
*votingpool.Pool, uint32, error) { err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
pool, err := votingpool.Create(vpNamespace, mgr, []byte{0x00}) ns := votingpoolNamespace(tx)
var err error
pool, err = votingpool.Create(ns, mgr, []byte{0x00})
if err != nil {
return err
}
// Create a 2-of-3 series.
seriesID = uint32(1)
requiredSignatures := uint32(2)
pubKeys := []string{
"xpub661MyMwAqRbcFDDrR5jY7LqsRioFDwg3cLjc7tML3RRcfYyhXqqgCH5SqMSQdpQ1Xh8EtVwcfm8psD8zXKPcRaCVSY4GCqbb3aMEs27GitE",
"xpub661MyMwAqRbcGsxyD8hTmJFtpmwoZhy4NBBVxzvFU8tDXD2ME49A6JjQCYgbpSUpHGP1q4S2S1Pxv2EqTjwfERS5pc9Q2yeLkPFzSgRpjs9",
"xpub661MyMwAqRbcEbc4uYVXvQQpH9L3YuZLZ1gxCmj59yAhNy33vXxbXadmRpx5YZEupNSqWRrR7PqU6duS2FiVCGEiugBEa5zuEAjsyLJjKCh",
}
err = pool.CreateSeries(ns, votingpool.CurrentVersion, seriesID, requiredSignatures, pubKeys)
if err != nil {
return err
}
return pool.ActivateSeries(ns, seriesID)
})
if err != nil { if err != nil {
return nil, 0, err panic(err)
} }
// Create a 2-of-3 series. return pool, seriesID
seriesID := uint32(1)
requiredSignatures := uint32(2)
pubKeys := []string{
"xpub661MyMwAqRbcFDDrR5jY7LqsRioFDwg3cLjc7tML3RRcfYyhXqqgCH5SqMSQdpQ1Xh8EtVwcfm8psD8zXKPcRaCVSY4GCqbb3aMEs27GitE",
"xpub661MyMwAqRbcGsxyD8hTmJFtpmwoZhy4NBBVxzvFU8tDXD2ME49A6JjQCYgbpSUpHGP1q4S2S1Pxv2EqTjwfERS5pc9Q2yeLkPFzSgRpjs9",
"xpub661MyMwAqRbcEbc4uYVXvQQpH9L3YuZLZ1gxCmj59yAhNy33vXxbXadmRpx5YZEupNSqWRrR7PqU6duS2FiVCGEiugBEa5zuEAjsyLJjKCh",
}
err = pool.CreateSeries(votingpool.CurrentVersion, seriesID, requiredSignatures, pubKeys)
if err != nil {
return nil, 0, err
}
err = pool.ActivateSeries(seriesID)
if err != nil {
return nil, 0, err
}
return pool, seriesID, nil
} }
func exampleCreateTxStore() (*wtxmgr.Store, func(), error) { func exampleCreateTxStore(ns walletdb.ReadWriteBucket) *wtxmgr.Store {
dir, err := ioutil.TempDir("", "pool_test_txstore") err := wtxmgr.Create(ns)
if err != nil { if err != nil {
return nil, nil, err panic(err)
} }
db, err := walletdb.Create("bdb", filepath.Join(dir, "txstore.db")) s, err := wtxmgr.Open(ns, &chaincfg.MainNetParams)
if err != nil { if err != nil {
return nil, nil, err panic(err)
} }
wtxmgrNamespace, err := db.Namespace([]byte("testtxstore")) return s
if err != nil {
return nil, nil, err
}
err = wtxmgr.Create(wtxmgrNamespace)
if err != nil {
return nil, nil, err
}
s, err := wtxmgr.Open(wtxmgrNamespace, &chaincfg.MainNetParams)
if err != nil {
return nil, nil, err
}
return s, func() { os.RemoveAll(dir) }, nil
} }

View file

@ -53,10 +53,10 @@ func getUniqueID() uint32 {
} }
// createWithdrawalTx creates a withdrawalTx with the given input and output amounts. // createWithdrawalTx creates a withdrawalTx with the given input and output amounts.
func createWithdrawalTx(t *testing.T, pool *Pool, inputAmounts []int64, outputAmounts []int64) *withdrawalTx { func createWithdrawalTx(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, inputAmounts []int64, outputAmounts []int64) *withdrawalTx {
net := pool.Manager().ChainParams() net := pool.Manager().ChainParams()
tx := newWithdrawalTx(defaultTxOptions) tx := newWithdrawalTx(defaultTxOptions)
_, credits := TstCreateCreditsOnNewSeries(t, pool, inputAmounts) _, credits := TstCreateCreditsOnNewSeries(t, dbtx, pool, inputAmounts)
for _, c := range credits { for _, c := range credits {
tx.addInput(c) tx.addInput(c)
} }
@ -99,15 +99,28 @@ func TstNewDepositScript(t *testing.T, p *Pool, seriesID uint32, branch Branch,
return script return script
} }
func TstRNamespaces(tx walletdb.ReadTx) (votingpoolNs, addrmgrNs walletdb.ReadBucket) {
return tx.ReadBucket(votingpoolNamespaceKey), tx.ReadBucket(addrmgrNamespaceKey)
}
func TstRWNamespaces(tx walletdb.ReadWriteTx) (votingpoolNs, addrmgrNs walletdb.ReadWriteBucket) {
return tx.ReadWriteBucket(votingpoolNamespaceKey), tx.ReadWriteBucket(addrmgrNamespaceKey)
}
func TstTxStoreRWNamespace(tx walletdb.ReadWriteTx) walletdb.ReadWriteBucket {
return tx.ReadWriteBucket(txmgrNamespaceKey)
}
// TstEnsureUsedAddr ensures the addresses defined by the given series/branch and // TstEnsureUsedAddr ensures the addresses defined by the given series/branch and
// index==0..idx are present in the set of used addresses for the given Pool. // index==0..idx are present in the set of used addresses for the given Pool.
func TstEnsureUsedAddr(t *testing.T, p *Pool, seriesID uint32, branch Branch, idx Index) []byte { func TstEnsureUsedAddr(t *testing.T, dbtx walletdb.ReadWriteTx, p *Pool, seriesID uint32, branch Branch, idx Index) []byte {
addr, err := p.getUsedAddr(seriesID, branch, idx) ns, addrmgrNs := TstRWNamespaces(dbtx)
addr, err := p.getUsedAddr(ns, addrmgrNs, seriesID, branch, idx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} else if addr != nil { } else if addr != nil {
var script []byte var script []byte
TstRunWithManagerUnlocked(t, p.Manager(), func() { TstRunWithManagerUnlocked(t, p.Manager(), addrmgrNs, func() {
script, err = addr.Script() script, err = addr.Script()
}) })
if err != nil { if err != nil {
@ -115,8 +128,8 @@ func TstEnsureUsedAddr(t *testing.T, p *Pool, seriesID uint32, branch Branch, id
} }
return script return script
} }
TstRunWithManagerUnlocked(t, p.Manager(), func() { TstRunWithManagerUnlocked(t, p.Manager(), addrmgrNs, func() {
err = p.EnsureUsedAddr(seriesID, branch, idx) err = p.EnsureUsedAddr(ns, addrmgrNs, seriesID, branch, idx)
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -124,8 +137,8 @@ func TstEnsureUsedAddr(t *testing.T, p *Pool, seriesID uint32, branch Branch, id
return TstNewDepositScript(t, p, seriesID, branch, idx) return TstNewDepositScript(t, p, seriesID, branch, idx)
} }
func TstCreatePkScript(t *testing.T, p *Pool, seriesID uint32, branch Branch, idx Index) []byte { func TstCreatePkScript(t *testing.T, dbtx walletdb.ReadWriteTx, p *Pool, seriesID uint32, branch Branch, idx Index) []byte {
script := TstEnsureUsedAddr(t, p, seriesID, branch, idx) script := TstEnsureUsedAddr(t, dbtx, p, seriesID, branch, idx)
addr, err := p.addressFor(script) addr, err := p.addressFor(script)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -137,30 +150,6 @@ func TstCreatePkScript(t *testing.T, p *Pool, seriesID uint32, branch Branch, id
return pkScript return pkScript
} }
func TstCreateTxStore(t *testing.T) (store *wtxmgr.Store, tearDown func()) {
dir, err := ioutil.TempDir("", "pool_test_txstore")
if err != nil {
t.Fatalf("Failed to create txstore dir: %v", err)
}
db, err := walletdb.Create("bdb", filepath.Join(dir, "txstore.db"))
if err != nil {
t.Fatalf("Failed to create walletdb: %v", err)
}
wtxmgrNamespace, err := db.Namespace([]byte("testtxstore"))
if err != nil {
t.Fatalf("Failed to create walletdb namespace: %v", err)
}
err = wtxmgr.Create(wtxmgrNamespace)
if err != nil {
t.Fatalf("Failed to create txstore: %v", err)
}
s, err := wtxmgr.Open(wtxmgrNamespace, &chaincfg.MainNetParams)
if err != nil {
t.Fatalf("Failed to open txstore: %v", err)
}
return s, func() { os.RemoveAll(dir) }
}
type TstSeriesDef struct { type TstSeriesDef struct {
ReqSigs uint32 ReqSigs uint32
PubKeys []string PubKeys []string
@ -172,15 +161,16 @@ type TstSeriesDef struct {
// TstCreateSeries creates a new Series for every definition in the given slice // TstCreateSeries creates a new Series for every definition in the given slice
// of TstSeriesDef. If the definition includes any private keys, the Series is // of TstSeriesDef. If the definition includes any private keys, the Series is
// empowered with them. // empowered with them.
func TstCreateSeries(t *testing.T, pool *Pool, definitions []TstSeriesDef) { func TstCreateSeries(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, definitions []TstSeriesDef) {
ns, addrmgrNs := TstRWNamespaces(dbtx)
for _, def := range definitions { for _, def := range definitions {
err := pool.CreateSeries(CurrentVersion, def.SeriesID, def.ReqSigs, def.PubKeys) err := pool.CreateSeries(ns, CurrentVersion, def.SeriesID, def.ReqSigs, def.PubKeys)
if err != nil { if err != nil {
t.Fatalf("Cannot creates series %d: %v", def.SeriesID, err) t.Fatalf("Cannot creates series %d: %v", def.SeriesID, err)
} }
TstRunWithManagerUnlocked(t, pool.Manager(), func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
for _, key := range def.PrivKeys { for _, key := range def.PrivKeys {
if err := pool.EmpowerSeries(def.SeriesID, key); err != nil { if err := pool.EmpowerSeries(ns, def.SeriesID, key); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
@ -222,35 +212,31 @@ func TstCreateSeriesDef(t *testing.T, pool *Pool, reqSigs uint32, keys []*hdkeyc
ReqSigs: reqSigs, SeriesID: seriesID, PubKeys: pubKeys, PrivKeys: privKeys} ReqSigs: reqSigs, SeriesID: seriesID, PubKeys: pubKeys, PrivKeys: privKeys}
} }
func TstCreatePoolAndTxStore(t *testing.T) (tearDown func(), pool *Pool, store *wtxmgr.Store) { func TstCreatePoolAndTxStore(t *testing.T) (tearDown func(), db walletdb.DB, pool *Pool, store *wtxmgr.Store) {
mgrTearDown, _, pool := TstCreatePool(t) teardown, db, pool := TstCreatePool(t)
store, storeTearDown := TstCreateTxStore(t) store = TstCreateTxStore(t, db)
tearDown = func() { return teardown, db, pool, store
mgrTearDown()
storeTearDown()
}
return tearDown, pool, store
} }
// TstCreateCreditsOnNewSeries creates a new Series (with a unique ID) and a // TstCreateCreditsOnNewSeries creates a new Series (with a unique ID) and a
// slice of credits locked to the series' address with branch==1 and index==0. // slice of credits locked to the series' address with branch==1 and index==0.
// The new Series will use a 2-of-3 configuration and will be empowered with // The new Series will use a 2-of-3 configuration and will be empowered with
// all of its private keys. // all of its private keys.
func TstCreateCreditsOnNewSeries(t *testing.T, pool *Pool, amounts []int64) (uint32, []credit) { func TstCreateCreditsOnNewSeries(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, amounts []int64) (uint32, []credit) {
masters := []*hdkeychain.ExtendedKey{ masters := []*hdkeychain.ExtendedKey{
TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)), TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)),
TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)), TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)),
TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)), TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)),
} }
def := TstCreateSeriesDef(t, pool, 2, masters) def := TstCreateSeriesDef(t, pool, 2, masters)
TstCreateSeries(t, pool, []TstSeriesDef{def}) TstCreateSeries(t, dbtx, pool, []TstSeriesDef{def})
return def.SeriesID, TstCreateSeriesCredits(t, pool, def.SeriesID, amounts) return def.SeriesID, TstCreateSeriesCredits(t, dbtx, pool, def.SeriesID, amounts)
} }
// TstCreateSeriesCredits creates a new credit for every item in the amounts // TstCreateSeriesCredits creates a new credit for every item in the amounts
// slice, locked to the given series' address with branch==1 and index==0. // slice, locked to the given series' address with branch==1 and index==0.
func TstCreateSeriesCredits(t *testing.T, pool *Pool, seriesID uint32, amounts []int64) []credit { func TstCreateSeriesCredits(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, seriesID uint32, amounts []int64) []credit {
addr := TstNewWithdrawalAddress(t, pool, seriesID, Branch(1), Index(0)) addr := TstNewWithdrawalAddress(t, dbtx, pool, seriesID, Branch(1), Index(0))
pkScript, err := txscript.PayToAddrScript(addr.addr) pkScript, err := txscript.PayToAddrScript(addr.addr)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -278,22 +264,21 @@ func TstCreateSeriesCredits(t *testing.T, pool *Pool, seriesID uint32, amounts [
// TstCreateSeriesCreditsOnStore inserts a new credit in the given store for // TstCreateSeriesCreditsOnStore inserts a new credit in the given store for
// every item in the amounts slice. These credits are locked to the votingpool // every item in the amounts slice. These credits are locked to the votingpool
// address composed of the given seriesID, branch==1 and index==0. // address composed of the given seriesID, branch==1 and index==0.
func TstCreateSeriesCreditsOnStore(t *testing.T, pool *Pool, seriesID uint32, amounts []int64, func TstCreateSeriesCreditsOnStore(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, seriesID uint32, amounts []int64,
store *wtxmgr.Store) []credit { store *wtxmgr.Store) []credit {
branch := Branch(1) branch := Branch(1)
idx := Index(0) idx := Index(0)
pkScript := TstCreatePkScript(t, pool, seriesID, branch, idx) pkScript := TstCreatePkScript(t, dbtx, pool, seriesID, branch, idx)
eligible := make([]credit, len(amounts)) eligible := make([]credit, len(amounts))
for i, credit := range TstCreateCreditsOnStore(t, store, pkScript, amounts) { for i, credit := range TstCreateCreditsOnStore(t, dbtx, store, pkScript, amounts) {
eligible[i] = newCredit(credit, *TstNewWithdrawalAddress(t, pool, seriesID, branch, idx)) eligible[i] = newCredit(credit, *TstNewWithdrawalAddress(t, dbtx, pool, seriesID, branch, idx))
} }
return eligible return eligible
} }
// TstCreateCreditsOnStore inserts a new credit in the given store for // TstCreateCreditsOnStore inserts a new credit in the given store for
// every item in the amounts slice. // every item in the amounts slice.
func TstCreateCreditsOnStore(t *testing.T, s *wtxmgr.Store, pkScript []byte, func TstCreateCreditsOnStore(t *testing.T, dbtx walletdb.ReadWriteTx, s *wtxmgr.Store, pkScript []byte, amounts []int64) []wtxmgr.Credit {
amounts []int64) []wtxmgr.Credit {
msgTx := createMsgTx(pkScript, amounts) msgTx := createMsgTx(pkScript, amounts)
meta := &wtxmgr.BlockMeta{ meta := &wtxmgr.BlockMeta{
Block: wtxmgr.Block{Height: TstInputsBlock}, Block: wtxmgr.Block{Height: TstInputsBlock},
@ -304,13 +289,14 @@ func TstCreateCreditsOnStore(t *testing.T, s *wtxmgr.Store, pkScript []byte,
t.Fatal(err) t.Fatal(err)
} }
if err := s.InsertTx(rec, meta); err != nil { txmgrNs := dbtx.ReadWriteBucket(txmgrNamespaceKey)
if err := s.InsertTx(txmgrNs, rec, meta); err != nil {
t.Fatal("Failed to create inputs: ", err) t.Fatal("Failed to create inputs: ", err)
} }
credits := make([]wtxmgr.Credit, len(msgTx.TxOut)) credits := make([]wtxmgr.Credit, len(msgTx.TxOut))
for i := range msgTx.TxOut { for i := range msgTx.TxOut {
if err := s.AddCredit(rec, meta, uint32(i), false); err != nil { if err := s.AddCredit(txmgrNs, rec, meta, uint32(i), false); err != nil {
t.Fatal("Failed to create inputs: ", err) t.Fatal("Failed to create inputs: ", err)
} }
credits[i] = wtxmgr.Credit{ credits[i] = wtxmgr.Credit{
@ -326,11 +312,16 @@ func TstCreateCreditsOnStore(t *testing.T, s *wtxmgr.Store, pkScript []byte,
return credits return credits
} }
var (
addrmgrNamespaceKey = []byte("waddrmgr")
votingpoolNamespaceKey = []byte("votingpool")
txmgrNamespaceKey = []byte("testtxstore")
)
// TstCreatePool creates a Pool on a fresh walletdb and returns it. It also // TstCreatePool creates a Pool on a fresh walletdb and returns it. It also
// returns the pool's waddrmgr.Manager (which uses the same walletdb, but with a // returns a teardown function that closes the Manager and removes the directory
// different namespace) as a convenience, and a teardown function that closes // used to store the database.
// the Manager and removes the directory used to store the database. func TstCreatePool(t *testing.T) (tearDownFunc func(), db walletdb.DB, pool *Pool) {
func TstCreatePool(t *testing.T) (tearDownFunc func(), mgr *waddrmgr.Manager, pool *Pool) {
// This should be moved somewhere else eventually as not all of our tests // This should be moved somewhere else eventually as not all of our tests
// call this function, but right now the only option would be to have the // call this function, but right now the only option would be to have the
// t.Parallel() call in each of our tests. // t.Parallel() call in each of our tests.
@ -341,40 +332,62 @@ func TstCreatePool(t *testing.T) (tearDownFunc func(), mgr *waddrmgr.Manager, po
if err != nil { if err != nil {
t.Fatalf("Failed to create db dir: %v", err) t.Fatalf("Failed to create db dir: %v", err)
} }
db, err := walletdb.Create("bdb", filepath.Join(dir, "wallet.db")) db, err = walletdb.Create("bdb", filepath.Join(dir, "wallet.db"))
if err != nil { if err != nil {
t.Fatalf("Failed to create wallet DB: %v", err) t.Fatalf("Failed to create wallet DB: %v", err)
} }
mgrNamespace, err := db.Namespace([]byte("waddrmgr")) var addrMgr *waddrmgr.Manager
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs, err := tx.CreateTopLevelBucket(addrmgrNamespaceKey)
if err != nil {
return err
}
votingpoolNs, err := tx.CreateTopLevelBucket(votingpoolNamespaceKey)
if err != nil {
return err
}
fastScrypt := &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
err = waddrmgr.Create(addrmgrNs, seed, pubPassphrase, privPassphrase,
&chaincfg.MainNetParams, fastScrypt)
if err != nil {
return err
}
addrMgr, err = waddrmgr.Open(addrmgrNs, pubPassphrase, &chaincfg.MainNetParams)
if err != nil {
return err
}
pool, err = Create(votingpoolNs, addrMgr, []byte{0x00})
return err
})
if err != nil { if err != nil {
t.Fatalf("Failed to create addr manager DB namespace: %v", err) t.Fatalf("Could not set up DB: %v", err)
}
var fastScrypt = &waddrmgr.ScryptOptions{N: 16, R: 8, P: 1}
err = waddrmgr.Create(mgrNamespace, seed, pubPassphrase, privPassphrase,
&chaincfg.MainNetParams, fastScrypt)
if err == nil {
mgr, err = waddrmgr.Open(mgrNamespace, pubPassphrase,
&chaincfg.MainNetParams, nil)
}
if err != nil {
t.Fatalf("Failed to create addr manager: %v", err)
}
// Create a walletdb for votingpools.
vpNamespace, err := db.Namespace([]byte("votingpool"))
if err != nil {
t.Fatalf("Failed to create VotingPool DB namespace: %v", err)
}
pool, err = Create(vpNamespace, mgr, []byte{0x00})
if err != nil {
t.Fatalf("Voting Pool creation failed: %v", err)
} }
tearDownFunc = func() { tearDownFunc = func() {
addrMgr.Close()
db.Close() db.Close()
mgr.Close()
os.RemoveAll(dir) os.RemoveAll(dir)
} }
return tearDownFunc, mgr, pool return tearDownFunc, db, pool
}
func TstCreateTxStore(t *testing.T, db walletdb.DB) *wtxmgr.Store {
var store *wtxmgr.Store
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
txmgrNs, err := tx.CreateTopLevelBucket(txmgrNamespaceKey)
if err != nil {
return err
}
err = wtxmgr.Create(txmgrNs)
if err != nil {
return err
}
store, err = wtxmgr.Open(txmgrNs, &chaincfg.MainNetParams)
return err
})
if err != nil {
t.Fatalf("Failed to create txmgr: %v", err)
}
return store
} }
func TstNewOutputRequest(t *testing.T, transaction uint32, address string, amount btcutil.Amount, func TstNewOutputRequest(t *testing.T, transaction uint32, address string, amount btcutil.Amount,
@ -406,12 +419,13 @@ func TstNewWithdrawalOutput(r OutputRequest, status outputStatus,
return output return output
} }
func TstNewWithdrawalAddress(t *testing.T, p *Pool, seriesID uint32, branch Branch, func TstNewWithdrawalAddress(t *testing.T, dbtx walletdb.ReadWriteTx, p *Pool, seriesID uint32, branch Branch,
index Index) (addr *WithdrawalAddress) { index Index) (addr *WithdrawalAddress) {
TstEnsureUsedAddr(t, p, seriesID, branch, index) TstEnsureUsedAddr(t, dbtx, p, seriesID, branch, index)
ns, addrmgrNs := TstRNamespaces(dbtx)
var err error var err error
TstRunWithManagerUnlocked(t, p.Manager(), func() { TstRunWithManagerUnlocked(t, p.Manager(), addrmgrNs, func() {
addr, err = p.WithdrawalAddress(seriesID, branch, index) addr, err = p.WithdrawalAddress(ns, addrmgrNs, seriesID, branch, index)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to get WithdrawalAddress: %v", err) t.Fatalf("Failed to get WithdrawalAddress: %v", err)
@ -431,17 +445,17 @@ func TstConstantFee(fee btcutil.Amount) func() btcutil.Amount {
return func() btcutil.Amount { return fee } return func() btcutil.Amount { return fee }
} }
func createAndFulfillWithdrawalRequests(t *testing.T, pool *Pool, roundID uint32) withdrawalInfo { func createAndFulfillWithdrawalRequests(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, roundID uint32) withdrawalInfo {
params := pool.Manager().ChainParams() params := pool.Manager().ChainParams()
seriesID, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{2e6, 4e6}) seriesID, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{2e6, 4e6})
requests := []OutputRequest{ requests := []OutputRequest{
TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 3e6, params), TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 3e6, params),
TstNewOutputRequest(t, 2, "3PbExiaztsSYgh6zeMswC49hLUwhTQ86XG", 2e6, params), TstNewOutputRequest(t, 2, "3PbExiaztsSYgh6zeMswC49hLUwhTQ86XG", 2e6, params),
} }
changeStart := TstNewChangeAddress(t, pool, seriesID, 0) changeStart := TstNewChangeAddress(t, pool, seriesID, 0)
dustThreshold := btcutil.Amount(1e4) dustThreshold := btcutil.Amount(1e4)
startAddr := TstNewWithdrawalAddress(t, pool, seriesID, 1, 0) startAddr := TstNewWithdrawalAddress(t, dbtx, pool, seriesID, 1, 0)
lastSeriesID := seriesID lastSeriesID := seriesID
w := newWithdrawal(roundID, requests, eligible, *changeStart) w := newWithdrawal(roundID, requests, eligible, *changeStart)
if err := w.fulfillRequests(); err != nil { if err := w.fulfillRequests(); err != nil {

View file

@ -13,6 +13,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/btcsuite/btcwallet/wtxmgr" "github.com/btcsuite/btcwallet/wtxmgr"
) )
@ -22,35 +23,42 @@ var (
) )
func TestGetEligibleInputs(t *testing.T) { func TestGetEligibleInputs(t *testing.T) {
tearDown, pool, store := TstCreatePoolAndTxStore(t) tearDown, db, pool, store := TstCreatePoolAndTxStore(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
series := []TstSeriesDef{ series := []TstSeriesDef{
{ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1}, {ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1},
{ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2}, {ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2},
} }
TstCreateSeries(t, pool, series) TstCreateSeries(t, dbtx, pool, series)
scripts := append( scripts := append(
getPKScriptsForAddressRange(t, pool, 1, 0, 2, 0, 4), getPKScriptsForAddressRange(t, dbtx, pool, 1, 0, 2, 0, 4),
getPKScriptsForAddressRange(t, pool, 2, 0, 2, 0, 6)...) getPKScriptsForAddressRange(t, dbtx, pool, 2, 0, 2, 0, 6)...)
// Create two eligible inputs locked to each of the PKScripts above. // Create two eligible inputs locked to each of the PKScripts above.
expNoEligibleInputs := 2 * len(scripts) expNoEligibleInputs := 2 * len(scripts)
eligibleAmounts := []int64{int64(dustThreshold + 1), int64(dustThreshold + 1)} eligibleAmounts := []int64{int64(dustThreshold + 1), int64(dustThreshold + 1)}
var inputs []wtxmgr.Credit var inputs []wtxmgr.Credit
for i := 0; i < len(scripts); i++ { for i := 0; i < len(scripts); i++ {
created := TstCreateCreditsOnStore(t, store, scripts[i], eligibleAmounts) created := TstCreateCreditsOnStore(t, dbtx, store, scripts[i], eligibleAmounts)
inputs = append(inputs, created...) inputs = append(inputs, created...)
} }
startAddr := TstNewWithdrawalAddress(t, pool, 1, 0, 0) startAddr := TstNewWithdrawalAddress(t, dbtx, pool, 1, 0, 0)
lastSeriesID := uint32(2) lastSeriesID := uint32(2)
currentBlock := int32(TstInputsBlock + eligibleInputMinConfirmations + 1) currentBlock := int32(TstInputsBlock + eligibleInputMinConfirmations + 1)
var eligibles []credit var eligibles []credit
var err error txmgrNs := dbtx.ReadBucket(txmgrNamespaceKey)
TstRunWithManagerUnlocked(t, pool.Manager(), func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
eligibles, err = pool.getEligibleInputs( eligibles, err = pool.getEligibleInputs(ns, addrmgrNs,
store, *startAddr, lastSeriesID, dustThreshold, int32(currentBlock), store, txmgrNs, *startAddr, lastSeriesID, dustThreshold, int32(currentBlock),
eligibleInputMinConfirmations) eligibleInputMinConfirmations)
}) })
if err != nil { if err != nil {
@ -73,29 +81,35 @@ func TestGetEligibleInputs(t *testing.T) {
} }
func TestNextAddrWithVaryingHighestIndices(t *testing.T) { func TestNextAddrWithVaryingHighestIndices(t *testing.T) {
tearDown, mgr, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
series := []TstSeriesDef{ series := []TstSeriesDef{
{ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1}, {ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1},
} }
TstCreateSeries(t, pool, series) TstCreateSeries(t, dbtx, pool, series)
stopSeriesID := uint32(2) stopSeriesID := uint32(2)
// Populate the used addr DB for branch 0 and indices ranging from 0 to 2. // Populate the used addr DB for branch 0 and indices ranging from 0 to 2.
TstEnsureUsedAddr(t, pool, 1, Branch(0), 2) TstEnsureUsedAddr(t, dbtx, pool, 1, Branch(0), 2)
// Populate the used addr DB for branch 1 and indices ranging from 0 to 1. // Populate the used addr DB for branch 1 and indices ranging from 0 to 1.
TstEnsureUsedAddr(t, pool, 1, Branch(1), 1) TstEnsureUsedAddr(t, dbtx, pool, 1, Branch(1), 1)
// Start with the address for branch==0, index==1. // Start with the address for branch==0, index==1.
addr := TstNewWithdrawalAddress(t, pool, 1, 0, 1) addr := TstNewWithdrawalAddress(t, dbtx, pool, 1, 0, 1)
var err error
// The first call to nextAddr() should give us the address for branch==1 // The first call to nextAddr() should give us the address for branch==1
// and index==1. // and index==1.
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID) addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to get next address: %v", err) t.Fatalf("Failed to get next address: %v", err)
@ -104,8 +118,8 @@ func TestNextAddrWithVaryingHighestIndices(t *testing.T) {
// The next call should give us the address for branch==0, index==2 since // The next call should give us the address for branch==0, index==2 since
// there are no used addresses for branch==2. // there are no used addresses for branch==2.
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID) addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to get next address: %v", err) t.Fatalf("Failed to get next address: %v", err)
@ -114,8 +128,8 @@ func TestNextAddrWithVaryingHighestIndices(t *testing.T) {
// Since the last addr for branch==1 was the one with index==1, a subsequent // Since the last addr for branch==1 was the one with index==1, a subsequent
// call will return nil. // call will return nil.
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID) addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to get next address: %v", err) t.Fatalf("Failed to get next address: %v", err)
@ -126,29 +140,35 @@ func TestNextAddrWithVaryingHighestIndices(t *testing.T) {
} }
func TestNextAddr(t *testing.T) { func TestNextAddr(t *testing.T) {
tearDown, mgr, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
series := []TstSeriesDef{ series := []TstSeriesDef{
{ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1}, {ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1},
{ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2}, {ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2},
} }
TstCreateSeries(t, pool, series) TstCreateSeries(t, dbtx, pool, series)
stopSeriesID := uint32(3) stopSeriesID := uint32(3)
lastIdx := Index(10) lastIdx := Index(10)
// Populate used addresses DB with entries for seriesID==1, branch==0..3, // Populate used addresses DB with entries for seriesID==1, branch==0..3,
// idx==0..10. // idx==0..10.
for _, i := range []int{0, 1, 2, 3} { for _, i := range []int{0, 1, 2, 3} {
TstEnsureUsedAddr(t, pool, 1, Branch(i), lastIdx) TstEnsureUsedAddr(t, dbtx, pool, 1, Branch(i), lastIdx)
} }
addr := TstNewWithdrawalAddress(t, pool, 1, 0, lastIdx-1) addr := TstNewWithdrawalAddress(t, dbtx, pool, 1, 0, lastIdx-1)
var err error
// nextAddr() first increments just the branch, which ranges from 0 to 3 // nextAddr() first increments just the branch, which ranges from 0 to 3
// here (because our series has 3 public keys). // here (because our series has 3 public keys).
for _, i := range []int{1, 2, 3} { for _, i := range []int{1, 2, 3} {
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID) addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to get next address: %v", err) t.Fatalf("Failed to get next address: %v", err)
@ -160,8 +180,8 @@ func TestNextAddr(t *testing.T) {
// idx=lastIdx-1, so the next 4 calls should give us the addresses with // idx=lastIdx-1, so the next 4 calls should give us the addresses with
// branch=[0-3] and idx=lastIdx. // branch=[0-3] and idx=lastIdx.
for _, i := range []int{0, 1, 2, 3} { for _, i := range []int{0, 1, 2, 3} {
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID) addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to get next address: %v", err) t.Fatalf("Failed to get next address: %v", err)
@ -172,13 +192,13 @@ func TestNextAddr(t *testing.T) {
// Populate used addresses DB with entries for seriesID==2, branch==0..3, // Populate used addresses DB with entries for seriesID==2, branch==0..3,
// idx==0..10. // idx==0..10.
for _, i := range []int{0, 1, 2, 3} { for _, i := range []int{0, 1, 2, 3} {
TstEnsureUsedAddr(t, pool, 2, Branch(i), lastIdx) TstEnsureUsedAddr(t, dbtx, pool, 2, Branch(i), lastIdx)
} }
// Now we've gone through all the available branch/idx combinations, so // Now we've gone through all the available branch/idx combinations, so
// we should move to the next series and start again with branch=0, idx=0. // we should move to the next series and start again with branch=0, idx=0.
for _, i := range []int{0, 1, 2, 3} { for _, i := range []int{0, 1, 2, 3} {
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID) addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to get next address: %v", err) t.Fatalf("Failed to get next address: %v", err)
@ -188,9 +208,9 @@ func TestNextAddr(t *testing.T) {
// Finally check that nextAddr() returns nil when we've reached the last // Finally check that nextAddr() returns nil when we've reached the last
// available address before stopSeriesID. // available address before stopSeriesID.
addr = TstNewWithdrawalAddress(t, pool, 2, 3, lastIdx) addr = TstNewWithdrawalAddress(t, dbtx, pool, 2, 3, lastIdx)
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID) addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to get next address: %v", err) t.Fatalf("Failed to get next address: %v", err)
@ -201,11 +221,17 @@ func TestNextAddr(t *testing.T) {
} }
func TestEligibleInputsAreEligible(t *testing.T) { func TestEligibleInputsAreEligible(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
var chainHeight int32 = 1000 var chainHeight int32 = 1000
_, credits := TstCreateCreditsOnNewSeries(t, pool, []int64{int64(dustThreshold)}) _, credits := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{int64(dustThreshold)})
c := credits[0] c := credits[0]
// Make sure credit is old enough to pass the minConf check. // Make sure credit is old enough to pass the minConf check.
c.BlockMeta.Height = int32(eligibleInputMinConfirmations) c.BlockMeta.Height = int32(eligibleInputMinConfirmations)
@ -216,11 +242,17 @@ func TestEligibleInputsAreEligible(t *testing.T) {
} }
func TestNonEligibleInputsAreNotEligible(t *testing.T) { func TestNonEligibleInputsAreNotEligible(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
var chainHeight int32 = 1000 var chainHeight int32 = 1000
_, credits := TstCreateCreditsOnNewSeries(t, pool, []int64{int64(dustThreshold - 1)}) _, credits := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{int64(dustThreshold - 1)})
c := credits[0] c := credits[0]
// Make sure credit is old enough to pass the minConf check. // Make sure credit is old enough to pass the minConf check.
c.BlockMeta.Height = int32(eligibleInputMinConfirmations) c.BlockMeta.Height = int32(eligibleInputMinConfirmations)
@ -231,7 +263,7 @@ func TestNonEligibleInputsAreNotEligible(t *testing.T) {
} }
// Check that a credit with not enough confirmations is rejected. // Check that a credit with not enough confirmations is rejected.
_, credits = TstCreateCreditsOnNewSeries(t, pool, []int64{int64(dustThreshold)}) _, credits = TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{int64(dustThreshold)})
c = credits[0] c = credits[0]
// The calculation of if it has been confirmed does this: chainheigt - bh + // The calculation of if it has been confirmed does this: chainheigt - bh +
// 1 >= target, which is quite weird, but the reason why I need to put 902 // 1 >= target, which is quite weird, but the reason why I need to put 902
@ -243,25 +275,31 @@ func TestNonEligibleInputsAreNotEligible(t *testing.T) {
} }
func TestCreditSortingByAddress(t *testing.T) { func TestCreditSortingByAddress(t *testing.T) {
teardown, _, pool := TstCreatePool(t) teardown, db, pool := TstCreatePool(t)
defer teardown() defer teardown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
series := []TstSeriesDef{ series := []TstSeriesDef{
{ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1}, {ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1},
{ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2}, {ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2},
} }
TstCreateSeries(t, pool, series) TstCreateSeries(t, dbtx, pool, series)
shaHash0 := bytes.Repeat([]byte{0}, 32) shaHash0 := bytes.Repeat([]byte{0}, 32)
shaHash1 := bytes.Repeat([]byte{1}, 32) shaHash1 := bytes.Repeat([]byte{1}, 32)
shaHash2 := bytes.Repeat([]byte{2}, 32) shaHash2 := bytes.Repeat([]byte{2}, 32)
c0 := newDummyCredit(t, pool, 1, 0, 0, shaHash0, 0) c0 := newDummyCredit(t, dbtx, pool, 1, 0, 0, shaHash0, 0)
c1 := newDummyCredit(t, pool, 1, 0, 0, shaHash0, 1) c1 := newDummyCredit(t, dbtx, pool, 1, 0, 0, shaHash0, 1)
c2 := newDummyCredit(t, pool, 1, 0, 0, shaHash1, 0) c2 := newDummyCredit(t, dbtx, pool, 1, 0, 0, shaHash1, 0)
c3 := newDummyCredit(t, pool, 1, 0, 0, shaHash2, 0) c3 := newDummyCredit(t, dbtx, pool, 1, 0, 0, shaHash2, 0)
c4 := newDummyCredit(t, pool, 1, 0, 1, shaHash0, 0) c4 := newDummyCredit(t, dbtx, pool, 1, 0, 1, shaHash0, 0)
c5 := newDummyCredit(t, pool, 1, 1, 0, shaHash0, 0) c5 := newDummyCredit(t, dbtx, pool, 1, 1, 0, shaHash0, 0)
c6 := newDummyCredit(t, pool, 2, 0, 0, shaHash0, 0) c6 := newDummyCredit(t, dbtx, pool, 2, 0, 0, shaHash0, 0)
randomCredits := [][]credit{ randomCredits := [][]credit{
{c6, c5, c4, c3, c2, c1, c0}, {c6, c5, c4, c3, c2, c1, c0},
@ -292,7 +330,7 @@ func TestCreditSortingByAddress(t *testing.T) {
// newDummyCredit creates a new credit with the given hash and outpointIdx, // newDummyCredit creates a new credit with the given hash and outpointIdx,
// locked to the votingpool address identified by the given // locked to the votingpool address identified by the given
// series/index/branch. // series/index/branch.
func newDummyCredit(t *testing.T, pool *Pool, series uint32, index Index, branch Branch, func newDummyCredit(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, series uint32, index Index, branch Branch,
txHash []byte, outpointIdx uint32) credit { txHash []byte, outpointIdx uint32) credit {
var hash chainhash.Hash var hash chainhash.Hash
if err := hash.SetBytes(txHash); err != nil { if err := hash.SetBytes(txHash); err != nil {
@ -300,8 +338,8 @@ func newDummyCredit(t *testing.T, pool *Pool, series uint32, index Index, branch
} }
// Ensure the address defined by the given series/branch/index is present on // Ensure the address defined by the given series/branch/index is present on
// the set of used addresses as that's a requirement of WithdrawalAddress. // the set of used addresses as that's a requirement of WithdrawalAddress.
TstEnsureUsedAddr(t, pool, series, branch, index) TstEnsureUsedAddr(t, dbtx, pool, series, branch, index)
addr := TstNewWithdrawalAddress(t, pool, series, branch, index) addr := TstNewWithdrawalAddress(t, dbtx, pool, series, branch, index)
c := wtxmgr.Credit{ c := wtxmgr.Credit{
OutPoint: wire.OutPoint{ OutPoint: wire.OutPoint{
Hash: hash, Hash: hash,
@ -337,12 +375,12 @@ func checkUniqueness(t *testing.T, credits byAddress) {
} }
} }
func getPKScriptsForAddressRange(t *testing.T, pool *Pool, seriesID uint32, func getPKScriptsForAddressRange(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, seriesID uint32,
startBranch, stopBranch Branch, startIdx, stopIdx Index) [][]byte { startBranch, stopBranch Branch, startIdx, stopIdx Index) [][]byte {
var pkScripts [][]byte var pkScripts [][]byte
for idx := startIdx; idx <= stopIdx; idx++ { for idx := startIdx; idx <= stopIdx; idx++ {
for branch := startBranch; branch <= stopBranch; branch++ { for branch := startBranch; branch <= stopBranch; branch++ {
pkScripts = append(pkScripts, TstCreatePkScript(t, pool, seriesID, branch, idx)) pkScripts = append(pkScripts, TstCreatePkScript(t, dbtx, pool, seriesID, branch, idx))
} }
} }
return pkScripts return pkScripts

View file

@ -16,37 +16,24 @@ var TstLastErr = lastErr
const TstEligibleInputMinConfirmations = eligibleInputMinConfirmations const TstEligibleInputMinConfirmations = eligibleInputMinConfirmations
// TstPutSeries transparently wraps the voting pool putSeries method. // TstPutSeries transparently wraps the voting pool putSeries method.
func (vp *Pool) TstPutSeries(version, seriesID, reqSigs uint32, inRawPubKeys []string) error { func (vp *Pool) TstPutSeries(ns walletdb.ReadWriteBucket, version, seriesID, reqSigs uint32, inRawPubKeys []string) error {
return vp.putSeries(version, seriesID, reqSigs, inRawPubKeys) return vp.putSeries(ns, version, seriesID, reqSigs, inRawPubKeys)
} }
var TstBranchOrder = branchOrder var TstBranchOrder = branchOrder
// TstExistsSeries checks whether a series is stored in the database. // TstExistsSeries checks whether a series is stored in the database.
func (vp *Pool) TstExistsSeries(seriesID uint32) (bool, error) { func (vp *Pool) TstExistsSeries(dbtx walletdb.ReadTx, seriesID uint32) (bool, error) {
var exists bool ns, _ := TstRNamespaces(dbtx)
err := vp.namespace.View( poolBucket := ns.NestedReadBucket(vp.ID)
func(tx walletdb.Tx) error { if poolBucket == nil {
poolBucket := tx.RootBucket().Bucket(vp.ID) return false, nil
if poolBucket == nil {
return nil
}
bucket := poolBucket.Bucket(seriesBucketName)
if bucket == nil {
return nil
}
exists = bucket.Get(uint32ToBytes(seriesID)) != nil
return nil
})
if err != nil {
return false, err
} }
return exists, nil bucket := poolBucket.NestedReadBucket(seriesBucketName)
} if bucket == nil {
return false, nil
// TstNamespace exposes the Pool's namespace as it's needed in some tests. }
func (vp *Pool) TstNamespace() walletdb.Namespace { return bucket.Get(uint32ToBytes(seriesID)) != nil, nil
return vp.namespace
} }
// TstGetRawPublicKeys gets a series public keys in string format. // TstGetRawPublicKeys gets a series public keys in string format.

View file

@ -19,18 +19,26 @@ import (
) )
func TestLoadPoolAndDepositScript(t *testing.T) { func TestLoadPoolAndDepositScript(t *testing.T) {
tearDown, manager, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
// setup // setup
poolID := "test" poolID := "test"
pubKeys := vp.TstPubKeys[0:3] pubKeys := vp.TstPubKeys[0:3]
err := vp.LoadAndCreateSeries(pool.TstNamespace(), manager, 1, poolID, 1, 2, pubKeys) err = vp.LoadAndCreateSeries(ns, pool.Manager(), 1, poolID, 1, 2, pubKeys)
if err != nil { if err != nil {
t.Fatalf("Failed to create voting pool and series: %v", err) t.Fatalf("Failed to create voting pool and series: %v", err)
} }
// execute // execute
script, err := vp.LoadAndGetDepositScript(pool.TstNamespace(), manager, poolID, 1, 0, 0) script, err := vp.LoadAndGetDepositScript(ns, pool.Manager(), poolID, 1, 0, 0)
if err != nil { if err != nil {
t.Fatalf("Failed to get deposit script: %v", err) t.Fatalf("Failed to get deposit script: %v", err)
} }
@ -45,21 +53,28 @@ func TestLoadPoolAndDepositScript(t *testing.T) {
} }
func TestLoadPoolAndCreateSeries(t *testing.T) { func TestLoadPoolAndCreateSeries(t *testing.T) {
tearDown, manager, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
poolID := "test" poolID := "test"
// first time, the voting pool is created // first time, the voting pool is created
pubKeys := vp.TstPubKeys[0:3] pubKeys := vp.TstPubKeys[0:3]
err := vp.LoadAndCreateSeries(pool.TstNamespace(), manager, 1, poolID, 1, 2, pubKeys) err = vp.LoadAndCreateSeries(ns, pool.Manager(), 1, poolID, 1, 2, pubKeys)
if err != nil { if err != nil {
t.Fatalf("Creating voting pool and Creating series failed: %v", err) t.Fatalf("Creating voting pool and Creating series failed: %v", err)
} }
// create another series where the voting pool is loaded this time // create another series where the voting pool is loaded this time
pubKeys = vp.TstPubKeys[3:6] pubKeys = vp.TstPubKeys[3:6]
err = vp.LoadAndCreateSeries(pool.TstNamespace(), manager, 1, poolID, 2, 2, pubKeys) err = vp.LoadAndCreateSeries(ns, pool.Manager(), 1, poolID, 2, 2, pubKeys)
if err != nil { if err != nil {
t.Fatalf("Loading voting pool and Creating series failed: %v", err) t.Fatalf("Loading voting pool and Creating series failed: %v", err)
@ -67,38 +82,52 @@ func TestLoadPoolAndCreateSeries(t *testing.T) {
} }
func TestLoadPoolAndReplaceSeries(t *testing.T) { func TestLoadPoolAndReplaceSeries(t *testing.T) {
tearDown, manager, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
// setup // setup
poolID := "test" poolID := "test"
pubKeys := vp.TstPubKeys[0:3] pubKeys := vp.TstPubKeys[0:3]
err := vp.LoadAndCreateSeries(pool.TstNamespace(), manager, 1, poolID, 1, 2, pubKeys) err = vp.LoadAndCreateSeries(ns, pool.Manager(), 1, poolID, 1, 2, pubKeys)
if err != nil { if err != nil {
t.Fatalf("Failed to create voting pool and series: %v", err) t.Fatalf("Failed to create voting pool and series: %v", err)
} }
pubKeys = vp.TstPubKeys[3:6] pubKeys = vp.TstPubKeys[3:6]
err = vp.LoadAndReplaceSeries(pool.TstNamespace(), manager, 1, poolID, 1, 2, pubKeys) err = vp.LoadAndReplaceSeries(ns, pool.Manager(), 1, poolID, 1, 2, pubKeys)
if err != nil { if err != nil {
t.Fatalf("Failed to replace series: %v", err) t.Fatalf("Failed to replace series: %v", err)
} }
} }
func TestLoadPoolAndEmpowerSeries(t *testing.T) { func TestLoadPoolAndEmpowerSeries(t *testing.T) {
tearDown, manager, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
// setup // setup
poolID := "test" poolID := "test"
pubKeys := vp.TstPubKeys[0:3] pubKeys := vp.TstPubKeys[0:3]
err := vp.LoadAndCreateSeries(pool.TstNamespace(), manager, 1, poolID, 1, 2, pubKeys) err = vp.LoadAndCreateSeries(ns, pool.Manager(), 1, poolID, 1, 2, pubKeys)
if err != nil { if err != nil {
t.Fatalf("Creating voting pool and Creating series failed: %v", err) t.Fatalf("Creating voting pool and Creating series failed: %v", err)
} }
vp.TstRunWithManagerUnlocked(t, pool.Manager(), func() { vp.TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
err = vp.LoadAndEmpowerSeries(pool.TstNamespace(), manager, poolID, 1, vp.TstPrivKeys[0]) err = vp.LoadAndEmpowerSeries(ns, pool.Manager(), poolID, 1, vp.TstPrivKeys[0])
}) })
if err != nil { if err != nil {
t.Fatalf("Load voting pool and Empower series failed: %v", err) t.Fatalf("Load voting pool and Empower series failed: %v", err)
@ -106,9 +135,16 @@ func TestLoadPoolAndEmpowerSeries(t *testing.T) {
} }
func TestDepositScriptAddress(t *testing.T) { func TestDepositScriptAddress(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
tests := []struct { tests := []struct {
version uint32 version uint32
series uint32 series uint32
@ -132,7 +168,7 @@ func TestDepositScriptAddress(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
if err := pool.CreateSeries(test.version, test.series, if err := pool.CreateSeries(ns, test.version, test.series,
test.reqSigs, test.pubKeys); err != nil { test.reqSigs, test.pubKeys); err != nil {
t.Fatalf("Cannot creates series %v", test.series) t.Fatalf("Cannot creates series %v", test.series)
} }
@ -160,24 +196,39 @@ func TestDepositScriptAddressForNonExistentSeries(t *testing.T) {
} }
func TestDepositScriptAddressForHardenedPubKey(t *testing.T) { func TestDepositScriptAddressForHardenedPubKey(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
if err := pool.CreateSeries(1, 1, 2, vp.TstPubKeys[0:3]); err != nil {
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
if err := pool.CreateSeries(ns, 1, 1, 2, vp.TstPubKeys[0:3]); err != nil {
t.Fatalf("Cannot creates series") t.Fatalf("Cannot creates series")
} }
// Ask for a DepositScriptAddress using an index for a hardened child, which should // Ask for a DepositScriptAddress using an index for a hardened child, which should
// fail as we use the extended public keys to derive childs. // fail as we use the extended public keys to derive childs.
_, err := pool.DepositScriptAddress(1, 0, vp.Index(hdkeychain.HardenedKeyStart+1)) _, err = pool.DepositScriptAddress(1, 0, vp.Index(hdkeychain.HardenedKeyStart+1))
vp.TstCheckError(t, "", err, vp.ErrKeyChain) vp.TstCheckError(t, "", err, vp.ErrKeyChain)
} }
func TestLoadPool(t *testing.T) { func TestLoadPool(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
pool2, err := vp.Load(pool.TstNamespace(), mgr, pool.ID) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
pool2, err := vp.Load(ns, pool.Manager(), pool.ID)
if err != nil { if err != nil {
t.Errorf("Error loading Pool: %v", err) t.Errorf("Error loading Pool: %v", err)
} }
@ -187,10 +238,17 @@ func TestLoadPool(t *testing.T) {
} }
func TestCreatePool(t *testing.T) { func TestCreatePool(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
pool2, err := vp.Create(pool.TstNamespace(), mgr, []byte{0x02}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
pool2, err := vp.Create(ns, pool.Manager(), []byte{0x02})
if err != nil { if err != nil {
t.Errorf("Error creating Pool: %v", err) t.Errorf("Error creating Pool: %v", err)
} }
@ -200,18 +258,32 @@ func TestCreatePool(t *testing.T) {
} }
func TestCreatePoolWhenAlreadyExists(t *testing.T) { func TestCreatePoolWhenAlreadyExists(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
_, err := vp.Create(pool.TstNamespace(), mgr, pool.ID) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
_, err = vp.Create(ns, pool.Manager(), pool.ID)
vp.TstCheckError(t, "", err, vp.ErrPoolAlreadyExists) vp.TstCheckError(t, "", err, vp.ErrPoolAlreadyExists)
} }
func TestCreateSeries(t *testing.T) { func TestCreateSeries(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
tests := []struct { tests := []struct {
version uint32 version uint32
series uint32 series uint32
@ -245,11 +317,11 @@ func TestCreateSeries(t *testing.T) {
} }
for testNum, test := range tests { for testNum, test := range tests {
err := pool.CreateSeries(test.version, test.series, test.reqSigs, test.pubKeys[:]) err := pool.CreateSeries(ns, test.version, test.series, test.reqSigs, test.pubKeys[:])
if err != nil { if err != nil {
t.Fatalf("%d: Cannot create series %d", testNum, test.series) t.Fatalf("%d: Cannot create series %d", testNum, test.series)
} }
exists, err := pool.TstExistsSeries(test.series) exists, err := pool.TstExistsSeries(dbtx, test.series)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -260,45 +332,74 @@ func TestCreateSeries(t *testing.T) {
} }
func TestPoolCreateSeriesInvalidID(t *testing.T) { func TestPoolCreateSeriesInvalidID(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
err := pool.CreateSeries(vp.CurrentVersion, 0, 1, vp.TstPubKeys[0:3]) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
err = pool.CreateSeries(ns, vp.CurrentVersion, 0, 1, vp.TstPubKeys[0:3])
vp.TstCheckError(t, "", err, vp.ErrSeriesIDInvalid) vp.TstCheckError(t, "", err, vp.ErrSeriesIDInvalid)
} }
func TestPoolCreateSeriesWhenAlreadyExists(t *testing.T) { func TestPoolCreateSeriesWhenAlreadyExists(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
pubKeys := vp.TstPubKeys[0:3] pubKeys := vp.TstPubKeys[0:3]
if err := pool.CreateSeries(1, 1, 1, pubKeys); err != nil { if err := pool.CreateSeries(ns, 1, 1, 1, pubKeys); err != nil {
t.Fatalf("Cannot create series: %v", err) t.Fatalf("Cannot create series: %v", err)
} }
err := pool.CreateSeries(1, 1, 1, pubKeys) err = pool.CreateSeries(ns, 1, 1, 1, pubKeys)
vp.TstCheckError(t, "", err, vp.ErrSeriesAlreadyExists) vp.TstCheckError(t, "", err, vp.ErrSeriesAlreadyExists)
} }
func TestPoolCreateSeriesIDNotSequential(t *testing.T) { func TestPoolCreateSeriesIDNotSequential(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
pubKeys := vp.TstPubKeys[0:4] pubKeys := vp.TstPubKeys[0:4]
if err := pool.CreateSeries(1, 1, 2, pubKeys); err != nil { if err := pool.CreateSeries(ns, 1, 1, 2, pubKeys); err != nil {
t.Fatalf("Cannot create series: %v", err) t.Fatalf("Cannot create series: %v", err)
} }
err := pool.CreateSeries(1, 3, 2, pubKeys) err = pool.CreateSeries(ns, 1, 3, 2, pubKeys)
vp.TstCheckError(t, "", err, vp.ErrSeriesIDNotSequential) vp.TstCheckError(t, "", err, vp.ErrSeriesIDNotSequential)
} }
func TestPutSeriesErrors(t *testing.T) { func TestPutSeriesErrors(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
tests := []struct { tests := []struct {
version uint32 version uint32
reqSigs uint32 reqSigs uint32
@ -335,40 +436,54 @@ func TestPutSeriesErrors(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
err := pool.TstPutSeries(test.version, uint32(i+1), test.reqSigs, test.pubKeys) err := pool.TstPutSeries(ns, test.version, uint32(i+1), test.reqSigs, test.pubKeys)
vp.TstCheckError(t, fmt.Sprintf("Create series #%d", i), err, test.err) vp.TstCheckError(t, fmt.Sprintf("Create series #%d", i), err, test.err)
} }
} }
func TestCannotReplaceEmpoweredSeries(t *testing.T) { func TestCannotReplaceEmpoweredSeries(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
seriesID := uint32(1) seriesID := uint32(1)
if err := pool.CreateSeries(1, seriesID, 3, vp.TstPubKeys[0:4]); err != nil { if err := pool.CreateSeries(ns, 1, seriesID, 3, vp.TstPubKeys[0:4]); err != nil {
t.Fatalf("Failed to create series: %v", err) t.Fatalf("Failed to create series: %v", err)
} }
vp.TstRunWithManagerUnlocked(t, mgr, func() { vp.TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
if err := pool.EmpowerSeries(seriesID, vp.TstPrivKeys[1]); err != nil { if err := pool.EmpowerSeries(ns, seriesID, vp.TstPrivKeys[1]); err != nil {
t.Fatalf("Failed to empower series: %v", err) t.Fatalf("Failed to empower series: %v", err)
} }
}) })
err := pool.ReplaceSeries(1, seriesID, 2, []string{vp.TstPubKeys[0], vp.TstPubKeys[2], err = pool.ReplaceSeries(ns, 1, seriesID, 2, []string{vp.TstPubKeys[0], vp.TstPubKeys[2],
vp.TstPubKeys[3]}) vp.TstPubKeys[3]})
vp.TstCheckError(t, "", err, vp.ErrSeriesAlreadyEmpowered) vp.TstCheckError(t, "", err, vp.ErrSeriesAlreadyEmpowered)
} }
func TestReplaceNonExistingSeries(t *testing.T) { func TestReplaceNonExistingSeries(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
pubKeys := vp.TstPubKeys[0:3] pubKeys := vp.TstPubKeys[0:3]
err := pool.ReplaceSeries(1, 1, 3, pubKeys) err = pool.ReplaceSeries(ns, 1, 1, 3, pubKeys)
vp.TstCheckError(t, "", err, vp.ErrSeriesNotExists) vp.TstCheckError(t, "", err, vp.ErrSeriesNotExists)
} }
@ -429,19 +544,26 @@ var replaceSeriesTestData = []replaceSeriesTestEntry{
} }
func TestReplaceExistingSeries(t *testing.T) { func TestReplaceExistingSeries(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
for _, data := range replaceSeriesTestData { for _, data := range replaceSeriesTestData {
seriesID := data.orig.id seriesID := data.orig.id
testID := data.testID testID := data.testID
if err := pool.CreateSeries(data.orig.version, seriesID, data.orig.reqSigs, data.orig.pubKeys); err != nil { if err := pool.CreateSeries(ns, data.orig.version, seriesID, data.orig.reqSigs, data.orig.pubKeys); err != nil {
t.Fatalf("Test #%d: failed to create series in replace series setup: %v", t.Fatalf("Test #%d: failed to create series in replace series setup: %v",
testID, err) testID, err)
} }
if err := pool.ReplaceSeries(data.replaceWith.version, seriesID, if err := pool.ReplaceSeries(ns, data.replaceWith.version, seriesID,
data.replaceWith.reqSigs, data.replaceWith.pubKeys); err != nil { data.replaceWith.reqSigs, data.replaceWith.pubKeys); err != nil {
t.Errorf("Test #%d: replaceSeries failed: %v", testID, err) t.Errorf("Test #%d: replaceSeries failed: %v", testID, err)
} }
@ -480,27 +602,41 @@ func validateReplaceSeries(t *testing.T, pool *vp.Pool, testID int, replacedWith
} }
func TestEmpowerSeries(t *testing.T) { func TestEmpowerSeries(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
seriesID := uint32(1) seriesID := uint32(1)
if err := pool.CreateSeries(1, seriesID, 2, vp.TstPubKeys[0:3]); err != nil { if err := pool.CreateSeries(ns, 1, seriesID, 2, vp.TstPubKeys[0:3]); err != nil {
t.Fatalf("Failed to create series: %v", err) t.Fatalf("Failed to create series: %v", err)
} }
vp.TstRunWithManagerUnlocked(t, mgr, func() { vp.TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
if err := pool.EmpowerSeries(seriesID, vp.TstPrivKeys[0]); err != nil { if err := pool.EmpowerSeries(ns, seriesID, vp.TstPrivKeys[0]); err != nil {
t.Errorf("Failed to empower series: %v", err) t.Errorf("Failed to empower series: %v", err)
} }
}) })
} }
func TestEmpowerSeriesErrors(t *testing.T) { func TestEmpowerSeriesErrors(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
seriesID := uint32(1) seriesID := uint32(1)
if err := pool.CreateSeries(1, seriesID, 2, vp.TstPubKeys[0:3]); err != nil { if err := pool.CreateSeries(ns, 1, seriesID, 2, vp.TstPubKeys[0:3]); err != nil {
t.Fatalf("Failed to create series: %v", err) t.Fatalf("Failed to create series: %v", err)
} }
@ -536,17 +672,25 @@ func TestEmpowerSeriesErrors(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
err := pool.EmpowerSeries(test.seriesID, test.key) err := pool.EmpowerSeries(ns, test.seriesID, test.key)
vp.TstCheckError(t, fmt.Sprintf("EmpowerSeries #%d", i), err, test.err) vp.TstCheckError(t, fmt.Sprintf("EmpowerSeries #%d", i), err, test.err)
} }
} }
func TestPoolSeries(t *testing.T) { func TestPoolSeries(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
expectedPubKeys := vp.CanonicalKeyOrder(vp.TstPubKeys[0:3]) expectedPubKeys := vp.CanonicalKeyOrder(vp.TstPubKeys[0:3])
if err := pool.CreateSeries(vp.CurrentVersion, 1, 2, expectedPubKeys); err != nil { if err := pool.CreateSeries(ns, vp.CurrentVersion, 1, 2, expectedPubKeys); err != nil {
t.Fatalf("Failed to create series: %v", err) t.Fatalf("Failed to create series: %v", err)
} }
@ -613,15 +757,16 @@ var testLoadAllSeriesTests = []testLoadAllSeriesTest{
}, },
} }
func setUpLoadAllSeries(t *testing.T, namespace walletdb.Namespace, mgr *waddrmgr.Manager, func setUpLoadAllSeries(t *testing.T, dbtx walletdb.ReadWriteTx, mgr *waddrmgr.Manager,
test testLoadAllSeriesTest) *vp.Pool { test testLoadAllSeriesTest) *vp.Pool {
pool, err := vp.Create(namespace, mgr, []byte{byte(test.id + 1)}) ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
pool, err := vp.Create(ns, mgr, []byte{byte(test.id + 1)})
if err != nil { if err != nil {
t.Fatalf("Voting Pool creation failed: %v", err) t.Fatalf("Voting Pool creation failed: %v", err)
} }
for _, series := range test.series { for _, series := range test.series {
err := pool.CreateSeries(series.version, series.id, err := pool.CreateSeries(ns, series.version, series.id,
series.reqSigs, series.pubKeys) series.reqSigs, series.pubKeys)
if err != nil { if err != nil {
t.Fatalf("Test #%d Series #%d: failed to create series: %v", t.Fatalf("Test #%d Series #%d: failed to create series: %v",
@ -629,8 +774,8 @@ func setUpLoadAllSeries(t *testing.T, namespace walletdb.Namespace, mgr *waddrmg
} }
for _, privKey := range series.privKeys { for _, privKey := range series.privKeys {
vp.TstRunWithManagerUnlocked(t, mgr, func() { vp.TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
if err := pool.EmpowerSeries(series.id, privKey); err != nil { if err := pool.EmpowerSeries(ns, series.id, privKey); err != nil {
t.Fatalf("Test #%d Series #%d: empower with privKey %v failed: %v", t.Fatalf("Test #%d Series #%d: empower with privKey %v failed: %v",
test.id, series.id, privKey, err) test.id, series.id, privKey, err)
} }
@ -641,14 +786,21 @@ func setUpLoadAllSeries(t *testing.T, namespace walletdb.Namespace, mgr *waddrmg
} }
func TestLoadAllSeries(t *testing.T) { func TestLoadAllSeries(t *testing.T) {
tearDown, manager, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
for _, test := range testLoadAllSeriesTests { for _, test := range testLoadAllSeriesTests {
pool := setUpLoadAllSeries(t, pool.TstNamespace(), manager, test) pool := setUpLoadAllSeries(t, dbtx, pool.Manager(), test)
pool.TstEmptySeriesLookup() pool.TstEmptySeriesLookup()
vp.TstRunWithManagerUnlocked(t, manager, func() { vp.TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
if err := pool.LoadAllSeries(); err != nil { if err := pool.LoadAllSeries(ns); err != nil {
t.Fatalf("Test #%d: failed to load voting pool: %v", test.id, err) t.Fatalf("Test #%d: failed to load voting pool: %v", test.id, err)
} }
}) })
@ -842,11 +994,18 @@ func TestReverse(t *testing.T) {
} }
func TestEmpowerSeriesNeuterFailed(t *testing.T) { func TestEmpowerSeriesNeuterFailed(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
seriesID := uint32(1) seriesID := uint32(1)
err := pool.CreateSeries(1, seriesID, 2, vp.TstPubKeys[0:3]) err = pool.CreateSeries(ns, 1, seriesID, 2, vp.TstPubKeys[0:3])
if err != nil { if err != nil {
t.Fatalf("Failed to create series: %v", err) t.Fatalf("Failed to create series: %v", err)
} }
@ -855,17 +1014,17 @@ func TestEmpowerSeriesNeuterFailed(t *testing.T) {
// error in (k *ExtendedKey).Neuter and the associated error path // error in (k *ExtendedKey).Neuter and the associated error path
// in EmpowerSeries. // in EmpowerSeries.
badKey := "wM5uZBNTYmaYGiK8VaGi7zPGbZGLuQgDiR2Zk4nGfbRFLXwHGcMUdVdazRpNHFSR7X7WLmzzbAq8dA1ViN6eWKgKqPye1rJTDQTvBiXvZ7E3nmdx" badKey := "wM5uZBNTYmaYGiK8VaGi7zPGbZGLuQgDiR2Zk4nGfbRFLXwHGcMUdVdazRpNHFSR7X7WLmzzbAq8dA1ViN6eWKgKqPye1rJTDQTvBiXvZ7E3nmdx"
err = pool.EmpowerSeries(seriesID, badKey) err = pool.EmpowerSeries(ns, seriesID, badKey)
vp.TstCheckError(t, "", err, vp.ErrKeyNeuter) vp.TstCheckError(t, "", err, vp.ErrKeyNeuter)
} }
func TestDecryptExtendedKeyCannotCreateResultKey(t *testing.T) { func TestDecryptExtendedKeyCannotCreateResultKey(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t) tearDown, _, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
// the plaintext not being base58 encoded triggers the error // the plaintext not being base58 encoded triggers the error
cipherText, err := mgr.Encrypt(waddrmgr.CKTPublic, []byte("not-base58-encoded")) cipherText, err := pool.Manager().Encrypt(waddrmgr.CKTPublic, []byte("not-base58-encoded"))
if err != nil { if err != nil {
t.Fatalf("Failed to encrypt plaintext: %v", err) t.Fatalf("Failed to encrypt plaintext: %v", err)
} }
@ -885,35 +1044,48 @@ func TestDecryptExtendedKeyCannotDecrypt(t *testing.T) {
} }
func TestPoolChangeAddress(t *testing.T) { func TestPoolChangeAddress(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
pubKeys := vp.TstPubKeys[1:4] pubKeys := vp.TstPubKeys[1:4]
vp.TstCreateSeries(t, pool, []vp.TstSeriesDef{{ReqSigs: 2, PubKeys: pubKeys, SeriesID: 1}}) vp.TstCreateSeries(t, dbtx, pool, []vp.TstSeriesDef{{ReqSigs: 2, PubKeys: pubKeys, SeriesID: 1}})
addr := vp.TstNewChangeAddress(t, pool, 1, 0) addr := vp.TstNewChangeAddress(t, pool, 1, 0)
checkPoolAddress(t, addr, 1, 0, 0) checkPoolAddress(t, addr, 1, 0, 0)
// When the series is not active, we should get an error. // When the series is not active, we should get an error.
pubKeys = vp.TstPubKeys[3:6] pubKeys = vp.TstPubKeys[3:6]
vp.TstCreateSeries(t, pool, vp.TstCreateSeries(t, dbtx, pool,
[]vp.TstSeriesDef{{ReqSigs: 2, PubKeys: pubKeys, SeriesID: 2, Inactive: true}}) []vp.TstSeriesDef{{ReqSigs: 2, PubKeys: pubKeys, SeriesID: 2, Inactive: true}})
_, err := pool.ChangeAddress(2, 0) _, err = pool.ChangeAddress(2, 0)
vp.TstCheckError(t, "", err, vp.ErrSeriesNotActive) vp.TstCheckError(t, "", err, vp.ErrSeriesNotActive)
} }
func TestPoolWithdrawalAddress(t *testing.T) { func TestPoolWithdrawalAddress(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t) tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
pubKeys := vp.TstPubKeys[1:4] pubKeys := vp.TstPubKeys[1:4]
vp.TstCreateSeries(t, pool, []vp.TstSeriesDef{{ReqSigs: 2, PubKeys: pubKeys, SeriesID: 1}}) vp.TstCreateSeries(t, dbtx, pool, []vp.TstSeriesDef{{ReqSigs: 2, PubKeys: pubKeys, SeriesID: 1}})
addr := vp.TstNewWithdrawalAddress(t, pool, 1, 0, 0) addr := vp.TstNewWithdrawalAddress(t, dbtx, pool, 1, 0, 0)
checkPoolAddress(t, addr, 1, 0, 0) checkPoolAddress(t, addr, 1, 0, 0)
// When the requested address is not present in the set of used addresses // When the requested address is not present in the set of used addresses
// for that Pool, we should get an error. // for that Pool, we should get an error.
_, err := pool.WithdrawalAddress(1, 2, 3) _, err = pool.WithdrawalAddress(ns, addrmgrNs, 1, 2, 3)
vp.TstCheckError(t, "", err, vp.ErrWithdrawFromUnusedAddr) vp.TstCheckError(t, "", err, vp.ErrWithdrawFromUnusedAddr)
} }

View file

@ -14,26 +14,32 @@ import (
) )
func TestPoolEnsureUsedAddr(t *testing.T) { func TestPoolEnsureUsedAddr(t *testing.T) {
tearDown, mgr, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
var err error dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
var script []byte var script []byte
var addr waddrmgr.ManagedScriptAddress var addr waddrmgr.ManagedScriptAddress
TstCreateSeries(t, pool, []TstSeriesDef{{ReqSigs: 2, PubKeys: TstPubKeys[0:3], SeriesID: 1}}) TstCreateSeries(t, dbtx, pool, []TstSeriesDef{{ReqSigs: 2, PubKeys: TstPubKeys[0:3], SeriesID: 1}})
idx := Index(0) idx := Index(0)
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
err = pool.EnsureUsedAddr(1, 0, idx) err = pool.EnsureUsedAddr(ns, addrmgrNs, 1, 0, idx)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to ensure used addresses: %v", err) t.Fatalf("Failed to ensure used addresses: %v", err)
} }
addr, err = pool.getUsedAddr(1, 0, 0) addr, err = pool.getUsedAddr(ns, addrmgrNs, 1, 0, 0)
if err != nil { if err != nil {
t.Fatalf("Failed to get addr from used addresses set: %v", err) t.Fatalf("Failed to get addr from used addresses set: %v", err)
} }
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
script, err = addr.Script() script, err = addr.Script()
}) })
if err != nil { if err != nil {
@ -45,18 +51,18 @@ func TestPoolEnsureUsedAddr(t *testing.T) {
} }
idx = Index(3) idx = Index(3)
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
err = pool.EnsureUsedAddr(1, 0, idx) err = pool.EnsureUsedAddr(ns, addrmgrNs, 1, 0, idx)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to ensure used addresses: %v", err) t.Fatalf("Failed to ensure used addresses: %v", err)
} }
for _, i := range []int{0, 1, 2, 3} { for _, i := range []int{0, 1, 2, 3} {
addr, err = pool.getUsedAddr(1, 0, Index(i)) addr, err = pool.getUsedAddr(ns, addrmgrNs, 1, 0, Index(i))
if err != nil { if err != nil {
t.Fatalf("Failed to get addr from used addresses set: %v", err) t.Fatalf("Failed to get addr from used addresses set: %v", err)
} }
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
script, err = addr.Script() script, err = addr.Script()
}) })
if err != nil { if err != nil {
@ -70,14 +76,21 @@ func TestPoolEnsureUsedAddr(t *testing.T) {
} }
func TestPoolGetUsedAddr(t *testing.T) { func TestPoolGetUsedAddr(t *testing.T) {
tearDown, mgr, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
TstCreateSeries(t, pool, []TstSeriesDef{{ReqSigs: 2, PubKeys: TstPubKeys[0:3], SeriesID: 1}}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
TstCreateSeries(t, dbtx, pool, []TstSeriesDef{{ReqSigs: 2, PubKeys: TstPubKeys[0:3], SeriesID: 1}})
// Addr with series=1, branch=0, index=10 has never been used, so it should // Addr with series=1, branch=0, index=10 has never been used, so it should
// return nil. // return nil.
addr, err := pool.getUsedAddr(1, 0, 10) addr, err := pool.getUsedAddr(ns, addrmgrNs, 1, 0, 10)
if err != nil { if err != nil {
t.Fatalf("Error when looking up used addr: %v", err) t.Fatalf("Error when looking up used addr: %v", err)
} }
@ -87,18 +100,18 @@ func TestPoolGetUsedAddr(t *testing.T) {
// Now we add that addr to the used addresses DB and check that the value // Now we add that addr to the used addresses DB and check that the value
// returned by getUsedAddr() is what we expect. // returned by getUsedAddr() is what we expect.
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
err = pool.addUsedAddr(1, 0, 10) err = pool.addUsedAddr(ns, addrmgrNs, 1, 0, 10)
}) })
if err != nil { if err != nil {
t.Fatalf("Error when storing addr in used addresses DB: %v", err) t.Fatalf("Error when storing addr in used addresses DB: %v", err)
} }
var script []byte var script []byte
addr, err = pool.getUsedAddr(1, 0, 10) addr, err = pool.getUsedAddr(ns, addrmgrNs, 1, 0, 10)
if err != nil { if err != nil {
t.Fatalf("Error when looking up used addr: %v", err) t.Fatalf("Error when looking up used addr: %v", err)
} }
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
script, err = addr.Script() script, err = addr.Script()
}) })
if err != nil { if err != nil {
@ -111,9 +124,16 @@ func TestPoolGetUsedAddr(t *testing.T) {
} }
func TestSerializationErrors(t *testing.T) { func TestSerializationErrors(t *testing.T) {
tearDown, mgr, _ := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
tests := []struct { tests := []struct {
version uint32 version uint32
pubKeys []string pubKeys []string
@ -147,13 +167,13 @@ func TestSerializationErrors(t *testing.T) {
active := true active := true
for testNum, test := range tests { for testNum, test := range tests {
encryptedPubs, err := encryptKeys(test.pubKeys, mgr, waddrmgr.CKTPublic) encryptedPubs, err := encryptKeys(test.pubKeys, pool.Manager(), waddrmgr.CKTPublic)
if err != nil { if err != nil {
t.Fatalf("Test #%d - Error encrypting pubkeys: %v", testNum, err) t.Fatalf("Test #%d - Error encrypting pubkeys: %v", testNum, err)
} }
var encryptedPrivs [][]byte var encryptedPrivs [][]byte
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
encryptedPrivs, err = encryptKeys(test.privKeys, mgr, waddrmgr.CKTPrivate) encryptedPrivs, err = encryptKeys(test.privKeys, pool.Manager(), waddrmgr.CKTPrivate)
}) })
if err != nil { if err != nil {
t.Fatalf("Test #%d - Error encrypting privkeys: %v", testNum, err) t.Fatalf("Test #%d - Error encrypting privkeys: %v", testNum, err)
@ -172,9 +192,16 @@ func TestSerializationErrors(t *testing.T) {
} }
func TestSerialization(t *testing.T) { func TestSerialization(t *testing.T) {
tearDown, mgr, _ := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
tests := []struct { tests := []struct {
version uint32 version uint32
active bool active bool
@ -213,12 +240,12 @@ func TestSerialization(t *testing.T) {
var encryptedPrivs [][]byte var encryptedPrivs [][]byte
for testNum, test := range tests { for testNum, test := range tests {
encryptedPubs, err := encryptKeys(test.pubKeys, mgr, waddrmgr.CKTPublic) encryptedPubs, err := encryptKeys(test.pubKeys, pool.Manager(), waddrmgr.CKTPublic)
if err != nil { if err != nil {
t.Fatalf("Test #%d - Error encrypting pubkeys: %v", testNum, err) t.Fatalf("Test #%d - Error encrypting pubkeys: %v", testNum, err)
} }
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
encryptedPrivs, err = encryptKeys(test.privKeys, mgr, waddrmgr.CKTPrivate) encryptedPrivs, err = encryptKeys(test.privKeys, pool.Manager(), waddrmgr.CKTPrivate)
}) })
if err != nil { if err != nil {
t.Fatalf("Test #%d - Error encrypting privkeys: %v", testNum, err) t.Fatalf("Test #%d - Error encrypting privkeys: %v", testNum, err)
@ -287,8 +314,7 @@ func TestSerialization(t *testing.T) {
} }
func TestDeserializationErrors(t *testing.T) { func TestDeserializationErrors(t *testing.T) {
tearDown, _, _ := TstCreatePool(t) t.Parallel()
defer tearDown()
tests := []struct { tests := []struct {
serialized []byte serialized []byte
@ -329,24 +355,31 @@ func TestDeserializationErrors(t *testing.T) {
} }
func TestValidateAndDecryptKeys(t *testing.T) { func TestValidateAndDecryptKeys(t *testing.T) {
tearDown, manager, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
rawPubKeys, err := encryptKeys(TstPubKeys[0:2], manager, waddrmgr.CKTPublic) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
rawPubKeys, err := encryptKeys(TstPubKeys[0:2], pool.Manager(), waddrmgr.CKTPublic)
if err != nil { if err != nil {
t.Fatalf("Failed to encrypt public keys: %v", err) t.Fatalf("Failed to encrypt public keys: %v", err)
} }
var rawPrivKeys [][]byte var rawPrivKeys [][]byte
TstRunWithManagerUnlocked(t, manager, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
rawPrivKeys, err = encryptKeys([]string{TstPrivKeys[0], ""}, manager, waddrmgr.CKTPrivate) rawPrivKeys, err = encryptKeys([]string{TstPrivKeys[0], ""}, pool.Manager(), waddrmgr.CKTPrivate)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to encrypt private keys: %v", err) t.Fatalf("Failed to encrypt private keys: %v", err)
} }
var pubKeys, privKeys []*hdkeychain.ExtendedKey var pubKeys, privKeys []*hdkeychain.ExtendedKey
TstRunWithManagerUnlocked(t, manager, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
pubKeys, privKeys, err = validateAndDecryptKeys(rawPubKeys, rawPrivKeys, pool) pubKeys, privKeys, err = validateAndDecryptKeys(rawPubKeys, rawPrivKeys, pool)
}) })
if err != nil { if err != nil {
@ -379,17 +412,24 @@ func TestValidateAndDecryptKeys(t *testing.T) {
} }
func TestValidateAndDecryptKeysErrors(t *testing.T) { func TestValidateAndDecryptKeysErrors(t *testing.T) {
tearDown, manager, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
encryptedPubKeys, err := encryptKeys(TstPubKeys[0:1], manager, waddrmgr.CKTPublic) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
encryptedPubKeys, err := encryptKeys(TstPubKeys[0:1], pool.Manager(), waddrmgr.CKTPublic)
if err != nil { if err != nil {
t.Fatalf("Failed to encrypt public key: %v", err) t.Fatalf("Failed to encrypt public key: %v", err)
} }
var encryptedPrivKeys [][]byte var encryptedPrivKeys [][]byte
TstRunWithManagerUnlocked(t, manager, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
encryptedPrivKeys, err = encryptKeys(TstPrivKeys[1:2], manager, waddrmgr.CKTPrivate) encryptedPrivKeys, err = encryptKeys(TstPrivKeys[1:2], pool.Manager(), waddrmgr.CKTPrivate)
}) })
if err != nil { if err != nil {
t.Fatalf("Failed to encrypt private key: %v", err) t.Fatalf("Failed to encrypt private key: %v", err)
@ -427,7 +467,7 @@ func TestValidateAndDecryptKeysErrors(t *testing.T) {
} }
for i, test := range tests { for i, test := range tests {
TstRunWithManagerUnlocked(t, manager, func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
_, _, err = validateAndDecryptKeys(test.rawPubKeys, test.rawPrivKeys, pool) _, _, err = validateAndDecryptKeys(test.rawPubKeys, test.rawPrivKeys, pool)
}) })
TstCheckError(t, fmt.Sprintf("Test #%d", i), err, test.err) TstCheckError(t, fmt.Sprintf("Test #%d", i), err, test.err)

View file

@ -14,8 +14,17 @@ import (
) )
func TestStartWithdrawal(t *testing.T) { func TestStartWithdrawal(t *testing.T) {
tearDown, pool, store := vp.TstCreatePoolAndTxStore(t) tearDown, db, pool, store := vp.TstCreatePoolAndTxStore(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
txmgrNs := vp.TstTxStoreRWNamespace(dbtx)
mgr := pool.Manager() mgr := pool.Manager()
masters := []*hdkeychain.ExtendedKey{ masters := []*hdkeychain.ExtendedKey{
@ -23,9 +32,9 @@ func TestStartWithdrawal(t *testing.T) {
vp.TstCreateMasterKey(t, bytes.Repeat([]byte{0x02, 0x01}, 16)), vp.TstCreateMasterKey(t, bytes.Repeat([]byte{0x02, 0x01}, 16)),
vp.TstCreateMasterKey(t, bytes.Repeat([]byte{0x03, 0x01}, 16))} vp.TstCreateMasterKey(t, bytes.Repeat([]byte{0x03, 0x01}, 16))}
def := vp.TstCreateSeriesDef(t, pool, 2, masters) def := vp.TstCreateSeriesDef(t, pool, 2, masters)
vp.TstCreateSeries(t, pool, []vp.TstSeriesDef{def}) vp.TstCreateSeries(t, dbtx, pool, []vp.TstSeriesDef{def})
// Create eligible inputs and the list of outputs we need to fulfil. // Create eligible inputs and the list of outputs we need to fulfil.
vp.TstCreateSeriesCreditsOnStore(t, pool, def.SeriesID, []int64{5e6, 4e6}, store) vp.TstCreateSeriesCreditsOnStore(t, dbtx, pool, def.SeriesID, []int64{5e6, 4e6}, store)
address1 := "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6" address1 := "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6"
address2 := "3PbExiaztsSYgh6zeMswC49hLUwhTQ86XG" address2 := "3PbExiaztsSYgh6zeMswC49hLUwhTQ86XG"
requests := []vp.OutputRequest{ requests := []vp.OutputRequest{
@ -34,15 +43,14 @@ func TestStartWithdrawal(t *testing.T) {
} }
changeStart := vp.TstNewChangeAddress(t, pool, def.SeriesID, 0) changeStart := vp.TstNewChangeAddress(t, pool, def.SeriesID, 0)
startAddr := vp.TstNewWithdrawalAddress(t, pool, def.SeriesID, 0, 0) startAddr := vp.TstNewWithdrawalAddress(t, dbtx, pool, def.SeriesID, 0, 0)
lastSeriesID := def.SeriesID lastSeriesID := def.SeriesID
dustThreshold := btcutil.Amount(1e4) dustThreshold := btcutil.Amount(1e4)
currentBlock := int32(vp.TstInputsBlock + vp.TstEligibleInputMinConfirmations + 1) currentBlock := int32(vp.TstInputsBlock + vp.TstEligibleInputMinConfirmations + 1)
var status *vp.WithdrawalStatus var status *vp.WithdrawalStatus
var err error vp.TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
vp.TstRunWithManagerUnlocked(t, mgr, func() { status, err = pool.StartWithdrawal(ns, addrmgrNs, 0, requests, *startAddr, lastSeriesID, *changeStart,
status, err = pool.StartWithdrawal(0, requests, *startAddr, lastSeriesID, *changeStart, store, txmgrNs, currentBlock, dustThreshold)
store, currentBlock, dustThreshold)
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -79,8 +87,8 @@ func TestStartWithdrawal(t *testing.T) {
// signatures). Must unlock the manager as signing involves looking up the // signatures). Must unlock the manager as signing involves looking up the
// redeem script, which is stored encrypted. // redeem script, which is stored encrypted.
msgtx := status.TstGetMsgTx(ntxid) msgtx := status.TstGetMsgTx(ntxid)
vp.TstRunWithManagerUnlocked(t, mgr, func() { vp.TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
if err = vp.SignTx(msgtx, txSigs, mgr, store); err != nil { if err = vp.SignTx(msgtx, txSigs, mgr, addrmgrNs, store, txmgrNs); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })
@ -88,9 +96,9 @@ func TestStartWithdrawal(t *testing.T) {
// Any subsequent StartWithdrawal() calls with the same parameters will // Any subsequent StartWithdrawal() calls with the same parameters will
// return the previously stored WithdrawalStatus. // return the previously stored WithdrawalStatus.
var status2 *vp.WithdrawalStatus var status2 *vp.WithdrawalStatus
vp.TstRunWithManagerUnlocked(t, mgr, func() { vp.TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
status2, err = pool.StartWithdrawal(0, requests, *startAddr, lastSeriesID, *changeStart, status2, err = pool.StartWithdrawal(ns, addrmgrNs, 0, requests, *startAddr, lastSeriesID, *changeStart,
store, currentBlock, dustThreshold) store, txmgrNs, currentBlock, dustThreshold)
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -23,9 +23,15 @@ import (
// TestOutputSplittingNotEnoughInputs checks that an output will get split if we // TestOutputSplittingNotEnoughInputs checks that an output will get split if we
// don't have enough inputs to fulfil it. // don't have enough inputs to fulfil it.
func TestOutputSplittingNotEnoughInputs(t *testing.T) { func TestOutputSplittingNotEnoughInputs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams() net := pool.Manager().ChainParams()
output1Amount := btcutil.Amount(2) output1Amount := btcutil.Amount(2)
output2Amount := btcutil.Amount(3) output2Amount := btcutil.Amount(3)
@ -36,7 +42,7 @@ func TestOutputSplittingNotEnoughInputs(t *testing.T) {
TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", output1Amount, net), TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", output1Amount, net),
TstNewOutputRequest(t, 2, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", output2Amount, net), TstNewOutputRequest(t, 2, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", output2Amount, net),
} }
seriesID, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{7}) seriesID, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{7})
w := newWithdrawal(0, requests, eligible, *TstNewChangeAddress(t, pool, seriesID, 0)) w := newWithdrawal(0, requests, eligible, *TstNewChangeAddress(t, pool, seriesID, 0))
w.txOptions = func(tx *withdrawalTx) { w.txOptions = func(tx *withdrawalTx) {
// Trigger an output split because of lack of inputs by forcing a high fee. // Trigger an output split because of lack of inputs by forcing a high fee.
@ -71,15 +77,21 @@ func TestOutputSplittingNotEnoughInputs(t *testing.T) {
} }
func TestOutputSplittingOversizeTx(t *testing.T) { func TestOutputSplittingOversizeTx(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
requestAmount := btcutil.Amount(5) requestAmount := btcutil.Amount(5)
bigInput := int64(3) bigInput := int64(3)
smallInput := int64(2) smallInput := int64(2)
request := TstNewOutputRequest( request := TstNewOutputRequest(
t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", requestAmount, pool.Manager().ChainParams()) t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", requestAmount, pool.Manager().ChainParams())
seriesID, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{smallInput, bigInput}) seriesID, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{smallInput, bigInput})
changeStart := TstNewChangeAddress(t, pool, seriesID, 0) changeStart := TstNewChangeAddress(t, pool, seriesID, 0)
w := newWithdrawal(0, []OutputRequest{request}, eligible, *changeStart) w := newWithdrawal(0, []OutputRequest{request}, eligible, *changeStart)
w.txOptions = func(tx *withdrawalTx) { w.txOptions = func(tx *withdrawalTx) {
@ -129,13 +141,19 @@ func TestOutputSplittingOversizeTx(t *testing.T) {
} }
func TestSplitLastOutputNoOutputs(t *testing.T) { func TestSplitLastOutputNoOutputs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
w := newWithdrawal(0, []OutputRequest{}, []credit{}, ChangeAddress{}) dbtx, err := db.BeginReadWriteTx()
w.current = createWithdrawalTx(t, pool, []int64{}, []int64{}) if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
err := w.splitLastOutput() w := newWithdrawal(0, []OutputRequest{}, []credit{}, ChangeAddress{})
w.current = createWithdrawalTx(t, dbtx, pool, []int64{}, []int64{})
err = w.splitLastOutput()
TstCheckError(t, "", err, ErrPreconditionNotMet) TstCheckError(t, "", err, ErrPreconditionNotMet)
} }
@ -143,12 +161,19 @@ func TestSplitLastOutputNoOutputs(t *testing.T) {
// Check that all outputs requested in a withdrawal match the outputs of the generated // Check that all outputs requested in a withdrawal match the outputs of the generated
// transaction(s). // transaction(s).
func TestWithdrawalTxOutputs(t *testing.T) { func TestWithdrawalTxOutputs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams() net := pool.Manager().ChainParams()
// Create eligible inputs and the list of outputs we need to fulfil. // Create eligible inputs and the list of outputs we need to fulfil.
seriesID, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{2e6, 4e6}) seriesID, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{2e6, 4e6})
outputs := []OutputRequest{ outputs := []OutputRequest{
TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 3e6, net), TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 3e6, net),
TstNewOutputRequest(t, 2, "3PbExiaztsSYgh6zeMswC49hLUwhTQ86XG", 2e6, net), TstNewOutputRequest(t, 2, "3PbExiaztsSYgh6zeMswC49hLUwhTQ86XG", 2e6, net),
@ -178,10 +203,16 @@ func TestWithdrawalTxOutputs(t *testing.T) {
// Check that withdrawal.status correctly states that no outputs were fulfilled when we // Check that withdrawal.status correctly states that no outputs were fulfilled when we
// don't have enough eligible credits for any of them. // don't have enough eligible credits for any of them.
func TestFulfillRequestsNoSatisfiableOutputs(t *testing.T) { func TestFulfillRequestsNoSatisfiableOutputs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
seriesID, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{1e6}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
seriesID, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{1e6})
request := TstNewOutputRequest( request := TstNewOutputRequest(
t, 1, "3Qt1EaKRD9g9FeL2DGkLLswhK1AKmmXFSe", btcutil.Amount(3e6), pool.Manager().ChainParams()) t, 1, "3Qt1EaKRD9g9FeL2DGkLLswhK1AKmmXFSe", btcutil.Amount(3e6), pool.Manager().ChainParams())
changeStart := TstNewChangeAddress(t, pool, seriesID, 0) changeStart := TstNewChangeAddress(t, pool, seriesID, 0)
@ -210,12 +241,19 @@ func TestFulfillRequestsNoSatisfiableOutputs(t *testing.T) {
// Check that some requested outputs are not fulfilled when we don't have credits for all // Check that some requested outputs are not fulfilled when we don't have credits for all
// of them. // of them.
func TestFulfillRequestsNotEnoughCreditsForAllRequests(t *testing.T) { func TestFulfillRequestsNotEnoughCreditsForAllRequests(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams() net := pool.Manager().ChainParams()
// Create eligible inputs and the list of outputs we need to fulfil. // Create eligible inputs and the list of outputs we need to fulfil.
seriesID, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{2e6, 4e6}) seriesID, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{2e6, 4e6})
out1 := TstNewOutputRequest( out1 := TstNewOutputRequest(
t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", btcutil.Amount(3e6), net) t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", btcutil.Amount(3e6), net)
out2 := TstNewOutputRequest( out2 := TstNewOutputRequest(
@ -261,10 +299,16 @@ func TestFulfillRequestsNotEnoughCreditsForAllRequests(t *testing.T) {
// TestRollbackLastOutput tests the case where we rollback one output // TestRollbackLastOutput tests the case where we rollback one output
// and one input, such that sum(in) >= sum(out) + fee. // and one input, such that sum(in) >= sum(out) + fee.
func TestRollbackLastOutput(t *testing.T) { func TestRollbackLastOutput(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{3, 3, 2, 1, 3}, []int64{3, 3, 2, 2}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{3, 3, 2, 1, 3}, []int64{3, 3, 2, 2})
initialInputs := tx.inputs initialInputs := tx.inputs
initialOutputs := tx.outputs initialOutputs := tx.outputs
@ -295,12 +339,18 @@ func TestRollbackLastOutput(t *testing.T) {
} }
func TestRollbackLastOutputMultipleInputsRolledBack(t *testing.T) { func TestRollbackLastOutputMultipleInputsRolledBack(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
// This tx will need the 3 last inputs to fulfill the second output, so they // This tx will need the 3 last inputs to fulfill the second output, so they
// should all be rolled back and returned in the reverse order they were added. // should all be rolled back and returned in the reverse order they were added.
tx := createWithdrawalTx(t, pool, []int64{1, 2, 3, 4}, []int64{1, 8}) tx := createWithdrawalTx(t, dbtx, pool, []int64{1, 2, 3, 4}, []int64{1, 8})
initialInputs := tx.inputs initialInputs := tx.inputs
initialOutputs := tx.outputs initialOutputs := tx.outputs
@ -328,10 +378,16 @@ func TestRollbackLastOutputMultipleInputsRolledBack(t *testing.T) {
// TestRollbackLastOutputNoInputsRolledBack tests the case where we roll back // TestRollbackLastOutputNoInputsRolledBack tests the case where we roll back
// one output but don't need to roll back any inputs. // one output but don't need to roll back any inputs.
func TestRollbackLastOutputNoInputsRolledBack(t *testing.T) { func TestRollbackLastOutputNoInputsRolledBack(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{4}, []int64{2, 3}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{4}, []int64{2, 3})
initialInputs := tx.inputs initialInputs := tx.inputs
initialOutputs := tx.outputs initialOutputs := tx.outputs
@ -375,11 +431,17 @@ func TestRollBackLastOutputInsufficientOutputs(t *testing.T) {
// TestRollbackLastOutputWhenNewOutputAdded checks that we roll back the last // TestRollbackLastOutputWhenNewOutputAdded checks that we roll back the last
// output if a tx becomes too big right after we add a new output to it. // output if a tx becomes too big right after we add a new output to it.
func TestRollbackLastOutputWhenNewOutputAdded(t *testing.T) { func TestRollbackLastOutputWhenNewOutputAdded(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams() net := pool.Manager().ChainParams()
series, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{5, 5}) series, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{5, 5})
requests := []OutputRequest{ requests := []OutputRequest{
// This is ordered by bailment ID // This is ordered by bailment ID
TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 1, net), TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 1, net),
@ -427,11 +489,17 @@ func TestRollbackLastOutputWhenNewOutputAdded(t *testing.T) {
// TestRollbackLastOutputWhenNewInputAdded checks that we roll back the last // TestRollbackLastOutputWhenNewInputAdded checks that we roll back the last
// output if a tx becomes too big right after we add a new input to it. // output if a tx becomes too big right after we add a new input to it.
func TestRollbackLastOutputWhenNewInputAdded(t *testing.T) { func TestRollbackLastOutputWhenNewInputAdded(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams() net := pool.Manager().ChainParams()
series, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{6, 5, 4, 3, 2, 1}) series, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{6, 5, 4, 3, 2, 1})
requests := []OutputRequest{ requests := []OutputRequest{
// This is manually ordered by outBailmentIDHash, which is the order in // This is manually ordered by outBailmentIDHash, which is the order in
// which they're going to be fulfilled by w.fulfillRequests(). // which they're going to be fulfilled by w.fulfillRequests().
@ -486,10 +554,16 @@ func TestRollbackLastOutputWhenNewInputAdded(t *testing.T) {
} }
func TestWithdrawalTxRemoveOutput(t *testing.T) { func TestWithdrawalTxRemoveOutput(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{}, []int64{1, 2}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{}, []int64{1, 2})
outputs := tx.outputs outputs := tx.outputs
// Make sure we have created the transaction with the expected // Make sure we have created the transaction with the expected
// outputs. // outputs.
@ -514,10 +588,16 @@ func TestWithdrawalTxRemoveOutput(t *testing.T) {
} }
func TestWithdrawalTxRemoveInput(t *testing.T) { func TestWithdrawalTxRemoveInput(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{1, 2}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{1, 2}, []int64{})
inputs := tx.inputs inputs := tx.inputs
// Make sure we have created the transaction with the expected inputs // Make sure we have created the transaction with the expected inputs
checkTxInputs(t, tx, inputs) checkTxInputs(t, tx, inputs)
@ -540,11 +620,17 @@ func TestWithdrawalTxRemoveInput(t *testing.T) {
} }
func TestWithdrawalTxAddChange(t *testing.T) { func TestWithdrawalTxAddChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
input, output, fee := int64(4e6), int64(3e6), int64(10) input, output, fee := int64(4e6), int64(3e6), int64(10)
tx := createWithdrawalTx(t, pool, []int64{input}, []int64{output}) tx := createWithdrawalTx(t, dbtx, pool, []int64{input}, []int64{output})
tx.calculateFee = TstConstantFee(btcutil.Amount(fee)) tx.calculateFee = TstConstantFee(btcutil.Amount(fee))
if !tx.addChange([]byte{}) { if !tx.addChange([]byte{}) {
@ -566,11 +652,17 @@ func TestWithdrawalTxAddChange(t *testing.T) {
// add a change output when there's no satoshis left after paying all // add a change output when there's no satoshis left after paying all
// outputs+fees. // outputs+fees.
func TestWithdrawalTxAddChangeNoChange(t *testing.T) { func TestWithdrawalTxAddChangeNoChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
input, output, fee := int64(4e6), int64(4e6), int64(0) input, output, fee := int64(4e6), int64(4e6), int64(0)
tx := createWithdrawalTx(t, pool, []int64{input}, []int64{output}) tx := createWithdrawalTx(t, dbtx, pool, []int64{input}, []int64{output})
tx.calculateFee = TstConstantFee(btcutil.Amount(fee)) tx.calculateFee = TstConstantFee(btcutil.Amount(fee))
if tx.addChange([]byte{}) { if tx.addChange([]byte{}) {
@ -583,20 +675,32 @@ func TestWithdrawalTxAddChangeNoChange(t *testing.T) {
} }
func TestWithdrawalTxToMsgTxNoInputsOrOutputsOrChange(t *testing.T) { func TestWithdrawalTxToMsgTxNoInputsOrOutputsOrChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{}, []int64{})
msgtx := tx.toMsgTx() msgtx := tx.toMsgTx()
compareMsgTxAndWithdrawalTxOutputs(t, msgtx, tx) compareMsgTxAndWithdrawalTxOutputs(t, msgtx, tx)
compareMsgTxAndWithdrawalTxInputs(t, msgtx, tx) compareMsgTxAndWithdrawalTxInputs(t, msgtx, tx)
} }
func TestWithdrawalTxToMsgTxNoInputsOrOutputsWithChange(t *testing.T) { func TestWithdrawalTxToMsgTxNoInputsOrOutputsWithChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{}, []int64{})
tx.changeOutput = wire.NewTxOut(int64(1), []byte{}) tx.changeOutput = wire.NewTxOut(int64(1), []byte{})
msgtx := tx.toMsgTx() msgtx := tx.toMsgTx()
@ -606,10 +710,16 @@ func TestWithdrawalTxToMsgTxNoInputsOrOutputsWithChange(t *testing.T) {
} }
func TestWithdrawalTxToMsgTxWithInputButNoOutputsWithChange(t *testing.T) { func TestWithdrawalTxToMsgTxWithInputButNoOutputsWithChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{1}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{1}, []int64{})
tx.changeOutput = wire.NewTxOut(int64(1), []byte{}) tx.changeOutput = wire.NewTxOut(int64(1), []byte{})
msgtx := tx.toMsgTx() msgtx := tx.toMsgTx()
@ -619,11 +729,16 @@ func TestWithdrawalTxToMsgTxWithInputButNoOutputsWithChange(t *testing.T) {
} }
func TestWithdrawalTxToMsgTxWithInputOutputsAndChange(t *testing.T) { func TestWithdrawalTxToMsgTxWithInputOutputsAndChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{1, 2, 3}, []int64{4, 5, 6}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{1, 2, 3}, []int64{4, 5, 6})
tx.changeOutput = wire.NewTxOut(int64(7), []byte{}) tx.changeOutput = wire.NewTxOut(int64(7), []byte{})
msgtx := tx.toMsgTx() msgtx := tx.toMsgTx()
@ -633,10 +748,16 @@ func TestWithdrawalTxToMsgTxWithInputOutputsAndChange(t *testing.T) {
} }
func TestWithdrawalTxInputTotal(t *testing.T) { func TestWithdrawalTxInputTotal(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{5}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{5}, []int64{})
if tx.inputTotal() != btcutil.Amount(5) { if tx.inputTotal() != btcutil.Amount(5) {
t.Fatalf("Wrong total output; got %v, want %v", tx.outputTotal(), btcutil.Amount(5)) t.Fatalf("Wrong total output; got %v, want %v", tx.outputTotal(), btcutil.Amount(5))
@ -644,10 +765,16 @@ func TestWithdrawalTxInputTotal(t *testing.T) {
} }
func TestWithdrawalTxOutputTotal(t *testing.T) { func TestWithdrawalTxOutputTotal(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{}, []int64{4}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{}, []int64{4})
tx.changeOutput = wire.NewTxOut(int64(1), []byte{}) tx.changeOutput = wire.NewTxOut(int64(1), []byte{})
if tx.outputTotal() != btcutil.Amount(4) { if tx.outputTotal() != btcutil.Amount(4) {
@ -656,18 +783,24 @@ func TestWithdrawalTxOutputTotal(t *testing.T) {
} }
func TestWithdrawalInfoMatch(t *testing.T) { func TestWithdrawalInfoMatch(t *testing.T) {
tearDown, _, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
roundID := uint32(0) roundID := uint32(0)
wi := createAndFulfillWithdrawalRequests(t, pool, roundID) wi := createAndFulfillWithdrawalRequests(t, dbtx, pool, roundID)
// Use freshly created values for requests, startAddress and changeStart // Use freshly created values for requests, startAddress and changeStart
// to simulate what would happen if we had recreated them from the // to simulate what would happen if we had recreated them from the
// serialized data in the DB. // serialized data in the DB.
requestsCopy := make([]OutputRequest, len(wi.requests)) requestsCopy := make([]OutputRequest, len(wi.requests))
copy(requestsCopy, wi.requests) copy(requestsCopy, wi.requests)
startAddr := TstNewWithdrawalAddress(t, pool, wi.startAddress.seriesID, wi.startAddress.branch, startAddr := TstNewWithdrawalAddress(t, dbtx, pool, wi.startAddress.seriesID, wi.startAddress.branch,
wi.startAddress.index) wi.startAddress.index)
changeStart := TstNewChangeAddress(t, pool, wi.changeStart.seriesID, wi.changeStart.index) changeStart := TstNewChangeAddress(t, pool, wi.changeStart.seriesID, wi.changeStart.index)
@ -708,7 +841,7 @@ func TestWithdrawalInfoMatch(t *testing.T) {
} }
// It should not match when startAddress is not equal. // It should not match when startAddress is not equal.
diffStartAddr := TstNewWithdrawalAddress(t, pool, startAddr.seriesID, startAddr.branch+1, diffStartAddr := TstNewWithdrawalAddress(t, dbtx, pool, startAddr.seriesID, startAddr.branch+1,
startAddr.index) startAddr.index)
matches = wi.match(requestsCopy, *diffStartAddr, wi.lastSeriesID, *changeStart, matches = wi.match(requestsCopy, *diffStartAddr, wi.lastSeriesID, *changeStart,
wi.dustThreshold) wi.dustThreshold)
@ -726,29 +859,33 @@ func TestWithdrawalInfoMatch(t *testing.T) {
} }
func TestGetWithdrawalStatus(t *testing.T) { func TestGetWithdrawalStatus(t *testing.T) {
tearDown, _, pool := TstCreatePool(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
roundID := uint32(0) roundID := uint32(0)
wi := createAndFulfillWithdrawalRequests(t, pool, roundID) wi := createAndFulfillWithdrawalRequests(t, dbtx, pool, roundID)
serialized, err := serializeWithdrawal(wi.requests, wi.startAddress, wi.lastSeriesID, serialized, err := serializeWithdrawal(wi.requests, wi.startAddress, wi.lastSeriesID,
wi.changeStart, wi.dustThreshold, wi.status) wi.changeStart, wi.dustThreshold, wi.status)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
err = pool.namespace.Update( err = putWithdrawal(ns, pool.ID, roundID, serialized)
func(tx walletdb.Tx) error {
return putWithdrawal(tx, pool.ID, roundID, serialized)
})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// Here we should get a WithdrawalStatus that matches wi.status. // Here we should get a WithdrawalStatus that matches wi.status.
var status *WithdrawalStatus var status *WithdrawalStatus
TstRunWithManagerUnlocked(t, pool.Manager(), func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
status, err = getWithdrawalStatus(pool, roundID, wi.requests, wi.startAddress, status, err = getWithdrawalStatus(pool, ns, addrmgrNs, roundID, wi.requests, wi.startAddress,
wi.lastSeriesID, wi.changeStart, wi.dustThreshold) wi.lastSeriesID, wi.changeStart, wi.dustThreshold)
}) })
if err != nil { if err != nil {
@ -759,8 +896,8 @@ func TestGetWithdrawalStatus(t *testing.T) {
// Here we should get a nil WithdrawalStatus because the parameters are not // Here we should get a nil WithdrawalStatus because the parameters are not
// identical to those of the stored WithdrawalStatus with this roundID. // identical to those of the stored WithdrawalStatus with this roundID.
dustThreshold := wi.dustThreshold + 1 dustThreshold := wi.dustThreshold + 1
TstRunWithManagerUnlocked(t, pool.Manager(), func() { TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
status, err = getWithdrawalStatus(pool, roundID, wi.requests, wi.startAddress, status, err = getWithdrawalStatus(pool, ns, addrmgrNs, roundID, wi.requests, wi.startAddress,
wi.lastSeriesID, wi.changeStart, dustThreshold) wi.lastSeriesID, wi.changeStart, dustThreshold)
}) })
if err != nil { if err != nil {
@ -772,12 +909,19 @@ func TestGetWithdrawalStatus(t *testing.T) {
} }
func TestSignMultiSigUTXO(t *testing.T) { func TestSignMultiSigUTXO(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
// Create a new tx with a single input that we're going to sign. // Create a new tx with a single input that we're going to sign.
mgr := pool.Manager() mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{4e6}) tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{4e6})
sigs, err := getRawSigs([]*withdrawalTx{tx}) sigs, err := getRawSigs([]*withdrawalTx{tx})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -788,68 +932,96 @@ func TestSignMultiSigUTXO(t *testing.T) {
idx := 0 // The index of the tx input we're going to sign. idx := 0 // The index of the tx input we're going to sign.
pkScript := tx.inputs[idx].PkScript pkScript := tx.inputs[idx].PkScript
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
if err = signMultiSigUTXO(mgr, msgtx, idx, pkScript, txSigs[idx]); err != nil { if err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, idx, pkScript, txSigs[idx]); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })
} }
func TestSignMultiSigUTXOUnparseablePkScript(t *testing.T) { func TestSignMultiSigUTXOUnparseablePkScript(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager() mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{}) tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
msgtx := tx.toMsgTx() msgtx := tx.toMsgTx()
unparseablePkScript := []byte{0x01} unparseablePkScript := []byte{0x01}
err := signMultiSigUTXO(mgr, msgtx, 0, unparseablePkScript, []RawSig{{}}) err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, 0, unparseablePkScript, []RawSig{{}})
TstCheckError(t, "", err, ErrTxSigning) TstCheckError(t, "", err, ErrTxSigning)
} }
func TestSignMultiSigUTXOPkScriptNotP2SH(t *testing.T) { func TestSignMultiSigUTXOPkScriptNotP2SH(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager() mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{}) tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
addr, _ := btcutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams()) addr, _ := btcutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams())
pubKeyHashPkScript, _ := txscript.PayToAddrScript(addr.(*btcutil.AddressPubKeyHash)) pubKeyHashPkScript, _ := txscript.PayToAddrScript(addr.(*btcutil.AddressPubKeyHash))
msgtx := tx.toMsgTx() msgtx := tx.toMsgTx()
err := signMultiSigUTXO(mgr, msgtx, 0, pubKeyHashPkScript, []RawSig{{}}) err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, 0, pubKeyHashPkScript, []RawSig{{}})
TstCheckError(t, "", err, ErrTxSigning) TstCheckError(t, "", err, ErrTxSigning)
} }
func TestSignMultiSigUTXORedeemScriptNotFound(t *testing.T) { func TestSignMultiSigUTXORedeemScriptNotFound(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager() mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{}) tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
// This is a P2SH address for which the addr manager doesn't have the redeem // This is a P2SH address for which the addr manager doesn't have the redeem
// script. // script.
addr, _ := btcutil.DecodeAddress("3Hb4xcebcKg4DiETJfwjh8sF4uDw9rqtVC", mgr.ChainParams()) addr, _ := btcutil.DecodeAddress("3Hb4xcebcKg4DiETJfwjh8sF4uDw9rqtVC", mgr.ChainParams())
if _, err := mgr.Address(addr); err == nil { if _, err := mgr.Address(addrmgrNs, addr); err == nil {
t.Fatalf("Address %s found in manager when it shouldn't", addr) t.Fatalf("Address %s found in manager when it shouldn't", addr)
} }
msgtx := tx.toMsgTx() msgtx := tx.toMsgTx()
pkScript, _ := txscript.PayToAddrScript(addr.(*btcutil.AddressScriptHash)) pkScript, _ := txscript.PayToAddrScript(addr.(*btcutil.AddressScriptHash))
err := signMultiSigUTXO(mgr, msgtx, 0, pkScript, []RawSig{{}}) err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, 0, pkScript, []RawSig{{}})
TstCheckError(t, "", err, ErrTxSigning) TstCheckError(t, "", err, ErrTxSigning)
} }
func TestSignMultiSigUTXONotEnoughSigs(t *testing.T) { func TestSignMultiSigUTXONotEnoughSigs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager() mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{}) tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
sigs, err := getRawSigs([]*withdrawalTx{tx}) sigs, err := getRawSigs([]*withdrawalTx{tx})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -862,36 +1034,49 @@ func TestSignMultiSigUTXONotEnoughSigs(t *testing.T) {
reqSigs := tx.inputs[idx].addr.series().TstGetReqSigs() reqSigs := tx.inputs[idx].addr.series().TstGetReqSigs()
txInSigs := txSigs[idx][:reqSigs-1] txInSigs := txSigs[idx][:reqSigs-1]
pkScript := tx.inputs[idx].PkScript pkScript := tx.inputs[idx].PkScript
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
err = signMultiSigUTXO(mgr, msgtx, idx, pkScript, txInSigs) err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, idx, pkScript, txInSigs)
}) })
TstCheckError(t, "", err, ErrTxSigning) TstCheckError(t, "", err, ErrTxSigning)
} }
func TestSignMultiSigUTXOWrongRawSigs(t *testing.T) { func TestSignMultiSigUTXOWrongRawSigs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager() mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{}) tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
sigs := []RawSig{{0x00}, {0x01}} sigs := []RawSig{{0x00}, {0x01}}
idx := 0 // The index of the tx input we're going to sign. idx := 0 // The index of the tx input we're going to sign.
pkScript := tx.inputs[idx].PkScript pkScript := tx.inputs[idx].PkScript
var err error TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
TstRunWithManagerUnlocked(t, mgr, func() { err = signMultiSigUTXO(mgr, addrmgrNs, tx.toMsgTx(), idx, pkScript, sigs)
err = signMultiSigUTXO(mgr, tx.toMsgTx(), idx, pkScript, sigs)
}) })
TstCheckError(t, "", err, ErrTxSigning) TstCheckError(t, "", err, ErrTxSigning)
} }
func TestGetRawSigs(t *testing.T) { func TestGetRawSigs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{5e6, 4e6}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
tx := createWithdrawalTx(t, dbtx, pool, []int64{5e6, 4e6}, []int64{})
sigs, err := getRawSigs([]*withdrawalTx{tx}) sigs, err := getRawSigs([]*withdrawalTx{tx})
if err != nil { if err != nil {
@ -908,14 +1093,20 @@ func TestGetRawSigs(t *testing.T) {
// Since we have all the necessary signatures (m-of-n), we construct the // Since we have all the necessary signatures (m-of-n), we construct the
// sigsnature scripts and execute them to make sure the raw signatures are // sigsnature scripts and execute them to make sure the raw signatures are
// valid. // valid.
signTxAndValidate(t, pool.Manager(), msgtx, txSigs, tx.inputs) signTxAndValidate(t, pool.Manager(), addrmgrNs, msgtx, txSigs, tx.inputs)
} }
func TestGetRawSigsOnlyOnePrivKeyAvailable(t *testing.T) { func TestGetRawSigsOnlyOnePrivKeyAvailable(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{5e6, 4e6}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{5e6, 4e6}, []int64{})
// Remove all private keys but the first one from the credit's series. // Remove all private keys but the first one from the credit's series.
series := tx.inputs[0].addr.series() series := tx.inputs[0].addr.series()
for i := range series.privateKeys[1:] { for i := range series.privateKeys[1:] {
@ -936,29 +1127,41 @@ func TestGetRawSigsOnlyOnePrivKeyAvailable(t *testing.T) {
} }
func TestGetRawSigsUnparseableRedeemScript(t *testing.T) { func TestGetRawSigsUnparseableRedeemScript(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{5e6, 4e6}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{5e6, 4e6}, []int64{})
// Change the redeem script for one of our tx inputs, to force an error in // Change the redeem script for one of our tx inputs, to force an error in
// getRawSigs(). // getRawSigs().
tx.inputs[0].addr.script = []byte{0x01} tx.inputs[0].addr.script = []byte{0x01}
_, err := getRawSigs([]*withdrawalTx{tx}) _, err = getRawSigs([]*withdrawalTx{tx})
TstCheckError(t, "", err, ErrRawSigning) TstCheckError(t, "", err, ErrRawSigning)
} }
func TestGetRawSigsInvalidAddrBranch(t *testing.T) { func TestGetRawSigsInvalidAddrBranch(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{5e6, 4e6}, []int64{}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{5e6, 4e6}, []int64{})
// Change the branch of our input's address to an invalid value, to force // Change the branch of our input's address to an invalid value, to force
// an error in getRawSigs(). // an error in getRawSigs().
tx.inputs[0].addr.branch = Branch(999) tx.inputs[0].addr.branch = Branch(999)
_, err := getRawSigs([]*withdrawalTx{tx}) _, err = getRawSigs([]*withdrawalTx{tx})
TstCheckError(t, "", err, ErrInvalidBranch) TstCheckError(t, "", err, ErrInvalidBranch)
} }
@ -982,10 +1185,16 @@ func TestOutBailmentIDSort(t *testing.T) {
} }
func TestTxTooBig(t *testing.T) { func TestTxTooBig(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{5}, []int64{1}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
tx := createWithdrawalTx(t, dbtx, pool, []int64{5}, []int64{1})
tx.calculateSize = func() int { return txMaxSize - 1 } tx.calculateSize = func() int { return txMaxSize - 1 }
if tx.isTooBig() { if tx.isTooBig() {
@ -1008,10 +1217,17 @@ func TestTxTooBig(t *testing.T) {
} }
func TestTxSizeCalculation(t *testing.T) { func TestTxSizeCalculation(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t) tearDown, db, pool := TstCreatePool(t)
defer tearDown() defer tearDown()
tx := createWithdrawalTx(t, pool, []int64{1, 5}, []int64{2}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
tx := createWithdrawalTx(t, dbtx, pool, []int64{1, 5}, []int64{2})
size := tx.calculateSize() size := tx.calculateSize()
@ -1027,7 +1243,7 @@ func TestTxSizeCalculation(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
signTxAndValidate(t, pool.Manager(), msgtx, sigs[tx.ntxid()], tx.inputs) signTxAndValidate(t, pool.Manager(), addrmgrNs, msgtx, sigs[tx.ntxid()], tx.inputs)
// ECDSA signatures have variable length (71-73 bytes) but in // ECDSA signatures have variable length (71-73 bytes) but in
// calculateSize() we use a dummy signature for the worst-case scenario (73 // calculateSize() we use a dummy signature for the worst-case scenario (73
@ -1080,16 +1296,23 @@ func TestTxFeeEstimationForLargeTx(t *testing.T) {
} }
func TestStoreTransactionsWithoutChangeOutput(t *testing.T) { func TestStoreTransactionsWithoutChangeOutput(t *testing.T) {
tearDown, pool, store := TstCreatePoolAndTxStore(t) tearDown, db, pool, store := TstCreatePoolAndTxStore(t)
defer tearDown() defer tearDown()
wtx := createWithdrawalTxWithStoreCredits(t, store, pool, []int64{4e6}, []int64{3e6}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
txmgrNs := dbtx.ReadWriteBucket(txmgrNamespaceKey)
wtx := createWithdrawalTxWithStoreCredits(t, dbtx, store, pool, []int64{4e6}, []int64{3e6})
tx := &changeAwareTx{MsgTx: wtx.toMsgTx(), changeIdx: int32(-1)} tx := &changeAwareTx{MsgTx: wtx.toMsgTx(), changeIdx: int32(-1)}
if err := storeTransactions(store, []*changeAwareTx{tx}); err != nil { if err := storeTransactions(store, txmgrNs, []*changeAwareTx{tx}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
credits, err := store.UnspentOutputs() credits, err := store.UnspentOutputs(txmgrNs)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1099,20 +1322,27 @@ func TestStoreTransactionsWithoutChangeOutput(t *testing.T) {
} }
func TestStoreTransactionsWithChangeOutput(t *testing.T) { func TestStoreTransactionsWithChangeOutput(t *testing.T) {
tearDown, pool, store := TstCreatePoolAndTxStore(t) tearDown, db, pool, store := TstCreatePoolAndTxStore(t)
defer tearDown() defer tearDown()
wtx := createWithdrawalTxWithStoreCredits(t, store, pool, []int64{5e6}, []int64{1e6, 1e6}) dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
txmgrNs := dbtx.ReadWriteBucket(txmgrNamespaceKey)
wtx := createWithdrawalTxWithStoreCredits(t, dbtx, store, pool, []int64{5e6}, []int64{1e6, 1e6})
wtx.changeOutput = wire.NewTxOut(int64(3e6), []byte{}) wtx.changeOutput = wire.NewTxOut(int64(3e6), []byte{})
msgtx := wtx.toMsgTx() msgtx := wtx.toMsgTx()
tx := &changeAwareTx{MsgTx: msgtx, changeIdx: int32(len(msgtx.TxOut) - 1)} tx := &changeAwareTx{MsgTx: msgtx, changeIdx: int32(len(msgtx.TxOut) - 1)}
if err := storeTransactions(store, []*changeAwareTx{tx}); err != nil { if err := storeTransactions(store, txmgrNs, []*changeAwareTx{tx}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
hash := msgtx.TxHash() hash := msgtx.TxHash()
txDetails, err := store.TxDetails(&hash) txDetails, err := store.TxDetails(txmgrNs, &hash)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1139,7 +1369,7 @@ func TestStoreTransactionsWithChangeOutput(t *testing.T) {
t.Fatalf("Unexpected input amount; got %v, want %v", inputTotal, btcutil.Amount(5e6)) t.Fatalf("Unexpected input amount; got %v, want %v", inputTotal, btcutil.Amount(5e6))
} }
credits, err := store.UnspentOutputs() credits, err := store.UnspentOutputs(txmgrNs)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1156,7 +1386,7 @@ func TestStoreTransactionsWithChangeOutput(t *testing.T) {
// createWithdrawalTxWithStoreCredits creates a new Credit in the given store // createWithdrawalTxWithStoreCredits creates a new Credit in the given store
// for each entry in inputAmounts, and uses them to construct a withdrawalTx // for each entry in inputAmounts, and uses them to construct a withdrawalTx
// with one output for every entry in outputAmounts. // with one output for every entry in outputAmounts.
func createWithdrawalTxWithStoreCredits(t *testing.T, store *wtxmgr.Store, pool *Pool, func createWithdrawalTxWithStoreCredits(t *testing.T, dbtx walletdb.ReadWriteTx, store *wtxmgr.Store, pool *Pool,
inputAmounts []int64, outputAmounts []int64) *withdrawalTx { inputAmounts []int64, outputAmounts []int64) *withdrawalTx {
masters := []*hdkeychain.ExtendedKey{ masters := []*hdkeychain.ExtendedKey{
TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)), TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)),
@ -1164,10 +1394,10 @@ func createWithdrawalTxWithStoreCredits(t *testing.T, store *wtxmgr.Store, pool
TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)), TstCreateMasterKey(t, bytes.Repeat(uint32ToBytes(getUniqueID()), 4)),
} }
def := TstCreateSeriesDef(t, pool, 2, masters) def := TstCreateSeriesDef(t, pool, 2, masters)
TstCreateSeries(t, pool, []TstSeriesDef{def}) TstCreateSeries(t, dbtx, pool, []TstSeriesDef{def})
net := pool.Manager().ChainParams() net := pool.Manager().ChainParams()
tx := newWithdrawalTx(defaultTxOptions) tx := newWithdrawalTx(defaultTxOptions)
for _, c := range TstCreateSeriesCreditsOnStore(t, pool, def.SeriesID, inputAmounts, store) { for _, c := range TstCreateSeriesCreditsOnStore(t, dbtx, pool, def.SeriesID, inputAmounts, store) {
tx.addInput(c) tx.addInput(c)
} }
for i, amount := range outputAmounts { for i, amount := range outputAmounts {
@ -1252,12 +1482,12 @@ func checkTxInputs(t *testing.T, tx *withdrawalTx, inputs []credit) {
// signTxAndValidate will construct the signature script for each input of the given // signTxAndValidate will construct the signature script for each input of the given
// transaction (using the given raw signatures and the pkScripts from credits) and execute // transaction (using the given raw signatures and the pkScripts from credits) and execute
// those scripts to validate them. // those scripts to validate them.
func signTxAndValidate(t *testing.T, mgr *waddrmgr.Manager, tx *wire.MsgTx, txSigs TxSigs, func signTxAndValidate(t *testing.T, mgr *waddrmgr.Manager, addrmgrNs walletdb.ReadBucket, tx *wire.MsgTx, txSigs TxSigs,
credits []credit) { credits []credit) {
for i := range tx.TxIn { for i := range tx.TxIn {
pkScript := credits[i].PkScript pkScript := credits[i].PkScript
TstRunWithManagerUnlocked(t, mgr, func() { TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
if err := signMultiSigUTXO(mgr, tx, i, pkScript, txSigs[i]); err != nil { if err := signMultiSigUTXO(mgr, addrmgrNs, tx, i, pkScript, txSigs[i]); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })