diff --git a/lib/cache.c b/lib/cache.c
index f9c9b62d35a0ff7331b2f8e7f6031ccd4db5f066..45de6e0794fe3fbbe5c22ba657c4926f040dde39 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -38,7 +38,50 @@
 #define txn_api(txn) ((txn)->owner->api)
 #define txn_is_valid(txn) ((txn) && (txn)->owner && txn_api(txn))
 
-/** @internal Check cache internal data version. Clear if it doesn't match. */
+
+/** @internal Removes all records from cache. */
+static int cache_purge(struct kr_cache_txn *txn)
+{
+	int ret = kr_error(EINVAL);
+	if (txn_is_valid(txn)) {
+		txn->owner->stats.delete += 1;
+		ret = txn_api(txn)->clear(&txn->t);
+	}
+	return ret;
+}
+
+/** @internal	Check cache internal data version. Clear if it doesn't match.
+ * returns :	EEXIST - cache data version matched.
+ *		0 - cache recreated, txn has to be committed.
+ *		Otherwise - cache recreation fails.
+ */
+static int assert_right_version_txn(struct kr_cache_txn *txn)
+{
+	/* Check cache ABI version */
+	knot_db_val_t key = { KEY_VERSION, 2 };
+	knot_db_val_t val = { NULL, 0 };
+	int ret = txn_api(txn)->find(&txn->t, &key, &val, 0);
+	if (ret == 0) {
+		ret = kr_error(EEXIST);
+	} else {
+		/*
+		 * Version doesn't match.
+		 * Recreate cache and write version key.
+		 */
+		ret = txn_api(txn)->count(&txn->t);
+		if (ret != 0) { /* Non-empty cache, purge it. */
+			kr_log_info("[cache] purging cache\n");
+			ret = cache_purge(txn);
+		}
+		/* Either purged or empty. */
+		if (ret == 0) {
+			ret = txn_api(txn)->insert(&txn->t, &key, &val, 0);
+		}
+	}
+	return ret;
+}
+
+/** @internal Open cache db transaction and check internal data version. */
 static void assert_right_version(struct kr_cache *cache)
 {
 	/* Check cache ABI version */
@@ -47,25 +90,11 @@ static void assert_right_version(struct kr_cache *cache)
 	if (ret != 0) {
 		return; /* N/A, doesn't work. */
 	}
-	knot_db_val_t key = { KEY_VERSION, 2 };
-	knot_db_val_t val = { NULL, 0 };
-	ret = txn_api(&txn)->find(&txn.t, &key, &val, 0);
-	if (ret == 0) { /* Version is OK */
-		kr_cache_txn_abort(&txn);
-		return;
-	}
-	/* Recreate cache and write version key */
-	ret = txn_api(&txn)->count(&txn.t);
-	if (ret > 0) { /* Non-empty cache, purge it. */
-		kr_log_info("[cache] purging cache\n");
-		kr_cache_clear(&txn);
-		kr_cache_txn_commit(&txn);
-		ret = kr_cache_txn_begin(cache, &txn, 0);
-	}
-	/* Either purged or empty. */
-	if (ret == 0) {
-		txn_api(&txn)->insert(&txn.t, &key, &val, 0);
+	ret = assert_right_version_txn(&txn);
+	if (ret == 0) { /* Cache recreated, commit. */
 		kr_cache_txn_commit(&txn);
+	} else {
+		kr_cache_txn_abort(&txn);
 	}
 }
 
@@ -290,9 +319,15 @@ int kr_cache_clear(struct kr_cache_txn *txn)
 	if (!txn_is_valid(txn)) {
 		return kr_error(EINVAL);
 	}
-
-	txn->owner->stats.delete += 1;
-	return txn_api(txn)->clear(&txn->t);
+	int ret = cache_purge(txn);
+	if (ret == 0) {
+		/*
+		 * normally must return 0, never EEXIST
+		 * (due to cache_purge())
+		 */
+		ret = assert_right_version_txn(txn);
+	}
+	return ret;
 }
 
 int kr_cache_peek_rr(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *rank, uint32_t *timestamp)
diff --git a/lib/dnssec/nsec3.c b/lib/dnssec/nsec3.c
index b8d4b5a112cbce3aa4c20f41bbf5c2f39e446df6..71a8949f9c39050e156e99ba01a37c180972c3e0 100644
--- a/lib/dnssec/nsec3.c
+++ b/lib/dnssec/nsec3.c
@@ -222,47 +222,44 @@ static int covers_name(int *flags, const knot_rrset_t *nsec3, const knot_dname_t
 	uint8_t *next_hash = NULL;
 	knot_nsec3_next_hashed(&nsec3->rrs, 0, &next_hash, &next_size);
 
-	if ((owner_hash.size != next_size) || (name_hash.size != next_size)) {
+	if ((owner_hash.size == next_size) && (name_hash.size == next_size)) {
 		/* All hash lengths must be same. */
-		goto fail;
-	}
-
-	const uint8_t *ownrd = owner_hash.data;
-	const uint8_t *nextd = next_hash;
-	if (memcmp(ownrd, nextd, next_size) < 0) {
-		/*
-		 * 0 (...) owner ... next (...) MAX
-		 *                ^
-		 *                name
-		 * ==>
-		 * (owner < name) && (name < next)
-		 */
-		if ((memcmp(ownrd, name_hash.data, next_size) >= 0) ||
-		    (memcmp(name_hash.data, nextd, next_size) >= 0)) {
-			goto fail;
-		}
-	} else {
-		/*
-		 * owner ... MAX, 0 ... next
-		 *        ^     ^    ^
-		 *        name  name name
-		 * =>
-		 * (owner < name) || (name < next)
-		 */
-		if ((memcmp(ownrd, name_hash.data, next_size) >= 0) &&
-		    (memcmp(name_hash.data, nextd, next_size) >= 0)) {
-			goto fail;
+		const uint8_t *ownrd = owner_hash.data;
+		const uint8_t *nextd = next_hash;
+		int covered = 0;
+		int greater_then_owner = (memcmp(ownrd, name_hash.data, next_size) < 0);
+		int less_then_next = (memcmp(name_hash.data, nextd, next_size) < 0);
+		if (memcmp(ownrd, nextd, next_size) < 0) {
+			/*
+			 * 0 (...) owner ... next (...) MAX
+			 *                ^
+			 *                name
+			 * ==>
+			 * (owner < name) && (name < next)
+			 */
+			covered = ((greater_then_owner) && (less_then_next));
+		} else {
+			/*
+			 * owner ... MAX, 0 ... next
+			 *        ^     ^    ^
+			 *        name  name name
+			 * =>
+			 * (owner < name) || (name < next)
+			 */
+			covered = ((greater_then_owner) || (less_then_next));
 		}
-	}
 
-	*flags |= FLG_NAME_COVERED;
+		if (covered) {
+			*flags |= FLG_NAME_COVERED;
 
-	uint8_t nsec3_flags = knot_nsec3_flags(&nsec3->rrs, 0);
-	if (nsec3_flags & ~OPT_OUT_BIT) {
-		/* RFC5155 3.1.2 */
-		ret = kr_error(EINVAL);
-	} else {
-		ret = kr_ok();
+			uint8_t nsec3_flags = knot_nsec3_flags(&nsec3->rrs, 0);
+			if (nsec3_flags & ~OPT_OUT_BIT) {
+				/* RFC5155 3.1.2 */
+				ret = kr_error(EINVAL);
+			} else {
+				ret = kr_ok();
+			}
+		}
 	}
 
 fail:
@@ -329,14 +326,12 @@ static int matches_name(int *flags, const knot_rrset_t *nsec3, const knot_dname_
 		goto fail;
 	}
 
-	if ((owner_hash.size != name_hash.size) ||
-	    (memcmp(owner_hash.data, name_hash.data, owner_hash.size) != 0)) {
-		goto fail;
+	if ((owner_hash.size == name_hash.size) &&
+	    (memcmp(owner_hash.data, name_hash.data, owner_hash.size) == 0)) {
+		*flags |= FLG_NAME_MATCHED;
+		ret = kr_ok();
 	}
 
-	*flags |= FLG_NAME_MATCHED;
-	ret = kr_ok();
-
 fail:
 	if (params.salt.data) {
 		dnssec_nsec3_params_free(&params);
@@ -505,7 +500,7 @@ int kr_nsec3_name_error_response_check(const knot_pkt_t *pkt, knot_section_t sec
  * @param type  Type to be checked.
  * @return      0 or error code.
  */
-static int maches_name_and_type(int *flags, const knot_rrset_t *nsec3,
+static int matches_name_and_type(int *flags, const knot_rrset_t *nsec3,
                                 const knot_dname_t *name, uint16_t type)
 {
 	assert(flags && nsec3 && name);
@@ -565,7 +560,7 @@ static int no_data_response_no_ds(const knot_pkt_t *pkt, knot_section_t section_
 		}
 		flags = 0;
 
-		int ret = maches_name_and_type(&flags, rrset, sname, stype);
+		int ret = matches_name_and_type(&flags, rrset, sname, stype);
 		if (ret != 0) {
 			return ret;
 		}
@@ -611,7 +606,7 @@ static int matches_closest_encloser_wildcard(const knot_pkt_t *pkt, knot_section
 		}
 		flags = 0;
 
-		int ret = maches_name_and_type(&flags, rrset, wildcard, stype);
+		int ret = matches_name_and_type(&flags, rrset, wildcard, stype);
 		if (ret != 0) {
 			return ret;
 		}
@@ -619,7 +614,10 @@ static int matches_closest_encloser_wildcard(const knot_pkt_t *pkt, knot_section
 		/* TODO -- The loop resembles no_data_response_no_ds() exept
 		 * the following condition.
 		 */
-		if ((flags & FLG_NAME_MATCHED) && (flags & FLG_TYPE_BIT_MISSING)) {
+		if ((flags & FLG_NAME_MATCHED) &&
+		    (flags & FLG_TYPE_BIT_MISSING) &&
+		    (flags & FLG_CNAME_BIT_MISSING)) {
+			/* rfc5155 8.7 */
 			return kr_ok();
 		}
 	}
@@ -659,13 +657,14 @@ int kr_nsec3_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_
 	return kr_error(ENOENT);
 }
 
+
 int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id,
                      const knot_dname_t *sname, uint16_t stype)
 {
 	/* DS record may be also matched by an existing NSEC3 RR. */
 	int ret = no_data_response_no_ds(pkt, section_id, sname, stype);
 	if (ret == 0) {
-		/* Satisfies RFC5155 8.5 and 8.6, first paragraph. */
+		/* Satisfies RFC5155 8.5 and 8.6, both first paragraph. */
 		return ret;
 	}
 
@@ -679,11 +678,28 @@ int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id,
 	}
 
 	assert(encloser_name && covering_next_nsec3);
-	if ((stype == KNOT_RRTYPE_DS) && has_optout(covering_next_nsec3)) {
-		/* Satisfies RFC5155 8.6, second paragraph. */
-		return 0;
+	ret = matches_closest_encloser_wildcard(pkt, section_id,
+	                                         encloser_name, stype);
+	if (ret == 0) {
+		/* Satisfies RFC5155 8.7 */
+		return ret;
 	}
 
-	return matches_closest_encloser_wildcard(pkt, section_id,
-	                                         encloser_name, stype);
+	if (!has_optout(covering_next_nsec3)) {
+		/* Bogus */
+		ret = kr_error(ENOENT);
+	} else {
+		/* 
+		 * Satisfies RFC5155 8.6 (QTYPE == DS), 2nd paragraph.
+		 * Also satisfies ERRATA 3441 8.5 (QTYPE != DS), 3rd paragraph.
+		 * - (wildcard) empty nonterminal
+		 * derived from unsecure delegation.
+		 * Denial of existance can not be proven.
+		 * Set error code to proceed unsecure.
+		 */
+		ret = kr_error(DNSSEC_NOT_FOUND);
+	}
+	
+	return ret;
 }
+
diff --git a/lib/dnssec/nsec3.h b/lib/dnssec/nsec3.h
index 4b154312d9c57ed256b5775cbda6335cbbcb95dd..97f36d2a3fe47c2bf33c9cb0903ad8d65c7db735 100644
--- a/lib/dnssec/nsec3.h
+++ b/lib/dnssec/nsec3.h
@@ -41,13 +41,15 @@ int kr_nsec3_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_
                                             const knot_dname_t *sname, int trim_to_next);
 
 /**
- * Authenticated denial of existence according to RFC5155 8.5, 8.6 and 8.7.
+ * Authenticated denial of existence according to RFC5155 8.5 and 8.7.
  * @note No RRSIGs are validated.
  * @param pkt        Packet structure to be processed.
  * @param section_id Packet section to be processed.
  * @param sname      Queried domain name.
  * @param stype      Queried type.
- * @return           0 or error code.
+ * @return           0 or error code:
+ * 		     DNSSEC_NOT_FOUND - denial of existence can't be proven
+ *		     due to opt-out, otherwise - bogus.
  */
 int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id,
                      const knot_dname_t *sname, uint16_t stype);
diff --git a/lib/layer/validate.c b/lib/layer/validate.c
index 453a00cafb2b53638e94be08d1c56a73da20f7e3..40ab2950cd33d8848eb97bdb6b99a7e3f6fe5c60 100644
--- a/lib/layer/validate.c
+++ b/lib/layer/validate.c
@@ -23,6 +23,7 @@
 #include <libknot/packet/wire.h>
 #include <libknot/rrtype/rdname.h>
 #include <libknot/rrtype/rrsig.h>
+#include <dnssec/error.h>
 
 #include "lib/dnssec/nsec.h"
 #include "lib/dnssec/nsec3.h"
@@ -295,6 +296,10 @@ static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_
 			ret = kr_nsec_existence_denial(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS);
 		} else {
 			ret = kr_nsec3_no_data(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS);
+			if (ret == kr_error(DNSSEC_NOT_FOUND)) {
+				/* Not bogus, but going insecure */
+				ret = 0;
+			}
 		}
 		if (ret != 0) {
 			DEBUG_MSG(qry, "<= bogus proof of DS non-existence\n");
@@ -424,9 +429,15 @@ static int validate(knot_layer_t *ctx, knot_pkt_t *pkt)
 				ret = kr_nsec3_no_data(pkt, KNOT_AUTHORITY, knot_pkt_qname(pkt), knot_pkt_qtype(pkt));
 			}
 			if (ret != 0) {
-				DEBUG_MSG(qry, "<= bad NODATA proof\n");
-				qry->flags |= QUERY_DNSSEC_BOGUS;
-				return KNOT_STATE_FAIL;
+				if (has_nsec3 && (ret == kr_error(DNSSEC_NOT_FOUND))) {
+					DEBUG_MSG(qry, "<= can't prove NODATA due to optout, going insecure\n");
+					qry->flags &= ~QUERY_DNSSEC_WANT;
+					qry->flags |= QUERY_DNSSEC_INSECURE;
+				} else {
+					DEBUG_MSG(qry, "<= bad NODATA proof\n");
+					qry->flags |= QUERY_DNSSEC_BOGUS;
+					return KNOT_STATE_FAIL;
+				}
 			}
 		}
 	}
diff --git a/tests/deckard b/tests/deckard
index 866b7b95ce7355d112b9e47504825c31c6fcb27a..e73a0854552d94e8bc5306e75c3a2229bc739531 160000
--- a/tests/deckard
+++ b/tests/deckard
@@ -1 +1 @@
-Subproject commit 866b7b95ce7355d112b9e47504825c31c6fcb27a
+Subproject commit e73a0854552d94e8bc5306e75c3a2229bc739531
diff --git a/tests/test_cache.c b/tests/test_cache.c
index 19c621bf733d15b784a0019c73c1eee2aa301232..e5a64eb9281c2878049b11cd3aa9103326ea4a56 100644
--- a/tests/test_cache.c
+++ b/tests/test_cache.c
@@ -394,8 +394,11 @@ static void test_clear(void **state)
 	struct kr_cache_txn *txn = test_txn_write(state);
 	int preempt_ret = kr_cache_clear(txn);
 	int commit_ret = kr_cache_txn_commit(txn);
+	int count_ret = txn->owner->api->count(&txn->t);
+
 	assert_int_equal(preempt_ret, KNOT_EOK);
 	assert_int_equal(commit_ret, KNOT_EOK);
+	assert_int_equal(count_ret, 1); /* Version record */
 }
 
 int main(void)