github.com/decred/dcrlnd@v0.7.6/chainntnfs/height_hint_cache_test.go (about) 1 package chainntnfs 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "testing" 7 8 "github.com/decred/dcrd/chaincfg/chainhash" 9 "github.com/decred/dcrd/wire" 10 "github.com/decred/dcrlnd/channeldb" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func initHintCache(t *testing.T) *HeightHintCache { 15 t.Helper() 16 17 defaultCfg := CacheConfig{ 18 QueryDisable: false, 19 } 20 21 return initHintCacheWithConfig(t, defaultCfg) 22 } 23 24 func initHintCacheWithConfig(t *testing.T, cfg CacheConfig) *HeightHintCache { 25 t.Helper() 26 27 tempDir, err := ioutil.TempDir("", "hintcache") 28 if err != nil { 29 t.Fatalf("unable to create temp dir: %v", err) 30 } 31 db, err := channeldb.Open(tempDir) 32 if err != nil { 33 t.Fatalf("unable to create db: %v", err) 34 } 35 hintCache, err := NewHeightHintCache(cfg, db.Backend) 36 if err != nil { 37 t.Fatalf("unable to create hint cache: %v", err) 38 } 39 40 return hintCache 41 } 42 43 // TestHeightHintCacheConfirms ensures that the height hint cache properly 44 // caches confirm hints for transactions. 45 func TestHeightHintCacheConfirms(t *testing.T) { 46 t.Parallel() 47 48 hintCache := initHintCache(t) 49 50 // Querying for a transaction hash not found within the cache should 51 // return an error indication so. 52 var unknownHash chainhash.Hash 53 copy(unknownHash[:], bytes.Repeat([]byte{0x01}, 32)) 54 unknownConfRequest := ConfRequest{TxID: unknownHash} 55 _, err := hintCache.QueryConfirmHint(unknownConfRequest) 56 if err != ErrConfirmHintNotFound { 57 t.Fatalf("expected ErrConfirmHintNotFound, got: %v", err) 58 } 59 60 // Now, we'll create some transaction hashes and commit them to the 61 // cache with the same confirm hint. 62 const height = 100 63 const numHashes = 5 64 confRequests := make([]ConfRequest, numHashes) 65 for i := 0; i < numHashes; i++ { 66 var txHash chainhash.Hash 67 copy(txHash[:], bytes.Repeat([]byte{byte(i + 1)}, 32)) 68 confRequests[i] = ConfRequest{TxID: txHash} 69 } 70 71 err = hintCache.CommitConfirmHint(height, confRequests...) 72 if err != nil { 73 t.Fatalf("unable to add entries to cache: %v", err) 74 } 75 76 // With the hashes committed, we'll now query the cache to ensure that 77 // we're able to properly retrieve the confirm hints. 78 for _, confRequest := range confRequests { 79 confirmHint, err := hintCache.QueryConfirmHint(confRequest) 80 if err != nil { 81 t.Fatalf("unable to query for hint of %v: %v", confRequest, err) 82 } 83 if confirmHint != height { 84 t.Fatalf("expected confirm hint %d, got %d", height, 85 confirmHint) 86 } 87 } 88 89 // We'll also attempt to purge all of them in a single database 90 // transaction. 91 if err := hintCache.PurgeConfirmHint(confRequests...); err != nil { 92 t.Fatalf("unable to remove confirm hints: %v", err) 93 } 94 95 // Finally, we'll attempt to query for each hash. We should expect not 96 // to find a hint for any of them. 97 for _, confRequest := range confRequests { 98 _, err := hintCache.QueryConfirmHint(confRequest) 99 if err != ErrConfirmHintNotFound { 100 t.Fatalf("expected ErrConfirmHintNotFound, got :%v", err) 101 } 102 } 103 } 104 105 // TestHeightHintCacheSpends ensures that the height hint cache properly caches 106 // spend hints for outpoints. 107 func TestHeightHintCacheSpends(t *testing.T) { 108 t.Parallel() 109 110 hintCache := initHintCache(t) 111 112 // Querying for an outpoint not found within the cache should return an 113 // error indication so. 114 unknownOutPoint := wire.OutPoint{Index: 1} 115 unknownSpendRequest := SpendRequest{OutPoint: unknownOutPoint} 116 _, err := hintCache.QuerySpendHint(unknownSpendRequest) 117 if err != ErrSpendHintNotFound { 118 t.Fatalf("expected ErrSpendHintNotFound, got: %v", err) 119 } 120 121 // Now, we'll create some outpoints and commit them to the cache with 122 // the same spend hint. 123 const height = 100 124 const numOutpoints = 5 125 spendRequests := make([]SpendRequest, numOutpoints) 126 for i := uint32(0); i < numOutpoints; i++ { 127 spendRequests[i] = SpendRequest{ 128 OutPoint: wire.OutPoint{Index: i + 1}, 129 } 130 } 131 132 err = hintCache.CommitSpendHint(height, spendRequests...) 133 if err != nil { 134 t.Fatalf("unable to add entries to cache: %v", err) 135 } 136 137 // With the outpoints committed, we'll now query the cache to ensure 138 // that we're able to properly retrieve the confirm hints. 139 for _, spendRequest := range spendRequests { 140 spendHint, err := hintCache.QuerySpendHint(spendRequest) 141 if err != nil { 142 t.Fatalf("unable to query for hint: %v", err) 143 } 144 if spendHint != height { 145 t.Fatalf("expected spend hint %d, got %d", height, 146 spendHint) 147 } 148 } 149 150 // We'll also attempt to purge all of them in a single database 151 // transaction. 152 if err := hintCache.PurgeSpendHint(spendRequests...); err != nil { 153 t.Fatalf("unable to remove spend hint: %v", err) 154 } 155 156 // Finally, we'll attempt to query for each outpoint. We should expect 157 // not to find a hint for any of them. 158 for _, spendRequest := range spendRequests { 159 _, err = hintCache.QuerySpendHint(spendRequest) 160 if err != ErrSpendHintNotFound { 161 t.Fatalf("expected ErrSpendHintNotFound, got: %v", err) 162 } 163 } 164 } 165 166 // TestQueryDisable asserts querying for confirmation or spend hints always 167 // return height zero when QueryDisabled is set to true in the CacheConfig. 168 func TestQueryDisable(t *testing.T) { 169 cfg := CacheConfig{ 170 QueryDisable: true, 171 } 172 173 hintCache := initHintCacheWithConfig(t, cfg) 174 175 // Insert a new confirmation hint with a non-zero height. 176 const confHeight = 100 177 confRequest := ConfRequest{ 178 TxID: chainhash.Hash{0x01, 0x02, 0x03}, 179 } 180 err := hintCache.CommitConfirmHint(confHeight, confRequest) 181 require.Nil(t, err) 182 183 // Query for the confirmation hint, which should return zero. 184 cachedConfHeight, err := hintCache.QueryConfirmHint(confRequest) 185 require.Nil(t, err) 186 require.Equal(t, uint32(0), cachedConfHeight) 187 188 // Insert a new spend hint with a non-zero height. 189 const spendHeight = 200 190 spendRequest := SpendRequest{ 191 OutPoint: wire.OutPoint{ 192 Hash: chainhash.Hash{0x4, 0x05, 0x06}, 193 Index: 42, 194 }, 195 } 196 err = hintCache.CommitSpendHint(spendHeight, spendRequest) 197 require.Nil(t, err) 198 199 // Query for the spend hint, which should return zero. 200 cachedSpendHeight, err := hintCache.QuerySpendHint(spendRequest) 201 require.Nil(t, err) 202 require.Equal(t, uint32(0), cachedSpendHeight) 203 }