fix wtxmgr tests
While making these tests compile and pass, we ended up tripping on the broken bolt cursor usage painfully discovered in dcrwallet, so i've ported that fix over as well. Would have learned about that a whole lot sooner if those tests were never disabled..
This commit is contained in:
parent
4e58d61556
commit
2bb45752e1
5 changed files with 477 additions and 326 deletions
43
wtxmgr/db.go
43
wtxmgr/db.go
|
@ -341,13 +341,23 @@ func (it *blockIterator) prev() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *blockIterator) delete() error {
|
// unavailable until https://github.com/boltdb/bolt/issues/620 is fixed.
|
||||||
err := it.c.Delete()
|
// func (it *blockIterator) delete() error {
|
||||||
if err != nil {
|
// err := it.c.Delete()
|
||||||
str := "failed to delete block record"
|
// if err != nil {
|
||||||
storeError(ErrDatabase, str, err)
|
// str := "failed to delete block record"
|
||||||
}
|
// storeError(ErrDatabase, str, err)
|
||||||
return nil
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (it *blockIterator) reposition(height int32) {
|
||||||
|
it.c.Seek(keyBlockRecord(height))
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteBlockRecord(ns walletdb.ReadWriteBucket, height int32) error {
|
||||||
|
k := keyBlockRecord(height)
|
||||||
|
return ns.NestedReadWriteBucket(bucketBlocks).Delete(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transaction records are keyed as such:
|
// Transaction records are keyed as such:
|
||||||
|
@ -1177,13 +1187,18 @@ func (it *unminedCreditIterator) next() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *unminedCreditIterator) delete() error {
|
// unavailable until https://github.com/boltdb/bolt/issues/620 is fixed.
|
||||||
err := it.c.Delete()
|
// func (it *unminedCreditIterator) delete() error {
|
||||||
if err != nil {
|
// err := it.c.Delete()
|
||||||
str := "failed to delete unmined credit"
|
// if err != nil {
|
||||||
return storeError(ErrDatabase, str, err)
|
// str := "failed to delete unmined credit"
|
||||||
}
|
// return storeError(ErrDatabase, str, err)
|
||||||
return nil
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (it *unminedCreditIterator) reposition(txHash *chainhash.Hash, index uint32) {
|
||||||
|
it.c.Seek(canonicalOutPoint(txHash, index))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Outpoints spent by unmined transactions are saved in the unmined inputs
|
// Outpoints spent by unmined transactions are saved in the unmined inputs
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/btcsuite/btcd/chaincfg"
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/btcsuite/btcwallet/walletdb"
|
||||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ var exampleBlock100 = makeBlockMeta(100)
|
||||||
// This example demonstrates reporting the Store balance given an unmined and
|
// This example demonstrates reporting the Store balance given an unmined and
|
||||||
// mined transaction given 0, 1, and 6 block confirmations.
|
// mined transaction given 0, 1, and 6 block confirmations.
|
||||||
func ExampleStore_Balance() {
|
func ExampleStore_Balance() {
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
@ -54,17 +55,24 @@ func ExampleStore_Balance() {
|
||||||
// Prints balances for 0 block confirmations, 1 confirmation, and 6
|
// Prints balances for 0 block confirmations, 1 confirmation, and 6
|
||||||
// confirmations.
|
// confirmations.
|
||||||
printBalances := func(syncHeight int32) {
|
printBalances := func(syncHeight int32) {
|
||||||
zeroConfBal, err := s.Balance(0, syncHeight)
|
dbtx, err := db.BeginReadTx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
oneConfBal, err := s.Balance(1, syncHeight)
|
defer dbtx.Rollback()
|
||||||
|
ns := dbtx.ReadBucket(namespaceKey)
|
||||||
|
zeroConfBal, err := s.Balance(ns, 0, syncHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sixConfBal, err := s.Balance(6, syncHeight)
|
oneConfBal, err := s.Balance(ns, 1, syncHeight)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sixConfBal, err := s.Balance(ns, 6, syncHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
|
@ -74,12 +82,14 @@ func ExampleStore_Balance() {
|
||||||
|
|
||||||
// Insert a transaction which outputs 10 BTC unmined and mark the output
|
// Insert a transaction which outputs 10 BTC unmined and mark the output
|
||||||
// as a credit.
|
// as a credit.
|
||||||
err = s.InsertTx(exampleTxRecordA, nil)
|
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
|
||||||
if err != nil {
|
ns := tx.ReadWriteBucket(namespaceKey)
|
||||||
fmt.Println(err)
|
err := s.InsertTx(ns, exampleTxRecordA, nil)
|
||||||
return
|
if err != nil {
|
||||||
}
|
return err
|
||||||
err = s.AddCredit(exampleTxRecordA, nil, 0, false)
|
}
|
||||||
|
return s.AddCredit(ns, exampleTxRecordA, nil, 0, false)
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
|
@ -88,7 +98,10 @@ func ExampleStore_Balance() {
|
||||||
|
|
||||||
// Mine the transaction in block 100 and print balances again with a
|
// Mine the transaction in block 100 and print balances again with a
|
||||||
// sync height of 100 and 105 blocks.
|
// sync height of 100 and 105 blocks.
|
||||||
err = s.InsertTx(exampleTxRecordA, &exampleBlock100)
|
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
|
||||||
|
ns := tx.ReadWriteBucket(namespaceKey)
|
||||||
|
return s.InsertTx(ns, exampleTxRecordA, &exampleBlock100)
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
|
@ -103,38 +116,43 @@ func ExampleStore_Balance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleStore_Rollback() {
|
func ExampleStore_Rollback() {
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert a transaction which outputs 10 BTC in a block at height 100.
|
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
|
||||||
err = s.InsertTx(exampleTxRecordA, &exampleBlock100)
|
ns := tx.ReadWriteBucket(namespaceKey)
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rollback everything from block 100 onwards.
|
// Insert a transaction which outputs 10 BTC in a block at height 100.
|
||||||
err = s.Rollback(100)
|
err := s.InsertTx(ns, exampleTxRecordA, &exampleBlock100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
return err
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Assert that the transaction is now unmined.
|
// Rollback everything from block 100 onwards.
|
||||||
details, err := s.TxDetails(&exampleTxRecordA.Hash)
|
err = s.Rollback(ns, 100)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert that the transaction is now unmined.
|
||||||
|
details, err := s.TxDetails(ns, &exampleTxRecordA.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if details == nil {
|
||||||
|
return fmt.Errorf("no details found")
|
||||||
|
}
|
||||||
|
fmt.Println(details.Block.Height)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if details == nil {
|
|
||||||
fmt.Println("No details found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(details.Block.Height)
|
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// -1
|
// -1
|
||||||
|
@ -149,20 +167,28 @@ func Example_basicUsage() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create or open a db namespace for the transaction store.
|
// Open a read-write transaction to operate on the database.
|
||||||
ns, err := db.Namespace([]byte("txstore"))
|
dbtx, err := db.BeginReadWriteTx()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer dbtx.Commit()
|
||||||
|
|
||||||
|
// Create a bucket for the transaction store.
|
||||||
|
b, err := dbtx.CreateTopLevelBucket([]byte("txstore"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create (or open) the transaction store in the provided namespace.
|
// Create and open the transaction store in the provided namespace.
|
||||||
err = wtxmgr.Create(ns)
|
err = wtxmgr.Create(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s, err := wtxmgr.Open(ns, &chaincfg.TestNet3Params)
|
s, err := wtxmgr.Open(b, &chaincfg.TestNet3Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
|
@ -170,12 +196,12 @@ func Example_basicUsage() {
|
||||||
|
|
||||||
// Insert an unmined transaction that outputs 10 BTC to a wallet address
|
// Insert an unmined transaction that outputs 10 BTC to a wallet address
|
||||||
// at output 0.
|
// at output 0.
|
||||||
err = s.InsertTx(exampleTxRecordA, nil)
|
err = s.InsertTx(b, exampleTxRecordA, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = s.AddCredit(exampleTxRecordA, nil, 0, false)
|
err = s.AddCredit(b, exampleTxRecordA, nil, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
|
@ -183,31 +209,31 @@ func Example_basicUsage() {
|
||||||
|
|
||||||
// Insert a second transaction which spends the output, and creates two
|
// Insert a second transaction which spends the output, and creates two
|
||||||
// outputs. Mark the second one (5 BTC) as wallet change.
|
// outputs. Mark the second one (5 BTC) as wallet change.
|
||||||
err = s.InsertTx(exampleTxRecordB, nil)
|
err = s.InsertTx(b, exampleTxRecordB, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = s.AddCredit(exampleTxRecordB, nil, 1, true)
|
err = s.AddCredit(b, exampleTxRecordB, nil, 1, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mine each transaction in a block at height 100.
|
// Mine each transaction in a block at height 100.
|
||||||
err = s.InsertTx(exampleTxRecordA, &exampleBlock100)
|
err = s.InsertTx(b, exampleTxRecordA, &exampleBlock100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = s.InsertTx(exampleTxRecordB, &exampleBlock100)
|
err = s.InsertTx(b, exampleTxRecordB, &exampleBlock100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the one confirmation balance.
|
// Print the one confirmation balance.
|
||||||
bal, err := s.Balance(1, 100)
|
bal, err := s.Balance(b, 1, 100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
|
@ -215,7 +241,7 @@ func Example_basicUsage() {
|
||||||
fmt.Println(bal)
|
fmt.Println(bal)
|
||||||
|
|
||||||
// Fetch unspent outputs.
|
// Fetch unspent outputs.
|
||||||
utxos, err := s.UnspentOutputs()
|
utxos, err := s.UnspentOutputs(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/btcsuite/btcutil"
|
"github.com/btcsuite/btcutil"
|
||||||
|
"github.com/btcsuite/btcwallet/walletdb"
|
||||||
. "github.com/btcsuite/btcwallet/wtxmgr"
|
. "github.com/btcsuite/btcwallet/wtxmgr"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ func deepCopyTxDetails(d *TxDetails) *TxDetails {
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *queryState) compare(t *testing.T, s *Store, changeDesc string) {
|
func (q *queryState) compare(t *testing.T, s *Store, ns walletdb.ReadBucket, changeDesc string) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatalf("Store state queries failed after '%s'", changeDesc)
|
t.Fatalf("Store state queries failed after '%s'", changeDesc)
|
||||||
|
@ -95,11 +96,11 @@ func (q *queryState) compare(t *testing.T, s *Store, changeDesc string) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := s.RangeTransactions(0, -1, checkBlock(fwdBlocks))
|
err := s.RangeTransactions(ns, 0, -1, checkBlock(fwdBlocks))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed in RangeTransactions (forwards iteration): %v", err)
|
t.Fatalf("Failed in RangeTransactions (forwards iteration): %v", err)
|
||||||
}
|
}
|
||||||
err = s.RangeTransactions(-1, 0, checkBlock(revBlocks))
|
err = s.RangeTransactions(ns, -1, 0, checkBlock(revBlocks))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed in RangeTransactions (reverse iteration): %v", err)
|
t.Fatalf("Failed in RangeTransactions (reverse iteration): %v", err)
|
||||||
}
|
}
|
||||||
|
@ -110,7 +111,7 @@ func (q *queryState) compare(t *testing.T, s *Store, changeDesc string) {
|
||||||
if blk.Height == -1 {
|
if blk.Height == -1 {
|
||||||
blk = nil
|
blk = nil
|
||||||
}
|
}
|
||||||
d, err := s.UniqueTxDetails(&txHash, blk)
|
d, err := s.UniqueTxDetails(ns, &txHash, blk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -128,7 +129,7 @@ func (q *queryState) compare(t *testing.T, s *Store, changeDesc string) {
|
||||||
// TxDetails (not looking up a tx at any particular
|
// TxDetails (not looking up a tx at any particular
|
||||||
// height) matches the last.
|
// height) matches the last.
|
||||||
detail := &details[len(details)-1]
|
detail := &details[len(details)-1]
|
||||||
d, err := s.TxDetails(&txHash)
|
d, err := s.TxDetails(ns, &txHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -237,13 +238,13 @@ func TestStoreQueries(t *testing.T) {
|
||||||
|
|
||||||
type queryTest struct {
|
type queryTest struct {
|
||||||
desc string
|
desc string
|
||||||
updates func() // Unwinds from t.Fatal if the update errors.
|
updates func(ns walletdb.ReadWriteBucket) // Unwinds from t.Fatal if the update errors.
|
||||||
state *queryState
|
state *queryState
|
||||||
}
|
}
|
||||||
var tests []queryTest
|
var tests []queryTest
|
||||||
|
|
||||||
// Create the store and test initial state.
|
// Create the store and test initial state.
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -251,19 +252,19 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState := newQueryState()
|
lastState := newQueryState()
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "initial store",
|
desc: "initial store",
|
||||||
updates: func() {},
|
updates: func(walletdb.ReadWriteBucket) {},
|
||||||
state: lastState,
|
state: lastState,
|
||||||
})
|
})
|
||||||
|
|
||||||
// simplify error handling
|
// simplify error handling
|
||||||
insertTx := func(rec *TxRecord, block *BlockMeta) {
|
insertTx := func(ns walletdb.ReadWriteBucket, rec *TxRecord, block *BlockMeta) {
|
||||||
err := s.InsertTx(rec, block)
|
err := s.InsertTx(ns, rec, block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addCredit := func(s *Store, rec *TxRecord, block *BlockMeta, index uint32, change bool) {
|
addCredit := func(s *Store, ns walletdb.ReadWriteBucket, rec *TxRecord, block *BlockMeta, index uint32, change bool) {
|
||||||
err := s.AddCredit(rec, block, index, change)
|
err := s.AddCredit(ns, rec, block, index, change)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -275,8 +276,8 @@ func TestStoreQueries(t *testing.T) {
|
||||||
}
|
}
|
||||||
return rec
|
return rec
|
||||||
}
|
}
|
||||||
rollback := func(height int32) {
|
rollback := func(ns walletdb.ReadWriteBucket, height int32) {
|
||||||
err := s.Rollback(height)
|
err := s.Rollback(ns, height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -300,7 +301,7 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "insert tx A unmined",
|
desc: "insert tx A unmined",
|
||||||
updates: func() { insertTx(recA, nil) },
|
updates: func(ns walletdb.ReadWriteBucket) { insertTx(ns, recA, nil) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -318,7 +319,7 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "mark unconfirmed txA:0 as credit",
|
desc: "mark unconfirmed txA:0 as credit",
|
||||||
updates: func() { addCredit(s, recA, nil, 0, true) },
|
updates: func(ns walletdb.ReadWriteBucket) { addCredit(s, ns, recA, nil, 0, true) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -343,7 +344,7 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "insert tx B unmined",
|
desc: "insert tx B unmined",
|
||||||
updates: func() { insertTx(recB, nil) },
|
updates: func(ns walletdb.ReadWriteBucket) { insertTx(ns, recB, nil) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
newState = lastState.deepCopy()
|
newState = lastState.deepCopy()
|
||||||
|
@ -359,7 +360,7 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "mark txB:0 as non-change credit",
|
desc: "mark txB:0 as non-change credit",
|
||||||
updates: func() { addCredit(s, recB, nil, 0, false) },
|
updates: func(ns walletdb.ReadWriteBucket) { addCredit(s, ns, recB, nil, 0, false) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -373,7 +374,7 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "mine tx A",
|
desc: "mine tx A",
|
||||||
updates: func() { insertTx(recA, &b100) },
|
updates: func(ns walletdb.ReadWriteBucket) { insertTx(ns, recA, &b100) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -385,13 +386,20 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "mine tx B",
|
desc: "mine tx B",
|
||||||
updates: func() { insertTx(recB, &b101) },
|
updates: func(ns walletdb.ReadWriteBucket) { insertTx(ns, recB, &b101) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
tst.updates()
|
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
|
||||||
tst.state.compare(t, s, tst.desc)
|
ns := tx.ReadWriteBucket(namespaceKey)
|
||||||
|
tst.updates(ns)
|
||||||
|
tst.state.compare(t, s, ns, tst.desc)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run some additional query tests with the current store's state:
|
// Run some additional query tests with the current store's state:
|
||||||
|
@ -402,62 +410,70 @@ func TestStoreQueries(t *testing.T) {
|
||||||
// - Verify that breaking early on RangeTransactions stops further
|
// - Verify that breaking early on RangeTransactions stops further
|
||||||
// iteration.
|
// iteration.
|
||||||
|
|
||||||
missingTx := spendOutput(&recB.Hash, 0, 40e8)
|
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
|
||||||
missingRec := newTxRecordFromMsgTx(missingTx, timeNow())
|
ns := tx.ReadWriteBucket(namespaceKey)
|
||||||
missingBlock := makeBlockMeta(102)
|
|
||||||
missingDetails, err := s.TxDetails(&missingRec.Hash)
|
missingTx := spendOutput(&recB.Hash, 0, 40e8)
|
||||||
if err != nil {
|
missingRec := newTxRecordFromMsgTx(missingTx, timeNow())
|
||||||
t.Fatal(err)
|
missingBlock := makeBlockMeta(102)
|
||||||
}
|
missingDetails, err := s.TxDetails(ns, &missingRec.Hash)
|
||||||
if missingDetails != nil {
|
|
||||||
t.Errorf("Expected no details, found details for tx %v", missingDetails.Hash)
|
|
||||||
}
|
|
||||||
missingUniqueTests := []struct {
|
|
||||||
hash *chainhash.Hash
|
|
||||||
block *Block
|
|
||||||
}{
|
|
||||||
{&missingRec.Hash, &b100.Block},
|
|
||||||
{&missingRec.Hash, &missingBlock.Block},
|
|
||||||
{&missingRec.Hash, nil},
|
|
||||||
{&recB.Hash, &b100.Block},
|
|
||||||
{&recB.Hash, &missingBlock.Block},
|
|
||||||
{&recB.Hash, nil},
|
|
||||||
}
|
|
||||||
for _, tst := range missingUniqueTests {
|
|
||||||
missingDetails, err = s.UniqueTxDetails(tst.hash, tst.block)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if missingDetails != nil {
|
if missingDetails != nil {
|
||||||
t.Errorf("Expected no details, found details for tx %v", missingDetails.Hash)
|
t.Errorf("Expected no details, found details for tx %v", missingDetails.Hash)
|
||||||
}
|
}
|
||||||
}
|
missingUniqueTests := []struct {
|
||||||
|
hash *chainhash.Hash
|
||||||
|
block *Block
|
||||||
|
}{
|
||||||
|
{&missingRec.Hash, &b100.Block},
|
||||||
|
{&missingRec.Hash, &missingBlock.Block},
|
||||||
|
{&missingRec.Hash, nil},
|
||||||
|
{&recB.Hash, &b100.Block},
|
||||||
|
{&recB.Hash, &missingBlock.Block},
|
||||||
|
{&recB.Hash, nil},
|
||||||
|
}
|
||||||
|
for _, tst := range missingUniqueTests {
|
||||||
|
missingDetails, err = s.UniqueTxDetails(ns, tst.hash, tst.block)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if missingDetails != nil {
|
||||||
|
t.Errorf("Expected no details, found details for tx %v", missingDetails.Hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iterations := 0
|
iterations := 0
|
||||||
err = s.RangeTransactions(0, -1, func([]TxDetails) (bool, error) {
|
err = s.RangeTransactions(ns, 0, -1, func([]TxDetails) (bool, error) {
|
||||||
iterations++
|
iterations++
|
||||||
return true, nil
|
return true, nil
|
||||||
|
})
|
||||||
|
if iterations != 1 {
|
||||||
|
t.Errorf("RangeTransactions (forwards) ran func %d times", iterations)
|
||||||
|
}
|
||||||
|
iterations = 0
|
||||||
|
err = s.RangeTransactions(ns, -1, 0, func([]TxDetails) (bool, error) {
|
||||||
|
iterations++
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
if iterations != 1 {
|
||||||
|
t.Errorf("RangeTransactions (reverse) ran func %d times", iterations)
|
||||||
|
}
|
||||||
|
// Make sure it also breaks early after one iteration through unmined transactions.
|
||||||
|
rollback(ns, b101.Height)
|
||||||
|
iterations = 0
|
||||||
|
err = s.RangeTransactions(ns, -1, 0, func([]TxDetails) (bool, error) {
|
||||||
|
iterations++
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
if iterations != 1 {
|
||||||
|
t.Errorf("RangeTransactions (reverse) ran func %d times", iterations)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
if iterations != 1 {
|
if err != nil {
|
||||||
t.Errorf("RangeTransactions (forwards) ran func %d times", iterations)
|
t.Fatal(err)
|
||||||
}
|
|
||||||
iterations = 0
|
|
||||||
err = s.RangeTransactions(-1, 0, func([]TxDetails) (bool, error) {
|
|
||||||
iterations++
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
if iterations != 1 {
|
|
||||||
t.Errorf("RangeTransactions (reverse) ran func %d times", iterations)
|
|
||||||
}
|
|
||||||
// Make sure it also breaks early after one iteration through unmined transactions.
|
|
||||||
rollback(b101.Height)
|
|
||||||
iterations = 0
|
|
||||||
err = s.RangeTransactions(-1, 0, func([]TxDetails) (bool, error) {
|
|
||||||
iterations++
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
if iterations != 1 {
|
|
||||||
t.Errorf("RangeTransactions (reverse) ran func %d times", iterations)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// None of the above tests have tested RangeTransactions with multiple
|
// None of the above tests have tested RangeTransactions with multiple
|
||||||
|
@ -472,7 +488,7 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests[:0:0], queryTest{
|
tests = append(tests[:0:0], queryTest{
|
||||||
desc: "move tx B to block 100",
|
desc: "move tx B to block 100",
|
||||||
updates: func() { insertTx(recB, &b100) },
|
updates: func(ns walletdb.ReadWriteBucket) { insertTx(ns, recB, &b100) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
newState = lastState.deepCopy()
|
newState = lastState.deepCopy()
|
||||||
|
@ -483,7 +499,7 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "rollback block 100",
|
desc: "rollback block 100",
|
||||||
updates: func() { rollback(b100.Height) },
|
updates: func(ns walletdb.ReadWriteBucket) { rollback(ns, b100.Height) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -510,7 +526,7 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "insert duplicate tx A",
|
desc: "insert duplicate tx A",
|
||||||
updates: func() { insertTx(recA, &b100); insertTx(recA, nil) },
|
updates: func(ns walletdb.ReadWriteBucket) { insertTx(ns, recA, &b100); insertTx(ns, recA, nil) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
newState = lastState.deepCopy()
|
newState = lastState.deepCopy()
|
||||||
|
@ -524,20 +540,27 @@ func TestStoreQueries(t *testing.T) {
|
||||||
lastState = newState
|
lastState = newState
|
||||||
tests = append(tests, queryTest{
|
tests = append(tests, queryTest{
|
||||||
desc: "mine duplicate tx A",
|
desc: "mine duplicate tx A",
|
||||||
updates: func() { insertTx(recA, &b101) },
|
updates: func(ns walletdb.ReadWriteBucket) { insertTx(ns, recA, &b101) },
|
||||||
state: newState,
|
state: newState,
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
tst.updates()
|
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
|
||||||
tst.state.compare(t, s, tst.desc)
|
ns := tx.ReadWriteBucket(namespaceKey)
|
||||||
|
tst.updates(ns)
|
||||||
|
tst.state.compare(t, s, ns, tst.desc)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPreviousPkScripts(t *testing.T) {
|
func TestPreviousPkScripts(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -593,14 +616,14 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
recD = newTxRecordFromMsgTx(txD)
|
recD = newTxRecordFromMsgTx(txD)
|
||||||
)
|
)
|
||||||
|
|
||||||
insertTx := func(rec *TxRecord, block *BlockMeta) {
|
insertTx := func(ns walletdb.ReadWriteBucket, rec *TxRecord, block *BlockMeta) {
|
||||||
err := s.InsertTx(rec, block)
|
err := s.InsertTx(ns, rec, block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addCredit := func(rec *TxRecord, block *BlockMeta, index uint32) {
|
addCredit := func(ns walletdb.ReadWriteBucket, rec *TxRecord, block *BlockMeta, index uint32) {
|
||||||
err := s.AddCredit(rec, block, index, false)
|
err := s.AddCredit(ns, rec, block, index, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -611,8 +634,8 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
block *Block
|
block *Block
|
||||||
scripts [][]byte
|
scripts [][]byte
|
||||||
}
|
}
|
||||||
runTest := func(tst *scriptTest) {
|
runTest := func(ns walletdb.ReadWriteBucket, tst *scriptTest) {
|
||||||
scripts, err := s.PreviousPkScripts(tst.rec, tst.block)
|
scripts, err := s.PreviousPkScripts(ns, tst.rec, tst.block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -634,12 +657,19 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbtx, err := db.BeginReadWriteTx()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer dbtx.Commit()
|
||||||
|
ns := dbtx.ReadWriteBucket(namespaceKey)
|
||||||
|
|
||||||
// Insert transactions A-C unmined, but mark no credits yet. Until
|
// Insert transactions A-C unmined, but mark no credits yet. Until
|
||||||
// these are marked as credits, PreviousPkScripts should not return
|
// these are marked as credits, PreviousPkScripts should not return
|
||||||
// them.
|
// them.
|
||||||
insertTx(recA, nil)
|
insertTx(ns, recA, nil)
|
||||||
insertTx(recB, nil)
|
insertTx(ns, recB, nil)
|
||||||
insertTx(recC, nil)
|
insertTx(ns, recC, nil)
|
||||||
|
|
||||||
b100 := makeBlockMeta(100)
|
b100 := makeBlockMeta(100)
|
||||||
b101 := makeBlockMeta(101)
|
b101 := makeBlockMeta(101)
|
||||||
|
@ -653,7 +683,7 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
{recC, &b100.Block, nil},
|
{recC, &b100.Block, nil},
|
||||||
}
|
}
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
runTest(&tst)
|
runTest(ns, &tst)
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatal("Failed after unmined tx inserts")
|
t.Fatal("Failed after unmined tx inserts")
|
||||||
|
@ -662,11 +692,11 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
// Mark credits. Tx C output 1 not marked as a credit: tx D will spend
|
// Mark credits. Tx C output 1 not marked as a credit: tx D will spend
|
||||||
// both later but when C is mined, output 1's script should not be
|
// both later but when C is mined, output 1's script should not be
|
||||||
// returned.
|
// returned.
|
||||||
addCredit(recA, nil, 0)
|
addCredit(ns, recA, nil, 0)
|
||||||
addCredit(recA, nil, 1)
|
addCredit(ns, recA, nil, 1)
|
||||||
addCredit(recB, nil, 0)
|
addCredit(ns, recB, nil, 0)
|
||||||
addCredit(recB, nil, 1)
|
addCredit(ns, recB, nil, 1)
|
||||||
addCredit(recC, nil, 0)
|
addCredit(ns, recC, nil, 0)
|
||||||
tests = []scriptTest{
|
tests = []scriptTest{
|
||||||
{recA, nil, nil},
|
{recA, nil, nil},
|
||||||
{recA, &b100.Block, nil},
|
{recA, &b100.Block, nil},
|
||||||
|
@ -676,23 +706,23 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
{recC, &b100.Block, nil},
|
{recC, &b100.Block, nil},
|
||||||
}
|
}
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
runTest(&tst)
|
runTest(ns, &tst)
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatal("Failed after marking unmined credits")
|
t.Fatal("Failed after marking unmined credits")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mine tx A in block 100. Test results should be identical.
|
// Mine tx A in block 100. Test results should be identical.
|
||||||
insertTx(recA, &b100)
|
insertTx(ns, recA, &b100)
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
runTest(&tst)
|
runTest(ns, &tst)
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatal("Failed after mining tx A")
|
t.Fatal("Failed after mining tx A")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mine tx B in block 101.
|
// Mine tx B in block 101.
|
||||||
insertTx(recB, &b101)
|
insertTx(ns, recB, &b101)
|
||||||
tests = []scriptTest{
|
tests = []scriptTest{
|
||||||
{recA, nil, nil},
|
{recA, nil, nil},
|
||||||
{recA, &b100.Block, nil},
|
{recA, &b100.Block, nil},
|
||||||
|
@ -702,7 +732,7 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
{recC, &b101.Block, nil},
|
{recC, &b101.Block, nil},
|
||||||
}
|
}
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
runTest(&tst)
|
runTest(ns, &tst)
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatal("Failed after mining tx B")
|
t.Fatal("Failed after mining tx B")
|
||||||
|
@ -710,7 +740,7 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
|
|
||||||
// Mine tx C in block 101 (same block as tx B) to test debits from the
|
// Mine tx C in block 101 (same block as tx B) to test debits from the
|
||||||
// same block.
|
// same block.
|
||||||
insertTx(recC, &b101)
|
insertTx(ns, recC, &b101)
|
||||||
tests = []scriptTest{
|
tests = []scriptTest{
|
||||||
{recA, nil, nil},
|
{recA, nil, nil},
|
||||||
{recA, &b100.Block, nil},
|
{recA, &b100.Block, nil},
|
||||||
|
@ -720,7 +750,7 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
{recC, &b101.Block, [][]byte{scriptB0, scriptB1}},
|
{recC, &b101.Block, [][]byte{scriptB0, scriptB1}},
|
||||||
}
|
}
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
runTest(&tst)
|
runTest(ns, &tst)
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatal("Failed after mining tx C")
|
t.Fatal("Failed after mining tx C")
|
||||||
|
@ -728,11 +758,11 @@ func TestPreviousPkScripts(t *testing.T) {
|
||||||
|
|
||||||
// Insert tx D, which spends C:0 and C:1. However, only C:0 is marked
|
// Insert tx D, which spends C:0 and C:1. However, only C:0 is marked
|
||||||
// as a credit, and only that output script should be returned.
|
// as a credit, and only that output script should be returned.
|
||||||
insertTx(recD, nil)
|
insertTx(ns, recD, nil)
|
||||||
tests = append(tests, scriptTest{recD, nil, [][]byte{scriptC0}})
|
tests = append(tests, scriptTest{recD, nil, [][]byte{scriptC0}})
|
||||||
tests = append(tests, scriptTest{recD, &b101.Block, nil})
|
tests = append(tests, scriptTest{recD, &b101.Block, nil})
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
runTest(&tst)
|
runTest(ns, &tst)
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatal("Failed after inserting tx D")
|
t.Fatal("Failed after inserting tx D")
|
||||||
|
|
76
wtxmgr/tx.go
76
wtxmgr/tx.go
|
@ -198,18 +198,26 @@ func (s *Store) moveMinedTx(ns walletdb.ReadWriteBucket, rec *TxRecord, recKey,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// For all mined transactions with unspent credits spent by this
|
// For all transaction inputs, remove the previous output marker from the
|
||||||
// transaction, mark each spent, remove from the unspents map, and
|
// unmined inputs bucket. For any mined transactions with unspent credits
|
||||||
// insert a debit record for the spent credit.
|
// spent by this transaction, mark each spent, remove from the unspents map,
|
||||||
|
// and insert a debit record for the spent credit.
|
||||||
debitIncidence := indexedIncidence{
|
debitIncidence := indexedIncidence{
|
||||||
incidence: incidence{txHash: rec.Hash, block: block.Block},
|
incidence: incidence{txHash: rec.Hash, block: block.Block},
|
||||||
// index set for each rec input below.
|
// index set for each rec input below.
|
||||||
}
|
}
|
||||||
for i, input := range rec.MsgTx.TxIn {
|
for i, input := range rec.MsgTx.TxIn {
|
||||||
unspentKey, credKey := existsUnspent(ns, &input.PreviousOutPoint)
|
unspentKey, credKey := existsUnspent(ns, &input.PreviousOutPoint)
|
||||||
|
|
||||||
|
err = deleteRawUnminedInput(ns, unspentKey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if credKey == nil {
|
if credKey == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
debitIncidence.index = uint32(i)
|
debitIncidence.index = uint32(i)
|
||||||
amt, err := spendCredit(ns, credKey, &debitIncidence)
|
amt, err := spendCredit(ns, credKey, &debitIncidence)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -225,11 +233,6 @@ func (s *Store) moveMinedTx(ns walletdb.ReadWriteBucket, rec *TxRecord, recKey,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = deleteRawUnminedInput(ns, unspentKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each output of the record that is marked as a credit, if the
|
// For each output of the record that is marked as a credit, if the
|
||||||
|
@ -261,10 +264,6 @@ func (s *Store) moveMinedTx(ns walletdb.ReadWriteBucket, rec *TxRecord, recKey,
|
||||||
cred.amount = amount
|
cred.amount = amount
|
||||||
cred.change = change
|
cred.change = change
|
||||||
|
|
||||||
err = it.delete()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = putUnspentCredit(ns, &cred)
|
err = putUnspentCredit(ns, &cred)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -273,12 +272,33 @@ func (s *Store) moveMinedTx(ns walletdb.ReadWriteBucket, rec *TxRecord, recKey,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reposition cursor before deleting, since the above puts have
|
||||||
|
// invalidated the cursor.
|
||||||
|
it.reposition(&rec.Hash, index)
|
||||||
|
|
||||||
|
// Avoid cursor deletion until bolt issue #620 is resolved.
|
||||||
|
// err = it.delete()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
minedBalance += amount
|
minedBalance += amount
|
||||||
}
|
}
|
||||||
if it.err != nil {
|
if it.err != nil {
|
||||||
return it.err
|
return it.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete all possible credits outside of the iteration since the cursor
|
||||||
|
// deletion is broken.
|
||||||
|
for i := 0; i < len(rec.MsgTx.TxOut); i++ {
|
||||||
|
k := canonicalOutPoint(&rec.Hash, uint32(i))
|
||||||
|
err = deleteRawUnminedCredit(ns, k)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = putMinedBalance(ns, minedBalance)
|
err = putMinedBalance(ns, minedBalance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -502,10 +522,16 @@ func (s *Store) rollback(ns walletdb.ReadWriteBucket, height int32) error {
|
||||||
// It is necessary to keep these in memory and fix the unmined
|
// It is necessary to keep these in memory and fix the unmined
|
||||||
// transactions later since blocks are removed in increasing order.
|
// transactions later since blocks are removed in increasing order.
|
||||||
var coinBaseCredits []wire.OutPoint
|
var coinBaseCredits []wire.OutPoint
|
||||||
|
var heightsToRemove []int32
|
||||||
|
|
||||||
it := makeBlockIterator(ns, height)
|
it := makeReverseBlockIterator(ns)
|
||||||
for it.next() {
|
for it.prev() {
|
||||||
b := &it.elem
|
b := &it.elem
|
||||||
|
if it.elem.Height < height {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
heightsToRemove = append(heightsToRemove, it.elem.Height)
|
||||||
|
|
||||||
log.Infof("Rolling back %d transactions from block %v height %d",
|
log.Infof("Rolling back %d transactions from block %v height %d",
|
||||||
len(b.transactions), b.Hash, b.Height)
|
len(b.transactions), b.Hash, b.Height)
|
||||||
|
@ -665,15 +691,29 @@ func (s *Store) rollback(ns walletdb.ReadWriteBucket, height int32) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = it.delete()
|
// reposition cursor before deleting this k/v pair and advancing to the
|
||||||
if err != nil {
|
// previous.
|
||||||
return err
|
it.reposition(it.elem.Height)
|
||||||
}
|
|
||||||
|
// Avoid cursor deletion until bolt issue #620 is resolved.
|
||||||
|
// err = it.delete()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
if it.err != nil {
|
if it.err != nil {
|
||||||
return it.err
|
return it.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete the block records outside of the iteration since cursor deletion
|
||||||
|
// is broken.
|
||||||
|
for _, h := range heightsToRemove {
|
||||||
|
err = deleteBlockRecord(ns, h)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, op := range coinBaseCredits {
|
for _, op := range coinBaseCredits {
|
||||||
opKey := canonicalOutPoint(&op.Hash, op.Index)
|
opKey := canonicalOutPoint(&op.Hash, op.Index)
|
||||||
unminedKey := existsRawUnminedInput(ns, opKey)
|
unminedKey := existsRawUnminedInput(ns, opKey)
|
||||||
|
|
|
@ -56,32 +56,38 @@ func testDB() (walletdb.DB, func(), error) {
|
||||||
return db, func() { os.RemoveAll(tmpDir) }, err
|
return db, func() { os.RemoveAll(tmpDir) }, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStore() (*Store, func(), error) {
|
var namespaceKey = []byte("txstore")
|
||||||
|
|
||||||
|
func testStore() (*Store, walletdb.DB, func(), error) {
|
||||||
tmpDir, err := ioutil.TempDir("", "wtxmgr_test")
|
tmpDir, err := ioutil.TempDir("", "wtxmgr_test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, func() {}, err
|
return nil, nil, func() {}, err
|
||||||
}
|
}
|
||||||
db, err := walletdb.Create("bdb", filepath.Join(tmpDir, "db"))
|
db, err := walletdb.Create("bdb", filepath.Join(tmpDir, "db"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
teardown := func() {
|
teardown := func() {
|
||||||
os.RemoveAll(tmpDir)
|
os.RemoveAll(tmpDir)
|
||||||
}
|
}
|
||||||
return nil, teardown, err
|
return nil, nil, teardown, err
|
||||||
}
|
}
|
||||||
teardown := func() {
|
teardown := func() {
|
||||||
db.Close()
|
db.Close()
|
||||||
os.RemoveAll(tmpDir)
|
os.RemoveAll(tmpDir)
|
||||||
}
|
}
|
||||||
ns, err := db.Namespace([]byte("txstore"))
|
var s *Store
|
||||||
if err != nil {
|
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
|
||||||
return nil, teardown, err
|
ns, err := tx.CreateTopLevelBucket(namespaceKey)
|
||||||
}
|
if err != nil {
|
||||||
err = Create(ns)
|
return err
|
||||||
if err != nil {
|
}
|
||||||
return nil, teardown, err
|
err = Create(ns)
|
||||||
}
|
if err != nil {
|
||||||
s, err := Open(ns, &chaincfg.TestNet3Params)
|
return err
|
||||||
return s, teardown, err
|
}
|
||||||
|
s, err = Open(ns, &chaincfg.TestNet3Params)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return s, db, teardown, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func serializeTx(tx *btcutil.Tx) []byte {
|
func serializeTx(tx *btcutil.Tx) []byte {
|
||||||
|
@ -122,14 +128,14 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
f func(*Store) (*Store, error)
|
f func(*Store, walletdb.ReadWriteBucket) (*Store, error)
|
||||||
bal, unc btcutil.Amount
|
bal, unc btcutil.Amount
|
||||||
unspents map[wire.OutPoint]struct{}
|
unspents map[wire.OutPoint]struct{}
|
||||||
unmined map[chainhash.Hash]struct{}
|
unmined map[chainhash.Hash]struct{}
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "new store",
|
name: "new store",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
return s, nil
|
return s, nil
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -139,17 +145,17 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "txout insert",
|
name: "txout insert",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, nil)
|
err = s.InsertTx(ns, rec, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.AddCredit(rec, nil, 0, false)
|
err = s.AddCredit(ns, rec, nil, 0, false)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -166,17 +172,17 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "insert duplicate unconfirmed",
|
name: "insert duplicate unconfirmed",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, nil)
|
err = s.InsertTx(ns, rec, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.AddCredit(rec, nil, 0, false)
|
err = s.AddCredit(ns, rec, nil, 0, false)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -193,17 +199,17 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "confirmed txout insert",
|
name: "confirmed txout insert",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, TstRecvTxBlockDetails)
|
err = s.InsertTx(ns, rec, TstRecvTxBlockDetails)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.AddCredit(rec, TstRecvTxBlockDetails, 0, false)
|
err = s.AddCredit(ns, rec, TstRecvTxBlockDetails, 0, false)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
|
bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
|
||||||
|
@ -218,17 +224,17 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "insert duplicate confirmed",
|
name: "insert duplicate confirmed",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, TstRecvTxBlockDetails)
|
err = s.InsertTx(ns, rec, TstRecvTxBlockDetails)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.AddCredit(rec, TstRecvTxBlockDetails, 0, false)
|
err = s.AddCredit(ns, rec, TstRecvTxBlockDetails, 0, false)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
|
bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
|
||||||
|
@ -243,8 +249,8 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "rollback confirmed credit",
|
name: "rollback confirmed credit",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
err := s.Rollback(TstRecvTxBlockDetails.Height)
|
err := s.Rollback(ns, TstRecvTxBlockDetails.Height)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -261,17 +267,17 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "insert confirmed double spend",
|
name: "insert confirmed double spend",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstDoubleSpendSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstDoubleSpendSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, TstRecvTxBlockDetails)
|
err = s.InsertTx(ns, rec, TstRecvTxBlockDetails)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.AddCredit(rec, TstRecvTxBlockDetails, 0, false)
|
err = s.AddCredit(ns, rec, TstRecvTxBlockDetails, 0, false)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: btcutil.Amount(TstDoubleSpendTx.MsgTx().TxOut[0].Value),
|
bal: btcutil.Amount(TstDoubleSpendTx.MsgTx().TxOut[0].Value),
|
||||||
|
@ -286,12 +292,12 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "insert unconfirmed debit",
|
name: "insert unconfirmed debit",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstSpendingSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstSpendingSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, nil)
|
err = s.InsertTx(ns, rec, nil)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -303,12 +309,12 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "insert unconfirmed debit again",
|
name: "insert unconfirmed debit again",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstDoubleSpendSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstDoubleSpendSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, TstRecvTxBlockDetails)
|
err = s.InsertTx(ns, rec, TstRecvTxBlockDetails)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -320,17 +326,17 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "insert change (index 0)",
|
name: "insert change (index 0)",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstSpendingSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstSpendingSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, nil)
|
err = s.InsertTx(ns, rec, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.AddCredit(rec, nil, 0, true)
|
err = s.AddCredit(ns, rec, nil, 0, true)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -347,16 +353,16 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "insert output back to this own wallet (index 1)",
|
name: "insert output back to this own wallet (index 1)",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstSpendingSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstSpendingSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, nil)
|
err = s.InsertTx(ns, rec, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.AddCredit(rec, nil, 1, true)
|
err = s.AddCredit(ns, rec, nil, 1, true)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -377,12 +383,12 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "confirm signed tx",
|
name: "confirm signed tx",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstSpendingSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstSpendingSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, TstSignedTxBlockDetails)
|
err = s.InsertTx(ns, rec, TstSignedTxBlockDetails)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
|
bal: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
|
||||||
|
@ -401,8 +407,8 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "rollback after spending tx",
|
name: "rollback after spending tx",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
err := s.Rollback(TstSignedTxBlockDetails.Height + 1)
|
err := s.Rollback(ns, TstSignedTxBlockDetails.Height+1)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
|
bal: btcutil.Amount(TstSpendingTx.MsgTx().TxOut[0].Value + TstSpendingTx.MsgTx().TxOut[1].Value),
|
||||||
|
@ -421,8 +427,8 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "rollback spending tx block",
|
name: "rollback spending tx block",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
err := s.Rollback(TstSignedTxBlockDetails.Height)
|
err := s.Rollback(ns, TstSignedTxBlockDetails.Height)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -443,8 +449,8 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "rollback double spend tx block",
|
name: "rollback double spend tx block",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
err := s.Rollback(TstRecvTxBlockDetails.Height)
|
err := s.Rollback(ns, TstRecvTxBlockDetails.Height)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: 0,
|
bal: 0,
|
||||||
|
@ -460,16 +466,16 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "insert original recv txout",
|
name: "insert original recv txout",
|
||||||
f: func(s *Store) (*Store, error) {
|
f: func(s *Store, ns walletdb.ReadWriteBucket) (*Store, error) {
|
||||||
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
rec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, TstRecvTxBlockDetails)
|
err = s.InsertTx(ns, rec, TstRecvTxBlockDetails)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = s.AddCredit(rec, TstRecvTxBlockDetails, 0, false)
|
err = s.AddCredit(ns, rec, TstRecvTxBlockDetails, 0, false)
|
||||||
return s, err
|
return s, err
|
||||||
},
|
},
|
||||||
bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
|
bal: btcutil.Amount(TstRecvTx.MsgTx().TxOut[0].Value),
|
||||||
|
@ -481,88 +487,101 @@ func TestInsertsCreditsDebitsRollbacks(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
tmpStore, err := test.f(s)
|
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
|
||||||
if err != nil {
|
ns := tx.ReadWriteBucket(namespaceKey)
|
||||||
t.Fatalf("%s: got error: %v", test.name, err)
|
tmpStore, err := test.f(s, ns)
|
||||||
}
|
if err != nil {
|
||||||
s = tmpStore
|
t.Fatalf("%s: got error: %v", test.name, err)
|
||||||
bal, err := s.Balance(1, TstRecvCurrentHeight)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: Confirmed Balance failed: %v", test.name, err)
|
|
||||||
}
|
|
||||||
if bal != test.bal {
|
|
||||||
t.Fatalf("%s: balance mismatch: expected: %d, got: %d", test.name, test.bal, bal)
|
|
||||||
}
|
|
||||||
unc, err := s.Balance(0, TstRecvCurrentHeight)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: Unconfirmed Balance failed: %v", test.name, err)
|
|
||||||
}
|
|
||||||
unc -= bal
|
|
||||||
if unc != test.unc {
|
|
||||||
t.Fatalf("%s: unconfirmed balance mismatch: expected %d, got %d", test.name, test.unc, unc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that unspent outputs match expected.
|
|
||||||
unspent, err := s.UnspentOutputs()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: failed to fetch unspent outputs: %v", test.name, err)
|
|
||||||
}
|
|
||||||
for _, cred := range unspent {
|
|
||||||
if _, ok := test.unspents[cred.OutPoint]; !ok {
|
|
||||||
t.Errorf("%s: unexpected unspent output: %v", test.name, cred.OutPoint)
|
|
||||||
}
|
}
|
||||||
delete(test.unspents, cred.OutPoint)
|
s = tmpStore
|
||||||
}
|
bal, err := s.Balance(ns, 1, TstRecvCurrentHeight)
|
||||||
if len(test.unspents) != 0 {
|
if err != nil {
|
||||||
t.Fatalf("%s: missing expected unspent output(s)", test.name)
|
t.Fatalf("%s: Confirmed Balance failed: %v", test.name, err)
|
||||||
}
|
}
|
||||||
|
if bal != test.bal {
|
||||||
// Check that unmined txs match expected.
|
t.Fatalf("%s: balance mismatch: expected: %d, got: %d", test.name, test.bal, bal)
|
||||||
unmined, err := s.UnminedTxs()
|
}
|
||||||
if err != nil {
|
unc, err := s.Balance(ns, 0, TstRecvCurrentHeight)
|
||||||
t.Fatalf("%s: cannot load unmined transactions: %v", test.name, err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("%s: Unconfirmed Balance failed: %v", test.name, err)
|
||||||
for _, tx := range unmined {
|
}
|
||||||
txHash := tx.TxHash()
|
unc -= bal
|
||||||
if _, ok := test.unmined[txHash]; !ok {
|
if unc != test.unc {
|
||||||
t.Fatalf("%s: unexpected unmined tx: %v", test.name, txHash)
|
t.Fatalf("%s: unconfirmed balance mismatch: expected %d, got %d", test.name, test.unc, unc)
|
||||||
}
|
}
|
||||||
delete(test.unmined, txHash)
|
|
||||||
}
|
|
||||||
if len(test.unmined) != 0 {
|
|
||||||
t.Fatalf("%s: missing expected unmined tx(s)", test.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Check that unspent outputs match expected.
|
||||||
|
unspent, err := s.UnspentOutputs(ns)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s: failed to fetch unspent outputs: %v", test.name, err)
|
||||||
|
}
|
||||||
|
for _, cred := range unspent {
|
||||||
|
if _, ok := test.unspents[cred.OutPoint]; !ok {
|
||||||
|
t.Errorf("%s: unexpected unspent output: %v", test.name, cred.OutPoint)
|
||||||
|
}
|
||||||
|
delete(test.unspents, cred.OutPoint)
|
||||||
|
}
|
||||||
|
if len(test.unspents) != 0 {
|
||||||
|
t.Fatalf("%s: missing expected unspent output(s)", test.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that unmined txs match expected.
|
||||||
|
unmined, err := s.UnminedTxs(ns)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s: cannot load unmined transactions: %v", test.name, err)
|
||||||
|
}
|
||||||
|
for _, tx := range unmined {
|
||||||
|
txHash := tx.TxHash()
|
||||||
|
if _, ok := test.unmined[txHash]; !ok {
|
||||||
|
t.Fatalf("%s: unexpected unmined tx: %v", test.name, txHash)
|
||||||
|
}
|
||||||
|
delete(test.unmined, txHash)
|
||||||
|
}
|
||||||
|
if len(test.unmined) != 0 {
|
||||||
|
t.Fatalf("%s: missing expected unmined tx(s)", test.name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindingSpentCredits(t *testing.T) {
|
func TestFindingSpentCredits(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbtx, err := db.BeginReadWriteTx()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer dbtx.Commit()
|
||||||
|
ns := dbtx.ReadWriteBucket(namespaceKey)
|
||||||
|
|
||||||
// Insert transaction and credit which will be spent.
|
// Insert transaction and credit which will be spent.
|
||||||
recvRec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
recvRec, err := NewTxRecord(TstRecvSerializedTx, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.InsertTx(recvRec, TstRecvTxBlockDetails)
|
err = s.InsertTx(ns, recvRec, TstRecvTxBlockDetails)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(recvRec, TstRecvTxBlockDetails, 0, false)
|
err = s.AddCredit(ns, recvRec, TstRecvTxBlockDetails, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -573,16 +592,16 @@ func TestFindingSpentCredits(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.InsertTx(spendingRec, TstSignedTxBlockDetails)
|
err = s.InsertTx(ns, spendingRec, TstSignedTxBlockDetails)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(spendingRec, TstSignedTxBlockDetails, 0, false)
|
err = s.AddCredit(ns, spendingRec, TstSignedTxBlockDetails, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bal, err := s.Balance(1, TstSignedTxBlockDetails.Height)
|
bal, err := s.Balance(ns, 1, TstSignedTxBlockDetails.Height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -590,7 +609,7 @@ func TestFindingSpentCredits(t *testing.T) {
|
||||||
if bal != expectedBal {
|
if bal != expectedBal {
|
||||||
t.Fatalf("bad balance: %v != %v", bal, expectedBal)
|
t.Fatalf("bad balance: %v != %v", bal, expectedBal)
|
||||||
}
|
}
|
||||||
unspents, err := s.UnspentOutputs()
|
unspents, err := s.UnspentOutputs(ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -634,12 +653,19 @@ func spendOutput(txHash *chainhash.Hash, index uint32, outputValues ...int64) *w
|
||||||
func TestCoinbases(t *testing.T) {
|
func TestCoinbases(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbtx, err := db.BeginReadWriteTx()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer dbtx.Commit()
|
||||||
|
ns := dbtx.ReadWriteBucket(namespaceKey)
|
||||||
|
|
||||||
b100 := BlockMeta{
|
b100 := BlockMeta{
|
||||||
Block: Block{Height: 100},
|
Block: Block{Height: 100},
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
|
@ -652,15 +678,15 @@ func TestCoinbases(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert coinbase and mark outputs 0 and 2 as credits.
|
// Insert coinbase and mark outputs 0 and 2 as credits.
|
||||||
err = s.InsertTx(cbRec, &b100)
|
err = s.InsertTx(ns, cbRec, &b100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(cbRec, &b100, 0, false)
|
err = s.AddCredit(ns, cbRec, &b100, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(cbRec, &b100, 2, false)
|
err = s.AddCredit(ns, cbRec, &b100, 2, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -746,7 +772,7 @@ func TestCoinbases(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tst := range balTests {
|
for i, tst := range balTests {
|
||||||
bal, err := s.Balance(tst.minConf, tst.height)
|
bal, err := s.Balance(ns, tst.minConf, tst.height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -766,11 +792,11 @@ func TestCoinbases(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.InsertTx(spenderARec, nil)
|
err = s.InsertTx(ns, spenderARec, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(spenderARec, nil, 0, false)
|
err = s.AddCredit(ns, spenderARec, nil, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -827,7 +853,7 @@ func TestCoinbases(t *testing.T) {
|
||||||
}
|
}
|
||||||
balTestsBeforeMaturity := balTests
|
balTestsBeforeMaturity := balTests
|
||||||
for i, tst := range balTests {
|
for i, tst := range balTests {
|
||||||
bal, err := s.Balance(tst.minConf, tst.height)
|
bal, err := s.Balance(ns, tst.minConf, tst.height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -844,7 +870,7 @@ func TestCoinbases(t *testing.T) {
|
||||||
Block: Block{Height: b100.Height + coinbaseMaturity},
|
Block: Block{Height: b100.Height + coinbaseMaturity},
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}
|
}
|
||||||
err = s.InsertTx(spenderARec, &bMaturity)
|
err = s.InsertTx(ns, spenderARec, &bMaturity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -910,7 +936,7 @@ func TestCoinbases(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tst := range balTests {
|
for i, tst := range balTests {
|
||||||
bal, err := s.Balance(tst.minConf, tst.height)
|
bal, err := s.Balance(ns, tst.minConf, tst.height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -934,16 +960,16 @@ func TestCoinbases(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.InsertTx(spenderBRec, &bMaturity)
|
err = s.InsertTx(ns, spenderBRec, &bMaturity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(spenderBRec, &bMaturity, 0, false)
|
err = s.AddCredit(ns, spenderBRec, &bMaturity, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for i, tst := range balTests {
|
for i, tst := range balTests {
|
||||||
bal, err := s.Balance(tst.minConf, tst.height)
|
bal, err := s.Balance(ns, tst.minConf, tst.height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -957,13 +983,13 @@ func TestCoinbases(t *testing.T) {
|
||||||
|
|
||||||
// Reorg out the block that matured the coinbase and check balances
|
// Reorg out the block that matured the coinbase and check balances
|
||||||
// again.
|
// again.
|
||||||
err = s.Rollback(bMaturity.Height)
|
err = s.Rollback(ns, bMaturity.Height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
balTests = balTestsBeforeMaturity
|
balTests = balTestsBeforeMaturity
|
||||||
for i, tst := range balTests {
|
for i, tst := range balTests {
|
||||||
bal, err := s.Balance(tst.minConf, tst.height)
|
bal, err := s.Balance(ns, tst.minConf, tst.height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -979,7 +1005,7 @@ func TestCoinbases(t *testing.T) {
|
||||||
// more transactions in the store (since the previous outputs referenced
|
// more transactions in the store (since the previous outputs referenced
|
||||||
// by the spending tx no longer exist), and the balance will always be
|
// by the spending tx no longer exist), and the balance will always be
|
||||||
// zero.
|
// zero.
|
||||||
err = s.Rollback(b100.Height)
|
err = s.Rollback(ns, b100.Height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +1035,7 @@ func TestCoinbases(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tst := range balTests {
|
for i, tst := range balTests {
|
||||||
bal, err := s.Balance(tst.minConf, tst.height)
|
bal, err := s.Balance(ns, tst.minConf, tst.height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -1020,7 +1046,7 @@ func TestCoinbases(t *testing.T) {
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatal("Failed balance checks after reorging coinbase block")
|
t.Fatal("Failed balance checks after reorging coinbase block")
|
||||||
}
|
}
|
||||||
unminedTxs, err := s.UnminedTxs()
|
unminedTxs, err := s.UnminedTxs(ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1033,12 +1059,19 @@ func TestCoinbases(t *testing.T) {
|
||||||
func TestMoveMultipleToSameBlock(t *testing.T) {
|
func TestMoveMultipleToSameBlock(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbtx, err := db.BeginReadWriteTx()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer dbtx.Commit()
|
||||||
|
ns := dbtx.ReadWriteBucket(namespaceKey)
|
||||||
|
|
||||||
b100 := BlockMeta{
|
b100 := BlockMeta{
|
||||||
Block: Block{Height: 100},
|
Block: Block{Height: 100},
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
|
@ -1051,15 +1084,15 @@ func TestMoveMultipleToSameBlock(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert coinbase and mark both outputs as credits.
|
// Insert coinbase and mark both outputs as credits.
|
||||||
err = s.InsertTx(cbRec, &b100)
|
err = s.InsertTx(ns, cbRec, &b100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(cbRec, &b100, 0, false)
|
err = s.AddCredit(ns, cbRec, &b100, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(cbRec, &b100, 1, false)
|
err = s.AddCredit(ns, cbRec, &b100, 1, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1072,15 +1105,15 @@ func TestMoveMultipleToSameBlock(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.InsertTx(spenderARec, nil)
|
err = s.InsertTx(ns, spenderARec, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(spenderARec, nil, 0, false)
|
err = s.AddCredit(ns, spenderARec, nil, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(spenderARec, nil, 1, false)
|
err = s.AddCredit(ns, spenderARec, nil, 1, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1090,15 +1123,15 @@ func TestMoveMultipleToSameBlock(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.InsertTx(spenderBRec, nil)
|
err = s.InsertTx(ns, spenderBRec, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(spenderBRec, nil, 0, false)
|
err = s.AddCredit(ns, spenderBRec, nil, 0, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.AddCredit(spenderBRec, nil, 1, false)
|
err = s.AddCredit(ns, spenderBRec, nil, 1, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1110,24 +1143,24 @@ func TestMoveMultipleToSameBlock(t *testing.T) {
|
||||||
Block: Block{Height: b100.Height + coinbaseMaturity},
|
Block: Block{Height: b100.Height + coinbaseMaturity},
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}
|
}
|
||||||
err = s.InsertTx(spenderARec, &bMaturity)
|
err = s.InsertTx(ns, spenderARec, &bMaturity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.InsertTx(spenderBRec, &bMaturity)
|
err = s.InsertTx(ns, spenderBRec, &bMaturity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that both transactions can be queried at the maturity block.
|
// Check that both transactions can be queried at the maturity block.
|
||||||
detailsA, err := s.UniqueTxDetails(&spenderARec.Hash, &bMaturity.Block)
|
detailsA, err := s.UniqueTxDetails(ns, &spenderARec.Hash, &bMaturity.Block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if detailsA == nil {
|
if detailsA == nil {
|
||||||
t.Fatal("No details found for first spender")
|
t.Fatal("No details found for first spender")
|
||||||
}
|
}
|
||||||
detailsB, err := s.UniqueTxDetails(&spenderBRec.Hash, &bMaturity.Block)
|
detailsB, err := s.UniqueTxDetails(ns, &spenderBRec.Hash, &bMaturity.Block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1177,7 +1210,7 @@ func TestMoveMultipleToSameBlock(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tst := range balTests {
|
for i, tst := range balTests {
|
||||||
bal, err := s.Balance(tst.minConf, tst.height)
|
bal, err := s.Balance(ns, tst.minConf, tst.height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
t.Fatalf("Balance test %d: Store.Balance failed: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -1188,7 +1221,7 @@ func TestMoveMultipleToSameBlock(t *testing.T) {
|
||||||
if t.Failed() {
|
if t.Failed() {
|
||||||
t.Fatal("Failed balance checks after moving both coinbase spenders")
|
t.Fatal("Failed balance checks after moving both coinbase spenders")
|
||||||
}
|
}
|
||||||
unminedTxs, err := s.UnminedTxs()
|
unminedTxs, err := s.UnminedTxs(ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1203,25 +1236,32 @@ func TestMoveMultipleToSameBlock(t *testing.T) {
|
||||||
func TestInsertUnserializedTx(t *testing.T) {
|
func TestInsertUnserializedTx(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
s, teardown, err := testStore()
|
s, db, teardown, err := testStore()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbtx, err := db.BeginReadWriteTx()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer dbtx.Commit()
|
||||||
|
ns := dbtx.ReadWriteBucket(namespaceKey)
|
||||||
|
|
||||||
tx := newCoinBase(50e8)
|
tx := newCoinBase(50e8)
|
||||||
rec, err := NewTxRecordFromMsgTx(tx, timeNow())
|
rec, err := NewTxRecordFromMsgTx(tx, timeNow())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
b100 := makeBlockMeta(100)
|
b100 := makeBlockMeta(100)
|
||||||
err = s.InsertTx(stripSerializedTx(rec), &b100)
|
err = s.InsertTx(ns, stripSerializedTx(rec), &b100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Insert for stripped TxRecord failed: %v", err)
|
t.Fatalf("Insert for stripped TxRecord failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure it can be retreived successfully.
|
// Ensure it can be retreived successfully.
|
||||||
details, err := s.UniqueTxDetails(&rec.Hash, &b100.Block)
|
details, err := s.UniqueTxDetails(ns, &rec.Hash, &b100.Block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1239,11 +1279,11 @@ func TestInsertUnserializedTx(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = s.InsertTx(rec, nil)
|
err = s.InsertTx(ns, rec, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
details, err = s.UniqueTxDetails(&rec.Hash, nil)
|
details, err = s.UniqueTxDetails(ns, &rec.Hash, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue