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"
"github.com/btcsuite/btclog"
"github.com/roasbeef/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/walletdb"
)
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,
// and locks it again before returning.
func TstRunWithManagerUnlocked(t *testing.T, mgr *waddrmgr.Manager, callback func()) {
if err := mgr.Unlock(privPassphrase); err != nil {
func TstRunWithManagerUnlocked(t *testing.T, mgr *waddrmgr.Manager, addrmgrNs walletdb.ReadBucket, callback func()) {
if err := mgr.Unlock(addrmgrNs, privPassphrase); err != nil {
t.Fatal(err)
}
defer mgr.Lock()

View file

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

View file

@ -40,13 +40,13 @@ var (
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,
fastScrypt)
if err != nil {
return nil, err
}
return waddrmgr.Open(ns, pubPassphrase, params, nil)
return waddrmgr.Open(ns, pubPassphrase, params)
}
func ExampleCreate() {
@ -59,8 +59,15 @@ func ExampleCreate() {
}
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.
mgrNamespace, err := db.Namespace([]byte("waddrmgr"))
mgrNamespace, err := dbtx.CreateTopLevelBucket([]byte("waddrmgr"))
if err != nil {
fmt.Println(err)
return
@ -74,7 +81,7 @@ func ExampleCreate() {
}
// Create a walletdb namespace for votingpools.
vpNamespace, err := db.Namespace([]byte("votingpool"))
vpNamespace, err := dbtx.CreateTopLevelBucket([]byte("votingpool"))
if err != nil {
fmt.Println(err)
return
@ -96,41 +103,43 @@ func ExampleCreate() {
func Example_depositAddress() {
// Create the address manager and votingpool DB namespace. See the example
// for the Create() function for more info on how this is done.
mgr, vpNamespace, tearDownFunc, err := exampleCreateMgrAndDBNamespace()
if err != nil {
fmt.Println(err)
return
}
defer tearDownFunc()
teardown, db, mgr := exampleCreateDBAndMgr()
defer teardown()
// Create the voting pool.
pool, err := votingpool.Create(vpNamespace, mgr, []byte{0x00})
if err != nil {
fmt.Println(err)
return
}
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
ns := votingpoolNamespace(tx)
// Create a 2-of-3 series.
seriesID := uint32(1)
requiredSignatures := uint32(2)
pubKeys := []string{
"xpub661MyMwAqRbcFDDrR5jY7LqsRioFDwg3cLjc7tML3RRcfYyhXqqgCH5SqMSQdpQ1Xh8EtVwcfm8psD8zXKPcRaCVSY4GCqbb3aMEs27GitE",
"xpub661MyMwAqRbcGsxyD8hTmJFtpmwoZhy4NBBVxzvFU8tDXD2ME49A6JjQCYgbpSUpHGP1q4S2S1Pxv2EqTjwfERS5pc9Q2yeLkPFzSgRpjs9",
"xpub661MyMwAqRbcEbc4uYVXvQQpH9L3YuZLZ1gxCmj59yAhNy33vXxbXadmRpx5YZEupNSqWRrR7PqU6duS2FiVCGEiugBEa5zuEAjsyLJjKCh",
}
err = pool.CreateSeries(votingpool.CurrentVersion, seriesID, requiredSignatures, pubKeys)
if err != nil {
fmt.Println(err)
return
}
// Create the voting pool.
pool, err := votingpool.Create(ns, mgr, []byte{0x00})
if err != nil {
return err
}
// Create a deposit address.
addr, err := pool.DepositScriptAddress(seriesID, votingpool.Branch(0), votingpool.Index(1))
// 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
}
// 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 {
fmt.Println(err)
return
}
fmt.Println("Generated deposit address:", addr.EncodeAddress())
// Output:
// Generated deposit address: 3QTzpc9d3tTbNLJLB7xwt87nWM38boAhAw
@ -141,30 +150,27 @@ func Example_depositAddress() {
func Example_empowerSeries() {
// Create the address manager and votingpool DB namespace. See the example
// for the Create() function for more info on how this is done.
mgr, vpNamespace, tearDownFunc, err := exampleCreateMgrAndDBNamespace()
if err != nil {
fmt.Println(err)
return
}
defer tearDownFunc()
teardown, db, mgr := exampleCreateDBAndMgr()
defer teardown()
// Create a pool and a series. See the DepositAddress example for more info
// on how this is done.
pool, seriesID, err := exampleCreatePoolAndSeries(mgr, vpNamespace)
if err != nil {
fmt.Println(err)
return
}
pool, seriesID := exampleCreatePoolAndSeries(db, mgr)
// Now empower the series with one of its private keys. Notice that in order
// to do that we need to unlock the address manager.
if err := mgr.Unlock(privPassphrase); err != nil {
fmt.Println(err)
return
}
defer mgr.Lock()
privKey := "xprv9s21ZrQH143K2j9PK4CXkCu8sgxkpUxCF7p1KVwiV5tdnkeYzJXReUkxz5iB2FUzTXC1L15abCDG4RMxSYT5zhm67uvsnLYxuDhZfoFcB6a"
err = pool.EmpowerSeries(seriesID, privKey)
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
ns := votingpoolNamespace(tx)
addrmgrNs := addrmgrNamespace(tx)
// Now empower the series with one of its private keys. Notice that in order
// to do that we need to unlock the address manager.
err := mgr.Unlock(addrmgrNs, privPassphrase)
if err != nil {
return err
}
defer mgr.Lock()
privKey := "xprv9s21ZrQH143K2j9PK4CXkCu8sgxkpUxCF7p1KVwiV5tdnkeYzJXReUkxz5iB2FUzTXC1L15abCDG4RMxSYT5zhm67uvsnLYxuDhZfoFcB6a"
return pool.EmpowerSeries(ns, seriesID, privKey)
})
if err != nil {
fmt.Println(err)
return
@ -178,70 +184,67 @@ func Example_empowerSeries() {
func Example_startWithdrawal() {
// Create the address manager and votingpool DB namespace. See the example
// for the Create() function for more info on how this is done.
mgr, vpNamespace, tearDownFunc, err := exampleCreateMgrAndDBNamespace()
if err != nil {
fmt.Println(err)
return
}
defer tearDownFunc()
teardown, db, mgr := exampleCreateDBAndMgr()
defer teardown()
// Create a pool and a series. See the DepositAddress example for more info
// on how this is done.
pool, seriesID, err := exampleCreatePoolAndSeries(mgr, vpNamespace)
if err != nil {
fmt.Println(err)
return
}
pool, seriesID := exampleCreatePoolAndSeries(db, mgr)
// Unlock the manager
if err := mgr.Unlock(privPassphrase); err != nil {
fmt.Println(err)
return
}
defer mgr.Lock()
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
ns := votingpoolNamespace(tx)
addrmgrNs := addrmgrNamespace(tx)
txmgrNs := txmgrNamespace(tx)
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))
// Create the transaction store for later use.
txstore := exampleCreateTxStore(txmgrNs)
// Unlock the manager
err := mgr.Unlock(addrmgrNs, privPassphrase)
if err != nil {
return err
}
defer mgr.Lock()
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 {
fmt.Println(err)
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:
//
@ -263,86 +266,99 @@ func createWalletDB() (walletdb.DB, func(), error) {
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()
if err != nil {
return nil, nil, nil, err
panic(err)
}
// 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 {
dbTearDown()
return nil, nil, nil, err
panic(err)
}
// Create the address manager
mgr, err := createWaddrmgr(mgrNamespace, &chaincfg.MainNetParams)
if err != nil {
dbTearDown()
return nil, nil, nil, err
}
tearDownFunc := func() {
teardown = func() {
mgr.Close()
dbTearDown()
}
// Create a walletdb namespace for votingpools.
vpNamespace, err := db.Namespace([]byte("votingpool"))
if err != nil {
tearDownFunc()
return nil, nil, nil, err
}
return mgr, vpNamespace, tearDownFunc, nil
return teardown, db, mgr
}
func exampleCreatePoolAndSeries(mgr *waddrmgr.Manager, vpNamespace walletdb.Namespace) (
*votingpool.Pool, uint32, error) {
pool, err := votingpool.Create(vpNamespace, mgr, []byte{0x00})
func exampleCreatePoolAndSeries(db walletdb.DB, mgr *waddrmgr.Manager) (pool *votingpool.Pool, seriesID uint32) {
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
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 {
return nil, 0, err
panic(err)
}
// Create a 2-of-3 series.
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
return pool, seriesID
}
func exampleCreateTxStore() (*wtxmgr.Store, func(), error) {
dir, err := ioutil.TempDir("", "pool_test_txstore")
func exampleCreateTxStore(ns walletdb.ReadWriteBucket) *wtxmgr.Store {
err := wtxmgr.Create(ns)
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 {
return nil, nil, err
panic(err)
}
wtxmgrNamespace, err := db.Namespace([]byte("testtxstore"))
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
return s
}

View file

@ -53,10 +53,10 @@ func getUniqueID() uint32 {
}
// 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()
tx := newWithdrawalTx(defaultTxOptions)
_, credits := TstCreateCreditsOnNewSeries(t, pool, inputAmounts)
_, credits := TstCreateCreditsOnNewSeries(t, dbtx, pool, inputAmounts)
for _, c := range credits {
tx.addInput(c)
}
@ -99,15 +99,28 @@ func TstNewDepositScript(t *testing.T, p *Pool, seriesID uint32, branch Branch,
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
// 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 {
addr, err := p.getUsedAddr(seriesID, branch, idx)
func TstEnsureUsedAddr(t *testing.T, dbtx walletdb.ReadWriteTx, p *Pool, seriesID uint32, branch Branch, idx Index) []byte {
ns, addrmgrNs := TstRWNamespaces(dbtx)
addr, err := p.getUsedAddr(ns, addrmgrNs, seriesID, branch, idx)
if err != nil {
t.Fatal(err)
} else if addr != nil {
var script []byte
TstRunWithManagerUnlocked(t, p.Manager(), func() {
TstRunWithManagerUnlocked(t, p.Manager(), addrmgrNs, func() {
script, err = addr.Script()
})
if err != nil {
@ -115,8 +128,8 @@ func TstEnsureUsedAddr(t *testing.T, p *Pool, seriesID uint32, branch Branch, id
}
return script
}
TstRunWithManagerUnlocked(t, p.Manager(), func() {
err = p.EnsureUsedAddr(seriesID, branch, idx)
TstRunWithManagerUnlocked(t, p.Manager(), addrmgrNs, func() {
err = p.EnsureUsedAddr(ns, addrmgrNs, seriesID, branch, idx)
})
if err != nil {
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)
}
func TstCreatePkScript(t *testing.T, p *Pool, seriesID uint32, branch Branch, idx Index) []byte {
script := TstEnsureUsedAddr(t, p, seriesID, branch, idx)
func TstCreatePkScript(t *testing.T, dbtx walletdb.ReadWriteTx, p *Pool, seriesID uint32, branch Branch, idx Index) []byte {
script := TstEnsureUsedAddr(t, dbtx, p, seriesID, branch, idx)
addr, err := p.addressFor(script)
if err != nil {
t.Fatal(err)
@ -137,30 +150,6 @@ func TstCreatePkScript(t *testing.T, p *Pool, seriesID uint32, branch Branch, id
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 {
ReqSigs uint32
PubKeys []string
@ -172,15 +161,16 @@ type TstSeriesDef struct {
// TstCreateSeries creates a new Series for every definition in the given slice
// of TstSeriesDef. If the definition includes any private keys, the Series is
// 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 {
err := pool.CreateSeries(CurrentVersion, def.SeriesID, def.ReqSigs, def.PubKeys)
err := pool.CreateSeries(ns, CurrentVersion, def.SeriesID, def.ReqSigs, def.PubKeys)
if err != nil {
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 {
if err := pool.EmpowerSeries(def.SeriesID, key); err != nil {
if err := pool.EmpowerSeries(ns, def.SeriesID, key); err != nil {
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}
}
func TstCreatePoolAndTxStore(t *testing.T) (tearDown func(), pool *Pool, store *wtxmgr.Store) {
mgrTearDown, _, pool := TstCreatePool(t)
store, storeTearDown := TstCreateTxStore(t)
tearDown = func() {
mgrTearDown()
storeTearDown()
}
return tearDown, pool, store
func TstCreatePoolAndTxStore(t *testing.T) (tearDown func(), db walletdb.DB, pool *Pool, store *wtxmgr.Store) {
teardown, db, pool := TstCreatePool(t)
store = TstCreateTxStore(t, db)
return teardown, db, pool, store
}
// 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.
// The new Series will use a 2-of-3 configuration and will be empowered with
// 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{
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)
TstCreateSeries(t, pool, []TstSeriesDef{def})
return def.SeriesID, TstCreateSeriesCredits(t, pool, def.SeriesID, amounts)
TstCreateSeries(t, dbtx, pool, []TstSeriesDef{def})
return def.SeriesID, TstCreateSeriesCredits(t, dbtx, pool, def.SeriesID, 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.
func TstCreateSeriesCredits(t *testing.T, pool *Pool, seriesID uint32, amounts []int64) []credit {
addr := TstNewWithdrawalAddress(t, pool, seriesID, Branch(1), Index(0))
func TstCreateSeriesCredits(t *testing.T, dbtx walletdb.ReadWriteTx, pool *Pool, seriesID uint32, amounts []int64) []credit {
addr := TstNewWithdrawalAddress(t, dbtx, pool, seriesID, Branch(1), Index(0))
pkScript, err := txscript.PayToAddrScript(addr.addr)
if err != nil {
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
// every item in the amounts slice. These credits are locked to the votingpool
// 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 {
branch := Branch(1)
idx := Index(0)
pkScript := TstCreatePkScript(t, pool, seriesID, branch, idx)
pkScript := TstCreatePkScript(t, dbtx, pool, seriesID, branch, idx)
eligible := make([]credit, len(amounts))
for i, credit := range TstCreateCreditsOnStore(t, store, pkScript, amounts) {
eligible[i] = newCredit(credit, *TstNewWithdrawalAddress(t, pool, seriesID, branch, idx))
for i, credit := range TstCreateCreditsOnStore(t, dbtx, store, pkScript, amounts) {
eligible[i] = newCredit(credit, *TstNewWithdrawalAddress(t, dbtx, pool, seriesID, branch, idx))
}
return eligible
}
// TstCreateCreditsOnStore inserts a new credit in the given store for
// every item in the amounts slice.
func TstCreateCreditsOnStore(t *testing.T, s *wtxmgr.Store, pkScript []byte,
amounts []int64) []wtxmgr.Credit {
func TstCreateCreditsOnStore(t *testing.T, dbtx walletdb.ReadWriteTx, s *wtxmgr.Store, pkScript []byte, amounts []int64) []wtxmgr.Credit {
msgTx := createMsgTx(pkScript, amounts)
meta := &wtxmgr.BlockMeta{
Block: wtxmgr.Block{Height: TstInputsBlock},
@ -304,13 +289,14 @@ func TstCreateCreditsOnStore(t *testing.T, s *wtxmgr.Store, pkScript []byte,
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)
}
credits := make([]wtxmgr.Credit, len(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)
}
credits[i] = wtxmgr.Credit{
@ -326,11 +312,16 @@ func TstCreateCreditsOnStore(t *testing.T, s *wtxmgr.Store, pkScript []byte,
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
// returns the pool's waddrmgr.Manager (which uses the same walletdb, but with a
// different namespace) as a convenience, and a teardown function that closes
// the Manager and removes the directory used to store the database.
func TstCreatePool(t *testing.T) (tearDownFunc func(), mgr *waddrmgr.Manager, pool *Pool) {
// returns a teardown function that closes the Manager and removes the directory
// used to store the database.
func TstCreatePool(t *testing.T) (tearDownFunc func(), db walletdb.DB, pool *Pool) {
// 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
// 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 {
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 {
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 {
t.Fatalf("Failed to create addr manager DB namespace: %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)
t.Fatalf("Could not set up DB: %v", err)
}
tearDownFunc = func() {
addrMgr.Close()
db.Close()
mgr.Close()
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,
@ -406,12 +419,13 @@ func TstNewWithdrawalOutput(r OutputRequest, status outputStatus,
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) {
TstEnsureUsedAddr(t, p, seriesID, branch, index)
TstEnsureUsedAddr(t, dbtx, p, seriesID, branch, index)
ns, addrmgrNs := TstRNamespaces(dbtx)
var err error
TstRunWithManagerUnlocked(t, p.Manager(), func() {
addr, err = p.WithdrawalAddress(seriesID, branch, index)
TstRunWithManagerUnlocked(t, p.Manager(), addrmgrNs, func() {
addr, err = p.WithdrawalAddress(ns, addrmgrNs, seriesID, branch, index)
})
if err != nil {
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 }
}
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()
seriesID, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{2e6, 4e6})
seriesID, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{2e6, 4e6})
requests := []OutputRequest{
TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 3e6, params),
TstNewOutputRequest(t, 2, "3PbExiaztsSYgh6zeMswC49hLUwhTQ86XG", 2e6, params),
}
changeStart := TstNewChangeAddress(t, pool, seriesID, 0)
dustThreshold := btcutil.Amount(1e4)
startAddr := TstNewWithdrawalAddress(t, pool, seriesID, 1, 0)
startAddr := TstNewWithdrawalAddress(t, dbtx, pool, seriesID, 1, 0)
lastSeriesID := seriesID
w := newWithdrawal(roundID, requests, eligible, *changeStart)
if err := w.fulfillRequests(); err != nil {

View file

@ -13,6 +13,7 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/walletdb"
"github.com/btcsuite/btcwallet/wtxmgr"
)
@ -22,35 +23,42 @@ var (
)
func TestGetEligibleInputs(t *testing.T) {
tearDown, pool, store := TstCreatePoolAndTxStore(t)
tearDown, db, pool, store := TstCreatePoolAndTxStore(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
series := []TstSeriesDef{
{ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1},
{ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2},
}
TstCreateSeries(t, pool, series)
TstCreateSeries(t, dbtx, pool, series)
scripts := append(
getPKScriptsForAddressRange(t, pool, 1, 0, 2, 0, 4),
getPKScriptsForAddressRange(t, pool, 2, 0, 2, 0, 6)...)
getPKScriptsForAddressRange(t, dbtx, pool, 1, 0, 2, 0, 4),
getPKScriptsForAddressRange(t, dbtx, pool, 2, 0, 2, 0, 6)...)
// Create two eligible inputs locked to each of the PKScripts above.
expNoEligibleInputs := 2 * len(scripts)
eligibleAmounts := []int64{int64(dustThreshold + 1), int64(dustThreshold + 1)}
var inputs []wtxmgr.Credit
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...)
}
startAddr := TstNewWithdrawalAddress(t, pool, 1, 0, 0)
startAddr := TstNewWithdrawalAddress(t, dbtx, pool, 1, 0, 0)
lastSeriesID := uint32(2)
currentBlock := int32(TstInputsBlock + eligibleInputMinConfirmations + 1)
var eligibles []credit
var err error
TstRunWithManagerUnlocked(t, pool.Manager(), func() {
eligibles, err = pool.getEligibleInputs(
store, *startAddr, lastSeriesID, dustThreshold, int32(currentBlock),
txmgrNs := dbtx.ReadBucket(txmgrNamespaceKey)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
eligibles, err = pool.getEligibleInputs(ns, addrmgrNs,
store, txmgrNs, *startAddr, lastSeriesID, dustThreshold, int32(currentBlock),
eligibleInputMinConfirmations)
})
if err != nil {
@ -73,29 +81,35 @@ func TestGetEligibleInputs(t *testing.T) {
}
func TestNextAddrWithVaryingHighestIndices(t *testing.T) {
tearDown, mgr, pool := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
series := []TstSeriesDef{
{ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1},
}
TstCreateSeries(t, pool, series)
TstCreateSeries(t, dbtx, pool, series)
stopSeriesID := uint32(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.
TstEnsureUsedAddr(t, pool, 1, Branch(1), 1)
TstEnsureUsedAddr(t, dbtx, pool, 1, Branch(1), 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
// and index==1.
TstRunWithManagerUnlocked(t, mgr, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
})
if err != nil {
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
// there are no used addresses for branch==2.
TstRunWithManagerUnlocked(t, mgr, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
})
if err != nil {
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
// call will return nil.
TstRunWithManagerUnlocked(t, mgr, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
})
if err != nil {
t.Fatalf("Failed to get next address: %v", err)
@ -126,29 +140,35 @@ func TestNextAddrWithVaryingHighestIndices(t *testing.T) {
}
func TestNextAddr(t *testing.T) {
tearDown, mgr, pool := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
series := []TstSeriesDef{
{ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1},
{ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2},
}
TstCreateSeries(t, pool, series)
TstCreateSeries(t, dbtx, pool, series)
stopSeriesID := uint32(3)
lastIdx := Index(10)
// Populate used addresses DB with entries for seriesID==1, branch==0..3,
// idx==0..10.
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)
var err error
addr := TstNewWithdrawalAddress(t, dbtx, pool, 1, 0, lastIdx-1)
// nextAddr() first increments just the branch, which ranges from 0 to 3
// here (because our series has 3 public keys).
for _, i := range []int{1, 2, 3} {
TstRunWithManagerUnlocked(t, mgr, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
})
if err != nil {
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
// branch=[0-3] and idx=lastIdx.
for _, i := range []int{0, 1, 2, 3} {
TstRunWithManagerUnlocked(t, mgr, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
})
if err != nil {
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,
// idx==0..10.
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
// we should move to the next series and start again with branch=0, idx=0.
for _, i := range []int{0, 1, 2, 3} {
TstRunWithManagerUnlocked(t, mgr, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
})
if err != nil {
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
// available address before stopSeriesID.
addr = TstNewWithdrawalAddress(t, pool, 2, 3, lastIdx)
TstRunWithManagerUnlocked(t, mgr, func() {
addr, err = nextAddr(pool, addr.seriesID, addr.branch, addr.index, stopSeriesID)
addr = TstNewWithdrawalAddress(t, dbtx, pool, 2, 3, lastIdx)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
addr, err = nextAddr(pool, ns, addrmgrNs, addr.seriesID, addr.branch, addr.index, stopSeriesID)
})
if err != nil {
t.Fatalf("Failed to get next address: %v", err)
@ -201,11 +221,17 @@ func TestNextAddr(t *testing.T) {
}
func TestEligibleInputsAreEligible(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
var chainHeight int32 = 1000
_, credits := TstCreateCreditsOnNewSeries(t, pool, []int64{int64(dustThreshold)})
_, credits := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{int64(dustThreshold)})
c := credits[0]
// Make sure credit is old enough to pass the minConf check.
c.BlockMeta.Height = int32(eligibleInputMinConfirmations)
@ -216,11 +242,17 @@ func TestEligibleInputsAreEligible(t *testing.T) {
}
func TestNonEligibleInputsAreNotEligible(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
var chainHeight int32 = 1000
_, credits := TstCreateCreditsOnNewSeries(t, pool, []int64{int64(dustThreshold - 1)})
_, credits := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{int64(dustThreshold - 1)})
c := credits[0]
// Make sure credit is old enough to pass the minConf check.
c.BlockMeta.Height = int32(eligibleInputMinConfirmations)
@ -231,7 +263,7 @@ func TestNonEligibleInputsAreNotEligible(t *testing.T) {
}
// 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]
// 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
@ -243,25 +275,31 @@ func TestNonEligibleInputsAreNotEligible(t *testing.T) {
}
func TestCreditSortingByAddress(t *testing.T) {
teardown, _, pool := TstCreatePool(t)
teardown, db, pool := TstCreatePool(t)
defer teardown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
series := []TstSeriesDef{
{ReqSigs: 2, PubKeys: TstPubKeys[1:4], SeriesID: 1},
{ReqSigs: 2, PubKeys: TstPubKeys[3:6], SeriesID: 2},
}
TstCreateSeries(t, pool, series)
TstCreateSeries(t, dbtx, pool, series)
shaHash0 := bytes.Repeat([]byte{0}, 32)
shaHash1 := bytes.Repeat([]byte{1}, 32)
shaHash2 := bytes.Repeat([]byte{2}, 32)
c0 := newDummyCredit(t, pool, 1, 0, 0, shaHash0, 0)
c1 := newDummyCredit(t, pool, 1, 0, 0, shaHash0, 1)
c2 := newDummyCredit(t, pool, 1, 0, 0, shaHash1, 0)
c3 := newDummyCredit(t, pool, 1, 0, 0, shaHash2, 0)
c4 := newDummyCredit(t, pool, 1, 0, 1, shaHash0, 0)
c5 := newDummyCredit(t, pool, 1, 1, 0, shaHash0, 0)
c6 := newDummyCredit(t, pool, 2, 0, 0, shaHash0, 0)
c0 := newDummyCredit(t, dbtx, pool, 1, 0, 0, shaHash0, 0)
c1 := newDummyCredit(t, dbtx, pool, 1, 0, 0, shaHash0, 1)
c2 := newDummyCredit(t, dbtx, pool, 1, 0, 0, shaHash1, 0)
c3 := newDummyCredit(t, dbtx, pool, 1, 0, 0, shaHash2, 0)
c4 := newDummyCredit(t, dbtx, pool, 1, 0, 1, shaHash0, 0)
c5 := newDummyCredit(t, dbtx, pool, 1, 1, 0, shaHash0, 0)
c6 := newDummyCredit(t, dbtx, pool, 2, 0, 0, shaHash0, 0)
randomCredits := [][]credit{
{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,
// locked to the votingpool address identified by the given
// 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 {
var hash chainhash.Hash
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
// the set of used addresses as that's a requirement of WithdrawalAddress.
TstEnsureUsedAddr(t, pool, series, branch, index)
addr := TstNewWithdrawalAddress(t, pool, series, branch, index)
TstEnsureUsedAddr(t, dbtx, pool, series, branch, index)
addr := TstNewWithdrawalAddress(t, dbtx, pool, series, branch, index)
c := wtxmgr.Credit{
OutPoint: wire.OutPoint{
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 {
var pkScripts [][]byte
for idx := startIdx; idx <= stopIdx; idx++ {
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

View file

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

View file

@ -19,18 +19,26 @@ import (
)
func TestLoadPoolAndDepositScript(t *testing.T) {
tearDown, manager, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
// setup
poolID := "test"
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 {
t.Fatalf("Failed to create voting pool and series: %v", err)
}
// 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 {
t.Fatalf("Failed to get deposit script: %v", err)
}
@ -45,21 +53,28 @@ func TestLoadPoolAndDepositScript(t *testing.T) {
}
func TestLoadPoolAndCreateSeries(t *testing.T) {
tearDown, manager, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
poolID := "test"
// first time, the voting pool is created
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 {
t.Fatalf("Creating voting pool and Creating series failed: %v", err)
}
// create another series where the voting pool is loaded this time
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 {
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) {
tearDown, manager, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
// setup
poolID := "test"
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 {
t.Fatalf("Failed to create voting pool and series: %v", err)
}
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 {
t.Fatalf("Failed to replace series: %v", err)
}
}
func TestLoadPoolAndEmpowerSeries(t *testing.T) {
tearDown, manager, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
// setup
poolID := "test"
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 {
t.Fatalf("Creating voting pool and Creating series failed: %v", err)
}
vp.TstRunWithManagerUnlocked(t, pool.Manager(), func() {
err = vp.LoadAndEmpowerSeries(pool.TstNamespace(), manager, poolID, 1, vp.TstPrivKeys[0])
vp.TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
err = vp.LoadAndEmpowerSeries(ns, pool.Manager(), poolID, 1, vp.TstPrivKeys[0])
})
if err != nil {
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) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
tests := []struct {
version uint32
series uint32
@ -132,7 +168,7 @@ func TestDepositScriptAddress(t *testing.T) {
}
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 {
t.Fatalf("Cannot creates series %v", test.series)
}
@ -160,24 +196,39 @@ func TestDepositScriptAddressForNonExistentSeries(t *testing.T) {
}
func TestDepositScriptAddressForHardenedPubKey(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
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")
}
// Ask for a DepositScriptAddress using an index for a hardened child, which should
// 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)
}
func TestLoadPool(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
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 {
t.Errorf("Error loading Pool: %v", err)
}
@ -187,10 +238,17 @@ func TestLoadPool(t *testing.T) {
}
func TestCreatePool(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
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 {
t.Errorf("Error creating Pool: %v", err)
}
@ -200,18 +258,32 @@ func TestCreatePool(t *testing.T) {
}
func TestCreatePoolWhenAlreadyExists(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
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)
}
func TestCreateSeries(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
tests := []struct {
version uint32
series uint32
@ -245,11 +317,11 @@ func TestCreateSeries(t *testing.T) {
}
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 {
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 {
t.Fatal(err)
}
@ -260,45 +332,74 @@ func TestCreateSeries(t *testing.T) {
}
func TestPoolCreateSeriesInvalidID(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
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)
}
func TestPoolCreateSeriesWhenAlreadyExists(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
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)
}
err := pool.CreateSeries(1, 1, 1, pubKeys)
err = pool.CreateSeries(ns, 1, 1, 1, pubKeys)
vp.TstCheckError(t, "", err, vp.ErrSeriesAlreadyExists)
}
func TestPoolCreateSeriesIDNotSequential(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
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)
}
err := pool.CreateSeries(1, 3, 2, pubKeys)
err = pool.CreateSeries(ns, 1, 3, 2, pubKeys)
vp.TstCheckError(t, "", err, vp.ErrSeriesIDNotSequential)
}
func TestPutSeriesErrors(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
tests := []struct {
version uint32
reqSigs uint32
@ -335,40 +436,54 @@ func TestPutSeriesErrors(t *testing.T) {
}
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)
}
}
func TestCannotReplaceEmpoweredSeries(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
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)
}
vp.TstRunWithManagerUnlocked(t, mgr, func() {
if err := pool.EmpowerSeries(seriesID, vp.TstPrivKeys[1]); err != nil {
vp.TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
if err := pool.EmpowerSeries(ns, seriesID, vp.TstPrivKeys[1]); err != nil {
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.TstCheckError(t, "", err, vp.ErrSeriesAlreadyEmpowered)
}
func TestReplaceNonExistingSeries(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
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)
}
@ -429,19 +544,26 @@ var replaceSeriesTestData = []replaceSeriesTestEntry{
}
func TestReplaceExistingSeries(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
for _, data := range replaceSeriesTestData {
seriesID := data.orig.id
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",
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 {
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) {
tearDown, mgr, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
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)
}
vp.TstRunWithManagerUnlocked(t, mgr, func() {
if err := pool.EmpowerSeries(seriesID, vp.TstPrivKeys[0]); err != nil {
vp.TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
if err := pool.EmpowerSeries(ns, seriesID, vp.TstPrivKeys[0]); err != nil {
t.Errorf("Failed to empower series: %v", err)
}
})
}
func TestEmpowerSeriesErrors(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
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)
}
@ -536,17 +672,25 @@ func TestEmpowerSeriesErrors(t *testing.T) {
}
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)
}
}
func TestPoolSeries(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
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])
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)
}
@ -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 {
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 {
t.Fatalf("Voting Pool creation failed: %v", err)
}
for _, series := range test.series {
err := pool.CreateSeries(series.version, series.id,
err := pool.CreateSeries(ns, series.version, series.id,
series.reqSigs, series.pubKeys)
if err != nil {
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 {
vp.TstRunWithManagerUnlocked(t, mgr, func() {
if err := pool.EmpowerSeries(series.id, privKey); err != nil {
vp.TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
if err := pool.EmpowerSeries(ns, series.id, privKey); err != nil {
t.Fatalf("Test #%d Series #%d: empower with privKey %v failed: %v",
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) {
tearDown, manager, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := vp.TstRWNamespaces(dbtx)
for _, test := range testLoadAllSeriesTests {
pool := setUpLoadAllSeries(t, pool.TstNamespace(), manager, test)
pool := setUpLoadAllSeries(t, dbtx, pool.Manager(), test)
pool.TstEmptySeriesLookup()
vp.TstRunWithManagerUnlocked(t, manager, func() {
if err := pool.LoadAllSeries(); err != nil {
vp.TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
if err := pool.LoadAllSeries(ns); err != nil {
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) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, _ := vp.TstRWNamespaces(dbtx)
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 {
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
// in EmpowerSeries.
badKey := "wM5uZBNTYmaYGiK8VaGi7zPGbZGLuQgDiR2Zk4nGfbRFLXwHGcMUdVdazRpNHFSR7X7WLmzzbAq8dA1ViN6eWKgKqPye1rJTDQTvBiXvZ7E3nmdx"
err = pool.EmpowerSeries(seriesID, badKey)
err = pool.EmpowerSeries(ns, seriesID, badKey)
vp.TstCheckError(t, "", err, vp.ErrKeyNeuter)
}
func TestDecryptExtendedKeyCannotCreateResultKey(t *testing.T) {
tearDown, mgr, pool := vp.TstCreatePool(t)
tearDown, _, pool := vp.TstCreatePool(t)
defer tearDown()
// 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 {
t.Fatalf("Failed to encrypt plaintext: %v", err)
}
@ -885,35 +1044,48 @@ func TestDecryptExtendedKeyCannotDecrypt(t *testing.T) {
}
func TestPoolChangeAddress(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
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)
checkPoolAddress(t, addr, 1, 0, 0)
// When the series is not active, we should get an error.
pubKeys = vp.TstPubKeys[3:6]
vp.TstCreateSeries(t, pool,
vp.TstCreateSeries(t, dbtx, pool,
[]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)
}
func TestPoolWithdrawalAddress(t *testing.T) {
tearDown, _, pool := vp.TstCreatePool(t)
tearDown, db, pool := vp.TstCreatePool(t)
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]
vp.TstCreateSeries(t, pool, []vp.TstSeriesDef{{ReqSigs: 2, PubKeys: pubKeys, SeriesID: 1}})
addr := vp.TstNewWithdrawalAddress(t, pool, 1, 0, 0)
vp.TstCreateSeries(t, dbtx, pool, []vp.TstSeriesDef{{ReqSigs: 2, PubKeys: pubKeys, SeriesID: 1}})
addr := vp.TstNewWithdrawalAddress(t, dbtx, pool, 1, 0, 0)
checkPoolAddress(t, addr, 1, 0, 0)
// When the requested address is not present in the set of used addresses
// 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)
}

View file

@ -14,26 +14,32 @@ import (
)
func TestPoolEnsureUsedAddr(t *testing.T) {
tearDown, mgr, pool := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
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 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)
TstRunWithManagerUnlocked(t, mgr, func() {
err = pool.EnsureUsedAddr(1, 0, idx)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
err = pool.EnsureUsedAddr(ns, addrmgrNs, 1, 0, idx)
})
if err != nil {
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 {
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()
})
if err != nil {
@ -45,18 +51,18 @@ func TestPoolEnsureUsedAddr(t *testing.T) {
}
idx = Index(3)
TstRunWithManagerUnlocked(t, mgr, func() {
err = pool.EnsureUsedAddr(1, 0, idx)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
err = pool.EnsureUsedAddr(ns, addrmgrNs, 1, 0, idx)
})
if err != nil {
t.Fatalf("Failed to ensure used addresses: %v", err)
}
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 {
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()
})
if err != nil {
@ -70,14 +76,21 @@ func TestPoolEnsureUsedAddr(t *testing.T) {
}
func TestPoolGetUsedAddr(t *testing.T) {
tearDown, mgr, pool := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
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
// return nil.
addr, err := pool.getUsedAddr(1, 0, 10)
addr, err := pool.getUsedAddr(ns, addrmgrNs, 1, 0, 10)
if err != nil {
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
// returned by getUsedAddr() is what we expect.
TstRunWithManagerUnlocked(t, mgr, func() {
err = pool.addUsedAddr(1, 0, 10)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
err = pool.addUsedAddr(ns, addrmgrNs, 1, 0, 10)
})
if err != nil {
t.Fatalf("Error when storing addr in used addresses DB: %v", err)
}
var script []byte
addr, err = pool.getUsedAddr(1, 0, 10)
addr, err = pool.getUsedAddr(ns, addrmgrNs, 1, 0, 10)
if err != nil {
t.Fatalf("Error when looking up used addr: %v", err)
}
TstRunWithManagerUnlocked(t, mgr, func() {
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
script, err = addr.Script()
})
if err != nil {
@ -111,9 +124,16 @@ func TestPoolGetUsedAddr(t *testing.T) {
}
func TestSerializationErrors(t *testing.T) {
tearDown, mgr, _ := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
tests := []struct {
version uint32
pubKeys []string
@ -147,13 +167,13 @@ func TestSerializationErrors(t *testing.T) {
active := true
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 {
t.Fatalf("Test #%d - Error encrypting pubkeys: %v", testNum, err)
}
var encryptedPrivs [][]byte
TstRunWithManagerUnlocked(t, mgr, func() {
encryptedPrivs, err = encryptKeys(test.privKeys, mgr, waddrmgr.CKTPrivate)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
encryptedPrivs, err = encryptKeys(test.privKeys, pool.Manager(), waddrmgr.CKTPrivate)
})
if err != nil {
t.Fatalf("Test #%d - Error encrypting privkeys: %v", testNum, err)
@ -172,9 +192,16 @@ func TestSerializationErrors(t *testing.T) {
}
func TestSerialization(t *testing.T) {
tearDown, mgr, _ := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
tests := []struct {
version uint32
active bool
@ -213,12 +240,12 @@ func TestSerialization(t *testing.T) {
var encryptedPrivs [][]byte
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 {
t.Fatalf("Test #%d - Error encrypting pubkeys: %v", testNum, err)
}
TstRunWithManagerUnlocked(t, mgr, func() {
encryptedPrivs, err = encryptKeys(test.privKeys, mgr, waddrmgr.CKTPrivate)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
encryptedPrivs, err = encryptKeys(test.privKeys, pool.Manager(), waddrmgr.CKTPrivate)
})
if err != nil {
t.Fatalf("Test #%d - Error encrypting privkeys: %v", testNum, err)
@ -287,8 +314,7 @@ func TestSerialization(t *testing.T) {
}
func TestDeserializationErrors(t *testing.T) {
tearDown, _, _ := TstCreatePool(t)
defer tearDown()
t.Parallel()
tests := []struct {
serialized []byte
@ -329,24 +355,31 @@ func TestDeserializationErrors(t *testing.T) {
}
func TestValidateAndDecryptKeys(t *testing.T) {
tearDown, manager, pool := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
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 {
t.Fatalf("Failed to encrypt public keys: %v", err)
}
var rawPrivKeys [][]byte
TstRunWithManagerUnlocked(t, manager, func() {
rawPrivKeys, err = encryptKeys([]string{TstPrivKeys[0], ""}, manager, waddrmgr.CKTPrivate)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
rawPrivKeys, err = encryptKeys([]string{TstPrivKeys[0], ""}, pool.Manager(), waddrmgr.CKTPrivate)
})
if err != nil {
t.Fatalf("Failed to encrypt private keys: %v", err)
}
var pubKeys, privKeys []*hdkeychain.ExtendedKey
TstRunWithManagerUnlocked(t, manager, func() {
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
pubKeys, privKeys, err = validateAndDecryptKeys(rawPubKeys, rawPrivKeys, pool)
})
if err != nil {
@ -379,17 +412,24 @@ func TestValidateAndDecryptKeys(t *testing.T) {
}
func TestValidateAndDecryptKeysErrors(t *testing.T) {
tearDown, manager, pool := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
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 {
t.Fatalf("Failed to encrypt public key: %v", err)
}
var encryptedPrivKeys [][]byte
TstRunWithManagerUnlocked(t, manager, func() {
encryptedPrivKeys, err = encryptKeys(TstPrivKeys[1:2], manager, waddrmgr.CKTPrivate)
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
encryptedPrivKeys, err = encryptKeys(TstPrivKeys[1:2], pool.Manager(), waddrmgr.CKTPrivate)
})
if err != nil {
t.Fatalf("Failed to encrypt private key: %v", err)
@ -427,7 +467,7 @@ func TestValidateAndDecryptKeysErrors(t *testing.T) {
}
for i, test := range tests {
TstRunWithManagerUnlocked(t, manager, func() {
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
_, _, err = validateAndDecryptKeys(test.rawPubKeys, test.rawPrivKeys, pool)
})
TstCheckError(t, fmt.Sprintf("Test #%d", i), err, test.err)

View file

@ -14,8 +14,17 @@ import (
)
func TestStartWithdrawal(t *testing.T) {
tearDown, pool, store := vp.TstCreatePoolAndTxStore(t)
tearDown, db, pool, store := vp.TstCreatePoolAndTxStore(t)
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()
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{0x03, 0x01}, 16))}
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.
vp.TstCreateSeriesCreditsOnStore(t, pool, def.SeriesID, []int64{5e6, 4e6}, store)
vp.TstCreateSeriesCreditsOnStore(t, dbtx, pool, def.SeriesID, []int64{5e6, 4e6}, store)
address1 := "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6"
address2 := "3PbExiaztsSYgh6zeMswC49hLUwhTQ86XG"
requests := []vp.OutputRequest{
@ -34,15 +43,14 @@ func TestStartWithdrawal(t *testing.T) {
}
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
dustThreshold := btcutil.Amount(1e4)
currentBlock := int32(vp.TstInputsBlock + vp.TstEligibleInputMinConfirmations + 1)
var status *vp.WithdrawalStatus
var err error
vp.TstRunWithManagerUnlocked(t, mgr, func() {
status, err = pool.StartWithdrawal(0, requests, *startAddr, lastSeriesID, *changeStart,
store, currentBlock, dustThreshold)
vp.TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
status, err = pool.StartWithdrawal(ns, addrmgrNs, 0, requests, *startAddr, lastSeriesID, *changeStart,
store, txmgrNs, currentBlock, dustThreshold)
})
if err != nil {
t.Fatal(err)
@ -79,8 +87,8 @@ func TestStartWithdrawal(t *testing.T) {
// signatures). Must unlock the manager as signing involves looking up the
// redeem script, which is stored encrypted.
msgtx := status.TstGetMsgTx(ntxid)
vp.TstRunWithManagerUnlocked(t, mgr, func() {
if err = vp.SignTx(msgtx, txSigs, mgr, store); err != nil {
vp.TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
if err = vp.SignTx(msgtx, txSigs, mgr, addrmgrNs, store, txmgrNs); err != nil {
t.Fatal(err)
}
})
@ -88,9 +96,9 @@ func TestStartWithdrawal(t *testing.T) {
// Any subsequent StartWithdrawal() calls with the same parameters will
// return the previously stored WithdrawalStatus.
var status2 *vp.WithdrawalStatus
vp.TstRunWithManagerUnlocked(t, mgr, func() {
status2, err = pool.StartWithdrawal(0, requests, *startAddr, lastSeriesID, *changeStart,
store, currentBlock, dustThreshold)
vp.TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
status2, err = pool.StartWithdrawal(ns, addrmgrNs, 0, requests, *startAddr, lastSeriesID, *changeStart,
store, txmgrNs, currentBlock, dustThreshold)
})
if err != nil {
t.Fatal(err)

View file

@ -23,9 +23,15 @@ import (
// TestOutputSplittingNotEnoughInputs checks that an output will get split if we
// don't have enough inputs to fulfil it.
func TestOutputSplittingNotEnoughInputs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams()
output1Amount := btcutil.Amount(2)
output2Amount := btcutil.Amount(3)
@ -36,7 +42,7 @@ func TestOutputSplittingNotEnoughInputs(t *testing.T) {
TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", output1Amount, 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.txOptions = func(tx *withdrawalTx) {
// 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) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
requestAmount := btcutil.Amount(5)
bigInput := int64(3)
smallInput := int64(2)
request := TstNewOutputRequest(
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)
w := newWithdrawal(0, []OutputRequest{request}, eligible, *changeStart)
w.txOptions = func(tx *withdrawalTx) {
@ -129,13 +141,19 @@ func TestOutputSplittingOversizeTx(t *testing.T) {
}
func TestSplitLastOutputNoOutputs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
w := newWithdrawal(0, []OutputRequest{}, []credit{}, ChangeAddress{})
w.current = createWithdrawalTx(t, pool, []int64{}, []int64{})
dbtx, err := db.BeginReadWriteTx()
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)
}
@ -143,12 +161,19 @@ func TestSplitLastOutputNoOutputs(t *testing.T) {
// Check that all outputs requested in a withdrawal match the outputs of the generated
// transaction(s).
func TestWithdrawalTxOutputs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams()
// 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{
TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 3e6, 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
// don't have enough eligible credits for any of them.
func TestFulfillRequestsNoSatisfiableOutputs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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(
t, 1, "3Qt1EaKRD9g9FeL2DGkLLswhK1AKmmXFSe", btcutil.Amount(3e6), pool.Manager().ChainParams())
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
// of them.
func TestFulfillRequestsNotEnoughCreditsForAllRequests(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams()
// 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(
t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", btcutil.Amount(3e6), net)
out2 := TstNewOutputRequest(
@ -261,10 +299,16 @@ func TestFulfillRequestsNotEnoughCreditsForAllRequests(t *testing.T) {
// TestRollbackLastOutput tests the case where we rollback one output
// and one input, such that sum(in) >= sum(out) + fee.
func TestRollbackLastOutput(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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
initialOutputs := tx.outputs
@ -295,12 +339,18 @@ func TestRollbackLastOutput(t *testing.T) {
}
func TestRollbackLastOutputMultipleInputsRolledBack(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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
// 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
initialOutputs := tx.outputs
@ -328,10 +378,16 @@ func TestRollbackLastOutputMultipleInputsRolledBack(t *testing.T) {
// TestRollbackLastOutputNoInputsRolledBack tests the case where we roll back
// one output but don't need to roll back any inputs.
func TestRollbackLastOutputNoInputsRolledBack(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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
initialOutputs := tx.outputs
@ -375,11 +431,17 @@ func TestRollBackLastOutputInsufficientOutputs(t *testing.T) {
// TestRollbackLastOutputWhenNewOutputAdded checks that we roll back the last
// output if a tx becomes too big right after we add a new output to it.
func TestRollbackLastOutputWhenNewOutputAdded(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
net := pool.Manager().ChainParams()
series, eligible := TstCreateCreditsOnNewSeries(t, pool, []int64{5, 5})
series, eligible := TstCreateCreditsOnNewSeries(t, dbtx, pool, []int64{5, 5})
requests := []OutputRequest{
// This is ordered by bailment ID
TstNewOutputRequest(t, 1, "34eVkREKgvvGASZW7hkgE2uNc1yycntMK6", 1, net),
@ -427,11 +489,17 @@ func TestRollbackLastOutputWhenNewOutputAdded(t *testing.T) {
// TestRollbackLastOutputWhenNewInputAdded checks that we roll back the last
// output if a tx becomes too big right after we add a new input to it.
func TestRollbackLastOutputWhenNewInputAdded(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
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{
// This is manually ordered by outBailmentIDHash, which is the order in
// which they're going to be fulfilled by w.fulfillRequests().
@ -486,10 +554,16 @@ func TestRollbackLastOutputWhenNewInputAdded(t *testing.T) {
}
func TestWithdrawalTxRemoveOutput(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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
// Make sure we have created the transaction with the expected
// outputs.
@ -514,10 +588,16 @@ func TestWithdrawalTxRemoveOutput(t *testing.T) {
}
func TestWithdrawalTxRemoveInput(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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
// Make sure we have created the transaction with the expected inputs
checkTxInputs(t, tx, inputs)
@ -540,11 +620,17 @@ func TestWithdrawalTxRemoveInput(t *testing.T) {
}
func TestWithdrawalTxAddChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
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))
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
// outputs+fees.
func TestWithdrawalTxAddChangeNoChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
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))
if tx.addChange([]byte{}) {
@ -583,20 +675,32 @@ func TestWithdrawalTxAddChangeNoChange(t *testing.T) {
}
func TestWithdrawalTxToMsgTxNoInputsOrOutputsOrChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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()
compareMsgTxAndWithdrawalTxOutputs(t, msgtx, tx)
compareMsgTxAndWithdrawalTxInputs(t, msgtx, tx)
}
func TestWithdrawalTxToMsgTxNoInputsOrOutputsWithChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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{})
msgtx := tx.toMsgTx()
@ -606,10 +710,16 @@ func TestWithdrawalTxToMsgTxNoInputsOrOutputsWithChange(t *testing.T) {
}
func TestWithdrawalTxToMsgTxWithInputButNoOutputsWithChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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{})
msgtx := tx.toMsgTx()
@ -619,11 +729,16 @@ func TestWithdrawalTxToMsgTxWithInputButNoOutputsWithChange(t *testing.T) {
}
func TestWithdrawalTxToMsgTxWithInputOutputsAndChange(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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{})
msgtx := tx.toMsgTx()
@ -633,10 +748,16 @@ func TestWithdrawalTxToMsgTxWithInputOutputsAndChange(t *testing.T) {
}
func TestWithdrawalTxInputTotal(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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) {
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) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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{})
if tx.outputTotal() != btcutil.Amount(4) {
@ -656,18 +783,24 @@ func TestWithdrawalTxOutputTotal(t *testing.T) {
}
func TestWithdrawalInfoMatch(t *testing.T) {
tearDown, _, pool := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
roundID := uint32(0)
wi := createAndFulfillWithdrawalRequests(t, pool, roundID)
wi := createAndFulfillWithdrawalRequests(t, dbtx, pool, roundID)
// Use freshly created values for requests, startAddress and changeStart
// to simulate what would happen if we had recreated them from the
// serialized data in the DB.
requestsCopy := make([]OutputRequest, len(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)
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.
diffStartAddr := TstNewWithdrawalAddress(t, pool, startAddr.seriesID, startAddr.branch+1,
diffStartAddr := TstNewWithdrawalAddress(t, dbtx, pool, startAddr.seriesID, startAddr.branch+1,
startAddr.index)
matches = wi.match(requestsCopy, *diffStartAddr, wi.lastSeriesID, *changeStart,
wi.dustThreshold)
@ -726,29 +859,33 @@ func TestWithdrawalInfoMatch(t *testing.T) {
}
func TestGetWithdrawalStatus(t *testing.T) {
tearDown, _, pool := TstCreatePool(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
ns, addrmgrNs := TstRWNamespaces(dbtx)
roundID := uint32(0)
wi := createAndFulfillWithdrawalRequests(t, pool, roundID)
wi := createAndFulfillWithdrawalRequests(t, dbtx, pool, roundID)
serialized, err := serializeWithdrawal(wi.requests, wi.startAddress, wi.lastSeriesID,
wi.changeStart, wi.dustThreshold, wi.status)
if err != nil {
t.Fatal(err)
}
err = pool.namespace.Update(
func(tx walletdb.Tx) error {
return putWithdrawal(tx, pool.ID, roundID, serialized)
})
err = putWithdrawal(ns, pool.ID, roundID, serialized)
if err != nil {
t.Fatal(err)
}
// Here we should get a WithdrawalStatus that matches wi.status.
var status *WithdrawalStatus
TstRunWithManagerUnlocked(t, pool.Manager(), func() {
status, err = getWithdrawalStatus(pool, roundID, wi.requests, wi.startAddress,
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
status, err = getWithdrawalStatus(pool, ns, addrmgrNs, roundID, wi.requests, wi.startAddress,
wi.lastSeriesID, wi.changeStart, wi.dustThreshold)
})
if err != nil {
@ -759,8 +896,8 @@ func TestGetWithdrawalStatus(t *testing.T) {
// Here we should get a nil WithdrawalStatus because the parameters are not
// identical to those of the stored WithdrawalStatus with this roundID.
dustThreshold := wi.dustThreshold + 1
TstRunWithManagerUnlocked(t, pool.Manager(), func() {
status, err = getWithdrawalStatus(pool, roundID, wi.requests, wi.startAddress,
TstRunWithManagerUnlocked(t, pool.Manager(), addrmgrNs, func() {
status, err = getWithdrawalStatus(pool, ns, addrmgrNs, roundID, wi.requests, wi.startAddress,
wi.lastSeriesID, wi.changeStart, dustThreshold)
})
if err != nil {
@ -772,12 +909,19 @@ func TestGetWithdrawalStatus(t *testing.T) {
}
func TestSignMultiSigUTXO(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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.
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})
if err != nil {
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.
pkScript := tx.inputs[idx].PkScript
TstRunWithManagerUnlocked(t, mgr, func() {
if err = signMultiSigUTXO(mgr, msgtx, idx, pkScript, txSigs[idx]); err != nil {
TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
if err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, idx, pkScript, txSigs[idx]); err != nil {
t.Fatal(err)
}
})
}
func TestSignMultiSigUTXOUnparseablePkScript(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{})
tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
msgtx := tx.toMsgTx()
unparseablePkScript := []byte{0x01}
err := signMultiSigUTXO(mgr, msgtx, 0, unparseablePkScript, []RawSig{{}})
err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, 0, unparseablePkScript, []RawSig{{}})
TstCheckError(t, "", err, ErrTxSigning)
}
func TestSignMultiSigUTXOPkScriptNotP2SH(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{})
tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
addr, _ := btcutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams())
pubKeyHashPkScript, _ := txscript.PayToAddrScript(addr.(*btcutil.AddressPubKeyHash))
msgtx := tx.toMsgTx()
err := signMultiSigUTXO(mgr, msgtx, 0, pubKeyHashPkScript, []RawSig{{}})
err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, 0, pubKeyHashPkScript, []RawSig{{}})
TstCheckError(t, "", err, ErrTxSigning)
}
func TestSignMultiSigUTXORedeemScriptNotFound(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
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
// script.
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)
}
msgtx := tx.toMsgTx()
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)
}
func TestSignMultiSigUTXONotEnoughSigs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{})
tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
sigs, err := getRawSigs([]*withdrawalTx{tx})
if err != nil {
t.Fatal(err)
@ -862,36 +1034,49 @@ func TestSignMultiSigUTXONotEnoughSigs(t *testing.T) {
reqSigs := tx.inputs[idx].addr.series().TstGetReqSigs()
txInSigs := txSigs[idx][:reqSigs-1]
pkScript := tx.inputs[idx].PkScript
TstRunWithManagerUnlocked(t, mgr, func() {
err = signMultiSigUTXO(mgr, msgtx, idx, pkScript, txInSigs)
TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
err = signMultiSigUTXO(mgr, addrmgrNs, msgtx, idx, pkScript, txInSigs)
})
TstCheckError(t, "", err, ErrTxSigning)
}
func TestSignMultiSigUTXOWrongRawSigs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
defer tearDown()
dbtx, err := db.BeginReadWriteTx()
if err != nil {
t.Fatal(err)
}
defer dbtx.Commit()
_, addrmgrNs := TstRWNamespaces(dbtx)
mgr := pool.Manager()
tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{})
tx := createWithdrawalTx(t, dbtx, pool, []int64{4e6}, []int64{})
sigs := []RawSig{{0x00}, {0x01}}
idx := 0 // The index of the tx input we're going to sign.
pkScript := tx.inputs[idx].PkScript
var err error
TstRunWithManagerUnlocked(t, mgr, func() {
err = signMultiSigUTXO(mgr, tx.toMsgTx(), idx, pkScript, sigs)
TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
err = signMultiSigUTXO(mgr, addrmgrNs, tx.toMsgTx(), idx, pkScript, sigs)
})
TstCheckError(t, "", err, ErrTxSigning)
}
func TestGetRawSigs(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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})
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
// sigsnature scripts and execute them to make sure the raw signatures are
// valid.
signTxAndValidate(t, pool.Manager(), msgtx, txSigs, tx.inputs)
signTxAndValidate(t, pool.Manager(), addrmgrNs, msgtx, txSigs, tx.inputs)
}
func TestGetRawSigsOnlyOnePrivKeyAvailable(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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.
series := tx.inputs[0].addr.series()
for i := range series.privateKeys[1:] {
@ -936,29 +1127,41 @@ func TestGetRawSigsOnlyOnePrivKeyAvailable(t *testing.T) {
}
func TestGetRawSigsUnparseableRedeemScript(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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
// getRawSigs().
tx.inputs[0].addr.script = []byte{0x01}
_, err := getRawSigs([]*withdrawalTx{tx})
_, err = getRawSigs([]*withdrawalTx{tx})
TstCheckError(t, "", err, ErrRawSigning)
}
func TestGetRawSigsInvalidAddrBranch(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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
// an error in getRawSigs().
tx.inputs[0].addr.branch = Branch(999)
_, err := getRawSigs([]*withdrawalTx{tx})
_, err = getRawSigs([]*withdrawalTx{tx})
TstCheckError(t, "", err, ErrInvalidBranch)
}
@ -982,10 +1185,16 @@ func TestOutBailmentIDSort(t *testing.T) {
}
func TestTxTooBig(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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 }
if tx.isTooBig() {
@ -1008,10 +1217,17 @@ func TestTxTooBig(t *testing.T) {
}
func TestTxSizeCalculation(t *testing.T) {
tearDown, pool, _ := TstCreatePoolAndTxStore(t)
tearDown, db, pool := TstCreatePool(t)
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()
@ -1027,7 +1243,7 @@ func TestTxSizeCalculation(t *testing.T) {
if err != nil {
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
// 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) {
tearDown, pool, store := TstCreatePoolAndTxStore(t)
tearDown, db, pool, store := TstCreatePoolAndTxStore(t)
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)}
if err := storeTransactions(store, []*changeAwareTx{tx}); err != nil {
if err := storeTransactions(store, txmgrNs, []*changeAwareTx{tx}); err != nil {
t.Fatal(err)
}
credits, err := store.UnspentOutputs()
credits, err := store.UnspentOutputs(txmgrNs)
if err != nil {
t.Fatal(err)
}
@ -1099,20 +1322,27 @@ func TestStoreTransactionsWithoutChangeOutput(t *testing.T) {
}
func TestStoreTransactionsWithChangeOutput(t *testing.T) {
tearDown, pool, store := TstCreatePoolAndTxStore(t)
tearDown, db, pool, store := TstCreatePoolAndTxStore(t)
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{})
msgtx := wtx.toMsgTx()
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)
}
hash := msgtx.TxHash()
txDetails, err := store.TxDetails(&hash)
txDetails, err := store.TxDetails(txmgrNs, &hash)
if err != nil {
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))
}
credits, err := store.UnspentOutputs()
credits, err := store.UnspentOutputs(txmgrNs)
if err != nil {
t.Fatal(err)
}
@ -1156,7 +1386,7 @@ func TestStoreTransactionsWithChangeOutput(t *testing.T) {
// createWithdrawalTxWithStoreCredits creates a new Credit in the given store
// for each entry in inputAmounts, and uses them to construct a withdrawalTx
// 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 {
masters := []*hdkeychain.ExtendedKey{
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)),
}
def := TstCreateSeriesDef(t, pool, 2, masters)
TstCreateSeries(t, pool, []TstSeriesDef{def})
TstCreateSeries(t, dbtx, pool, []TstSeriesDef{def})
net := pool.Manager().ChainParams()
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)
}
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
// transaction (using the given raw signatures and the pkScripts from credits) and execute
// 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) {
for i := range tx.TxIn {
pkScript := credits[i].PkScript
TstRunWithManagerUnlocked(t, mgr, func() {
if err := signMultiSigUTXO(mgr, tx, i, pkScript, txSigs[i]); err != nil {
TstRunWithManagerUnlocked(t, mgr, addrmgrNs, func() {
if err := signMultiSigUTXO(mgr, addrmgrNs, tx, i, pkScript, txSigs[i]); err != nil {
t.Fatal(err)
}
})