package channeldb import ( "crypto/sha256" "testing" "github.com/lightningnetwork/lnd/lntypes" "github.com/stretchr/testify/require" ) // TestWitnessCacheSha256Retrieval tests that we're able to add and lookup new // sha256 preimages to the witness cache. func TestWitnessCacheSha256Retrieval(t *testing.T) { t.Parallel() cdb, err := MakeTestDB(t) require.NoError(t, err, "unable to make test database") wCache := cdb.NewWitnessCache() // We'll be attempting to add then lookup two simple sha256 preimages // within this test. preimage1 := lntypes.Preimage(rev) preimage2 := lntypes.Preimage(key) preimages := []lntypes.Preimage{preimage1, preimage2} hashes := []lntypes.Hash{preimage1.Hash(), preimage2.Hash()} // First, we'll attempt to add the preimages to the database. err = wCache.AddSha256Witnesses(preimages...) require.NoError(t, err, "unable to add witness") // With the preimages stored, we'll now attempt to look them up. for i, hash := range hashes { preimage := preimages[i] // We should get back the *exact* same preimage as we originally // stored. dbPreimage, err := wCache.LookupSha256Witness(hash) if err != nil { t.Fatalf("unable to look up witness: %v", err) } if preimage != dbPreimage { t.Fatalf("witnesses don't match: expected %x, got %x", preimage[:], dbPreimage[:]) } } } // TestWitnessCacheSha256Deletion tests that we're able to delete a single // sha256 preimage, and also a class of witnesses from the cache. func TestWitnessCacheSha256Deletion(t *testing.T) { t.Parallel() cdb, err := MakeTestDB(t) require.NoError(t, err, "unable to make test database") wCache := cdb.NewWitnessCache() // We'll start by adding two preimages to the cache. preimage1 := lntypes.Preimage(key) hash1 := preimage1.Hash() preimage2 := lntypes.Preimage(rev) hash2 := preimage2.Hash() if err := wCache.AddSha256Witnesses(preimage1); err != nil { t.Fatalf("unable to add witness: %v", err) } if err := wCache.AddSha256Witnesses(preimage2); err != nil { t.Fatalf("unable to add witness: %v", err) } // We'll now delete the first preimage. If we attempt to look it up, we // should get ErrNoWitnesses. err = wCache.DeleteSha256Witness(hash1) require.NoError(t, err, "unable to delete witness") _, err = wCache.LookupSha256Witness(hash1) if err != ErrNoWitnesses { t.Fatalf("expected ErrNoWitnesses instead got: %v", err) } // Next, we'll attempt to delete the entire witness class itself. When // we try to lookup the second preimage, we should again get // ErrNoWitnesses. if err := wCache.DeleteWitnessClass(Sha256HashWitness); err != nil { t.Fatalf("unable to delete witness class: %v", err) } _, err = wCache.LookupSha256Witness(hash2) if err != ErrNoWitnesses { t.Fatalf("expected ErrNoWitnesses instead got: %v", err) } } // TestWitnessCacheUnknownWitness tests that we get an error if we attempt to // query/add/delete an unknown witness. func TestWitnessCacheUnknownWitness(t *testing.T) { t.Parallel() cdb, err := MakeTestDB(t) require.NoError(t, err, "unable to make test database") wCache := cdb.NewWitnessCache() // We'll attempt to add a new, undefined witness type to the database. // We should get an error. err = wCache.legacyAddWitnesses(234, key[:]) if err != ErrUnknownWitnessType { t.Fatalf("expected ErrUnknownWitnessType, got %v", err) } } // TestAddSha256Witnesses tests that insertion using AddSha256Witnesses behaves // identically to the insertion via the generalized interface. func TestAddSha256Witnesses(t *testing.T) { cdb, err := MakeTestDB(t) require.NoError(t, err, "unable to make test database") wCache := cdb.NewWitnessCache() // We'll start by adding a witnesses to the cache using the generic // AddWitnesses method. witness1 := rev[:] preimage1 := lntypes.Preimage(rev) hash1 := preimage1.Hash() witness2 := key[:] preimage2 := lntypes.Preimage(key) hash2 := preimage2.Hash() var ( witnesses = [][]byte{witness1, witness2} preimages = []lntypes.Preimage{preimage1, preimage2} hashes = []lntypes.Hash{hash1, hash2} ) err = wCache.legacyAddWitnesses(Sha256HashWitness, witnesses...) require.NoError(t, err, "unable to add witness") for i, hash := range hashes { preimage := preimages[i] dbPreimage, err := wCache.LookupSha256Witness(hash) if err != nil { t.Fatalf("unable to lookup witness: %v", err) } // Assert that the retrieved witness matches the original. if dbPreimage != preimage { t.Fatalf("retrieved witness mismatch, want: %x, "+ "got: %x", preimage, dbPreimage) } // We'll now delete the witness, as we'll be reinserting it // using the specialized AddSha256Witnesses method. err = wCache.DeleteSha256Witness(hash) if err != nil { t.Fatalf("unable to delete witness: %v", err) } } // Now, add the same witnesses using the type-safe interface for // lntypes.Preimages.. err = wCache.AddSha256Witnesses(preimages...) require.NoError(t, err, "unable to add sha256 preimage") // Finally, iterate over the keys and assert that the returned witnesses // match the original witnesses. This asserts that the specialized // insertion method behaves identically to the generalized interface. for i, hash := range hashes { preimage := preimages[i] dbPreimage, err := wCache.LookupSha256Witness(hash) if err != nil { t.Fatalf("unable to lookup witness: %v", err) } // Assert that the retrieved witness matches the original. if dbPreimage != preimage { t.Fatalf("retrieved witness mismatch, want: %x, "+ "got: %x", preimage, dbPreimage) } } } // legacyAddWitnesses adds a batch of new witnesses of wType to the witness // cache. The type of the witness will be used to map each witness to the key // that will be used to look it up. All witnesses should be of the same // WitnessType. // // NOTE: Previously this method exposed a generic interface for adding // witnesses, which has since been deprecated in favor of a strongly typed // interface for each witness class. We keep this method around to assert the // correctness of specialized witness adding methods. func (w *WitnessCache) legacyAddWitnesses(wType WitnessType, witnesses ...[]byte) error { // Optimistically compute the witness keys before attempting to start // the db transaction. entries := make([]witnessEntry, 0, len(witnesses)) for _, witness := range witnesses { // Map each witness to its key by applying the appropriate // transformation for the given witness type. switch wType { case Sha256HashWitness: key := sha256.Sum256(witness) entries = append(entries, witnessEntry{ key: key[:], witness: witness, }) default: return ErrUnknownWitnessType } } return w.addWitnessEntries(wType, entries) }