decred.org/dcrdex@v1.0.5/client/asset/btc/txdb_test.go (about) 1 // This code is available on the terms of the project LICENSE.md file, 2 // also available online at https://blueoakcouncil.org/license/1.0.0. 3 4 package btc 5 6 import ( 7 "context" 8 "encoding/hex" 9 "errors" 10 "reflect" 11 "testing" 12 13 "decred.org/dcrdex/client/asset" 14 "decred.org/dcrdex/dex" 15 "decred.org/dcrdex/dex/encode" 16 ) 17 18 func TestTxDB(t *testing.T) { 19 tempDir := t.TempDir() 20 tLogger := dex.StdOutLogger("TXDB", dex.LevelTrace) 21 22 txHistoryStore := NewBadgerTxDB(tempDir, tLogger) 23 24 ctx, cancel := context.WithCancel(context.Background()) 25 defer cancel() 26 27 wg, err := txHistoryStore.Connect(ctx) 28 if err != nil { 29 t.Fatalf("error connecting to tx history store: %v", err) 30 } 31 defer func() { 32 cancel() 33 wg.Wait() 34 }() 35 36 txs, err := txHistoryStore.GetTxs(0, nil, true) 37 if err != nil { 38 t.Fatalf("error retrieving txs: %v", err) 39 } 40 if len(txs) != 0 { 41 t.Fatalf("expected 0 txs but got %d", len(txs)) 42 } 43 44 tx1 := &ExtendedWalletTx{ 45 WalletTransaction: &asset.WalletTransaction{ 46 Type: asset.Send, 47 ID: hex.EncodeToString(encode.RandomBytes(32)), 48 Amount: 1e8, 49 Fees: 1e5, 50 BlockNumber: 0, 51 }, 52 Submitted: false, 53 } 54 55 tx2 := &ExtendedWalletTx{ 56 WalletTransaction: &asset.WalletTransaction{ 57 Type: asset.Receive, 58 ID: hex.EncodeToString(encode.RandomBytes(32)), 59 Amount: 1e8, 60 Fees: 3e5, 61 BlockNumber: 0, 62 }, 63 Submitted: true, 64 } 65 66 tx3 := &ExtendedWalletTx{ 67 WalletTransaction: &asset.WalletTransaction{ 68 Type: asset.Swap, 69 ID: hex.EncodeToString(encode.RandomBytes(32)), 70 Amount: 1e8, 71 Fees: 2e5, 72 BlockNumber: 0, 73 }, 74 Submitted: true, 75 } 76 77 GetTxsAndCheck := func(n int, refID *string, past bool, expected []*asset.WalletTransaction) { 78 t.Helper() 79 80 txs, err = txHistoryStore.GetTxs(n, refID, past) 81 if err != nil { 82 t.Fatalf("failed to get txs: %v", err) 83 } 84 if len(txs) != len(expected) { 85 t.Fatalf("expected %d txs but got %d", len(expected), len(txs)) 86 } 87 for i, expectedTx := range expected { 88 if !reflect.DeepEqual(expectedTx, txs[i]) { 89 t.Fatalf("transaction %d: %+v != %+v", i, expectedTx, txs[i]) 90 } 91 } 92 } 93 94 getPendingTxsAndCheck := func(expected []*ExtendedWalletTx) { 95 t.Helper() 96 97 txs, err := txHistoryStore.GetPendingTxs() 98 if err != nil { 99 t.Fatalf("failed to get unconfirmed txs: %v", err) 100 } 101 102 if len(txs) != len(expected) { 103 t.Fatalf("expected %d txs but got %d", len(expected), len(txs)) 104 } 105 106 for i, expectedTx := range expected { 107 if !reflect.DeepEqual(expectedTx.WalletTransaction, txs[i].WalletTransaction) { 108 t.Fatalf("transaction %+v != %+v", expectedTx.WalletTransaction, txs[i].WalletTransaction) 109 } 110 } 111 } 112 113 err = txHistoryStore.StoreTx(tx1) 114 if err != nil { 115 t.Fatalf("failed to store tx: %v", err) 116 } 117 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{}) 118 getPendingTxsAndCheck([]*ExtendedWalletTx{tx1}) 119 120 err = txHistoryStore.MarkTxAsSubmitted(tx1.ID) 121 if err != nil { 122 t.Fatalf("failed to mark tx as submitted: %v", err) 123 } 124 tx1.Submitted = true 125 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{tx1.WalletTransaction}) 126 getPendingTxsAndCheck([]*ExtendedWalletTx{tx1}) 127 128 // Storing same pending tx twice should not change anything. 129 err = txHistoryStore.StoreTx(tx1) 130 if err != nil { 131 t.Fatalf("failed to store tx: %v", err) 132 } 133 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{tx1.WalletTransaction}) 134 getPendingTxsAndCheck([]*ExtendedWalletTx{tx1}) 135 136 tx1.BlockNumber = 100 137 err = txHistoryStore.StoreTx(tx1) 138 if err != nil { 139 t.Fatalf("failed to store tx: %v", err) 140 } 141 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{tx1.WalletTransaction}) 142 getPendingTxsAndCheck([]*ExtendedWalletTx{tx1}) 143 144 err = txHistoryStore.StoreTx(tx2) 145 if err != nil { 146 t.Fatalf("failed to store tx: %v", err) 147 } 148 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{tx2.WalletTransaction, tx1.WalletTransaction}) 149 getPendingTxsAndCheck([]*ExtendedWalletTx{tx2, tx1}) 150 151 tx2.BlockNumber = 99 152 tx2.Confirmed = true 153 err = txHistoryStore.StoreTx(tx2) 154 if err != nil { 155 t.Fatalf("failed to store tx: %v", err) 156 } 157 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{tx1.WalletTransaction, tx2.WalletTransaction}) 158 getPendingTxsAndCheck([]*ExtendedWalletTx{tx1}) 159 160 err = txHistoryStore.StoreTx(tx3) 161 if err != nil { 162 t.Fatalf("failed to store tx: %v", err) 163 } 164 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{tx3.WalletTransaction, tx1.WalletTransaction, tx2.WalletTransaction}) 165 GetTxsAndCheck(2, &tx1.ID, false, []*asset.WalletTransaction{tx3.WalletTransaction, tx1.WalletTransaction}) 166 GetTxsAndCheck(2, &tx1.ID, true, []*asset.WalletTransaction{tx1.WalletTransaction, tx2.WalletTransaction}) 167 getPendingTxsAndCheck([]*ExtendedWalletTx{tx3, tx1}) 168 169 err = txHistoryStore.RemoveTx(tx1.ID) 170 if err != nil { 171 t.Fatalf("failed to remove tx: %v", err) 172 } 173 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{tx3.WalletTransaction, tx2.WalletTransaction}) 174 175 err = txHistoryStore.RemoveTx(tx2.ID) 176 if err != nil { 177 t.Fatalf("failed to remove tx: %v", err) 178 } 179 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{tx3.WalletTransaction}) 180 181 err = txHistoryStore.RemoveTx(tx3.ID) 182 if err != nil { 183 t.Fatalf("failed to remove tx: %v", err) 184 } 185 GetTxsAndCheck(0, nil, true, []*asset.WalletTransaction{}) 186 187 _, err = txHistoryStore.GetTxs(1, &tx2.ID, true) 188 if !errors.Is(err, asset.CoinNotFoundError) { 189 t.Fatalf("expected coin not found error but got %v", err) 190 } 191 } 192 193 func TestSetAndGetLastQuery(t *testing.T) { 194 tempDir := t.TempDir() 195 tLogger := dex.StdOutLogger("TXDB", dex.LevelTrace) 196 197 ctx, cancel := context.WithCancel(context.Background()) 198 defer cancel() 199 200 txHistoryStore := NewBadgerTxDB(tempDir, tLogger) 201 wg, err := txHistoryStore.Connect(ctx) 202 if err != nil { 203 t.Fatalf("error connecting to tx history store: %v", err) 204 } 205 defer func() { 206 cancel() 207 wg.Wait() 208 }() 209 210 _, err = txHistoryStore.GetLastReceiveTxQuery() 211 if !errors.Is(err, ErrNeverQueried) { 212 t.Fatalf("Failed to get last query: %v", err) 213 } 214 215 block := uint64(12345) 216 err = txHistoryStore.SetLastReceiveTxQuery(block) 217 if err != nil { 218 t.Fatalf("Failed to set last query: %v", err) 219 } 220 221 lastQuery, err := txHistoryStore.GetLastReceiveTxQuery() 222 if err != nil { 223 t.Fatalf("Failed to get last query: %v", err) 224 } 225 if lastQuery != block { 226 t.Fatalf("Expected last query to be %d, but got %d", block, lastQuery) 227 } 228 }