diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c
index 185704b784c8225233aad420971392f7978a78ae..51c25c72856f4b426a9515f6d4837eb2767b1d65 100644
--- a/src/knot/ctl/knotc_main.c
+++ b/src/knot/ctl/knotc_main.c
@@ -123,7 +123,7 @@ static int cmd_remote_print_reply(const knot_rrset_t *rr)
 		return KNOT_EMALF;
 	}
 
-	uint16_t rr_count = knot_rrset_rr_count(rr);
+	uint16_t rr_count = rr->rrs.rr_count;
 	for (uint16_t i = 0; i < rr_count; i++) {
 		/* Parse TXT. */
 		remote_print_txt(rr, i);
diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 9a1142dca6e5bd166b69fb23b69d4ec522addaec..d76825e67d05a2100f99a4fd9ade0acf5527ccbc 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -99,7 +99,7 @@ static int remote_rdata_apply(server_t *s, remote_cmdargs_t* a, remote_zonef_t *
 			continue;
 		}
 
-		uint16_t rr_count = knot_rrset_rr_count(rr);
+		uint16_t rr_count = rr->rrs.rr_count;
 		for (uint16_t i = 0; i < rr_count; i++) {
 			const knot_dname_t *dn = knot_ns_name(&rr->rrs, i);
 			rcu_read_lock();
@@ -537,7 +537,7 @@ static void log_command(const char *cmd, const remote_cmdargs_t* args)
 			continue;
 		}
 
-		uint16_t rr_count = knot_rrset_rr_count(rr);
+		uint16_t rr_count = rr->rrs.rr_count;
 		for (uint16_t j = 0; j < rr_count; j++) {
 			const knot_dname_t *dn = knot_ns_name(&rr->rrs, j);
 			char *name = knot_dname_to_str(dn);
@@ -842,7 +842,7 @@ int remote_create_ns(knot_rrset_t *rr, const char *d)
 
 int remote_print_txt(const knot_rrset_t *rr, uint16_t i)
 {
-	if (!rr || knot_rrset_rr_count(rr) < 1) {
+	if (!rr || rr->rrs.rr_count < 1) {
 		return -1;
 	}
 
diff --git a/src/knot/dnssec/nsec-chain.c b/src/knot/dnssec/nsec-chain.c
index b21f10e48963d6efd5776f32091e7f2461814e48..d7f5816549848ef4b072f7c3b86b4c17331a16c2 100644
--- a/src/knot/dnssec/nsec-chain.c
+++ b/src/knot/dnssec/nsec-chain.c
@@ -93,7 +93,7 @@ static int connect_nsec_nodes(knot_node_t *a, knot_node_t *b,
 	assert(b);
 	assert(data);
 
-	if (b->rrset_count == 0 || knot_node_is_non_auth(b)) {
+	if (b->rrset_count == 0 || b->flags & KNOT_NODE_FLAGS_NONAUTH) {
 		return NSEC_NODE_SKIP;
 	}
 
@@ -132,7 +132,7 @@ static int connect_nsec_nodes(knot_node_t *a, knot_node_t *b,
 
 		dbg_dnssec_detail("NSECs not equal, replacing.\n");
 		// Mark the node so that we do not sign this NSEC
-		knot_node_set_removed_nsec(a);
+		a->flags |= KNOT_NODE_FLAGS_REMOVED_NSEC;
 		ret = knot_nsec_changeset_remove(a, data->changeset);
 		if (ret != KNOT_EOK) {
 			knot_rrset_free(&new_nsec, NULL);
diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c
index e06c3e19500c289e768c06814b0c39e00e8f429d..3f5fd123ac82ea701d5eb0d1624da801070b23cd 100644
--- a/src/knot/dnssec/nsec3-chain.c
+++ b/src/knot/dnssec/nsec3-chain.c
@@ -175,8 +175,8 @@ static void free_nsec3_tree(knot_zone_tree_t *nodes)
 	for (/* NOP */; !hattrie_iter_finished(it); hattrie_iter_next(it)) {
 		knot_node_t *node = (knot_node_t *)*hattrie_iter_val(it);
 		// newly allocated NSEC3 nodes
-		knot_rdataset_t *nsec3 = knot_node_get_rdataset(node, KNOT_RRTYPE_NSEC3);
-		knot_rdataset_t *rrsig = knot_node_get_rdataset(node, KNOT_RRTYPE_RRSIG);
+		knot_rdataset_t *nsec3 = knot_node_rdataset(node, KNOT_RRTYPE_NSEC3);
+		knot_rdataset_t *rrsig = knot_node_rdataset(node, KNOT_RRTYPE_RRSIG);
 		knot_rdataset_clear(nsec3, NULL);
 		knot_rdataset_clear(rrsig, NULL);
 		knot_node_free(&node);
@@ -283,11 +283,12 @@ static knot_node_t *create_nsec3_node(knot_dname_t *owner,
 	assert(apex_node);
 	assert(rr_types);
 
-	uint8_t flags = 0;
-	knot_node_t *new_node = knot_node_new(owner, apex_node, flags);
+	knot_node_t *new_node = knot_node_new(owner);
 	if (!new_node) {
 		return NULL;
 	}
+	
+	knot_node_set_parent(new_node, apex_node);
 
 	knot_rrset_t nsec3_rrset;
 	int ret = create_nsec3_rrset(&nsec3_rrset, owner, nsec3_params,
@@ -367,7 +368,7 @@ static int connect_nsec3_nodes(knot_node_t *a, knot_node_t *b,
 
 	assert(a->rrset_count == 1);
 
-	knot_rdataset_t *a_rrs = knot_node_get_rdataset(a, KNOT_RRTYPE_NSEC3);
+	knot_rdataset_t *a_rrs = knot_node_rdataset(a, KNOT_RRTYPE_NSEC3);
 	assert(a_rrs);
 	uint8_t algorithm = knot_nsec3_algorithm(a_rrs, 0);
 	if (algorithm == 0) {
@@ -440,9 +441,9 @@ static int create_nsec3_nodes(const knot_zone_contents_t *zone, uint32_t ttl,
 			break;
 		}
 		if (knot_node_rrtype_exists(node, KNOT_RRTYPE_NSEC)) {
-			knot_node_set_removed_nsec(node);
+			node->flags |= KNOT_NODE_FLAGS_REMOVED_NSEC;
 		}
-		if (knot_node_is_non_auth(node) || knot_node_is_empty(node)) {
+		if (node->flags & KNOT_NODE_FLAGS_NONAUTH || node->flags & KNOT_NODE_FLAGS_EMPTY) {
 			hattrie_iter_next(it);
 			continue;
 		}
@@ -480,7 +481,7 @@ static int create_nsec3_nodes(const knot_zone_contents_t *zone, uint32_t ttl,
  */
 static bool nsec3_is_empty(knot_node_t *node)
 {
-	if (knot_node_children(node) > 0) {
+	if (node->children > 0) {
 		return false;
 	}
 
@@ -499,12 +500,12 @@ static int nsec3_mark_empty(knot_node_t **node_p, void *data)
 	UNUSED(data);
 	knot_node_t *node = *node_p;
 
-	if (!knot_node_is_empty(node) && nsec3_is_empty(node)) {
+	if (!(node->flags & KNOT_NODE_FLAGS_EMPTY) && nsec3_is_empty(node)) {
 		/*!
 		 * Mark this node and all parent nodes that meet the same
 		 * criteria as empty.
 		 */
-		knot_node_set_empty(node);
+		node->flags |= KNOT_NODE_FLAGS_EMPTY;
 
 		if (node->parent) {
 			/* We must decrease the parent's children count,
@@ -548,13 +549,13 @@ static int nsec3_reset(knot_node_t **node_p, void *data)
 	UNUSED(data);
 	knot_node_t *node = *node_p;
 
-	if (knot_node_is_empty(node)) {
+	if (node->flags & KNOT_NODE_FLAGS_EMPTY) {
 		/* If node was marked as empty, increase its parent's children
 		 * count.
 		 */
 		node->parent->children++;
 		/* Clear the 'empty' flag. */
-		knot_node_clear_empty(node);
+		node->flags &= ~KNOT_NODE_FLAGS_EMPTY;
 	}
 
 	return KNOT_EOK;
diff --git a/src/knot/dnssec/zone-nsec.c b/src/knot/dnssec/zone-nsec.c
index 54358e12edc9ed495824c68a5f6f4eab67479f5b..caaa0b9628ed2611bd69c282a3461a7d08df9aea 100644
--- a/src/knot/dnssec/zone-nsec.c
+++ b/src/knot/dnssec/zone-nsec.c
@@ -136,7 +136,7 @@ static int mark_nsec3(knot_rrset_t *rrset, void *data)
 		}
 
 		if (node != NULL) {
-			knot_node_set_removed_nsec(node);
+			node->flags |= KNOT_NODE_FLAGS_REMOVED_NSEC;
 		}
 	}
 
diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c
index 45e918e7efd308bb8e9fac26b4946b1a7565490a..439b38266161c0bca024cf8a20f57a0b3640595b 100644
--- a/src/knot/dnssec/zone-sign.c
+++ b/src/knot/dnssec/zone-sign.c
@@ -78,7 +78,7 @@ static bool valid_signature_exists(const knot_rrset_t *covered,
 		return false;
 	}
 
-	uint16_t rrsigs_rdata_count = knot_rrset_rr_count(rrsigs);
+	uint16_t rrsigs_rdata_count = rrsigs->rrs.rr_count;
 	for (uint16_t i = 0; i < rrsigs_rdata_count; i++) {
 		uint16_t keytag = knot_rrsig_key_tag(&rrsigs->rrs, i);
 		uint16_t type_covered = knot_rrsig_type_covered(&rrsigs->rrs, i);
@@ -238,7 +238,7 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered,
 		return KNOT_EOK;
 	}
 
-	uint16_t rrsig_rdata_count = knot_rrset_rr_count(&synth_rrsig);
+	uint16_t rrsig_rdata_count = synth_rrsig.rrs.rr_count;
 	for (uint16_t i = 0; i < rrsig_rdata_count; i++) {
 		const knot_zone_key_t *key;
 		key = get_matching_zone_key(&synth_rrsig, i, zone_keys);
@@ -459,7 +459,7 @@ static int remove_standalone_rrsigs(const knot_node_t *node,
 		return KNOT_EOK;
 	}
 
-	uint16_t rrsigs_rdata_count = knot_rrset_rr_count(rrsigs);
+	uint16_t rrsigs_rdata_count = rrsigs->rrs.rr_count;
 	for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) {
 		uint16_t type_covered = knot_rrsig_type_covered(&rrsigs->rrs, i);
 		if (!knot_node_rrtype_exists(node, type_covered)) {
@@ -569,13 +569,13 @@ static int sign_node(knot_node_t **node, void *data)
 		return KNOT_EOK;
 	}
 
-	if (knot_node_is_non_auth(*node)) {
+	if ((*node)->flags & KNOT_NODE_FLAGS_NONAUTH) {
 		return KNOT_EOK;
 	}
 
 	int result = sign_node_rrsets(*node, args->zone_keys, args->policy,
 	                              args->changeset, &args->expires_at);
-	knot_node_clear_removed_nsec(*node);
+	(*node)->flags &= ~KNOT_NODE_FLAGS_REMOVED_NSEC;
 
 	return result;
 }
@@ -696,7 +696,7 @@ static bool dnskey_exists_in_zone(const knot_rrset_t *dnskeys,
 	assert(!knot_rrset_empty(dnskeys));
 	assert(key);
 
-	uint16_t dnskeys_rdata_count = knot_rrset_rr_count(dnskeys);
+	uint16_t dnskeys_rdata_count = dnskeys->rrs.rr_count;
 	for (uint16_t i = 0; i < dnskeys_rdata_count; i++) {
 		uint8_t *rdata = knot_rrset_rr_rdata(dnskeys, i);
 		uint16_t rdata_size = knot_rrset_rr_size(dnskeys, i);
@@ -757,7 +757,7 @@ static int remove_invalid_dnskeys(const knot_rrset_t *soa,
 		goto done;
 	}
 
-	uint16_t dnskeys_rdata_count = knot_rrset_rr_count(dnskeys);
+	uint16_t dnskeys_rdata_count = dnskeys->rrs.rr_count;
 	for (uint16_t i = 0; i < dnskeys_rdata_count; i++) {
 		uint8_t *rdata = knot_rrset_rr_rdata(dnskeys, i);
 		uint16_t rdata_size = knot_rrset_rr_size(dnskeys, i);
@@ -921,7 +921,7 @@ static int update_dnskeys_rrsigs(const knot_rrset_t *dnskeys,
 	}
 
 	// add unknown keys from zone
-	uint16_t dnskeys_rdata_count = knot_rrset_rr_count(dnskeys);
+	uint16_t dnskeys_rdata_count = dnskeys->rrs.rr_count;
 	for (uint16_t i = 0; i < dnskeys_rdata_count; i++) {
 		uint8_t *rdata = knot_rrset_rr_rdata(dnskeys, i);
 		uint16_t rdata_size = knot_rrset_rr_size(dnskeys, i);
@@ -1478,7 +1478,7 @@ int knot_zone_sign_rr_should_be_signed(const knot_node_t *node,
 	}
 
 	// SOA and DNSKEYs are handled separately in the zone apex
-	if (knot_node_is_apex(node)) {
+	if (node->flags & KNOT_NODE_FLAGS_APEX) {
 		if (rrset->type == KNOT_RRTYPE_SOA) {
 			return KNOT_EOK;
 		}
@@ -1489,7 +1489,7 @@ int knot_zone_sign_rr_should_be_signed(const knot_node_t *node,
 	}
 
 	// At delegation points we only want to sign NSECs and DSs
-	if (knot_node_is_deleg_point(node)) {
+	if ((node->flags & KNOT_NODE_FLAGS_DELEG)) {
 		if (!(rrset->type == KNOT_RRTYPE_NSEC ||
 		    rrset->type == KNOT_RRTYPE_DS)) {
 			return KNOT_EOK;
@@ -1497,7 +1497,7 @@ int knot_zone_sign_rr_should_be_signed(const knot_node_t *node,
 	}
 
 	// These RRs have their signatures stored in changeset already
-	if (knot_node_is_removed_nsec(node)
+	if (node->flags & KNOT_NODE_FLAGS_REMOVED_NSEC
 	    && ((rrset->type == KNOT_RRTYPE_NSEC)
 	         || (rrset->type == KNOT_RRTYPE_NSEC3))) {
 		return KNOT_EOK;
diff --git a/src/knot/nameserver/axfr.c b/src/knot/nameserver/axfr.c
index 1fb1be0f2a70da8307d55d245022c1d18b5fdfa4..ed08db9054426045e4079a9c819cd58db2a9d01e 100644
--- a/src/knot/nameserver/axfr.c
+++ b/src/knot/nameserver/axfr.c
@@ -33,7 +33,7 @@ static int put_rrsets(knot_pkt_t *pkt, knot_node_t *node, struct axfr_proc *stat
 {
 	int ret = KNOT_EOK;
 	int i = state->cur_rrset;
-	int rrset_count = knot_node_rrset_count(node);
+	uint16_t rrset_count = node->rrset_count;
 	unsigned flags = KNOT_PF_NOTRUNC;
 
 	/* Append all RRs. */
diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c
index 18f85a38e820092cd766c67fa77b6ef54c810953..f0dfa4edffd8d1e20ba794505dd901277b5ed25c 100644
--- a/src/knot/nameserver/internet.c
+++ b/src/knot/nameserver/internet.c
@@ -192,7 +192,7 @@ static int put_answer(knot_pkt_t *pkt, uint16_t type, struct query_data *qdata)
 			knot_wire_set_tc(pkt->wire);
 			return KNOT_ESPACE;
 		}
-		for (unsigned i = 0; i < knot_node_rrset_count(qdata->node); ++i) {
+		for (unsigned i = 0; i < qdata->node->rrset_count; ++i) {
 			rrset = knot_node_rrset_at(qdata->node, i);
 			ret = ns_put_rr(pkt, &rrset, NULL, compr_hint, 0, qdata);
 			if (ret != KNOT_EOK) {
@@ -285,8 +285,8 @@ static int put_authority_soa(knot_pkt_t *pkt, struct query_data *qdata,
 static int put_delegation(knot_pkt_t *pkt, struct query_data *qdata)
 {
 	/* Find closest delegation point. */
-	while (!knot_node_is_deleg_point(qdata->node)) {
-		qdata->node = knot_node_parent(qdata->node);
+	while (!(qdata->node->flags & KNOT_NODE_FLAGS_DELEG)) {
+		qdata->node = qdata->node->parent;
 	}
 
 	/* Insert NS record. */
@@ -310,7 +310,7 @@ static int put_additional(knot_pkt_t *pkt, const knot_rrset_t *rr,
 	const knot_node_t *node = NULL;
 
 	/* All RRs should have additional node cached or NULL. */
-	uint16_t rr_rdata_count = knot_rrset_rr_count(rr);
+	uint16_t rr_rdata_count = rr->rrs.rr_count;
 	for (uint16_t i = 0; i < rr_rdata_count; i++) {
 		hint = knot_pkt_compr_hint(info, COMPR_HINT_RDATA + i);
 		node = rr->additional[i];
@@ -438,7 +438,7 @@ static int name_found(knot_pkt_t *pkt, struct query_data *qdata)
 	/* DS query is answered normally, but everything else at/below DP
 	 * triggers referral response. */
 	if (qtype != KNOT_RRTYPE_DS &&
-	    (knot_node_is_deleg_point(qdata->node) || knot_node_is_non_auth(qdata->node))) {
+	    ((qdata->node->flags & KNOT_NODE_FLAGS_DELEG) || qdata->node->flags & KNOT_NODE_FLAGS_NONAUTH)) {
 		dbg_ns("%s: solving REFERRAL\n", __func__);
 		return DELEG;
 	}
@@ -468,7 +468,7 @@ static int name_not_found(knot_pkt_t *pkt, struct query_data *qdata)
 	dbg_ns("%s(%p, %p)\n", __func__, pkt, qdata);
 
 	/* Name is covered by wildcard. */
-	if (knot_node_has_wildcard_child(qdata->encloser)) {
+	if (qdata->encloser->flags & KNOT_NODE_FLAGS_WILDCARD_CHILD) {
 		dbg_ns("%s: name %p covered by wildcard\n", __func__, qdata->name);
 
 		/* Find wildcard child in the zone. */
@@ -502,7 +502,7 @@ static int name_not_found(knot_pkt_t *pkt, struct query_data *qdata)
 	}
 
 	/* Name is below delegation. */
-	if (knot_node_is_deleg_point(qdata->encloser)) {
+	if ((qdata->encloser->flags & KNOT_NODE_FLAGS_DELEG)) {
 		dbg_ns("%s: name below delegation point %p\n", __func__, qdata->name);
 		qdata->node = qdata->encloser;
 		return DELEG;
@@ -693,7 +693,7 @@ int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr,
               const knot_rrset_t *rrsigs, uint16_t compr_hint,
               uint32_t flags, struct query_data *qdata)
 {
-	if (knot_rrset_rr_count(rr) < 1) {
+	if (rr->rrs.rr_count < 1) {
 		dbg_ns("%s: refusing to put empty RR of type %u\n", __func__, rr->type);
 		return KNOT_EMALF;
 	}
diff --git a/src/knot/nameserver/ixfr.c b/src/knot/nameserver/ixfr.c
index 57f18f5bd759b8f029630d27f89fe39050389c9b..452700d4de9e6281f87a25e3153e8b7bb3684ba9 100644
--- a/src/knot/nameserver/ixfr.c
+++ b/src/knot/nameserver/ixfr.c
@@ -53,7 +53,7 @@ static int ixfr_put_rrlist(knot_pkt_t *pkt, struct ixfr_proc *ixfr, list_t *list
 	 * rejoin the iteration at any point. */
 	while(ixfr->cur->next) {
 		knot_rr_ln_t *rr_item = (knot_rr_ln_t *)(ixfr->cur);
-		if (knot_rrset_rr_count(rr_item->rr) > 0) {
+		if (rr_item->rr->rrs.rr_count > 0) {
 			IXFR_SAFE_PUT(pkt, rr_item->rr);
 		} else {
 			dbg_ns("%s: empty RR %p, skipping\n", __func__, rr_item->rr);
diff --git a/src/knot/nameserver/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c
index b0fd02da4a66c3775f57b5068c5d83f070e74ff8..53958c8484dd5c6addef0c2835b03edc7b0633cc 100644
--- a/src/knot/nameserver/nsec_proofs.c
+++ b/src/knot/nameserver/nsec_proofs.c
@@ -155,8 +155,7 @@ static int ns_put_nsec3_closest_encloser_proof(
 
 	if (knot_zone_contents_nsec3params(zone) == NULL) {
 dbg_ns_exec_verb(
-		char *name = knot_dname_to_str(knot_node_owner(
-				knot_zone_contents_apex(zone)));
+		char *name = knot_dname_to_str(zone->apex->owner);
 		dbg_ns_verb("No NSEC3PARAM found in zone %s.\n", name);
 		free(name);
 );
@@ -164,7 +163,7 @@ dbg_ns_exec_verb(
 	}
 
 dbg_ns_exec_detail(
-	char *name = knot_dname_to_str(knot_node_owner(*closest_encloser));
+	char *name = knot_dname_to_str((*closest_encloser)->owner);
 	dbg_ns_detail("Closest encloser: %s\n", name);
 	free(name);
 );
@@ -174,10 +173,10 @@ dbg_ns_exec_detail(
 	 */
 	const knot_node_t *nsec3_node = NULL;
 	const knot_dname_t *next_closer = NULL;
-	while ((nsec3_node = knot_node_nsec3_node((*closest_encloser)))
+	while ((nsec3_node = (*closest_encloser)->nsec3_node)
 	       == NULL) {
-		next_closer = knot_node_owner((*closest_encloser));
-		*closest_encloser = knot_node_parent(*closest_encloser);
+		next_closer = (*closest_encloser)->owner;
+		*closest_encloser = (*closest_encloser)->parent;
 		if (*closest_encloser == NULL) {
 			// there are no NSEC3s to add
 			return KNOT_EOK;
@@ -212,8 +211,8 @@ dbg_ns_exec_verb(
 	 */
 	if (next_closer == NULL) {
 		// create the "next closer" name by appending from qname
-		knot_dname_t *new_next_closer = ns_next_closer(
-			knot_node_owner(*closest_encloser), qname);
+		knot_dname_t *new_next_closer = ns_next_closer((*closest_encloser)->owner,
+							       qname);
 
 		if (new_next_closer == NULL) {
 			return KNOT_ERROR; /*servfail */
@@ -286,14 +285,6 @@ static int ns_put_nsec_wildcard(const knot_zone_contents_t *zone,
 	if (previous == NULL) {
 		previous = knot_zone_contents_find_previous(zone, qname);
 		assert(previous != NULL);
-
-		/*!
-		 * \todo isn't this handled in adjusting?
-		 * knot_zone_contents_adjust_node_in_tree_ptr()
-		 */
-		while (!knot_node_is_auth(previous)) {
-			previous = knot_node_previous(previous);
-		}
 	}
 
 	knot_rrset_t rrset = knot_node_rrset(previous, KNOT_RRTYPE_NSEC);
@@ -432,8 +423,8 @@ static int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node,
 	// if wildcard answer, add NSEC / NSEC3
 
 	int ret = KNOT_EOK;
-	if (knot_dname_is_wildcard(knot_node_owner(node))
-	    && !knot_dname_is_equal(qname, knot_node_owner(node))) {
+	if (knot_dname_is_wildcard(node->owner)
+	    && !knot_dname_is_equal(qname, node->owner)) {
 		dbg_ns_verb("Adding NSEC/NSEC3 for wildcard answer.\n");
 		if (knot_is_nsec3_enabled(zone)) {
 			ret = ns_put_nsec3_wildcard(zone, closest_encloser,
@@ -480,14 +471,6 @@ static int ns_put_nsec_nxdomain(const knot_dname_t *qname,
 		/*! \todo Check version. */
 		previous = knot_zone_contents_find_previous(zone, qname);
 		assert(previous != NULL);
-
-		/*!
-		 * \todo isn't this handled in adjusting?
-		 * knot_zone_contents_adjust_node_in_tree_ptr()
-		 */
-		while (!knot_node_is_auth(previous)) {
-			previous = knot_node_previous(previous);
-		}
 	}
 
 dbg_ns_exec_verb(
@@ -526,21 +509,19 @@ dbg_ns_exec_verb(
 
 	const knot_node_t *prev_new = previous;
 
-	while (knot_dname_cmp(knot_node_owner(prev_new),
-				    wildcard) > 0) {
+	while (knot_dname_cmp(prev_new->owner, wildcard) > 0) {
 dbg_ns_exec_verb(
-		char *name = knot_dname_to_str(knot_node_owner(prev_new));
+		char *name = knot_dname_to_str(prev_new->owner);
 		dbg_ns_verb("Previous node: %s\n", name);
 		free(name);
 );
-		assert(prev_new != knot_zone_contents_apex(zone));
-		prev_new = knot_node_previous(prev_new);
+		assert(prev_new != zone->apex);
+		prev_new = prev_new->prev;
 	}
-	assert(knot_dname_cmp(knot_node_owner(prev_new),
-	                            wildcard) < 0);
+	assert(knot_dname_cmp(prev_new->owner, wildcard) < 0);
 
 dbg_ns_exec_verb(
-	char *name = knot_dname_to_str(knot_node_owner(prev_new));
+	char *name = knot_dname_to_str(prev_new->owner);
 	dbg_ns_verb("Previous node: %s\n", name);
 	free(name);
 );
@@ -665,7 +646,7 @@ static int ns_put_nsec_nsec3_nodata(const knot_node_t *node,
                                     knot_pkt_t *resp)
 {
 	// This case must be handled first, before handling the wildcard case
-	if (knot_node_rrset_count(node) == 0 && !knot_is_nsec3_enabled(zone)) {
+	if (node->rrset_count == 0 && !knot_is_nsec3_enabled(zone)) {
 		// node is an empty non-terminal => NSEC for NXDOMAIN
 		return ns_put_nsec_nxdomain(qname, zone, previous,
 		                            closest_encloser, qdata, resp);
@@ -687,7 +668,7 @@ static int ns_put_nsec_nsec3_nodata(const knot_node_t *node,
 
 		/* RFC5155 7.2.3-7.2.5 common proof. */
 		dbg_ns("%s: adding NSEC3 NODATA\n", __func__);
-		const knot_node_t *nsec3_node = knot_node_nsec3_node(node);
+		const knot_node_t *nsec3_node = node->nsec3_node;
 		if (nsec3_node) {
 			ret = ns_put_nsec3_from_node(nsec3_node, qdata, resp);
 		} else {
@@ -722,7 +703,7 @@ int nsec_prove_wildcards(knot_pkt_t *pkt, struct query_data *qdata)
 	WALK_LIST(item, qdata->wildcards) {
 		ret = ns_put_nsec_nsec3_wildcard_answer(
 					item->node,
-					knot_node_parent(item->node),
+					item->node->parent,
 					NULL, qdata->zone->contents,
 					item->sname, qdata,
 					pkt);
diff --git a/src/knot/server/serialization.c b/src/knot/server/serialization.c
index c036f221cd5c51fb5f203a4096d8f060f2e99520..f79ec458bddd409ab50ba04c3da6603c37b2c1e0 100644
--- a/src/knot/server/serialization.c
+++ b/src/knot/server/serialization.c
@@ -32,7 +32,7 @@ static size_t rr_binary_size(const knot_rrset_t *rrset, size_t rdata_pos)
 
 static uint64_t rrset_binary_size(const knot_rrset_t *rrset)
 {
-	if (rrset == NULL || knot_rrset_rr_count(rrset) == 0) {
+	if (rrset == NULL || rrset->rrs.rr_count == 0) {
 		return 0;
 	}
 	uint64_t size = sizeof(uint64_t) + // size at the beginning
@@ -40,7 +40,7 @@ static uint64_t rrset_binary_size(const knot_rrset_t *rrset)
 	              sizeof(uint16_t) + // type
 	              sizeof(uint16_t) + // class
 	              sizeof(uint16_t);  //RR count
-	uint16_t rdata_count = knot_rrset_rr_count(rrset);
+	uint16_t rdata_count = rrset->rrs.rr_count;
 	for (uint16_t i = 0; i < rdata_count; i++) {
 		/* Space to store length of one RR. */
 		size += sizeof(uint32_t);
@@ -109,7 +109,7 @@ int rrset_serialize(const knot_rrset_t *rrset, uint8_t *stream, size_t *size)
 
 	size_t offset = sizeof(uint64_t);
 	/* Save RR count. */
-	const uint16_t rr_count = knot_rrset_rr_count(rrset);
+	const uint16_t rr_count = rrset->rrs.rr_count;
 	memcpy(stream + offset, &rr_count, sizeof(uint16_t));
 	offset += sizeof(uint16_t);
 	/* Save owner. */
diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c
index 461b76aae87a718c572ce87199eff44f5efa54cc..e16ea328d61bba1bb3f389acf730091c87495279 100644
--- a/src/knot/server/xfr-handler.c
+++ b/src/knot/server/xfr-handler.c
@@ -560,8 +560,7 @@ int knot_ns_switch_zone(knot_ns_xfr_t *xfr)
 	 * a reload occurs when transfer is pending. */
 	zone_t *z = xfr->zone;
 	if (z == NULL) {
-		char *name = knot_dname_to_str(knot_node_owner(
-				knot_zone_contents_apex(zone)));
+		char *name = knot_dname_to_str(zone->apex->owner);
 		dbg_xfr("Failed to replace zone %s, old zone "
 		       "not found\n", name);
 		free(name);
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index f00d61080b558b45553ad987bf74e48c2fa84dcd..2fcfd708afe95c356802ed6d5a8435cdc553d299 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -1140,7 +1140,7 @@ int zones_save_zone(const knot_ns_xfr_t *xfr)
 	/* Check if the new zone apex dname matches zone name. */
 	knot_dname_t *cur_name = knot_dname_from_str(xfr->zone->conf->name);
 	const knot_dname_t *new_name = NULL;
-	new_name = knot_node_owner(knot_zone_contents_apex(new_zone));
+	new_name = new_zone->apex->owner;
 	int r = knot_dname_cmp(cur_name, new_name);
 	knot_dname_free(&cur_name, NULL);
 	if (r != 0) {
diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c
index 04a46f63389968d5b96c49a05c723b275c0d121d..0734d1d2026619d6f724998730af2428e16e6256 100644
--- a/src/knot/updates/ddns.c
+++ b/src/knot/updates/ddns.c
@@ -164,7 +164,7 @@ static int check_in_use(const knot_zone_contents_t *zone,
 	if (node == NULL) {
 		*rcode = KNOT_RCODE_NXDOMAIN;
 		return KNOT_EPREREQ;
-	} else if (knot_node_rrset_count(node) == 0) {
+	} else if (node->rrset_count == 0) {
 		*rcode = KNOT_RCODE_NXDOMAIN;
 		return KNOT_EPREREQ;
 	}
@@ -183,7 +183,7 @@ static int check_not_in_use(const knot_zone_contents_t *zone,
 	const knot_node_t *node = knot_zone_contents_find_node(zone, dname);
 	if (node == NULL) {
 		return KNOT_EOK;
-	} else if (knot_node_rrset_count(node) == 0) {
+	} else if (node->rrset_count == 0) {
 		return KNOT_EOK;
 	}
 
@@ -194,7 +194,7 @@ static int check_not_in_use(const knot_zone_contents_t *zone,
 /*!< \brief Returns true if rrset has 0 data or RDATA of size 0 (we need TTL). */
 static bool rrset_empty(const knot_rrset_t *rrset)
 {
-	uint16_t rr_count = knot_rrset_rr_count(rrset);
+	uint16_t rr_count = rrset->rrs.rr_count;
 	if (rr_count == 0) {
 		return true;
 	}
diff --git a/src/knot/updates/xfr-in.c b/src/knot/updates/xfr-in.c
index aa59618f5c89f5e370726939b991c4a15c756d98..4f6af9a6cf8e9049bce67c5d9daece883d08df36 100644
--- a/src/knot/updates/xfr-in.c
+++ b/src/knot/updates/xfr-in.c
@@ -81,10 +81,9 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone,
 	 * Retrieve the local Serial
 	 */
 	const knot_rdataset_t *soa_rrs =
-		knot_node_rdataset(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
+		knot_node_rdataset(zone->apex, KNOT_RRTYPE_SOA);
 	if (soa_rrs == NULL) {
-		char *name = knot_dname_to_str(knot_node_owner(
-				knot_zone_contents_apex(zone)));
+		char *name = knot_dname_to_str(zone->apex->owner);
 		dbg_xfrin("SOA RRSet missing in the zone %s!\n", name);
 		free(name);
 		return KNOT_ERROR;
@@ -698,7 +697,7 @@ static int xfrin_replace_rrs_with_copy(knot_node_t *node,
 
 static void clear_new_rrs(knot_node_t *node, uint16_t type)
 {
-	knot_rdataset_t *new_rrs = knot_node_get_rdataset(node, type);
+	knot_rdataset_t *new_rrs = knot_node_rdataset(node, type);
 	if (new_rrs) {
 		knot_rdataset_clear(new_rrs, NULL);
 	}
@@ -774,7 +773,7 @@ static int remove_rr(knot_node_t *node, const knot_rrset_t *rr,
 		return ret;
 	}
 
-	knot_rdataset_t *changed_rrs = knot_node_get_rdataset(node, rr->type);
+	knot_rdataset_t *changed_rrs = knot_node_rdataset(node, rr->type);
 	// Subtract changeset RRS from node RRS.
 	ret = knot_rdataset_subtract(changed_rrs, &rr->rrs, NULL);
 	if (ret != KNOT_EOK) {
@@ -842,7 +841,7 @@ static int add_rr(knot_node_t *node, const knot_rrset_t *rr,
 		}
 
 		// Extract copy, merge into it
-		knot_rdataset_t *changed_rrs = knot_node_get_rdataset(node, rr->type);
+		knot_rdataset_t *changed_rrs = knot_node_rdataset(node, rr->type);
 		ret = knot_rdataset_merge(changed_rrs, &rr->rrs, NULL);
 		if (ret != KNOT_EOK) {
 			clear_new_rrs(node, rr->type);
@@ -869,7 +868,7 @@ static int add_rr(knot_node_t *node, const knot_rrset_t *rr,
 	}
 
 	// Get changed RRS and store for possible rollback.
-	knot_rdataset_t *rrs = knot_node_get_rdataset(node, rr->type);
+	knot_rdataset_t *rrs = knot_node_rdataset(node, rr->type);
 	int ret = add_new_data(chset, rrs->data);
 	if (ret != KNOT_EOK) {
 		knot_rdataset_clear(rrs, NULL);
@@ -980,7 +979,7 @@ static int xfrin_mark_empty(knot_node_t **node_p, void *data)
 	list_t *l = (list_t *)data;
 	assert(data);
 	if (node->rrset_count == 0 && node->children == 0 &&
-	    !knot_node_is_empty(node)) {
+	    !(node->flags & KNOT_NODE_FLAGS_EMPTY)) {
 		/*!
 		 * Mark this node and all parent nodes that have 0 RRSets and
 		 * no children for removal.
@@ -989,11 +988,11 @@ static int xfrin_mark_empty(knot_node_t **node_p, void *data)
 		if (ret != KNOT_EOK) {
 			return ret;
 		}
-		knot_node_set_empty(node);
+		node->flags |= KNOT_NODE_FLAGS_EMPTY;
 		if (node->parent) {
-			if (knot_node_has_wildcard_child(node->parent)
+			if ((node->parent->flags & KNOT_NODE_FLAGS_WILDCARD_CHILD)
 			    && knot_dname_is_wildcard(node->owner)) {
-				knot_node_clear_wildcard_child(node->parent);
+				node->parent->flags &= ~KNOT_NODE_FLAGS_WILDCARD_CHILD;
 			}
 			node->parent->children--;
 			// Recurse using the parent node
@@ -1092,7 +1091,7 @@ int xfrin_prepare_zone_copy(knot_zone_contents_t *old_contents,
 		return ret;
 	}
 
-	assert(knot_zone_contents_apex(contents_copy) != NULL);
+	assert(contents_copy->apex != NULL);
 
 	*new_contents = contents_copy;
 
@@ -1141,7 +1140,7 @@ int xfrin_finalize_updated_zone(knot_zone_contents_t *contents_copy,
 		return ret;
 	}
 
-	assert(knot_zone_contents_apex(contents_copy) != NULL);
+	assert(contents_copy->apex != NULL);
 
 	return KNOT_EOK;
 }
@@ -1251,7 +1250,7 @@ int xfrin_apply_changesets(zone_t *zone,
 			return ret;
 		}
 	}
-	assert(knot_zone_contents_apex(contents_copy) != NULL);
+	assert(contents_copy->apex != NULL);
 
 	/*!
 	 * \todo Test failure of IXFR.
diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c
index dbbfa62b9a5dc9d66b96f8809629b9850bf344f8..1c02ee622197cfdef9744715da05506a6d741418 100644
--- a/src/knot/zone/node.c
+++ b/src/knot/zone/node.c
@@ -44,30 +44,6 @@ static inline void knot_node_flags_set(knot_node_t *node, uint8_t flag)
 }
 
 /*----------------------------------------------------------------------------*/
-/*!
- * \brief Returns the given flag from node's flags.
- *
- * \param node Node to set the flag in.
- * \param flag Flag to retrieve.
- *
- * \return A byte with only the given flag set if it was set in \a node.
- */
-static inline uint8_t knot_node_flags_get(const knot_node_t *node, uint8_t flag)
-{
-	return node->flags & flag;
-}
-
-/*----------------------------------------------------------------------------*/
-/*!
- * \brief Clears the given flag in node's flags.
- *
- * \param node Node to clear the flag in.
- * \param flag Flag to clear.
- */
-static inline void knot_node_flags_clear(knot_node_t *node, uint8_t flag)
-{
-	node->flags &= ~flag;
-}
 
 static void rr_data_clear(struct rr_data *data, mm_ctx_t *mm)
 {
@@ -91,29 +67,25 @@ static int rr_data_from(const knot_rrset_t *rrset, struct rr_data *data, mm_ctx_
 /* API functions                                                              */
 /*----------------------------------------------------------------------------*/
 
-knot_node_t *knot_node_new(const knot_dname_t *owner, knot_node_t *parent,
-                           uint8_t flags)
+knot_node_t *knot_node_new(const knot_dname_t *owner)
 {
-	knot_node_t *ret = (knot_node_t *)calloc(1, sizeof(knot_node_t));
+	knot_node_t *ret = malloc(sizeof(knot_node_t));
 	if (ret == NULL) {
 		ERR_ALLOC_FAILED;
 		return NULL;
 	}
 
-	/*! \todo This is inconsistent: knot_rrset_new() does not copy owner.
-	 *        Either copy in all _new() functions, or in none. I vote for
-	 *        the former, as it should be responsibility of the caller to
-	 *        do the copying (or not if he decides to do so).
-	 */
+	memset(ret, 0, sizeof(*ret));
+
 	if (owner) {
 		ret->owner = knot_dname_copy(owner, NULL);
+		if (ret->owner == NULL) {
+			free(ret);
+			return NULL;
+		}
 	}
 
-	knot_node_set_parent(ret, parent);
-	ret->rrs = NULL;
-	ret->flags = flags;
-
-	assert(ret->children == 0);
+	ret->flags = KNOT_NODE_FLAGS_NULL;
 
 	return ret;
 }
@@ -169,12 +141,7 @@ int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset,  bool *ttl
 
 /*----------------------------------------------------------------------------*/
 
-const knot_rdataset_t *knot_node_rdataset(const knot_node_t *node, uint16_t type)
-{
-	return (const knot_rdataset_t *)knot_node_get_rdataset(node, type);
-}
-
-knot_rdataset_t *knot_node_get_rdataset(const knot_node_t *node, uint16_t type)
+knot_rdataset_t *knot_node_rdataset(const knot_node_t *node, uint16_t type)
 {
 	if (node == NULL) {
 		return NULL;
@@ -228,39 +195,6 @@ void knot_node_remove_rrset(knot_node_t *node, uint16_t type)
 
 /*----------------------------------------------------------------------------*/
 
-short knot_node_rrset_count(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	return node->rrset_count;
-}
-
-/*----------------------------------------------------------------------------*/
-
-const knot_node_t *knot_node_parent(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return NULL;
-	}
-
-	return knot_node_get_parent(node);
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_node_t *knot_node_get_parent(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return NULL;
-	}
-
-	return node->parent;
-}
-
-/*----------------------------------------------------------------------------*/
-
 void knot_node_set_parent(knot_node_t *node, knot_node_t *parent)
 {
 	if (node == NULL || node->parent == parent) {
@@ -282,257 +216,6 @@ void knot_node_set_parent(knot_node_t *node, knot_node_t *parent)
 
 /*----------------------------------------------------------------------------*/
 
-unsigned int knot_node_children(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	return node->children;
-}
-
-/*----------------------------------------------------------------------------*/
-
-const knot_node_t *knot_node_previous(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return NULL;
-	}
-
-	return knot_node_get_previous(node);
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_node_t *knot_node_get_previous(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return NULL;
-	}
-
-	return node->prev;
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_previous(knot_node_t *node, knot_node_t *prev)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	node->prev = prev;
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_node_t *knot_node_get_nsec3_node(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return NULL;
-	}
-
-	return node->nsec3_node;
-}
-
-/*----------------------------------------------------------------------------*/
-
-const knot_node_t *knot_node_nsec3_node(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return NULL;
-	}
-
-	return knot_node_get_nsec3_node(node);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_nsec3_node(knot_node_t *node, knot_node_t *nsec3_node)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	node->nsec3_node = nsec3_node;
-}
-
-/*----------------------------------------------------------------------------*/
-
-const knot_dname_t *knot_node_owner(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return NULL;
-	}
-
-	return node->owner;
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_dname_t *knot_node_get_owner(const knot_node_t *node)
-{
-	return node->owner;
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_wildcard_child(knot_node_t *node)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	knot_node_flags_set(node, KNOT_NODE_FLAGS_WILDCARD_CHILD);
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_node_has_wildcard_child(const knot_node_t *node)
-{
-	return knot_node_flags_get(node, KNOT_NODE_FLAGS_WILDCARD_CHILD);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_clear_wildcard_child(knot_node_t *node)
-{
-	knot_node_flags_clear(node, KNOT_NODE_FLAGS_WILDCARD_CHILD);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_deleg_point(knot_node_t *node)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	knot_node_flags_set(node, KNOT_NODE_FLAGS_DELEG);
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_node_is_deleg_point(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	return knot_node_flags_get(node, KNOT_NODE_FLAGS_DELEG);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_non_auth(knot_node_t *node)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	knot_node_flags_set(node, KNOT_NODE_FLAGS_NONAUTH);
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_node_is_non_auth(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	return knot_node_flags_get(node, KNOT_NODE_FLAGS_NONAUTH);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_auth(knot_node_t *node)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	knot_node_flags_clear(node, KNOT_NODE_FLAGS_NONAUTH);
-	knot_node_flags_clear(node, KNOT_NODE_FLAGS_DELEG);
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_node_is_auth(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	return (node->flags == 0);
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_node_is_empty(const knot_node_t *node)
-{
-	return knot_node_flags_get(node, KNOT_NODE_FLAGS_EMPTY);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_empty(knot_node_t *node)
-{
-	knot_node_flags_set(node, KNOT_NODE_FLAGS_EMPTY);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_clear_empty(knot_node_t *node)
-{
-	knot_node_flags_clear(node, KNOT_NODE_FLAGS_EMPTY);
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_node_is_removed_nsec(const knot_node_t *node)
-{
-	return knot_node_flags_get(node, KNOT_NODE_FLAGS_REMOVED_NSEC);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_removed_nsec(knot_node_t *node)
-{
-	knot_node_flags_set(node, KNOT_NODE_FLAGS_REMOVED_NSEC);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_clear_removed_nsec(knot_node_t *node)
-{
-	knot_node_flags_clear(node, KNOT_NODE_FLAGS_REMOVED_NSEC);
-}
-
-/*----------------------------------------------------------------------------*/
-
-void knot_node_set_apex(knot_node_t *node)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	knot_node_flags_set(node, KNOT_NODE_FLAGS_APEX);
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_node_is_apex(const knot_node_t *node)
-{
-	if (node == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	return knot_node_flags_get(node, KNOT_NODE_FLAGS_APEX);
-}
-
-/*----------------------------------------------------------------------------*/
-
 void knot_node_free_rrsets(knot_node_t *node)
 {
 	if (node == NULL) {
@@ -578,18 +261,12 @@ int knot_node_shallow_copy(const knot_node_t *from, knot_node_t **to)
 	}
 
 	// create new node
-	*to = knot_node_new(NULL, NULL, from->flags);
+	*to = knot_node_new(from->owner);
 	if (*to == NULL) {
 		return KNOT_ENOMEM;
 	}
-	memset(*to, 0, sizeof(knot_node_t));
-
-	// Copy owner
-	(*to)->owner = knot_dname_copy(from->owner, NULL);
-	if ((*to)->owner == NULL) {
-		free(*to);
-		return KNOT_ENOMEM;
-	}
+	
+	(*to)->flags = from->flags;
 
 	// copy RRSets
 	(*to)->rrset_count = from->rrset_count;
diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h
index c6abc10be3c3ce2111c395d443e899a2813a1fd6..a7c42edb1729f0c729bd37a5fa1ae66215d74177 100644
--- a/src/knot/zone/node.h
+++ b/src/knot/zone/node.h
@@ -89,37 +89,31 @@ struct rr_data {
 /*----------------------------------------------------------------------------*/
 /*! \brief Flags used to mark nodes with some property. */
 typedef enum {
+	/*! \brief Empty flag initializer. */
+	KNOT_NODE_FLAGS_NULL =            0 << 0,
+	/*! \brief Node is authoritative. */
+	KNOT_NODE_FLAGS_AUTH =            1 << 0,
 	/*! \brief Node is a delegation point (i.e. marking a zone cut). */
-	KNOT_NODE_FLAGS_DELEG = 1 << 0,
+	KNOT_NODE_FLAGS_DELEG =           1 << 1,
 	/*! \brief Node is not authoritative (i.e. below a zone cut). */
-	KNOT_NODE_FLAGS_NONAUTH = 1 << 1,
+	KNOT_NODE_FLAGS_NONAUTH =         1 << 2,
 	/*! \brief Node is an apex node. */
-	KNOT_NODE_FLAGS_APEX = 1 << 2,
+	KNOT_NODE_FLAGS_APEX =            1 << 3,
 	/*! \brief NSEC/NSEC3 was removed from this node. */
-	KNOT_NODE_FLAGS_REMOVED_NSEC = 1 << 3,
-	/*! \brief Node is empty and will be deleted after update.
-	 *  \todo Remove after dname refactoring, update description in node. */
-	KNOT_NODE_FLAGS_EMPTY = 1 << 4,
+	KNOT_NODE_FLAGS_REMOVED_NSEC =    1 << 4,
+	/*! \brief Node is empty and will be deleted after update. */
+	KNOT_NODE_FLAGS_EMPTY =           1 << 5,
 	/*! \brief Node has a wildcard child. */
-	KNOT_NODE_FLAGS_WILDCARD_CHILD = 1 << 5
+	KNOT_NODE_FLAGS_WILDCARD_CHILD =  1 << 6
 } knot_node_flags_t;
 
 /*----------------------------------------------------------------------------*/
 /*!
  * \brief Creates and initializes new node structure.
  *
- * \todo Owner reference counter will be increased.
- *
- * \param owner Owner of the created node.
- * \param parent Parent of the created node.
- * \param flags Document me.
- *
- * \todo Document missing parameters.
- *
  * \return Newly created node or NULL if an error occured.
  */
-knot_node_t *knot_node_new(const knot_dname_t *owner, knot_node_t *parent,
-                               uint8_t flags);
+knot_node_t *knot_node_new(const knot_dname_t *owner);
 
 /*!
  * \brief Adds an RRSet to the node.
@@ -132,8 +126,7 @@ knot_node_t *knot_node_new(const knot_dname_t *owner, knot_node_t *parent,
  */
 int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset, bool *ttl_err);
 
-const knot_rdataset_t *knot_node_rdataset(const knot_node_t *node, uint16_t type);
-knot_rdataset_t *knot_node_get_rdataset(const knot_node_t *node, uint16_t type);
+knot_rdataset_t *knot_node_rdataset(const knot_node_t *node, uint16_t type);
 
 /*!
  * \brief Returns the RRSet of the given type from the node (non-const version).
@@ -148,27 +141,6 @@ knot_rrset_t *knot_node_create_rrset(const knot_node_t *node, uint16_t type);
 
 void knot_node_remove_rrset(knot_node_t *node, uint16_t type);
 
-/*!
- * \brief Returns number of RRSets in the node.
- *
- * \param node Node to get the RRSet count from.
- *
- * \return Number of RRSets in \a node.
- */
-short knot_node_rrset_count(const knot_node_t *node);
-
-/*!
- * \brief Returns the parent of the node.
- *
- * \param node Node to get the parent of.
- *
- * \return Parent node of the given node or NULL if no parent has been set (e.g.
- *         node in a zone apex has no parent).
- */
-const knot_node_t *knot_node_parent(const knot_node_t *node);
-
-knot_node_t *knot_node_get_parent(const knot_node_t *node);
-
 /*!
  * \brief Sets the parent of the node.
  *
@@ -177,173 +149,6 @@ knot_node_t *knot_node_get_parent(const knot_node_t *node);
  */
 void knot_node_set_parent(knot_node_t *node, knot_node_t *parent);
 
-unsigned int knot_node_children(const knot_node_t *node);
-
-/*!
- * \brief Returns the previous authoritative node or delegation point in
- *        canonical order or the first node in zone.
- *
- * \param node Node to get the previous node of.
- *
- * \return Previous authoritative node or delegation point in canonical order or
- *         the first node in zone if \a node is the last node in zone.
- * \retval NULL if previous node is not set.
- */
-const knot_node_t *knot_node_previous(const knot_node_t *node);
-
-/*!
- * \brief Returns the previous authoritative node or delegation point in
- *        canonical order or the first node in zone.
- *
- * \note This function is identical to knot_node_previous() except that it
- *       returns non-const node.
- *
- * \param node Node to get the previous node of.
- *
- * \return Previous authoritative node or delegation point in canonical order or
- *         the first node in zone if \a node is the last node in zone.
- * \retval NULL if previous node is not set.
- */
-knot_node_t *knot_node_get_previous(const knot_node_t *node);
-
-/*!
- * \brief Sets the previous node of the given node.
- *
- * \param node Node to set the previous node to.
- * \param prev Previous node to set.
- */
-void knot_node_set_previous(knot_node_t *node, knot_node_t *prev);
-
-/*!
- * \brief Returns the NSEC3 node corresponding to the given node.
- *
- * \param node Node to get the NSEC3 node for.
- *
- * \return NSEC3 node corresponding to \a node (i.e. node with owner name
- *         created by concatenating the hash of owner domain name of \a node
- *         and the name of the zone \a node belongs to).
- * \retval NULL if the NSEC3 node is not set.
- */
-knot_node_t *knot_node_get_nsec3_node(const knot_node_t *node);
-
-/*!
- * \brief Returns the NSEC3 node corresponding to the given node.
- *
- * \param node Node to get the NSEC3 node for.
- *
- * \return NSEC3 node corresponding to \a node (i.e. node with owner name
- *         created by concatenating the hash of owner domain name of \a node
- *         and the name of the zone \a node belongs to).
- * \retval NULL if the NSEC3 node is not set.
- */
-const knot_node_t *knot_node_nsec3_node(const knot_node_t *node);
-
-/*!
- * \brief Sets the corresponding NSEC3 node of the given node.
- *
- * \param node Node to set the NSEC3 node to.
- * \param nsec3_node NSEC3 node to set.
- */
-void knot_node_set_nsec3_node(knot_node_t *node, knot_node_t *nsec3_node);
-
-/*!
- * \brief Returns the owner of the node.
- *
- * \param node Node to get the owner of.
- *
- * \return Owner of the given node.
- */
-const knot_dname_t *knot_node_owner(const knot_node_t *node);
-
-/*!
- * \brief Returns the owner of the node as a non-const reference.
- *
- * \param node Node to get the owner of.
- *
- * \return Owner of the given node.
- */
-knot_dname_t *knot_node_get_owner(const knot_node_t *node);
-
-/*!
- * \brief Sets the wildcard child flag of the node.
- *
- * \param node Node that has wildcard.
- */
-void knot_node_set_wildcard_child(knot_node_t *node);
-
-/*!
- * \brief Checks if node has a wildcard child.
- *
- * \param node Node to check.
- *
- * \retval > 0 if the node has a wildcard child.
- * \retval 0 otherwise.
- */
-int knot_node_has_wildcard_child(const knot_node_t *node);
-
-/*!
- * \brief Clears the node's wildcard child flag.
- *
- * \param node Node to clear the flag in.
- */
-void knot_node_clear_wildcard_child(knot_node_t *node);
-
-/*!
- * \brief Mark the node as a delegation point.
- *
- * \param node Node to mark as a delegation point.
- */
-void knot_node_set_deleg_point(knot_node_t *node);
-
-/*!
- * \brief Checks if the node is a delegation point.
- *
- * \param node Node to check.
- *
- * \retval <> 0 if \a node is marked as delegation point.
- * \retval 0 otherwise.
- */
-int knot_node_is_deleg_point(const knot_node_t *node);
-
-/*!
- * \brief Mark the node as non-authoritative.
- *
- * \param node Node to mark as non-authoritative.
- */
-void knot_node_set_non_auth(knot_node_t *node);
-
-/*!
- * \brief Checks if the node is non-authoritative.
- *
- * \param node Node to check.
- *
- * \retval <> 0 if \a node is marked as non-authoritative.
- * \retval 0 otherwise.
- */
-int knot_node_is_non_auth(const knot_node_t *node);
-
-void knot_node_set_auth(knot_node_t *node);
-
-int knot_node_is_auth(const knot_node_t *node);
-
-int knot_node_is_removed_nsec(const knot_node_t *node);
-
-void knot_node_set_removed_nsec(knot_node_t *node);
-
-void knot_node_clear_removed_nsec(knot_node_t *node);
-
-void knot_node_set_apex(knot_node_t *node);
-
-int knot_node_is_apex(const knot_node_t *node);
-
-//! \todo remove after dname refactoring
-int knot_node_is_empty(const knot_node_t *node);
-
-//! \todo remove after dname refactoring
-void knot_node_set_empty(knot_node_t *node);
-
-void knot_node_clear_empty(knot_node_t *node);
-
 /*!
  * \brief Destroys the RRSets within the node structure.
  *
diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c
index 66a3d3a35bf6c4bb981e92653a8169d62c9432dd..d531a09de1b5a72005f5feae46e80fafbbedc7c6 100644
--- a/src/knot/zone/semantic-check.c
+++ b/src/knot/zone/semantic-check.c
@@ -177,7 +177,7 @@ static void log_error_from_node(err_handler_t *handler,
 
 	handler->error_count++;
 
-	char *name = knot_dname_to_str(knot_node_owner(node));
+	char *name = knot_dname_to_str(node->owner);
 	const char *errmsg = error_messages[-error];
 
 	log_zone_warning("Semantic warning in node: %s: %s%s%s\n",
@@ -332,7 +332,7 @@ static int check_rrsig_rdata(err_handler_t *handler,
 	/* check original TTL */
 	uint32_t original_ttl = knot_rrsig_original_ttl(rrsig, rr_pos);
 
-	uint16_t rr_count = knot_rrset_rr_count(rrset);
+	uint16_t rr_count = rrset->rrs.rr_count;
 	for (uint16_t i = 0; i < rr_count; ++i) {
 		if (original_ttl != knot_rrset_rr_ttl(rrset, i)) {
 			err_handler_handle_error(handler, node,
@@ -373,7 +373,7 @@ static int check_rrsig_rdata(err_handler_t *handler,
 	int match = 0;
 	uint8_t rrsig_alg = knot_rrsig_algorithm(rrsig, rr_pos);
 	uint16_t key_tag_rrsig = knot_rrsig_key_tag(rrsig, rr_pos);
-	for (uint16_t i = 0; i < knot_rrset_rr_count(dnskey_rrset) &&
+	for (uint16_t i = 0; i < dnskey_rrset->rrs.rr_count &&
 	     !match; ++i) {
 		uint8_t dnskey_alg =
 			knot_dnskey_alg(&dnskey_rrset->rrs, i);
@@ -585,7 +585,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
                                     knot_node_t *node, err_handler_t *handler)
 {
 	assert(handler);
-	const knot_node_t *nsec3_node = knot_node_nsec3_node(node);
+	const knot_node_t *nsec3_node = node->nsec3_node;
 
 	if (nsec3_node == NULL) {
 		/* I know it's probably not what RFCs say, but it will have to
@@ -602,7 +602,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 			const knot_node_t *nsec3_node;
 
 			if (knot_zone_contents_find_nsec3_for_name(zone,
-						knot_node_owner(node),
+						node->owner,
 						&nsec3_node,
 						&nsec3_previous) != 0) {
 				err_handler_handle_error(handler, node,
@@ -655,7 +655,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 	}
 
 	/* Result is a dname, it can't be larger */
-	const knot_node_t *apex = knot_zone_contents_apex(zone);
+	const knot_node_t *apex = zone->apex;
 	uint8_t *next_dname_str = NULL;
 	uint8_t next_dname_size = 0;
 	knot_nsec3_next_hashed(nsec3_rrs, 0, &next_dname_str,
@@ -700,7 +700,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 	}
 
 	/* Check that the node only contains NSEC3 and RRSIG. */
-	for (int i = 0; i < knot_node_rrset_count(nsec3_node); i++) {
+	for (int i = 0; i < nsec3_node->rrset_count; i++) {
 		knot_rrset_t rrset = knot_node_rrset_at(nsec3_node, i);
 		uint16_t type = rrset.type;
 		if (!(type == KNOT_RRTYPE_NSEC3 ||
@@ -721,11 +721,11 @@ static int sem_check_node_mandatory(const knot_node_t *node,
 {
 	const knot_rdataset_t *cname_rrs = knot_node_rdataset(node, KNOT_RRTYPE_CNAME);
 	if (cname_rrs) {
-		if (knot_node_rrset_count(node) != 1) {
+		if (node->rrset_count != 1) {
 			/* With DNSSEC node can contain RRSIGs or NSEC */
 			if (!(knot_node_rrtype_exists(node, KNOT_RRTYPE_NSEC) ||
 			      knot_node_rrtype_exists(node, KNOT_RRTYPE_RRSIG)) ||
-			    knot_node_rrset_count(node) > 3) {
+			    node->rrset_count > 3) {
 				*fatal_error = true;
 				err_handler_handle_error(handler, node,
 				ZC_ERR_CNAME_EXTRA_RECORDS_DNSSEC, NULL);
@@ -770,7 +770,7 @@ static int sem_check_node_optional(const knot_zone_contents_t *zone,
                                    const knot_node_t *node,
                                    err_handler_t *handler)
 {
-	if (!(knot_node_is_deleg_point(node) || knot_zone_contents_apex(zone) ==
+	if (!((node->flags & KNOT_NODE_FLAGS_DELEG) || zone->apex ==
 	                node)) {
 		return KNOT_EOK;
 	}
@@ -789,7 +789,7 @@ static int sem_check_node_optional(const knot_zone_contents_t *zone,
 			knot_zone_contents_find_node(zone, ns_dname);
 
 		if (knot_dname_is_sub(ns_dname,
-			      knot_node_owner(knot_zone_contents_apex(zone)))) {
+			      zone->apex->owner)) {
 			if (glue_node == NULL) {
 				/* Try wildcard ([1]* + suffix). */
 				knot_dname_t wildcard[KNOT_DNAME_MAXLEN];
@@ -876,9 +876,9 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone,
 {
 	assert(handler);
 	assert(node);
-	bool auth = !knot_node_is_non_auth(node);
-	bool deleg = knot_node_is_deleg_point(node);
-	short rrset_count = knot_node_rrset_count(node);
+	bool auth = !(node->flags & KNOT_NODE_FLAGS_NONAUTH);
+	bool deleg = (node->flags & KNOT_NODE_FLAGS_DELEG);
+	short rrset_count = node->rrset_count;
 	knot_rrset_t dnskey_rrset = knot_node_rrset(zone->apex, KNOT_RRTYPE_DNSKEY);
 
 	int ret = KNOT_EOK;
@@ -988,9 +988,6 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone,
  */
 static int do_checks_in_tree(knot_node_t *node, void *data)
 {
-	dbg_semcheck_verb("semcheck: do_check_in_tree: Checking node: %s\n",
-	                  knot_dname_to_str(node->owner));
-
 	arg_t *args = (arg_t *)data;
 
 	knot_zone_contents_t *zone = (knot_zone_contents_t *)args->arg1;
@@ -1075,7 +1072,7 @@ void log_cyclic_errors_in_zone(err_handler_t *handler,
 		}
 
 		/* Result is a dname, it can't be larger */
-		const knot_node_t *apex = knot_zone_contents_apex(zone);
+		const knot_node_t *apex = zone->apex;
 		uint8_t *next_dname_str = NULL;
 		uint8_t next_dname_size = 0;
 		knot_nsec3_next_hashed(nsec3_rrs, 0, &next_dname_str,
@@ -1122,7 +1119,7 @@ void log_cyclic_errors_in_zone(err_handler_t *handler,
 			assert(next_dname);
 
 			const knot_dname_t *apex_dname =
-				knot_node_owner(knot_zone_contents_apex(zone));
+				zone->apex->owner;
 			assert(apex_dname);
 
 			if (knot_dname_cmp(next_dname, apex_dname) !=0) {
diff --git a/src/knot/zone/zone-contents.c b/src/knot/zone/zone-contents.c
index 2cbe537384353e92d9361e2f8061b2d42f817609..43c065a45a352dfa684031e2193af791f50c28a7 100644
--- a/src/knot/zone/zone-contents.c
+++ b/src/knot/zone/zone-contents.c
@@ -92,16 +92,7 @@ static int knot_zone_contents_check_node(
 	assert(contents->apex != NULL);
 
 	if (!knot_dname_is_sub(node->owner,
-				       knot_node_owner(contents->apex))) {
-dbg_zone_exec(
-		char *node_owner = knot_dname_to_str(knot_node_owner(node));
-		char *apex_owner = knot_dname_to_str(contents->apex->owner);
-		dbg_zone("zone: Trying to insert foreign node to a "
-			 "zone. Node owner: %s, zone apex: %s\n",
-			 node_owner, apex_owner);
-		free(node_owner);
-		free(apex_owner);
-);
+				       contents->apex->owner)) {
 		return KNOT_EOUTOFZONE;
 	}
 	return KNOT_EOK;
@@ -179,7 +170,7 @@ static int discover_additionals(struct rr_data *rr_data,
 		dname = knot_rdata_name(rrs, i, rr_data->type);
 		knot_zone_contents_find_dname(zone, dname, &node, &encloser, &prev);
 		if (node == NULL && encloser
-		    && knot_node_has_wildcard_child(encloser)) {
+		    && (encloser->flags & KNOT_NODE_FLAGS_WILDCARD_CHILD)) {
 			/* Find wildcard child in the zone. */
 			node = knot_zone_contents_find_wildcard_child(zone,
 			                                              encloser);
@@ -208,36 +199,37 @@ static int adjust_pointers(knot_node_t **tnode, void *data)
 	}
 
 	// clear Removed NSEC flag so that no relicts remain
-	knot_node_clear_removed_nsec(node);
+	node->flags &= ~KNOT_NODE_FLAGS_REMOVED_NSEC;
 
 	// check if this node is not a wildcard child of its parent
 
-	if (knot_dname_is_wildcard(knot_node_owner(node))) {
-		assert(knot_node_parent(node) != NULL);
-		knot_node_set_wildcard_child(knot_node_get_parent(node));
+	if (knot_dname_is_wildcard(node->owner)) {
+		assert(node->parent != NULL);
+		node->parent->flags |= KNOT_NODE_FLAGS_WILDCARD_CHILD;
 	}
 
 	// set flags (delegation point, non-authoritative)
 
-	if (knot_node_parent(node)
-	    && (knot_node_is_deleg_point(knot_node_parent(node))
-		|| knot_node_is_non_auth(knot_node_parent(node)))
+	if (node->parent
+	    && ((node->parent->flags & KNOT_NODE_FLAGS_DELEG)
+		|| node->parent->flags & KNOT_NODE_FLAGS_NONAUTH)
 	) {
-		knot_node_set_non_auth(node);
+		node->flags |= KNOT_NODE_FLAGS_NONAUTH;
 	} else if (knot_node_rrtype_exists(node, KNOT_RRTYPE_NS)
 		   && node != args->zone->apex) {
-		knot_node_set_deleg_point(node);
+		node->flags |= KNOT_NODE_FLAGS_DELEG;
 	} else {
-		knot_node_set_auth(node);
+		node->flags |= KNOT_NODE_FLAGS_AUTH;
 	}
 
 	// set pointer to previous node
 
-	knot_node_set_previous(node, args->previous_node);
+	node->prev = args->previous_node;
 
 	// update remembered previous pointer only if authoritative
 
-	if (!knot_node_is_non_auth(node) && knot_node_rrset_count(node) > 0) {
+	if (!(node->flags & KNOT_NODE_FLAGS_NONAUTH) &&
+	    node->rrset_count > 0) {
 		args->previous_node = node;
 	}
 
@@ -254,14 +246,14 @@ static int adjust_nsec3_pointers(knot_node_t **tnode, void *data)
 	knot_node_t *nsec3 = NULL;
 	knot_dname_t *nsec3_name = NULL;
 	int ret = knot_zone_contents_nsec3_name(args->zone,
-	                                        knot_node_owner(node),
+	                                        node->owner,
 	                                        &nsec3_name);
 	if (ret == KNOT_EOK) {
 		assert(nsec3_name);
 		knot_zone_tree_get(args->zone->nsec3_nodes, nsec3_name, &nsec3);
-		knot_node_set_nsec3_node(node, nsec3);
+		node->nsec3_node = nsec3;
 	} else if (ret == KNOT_ENSEC3PAR) {
-		knot_node_set_nsec3_node(node, NULL);
+		node->nsec3_node = NULL;
 		ret = KNOT_EOK;
 	}
 
@@ -325,7 +317,7 @@ static int knot_zone_contents_adjust_nsec3_node(knot_node_t **tnode,
 
 	// set previous node
 
-	knot_node_set_previous(node, args->previous_node);
+	node->prev = args->previous_node;
 	args->previous_node = node;
 
 	return KNOT_EOK;
@@ -438,7 +430,7 @@ knot_zone_contents_t *knot_zone_contents_new(const knot_dname_t *apex_name)
 
 	memset(contents, 0, sizeof(knot_zone_contents_t));
 	contents->node_count = 1;
-	contents->apex = knot_node_new(apex_name, NULL, 0);
+	contents->apex = knot_node_new(apex_name);
 	if (contents->apex == NULL) {
 		goto cleanup;
 	}
@@ -514,19 +506,12 @@ static knot_node_t *knot_zone_contents_get_node(const knot_zone_contents_t *zone
 /*----------------------------------------------------------------------------*/
 
 static int knot_zone_contents_add_node(knot_zone_contents_t *zone,
-                                  knot_node_t *node, int create_parents,
-                                  uint8_t flags)
+                                  knot_node_t *node, int create_parents)
 {
 	if (zone == NULL || node == NULL) {
 		return KNOT_EINVAL;
 	}
 
-dbg_zone_exec_detail(
-	char *name = knot_dname_to_str(knot_node_owner(node));
-	dbg_zone_detail("Adding node to zone: %s.\n", name);
-	free(name);
-);
-
 	int ret = 0;
 	if ((ret = knot_zone_contents_check_node(zone, node)) != 0) {
 		dbg_zone("Node check failed.\n");
@@ -552,15 +537,15 @@ dbg_zone_exec_detail(
 		return KNOT_EOK;
 
 	knot_node_t *next_node = NULL;
-	const uint8_t *parent = knot_wire_next_label(knot_node_owner(node), NULL);
+	const uint8_t *parent = knot_wire_next_label(node->owner, NULL);
 
-	if (knot_dname_cmp(knot_node_owner(zone->apex), parent) == 0) {
+	if (knot_dname_cmp(zone->apex->owner, parent) == 0) {
 		dbg_zone_detail("Zone apex is the parent.\n");
 		knot_node_set_parent(node, zone->apex);
 
 		// check if the node is not wildcard child of the parent
-		if (knot_dname_is_wildcard(knot_node_owner(node))) {
-			knot_node_set_wildcard_child(zone->apex);
+		if (knot_dname_is_wildcard(node->owner)) {
+			zone->apex->flags |= KNOT_NODE_FLAGS_WILDCARD_CHILD;
 		}
 	} else {
 		while (parent != NULL &&
@@ -568,7 +553,7 @@ dbg_zone_exec_detail(
 
 			/* Create a new node. */
 			dbg_zone_detail("Creating new node.\n");
-			next_node = knot_node_new(parent, NULL, flags);
+			next_node = knot_node_new(parent);
 			if (next_node == NULL) {
 				return KNOT_ENOMEM;
 			}
@@ -583,8 +568,8 @@ dbg_zone_exec_detail(
 
 			/* Update node pointers. */
 			knot_node_set_parent(node, next_node);
-			if (knot_dname_is_wildcard(knot_node_owner(node))) {
-				knot_node_set_wildcard_child(next_node);
+			if (knot_dname_is_wildcard(node->owner)) {
+				next_node->flags |= KNOT_NODE_FLAGS_WILDCARD_CHILD;
 			}
 
 			++zone->node_count;
@@ -596,7 +581,7 @@ dbg_zone_exec_detail(
 
 		// set the found parent (in the zone) as the parent of the last
 		// inserted node
-		assert(knot_node_parent(node) == NULL);
+		assert(node->parent == NULL);
 		knot_node_set_parent(node, next_node);
 
 		dbg_zone_detail("Created all parents.\n");
@@ -684,12 +669,12 @@ static int insert_rr(knot_zone_contents_t *z,
 		             knot_zone_contents_get_node(z, rr->owner);
 		if (*n == NULL) {
 			// Create new, insert
-			*n = knot_node_new(rr->owner, NULL, 0);
+			*n = knot_node_new(rr->owner);
 			if (*n == NULL) {
 				return KNOT_ENOMEM;
 			}
 			ret = nsec3 ? knot_zone_contents_add_nsec3_node(z, *n) :
-			              knot_zone_contents_add_node(z, *n, true, 0);
+			              knot_zone_contents_add_node(z, *n, true);
 			if (ret != KNOT_EOK) {
 				knot_node_free(n);
 			}
@@ -740,7 +725,7 @@ static int recreate_normal_tree(const knot_zone_contents_t *z,
 			hattrie_iter_free(itt);
 			return ret;
 		}
-		ret = knot_zone_contents_add_node(out, to_add, true, 0);
+		ret = knot_zone_contents_add_node(out, to_add, true);
 		if (ret != KNOT_EOK) {
 			knot_node_free(&to_add);
 			hattrie_iter_free(itt);
@@ -932,17 +917,16 @@ dbg_zone_detail("Search function returned %d, node %s (%p) and prev: %s (%p)\n",
 		*closest_encloser = *previous;
 		assert(*closest_encloser != NULL);
 
-		int matched_labels = knot_dname_matched_labels(
-				knot_node_owner((*closest_encloser)), name);
-		while (matched_labels < knot_dname_labels(
-				knot_node_owner((*closest_encloser)), NULL)) {
+		int matched_labels = knot_dname_matched_labels((*closest_encloser)->owner,
+							       name);
+		while (matched_labels < knot_dname_labels((*closest_encloser)->owner, NULL)) {
 			(*closest_encloser) =
-				knot_node_parent((*closest_encloser));
+				(*closest_encloser)->parent;
 			assert(*closest_encloser);
 		}
 	}
 dbg_zone_exec(
-	char *n = knot_dname_to_str(knot_node_owner((*closest_encloser)));
+	char *n = knot_dname_to_str((*closest_encloser)->owner);
 	dbg_zone_detail("Closest encloser: %s\n", n);
 	free(n);
 );
@@ -1054,7 +1038,7 @@ dbg_zone_exec_detail(
 		// set the previous node of the found node
 		assert(exact_match);
 		assert(*nsec3_node != NULL);
-		*nsec3_previous = knot_node_previous(*nsec3_node);
+		*nsec3_previous = (*nsec3_node)->prev;
 	} else {
 		*nsec3_previous = prev;
 	}
@@ -1089,12 +1073,11 @@ dbg_zone_exec_detail(
 		}
 
 		/* This RRSET was not a match, try the one from previous node. */
-		*nsec3_previous = knot_node_previous(*nsec3_previous);
+		*nsec3_previous = (*nsec3_previous)->prev;
 		nsec3_rrs = knot_node_rdataset(*nsec3_previous, KNOT_RRTYPE_NSEC3);
 		dbg_zone_exec_detail(
 		char *name = (*nsec3_previous)
-				? knot_dname_to_str(
-					  knot_node_owner(*nsec3_previous))
+				? knot_dname_to_str((*nsec3_previous)->owner)
 				: "none";
 		dbg_zone_detail("Previous node: %s, checking parameters...\n",
 				name);
@@ -1116,18 +1099,6 @@ dbg_zone_exec_detail(
 
 /*----------------------------------------------------------------------------*/
 
-const knot_node_t *knot_zone_contents_apex(
-	const knot_zone_contents_t *zone)
-{
-	if (zone == NULL) {
-		return NULL;
-	}
-
-	return zone->apex;
-}
-
-/*----------------------------------------------------------------------------*/
-
 const knot_node_t *knot_zone_contents_find_wildcard_child(
                 const knot_zone_contents_t *contents, const knot_node_t *parent)
 {
@@ -1160,8 +1131,9 @@ static int knot_zone_contents_adjust_nodes(knot_zone_tree_t *nodes,
 	hattrie_build_index(nodes);
 	int result = knot_zone_tree_apply_inorder(nodes, callback, adjust_arg);
 
-	knot_node_set_previous(adjust_arg->first_node,
-	                       adjust_arg->previous_node);
+	if (adjust_arg->first_node) {
+		adjust_arg->first_node->prev = adjust_arg->previous_node;
+	}
 
 	return result;
 }
@@ -1190,7 +1162,7 @@ int knot_zone_contents_adjust_pointers(knot_zone_contents_t *contents)
 		return ret;
 	}
 
-	knot_node_set_apex(contents->apex);
+	contents->apex->flags |= KNOT_NODE_FLAGS_APEX;
 
 	// adjusting parameters
 	knot_zone_adjust_arg_t adjust_arg = { .first_node = NULL,
@@ -1240,7 +1212,7 @@ int knot_zone_contents_adjust_full(knot_zone_contents_t *zone,
 		return result;
 	}
 
-	knot_node_set_apex(zone->apex);
+	zone->apex->flags |= KNOT_NODE_FLAGS_APEX;
 
 	// adjusting parameters
 
@@ -1454,7 +1426,7 @@ uint32_t knot_zone_serial(const knot_zone_contents_t *zone)
 {
 	if (!zone) return 0;
 	const knot_rdataset_t *soa = NULL;
-	soa = knot_node_rdataset(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
+	soa = knot_node_rdataset(zone->apex, KNOT_RRTYPE_SOA);
 	uint32_t serial = knot_soa_serial(soa);
 	return serial;
 }
@@ -1481,9 +1453,9 @@ knot_node_t *zone_contents_get_node_for_rr(knot_zone_contents_t *zone,
 
 	if (node == NULL) {
 		int ret = KNOT_EOK;
-		node = knot_node_new(rrset->owner, NULL, 0);
+		node = knot_node_new(rrset->owner);
 		if (!nsec3) {
-			ret = knot_zone_contents_add_node(zone, node, 1, 0);
+			ret = knot_zone_contents_add_node(zone, node, 1);
 		} else {
 			ret = knot_zone_contents_add_nsec3_node(zone, node);
 		}
diff --git a/src/knot/zone/zone-contents.h b/src/knot/zone/zone-contents.h
index f25c8c3e3b2801a9e22a63b2cb2bb16ba668377b..2698b00b6458e4174928e76f8b153634f7221108 100644
--- a/src/knot/zone/zone-contents.h
+++ b/src/knot/zone/zone-contents.h
@@ -188,15 +188,6 @@ int knot_zone_contents_find_nsec3_for_name(
                                     const knot_dname_t *name,
                                     const knot_node_t **nsec3_node,
                                     const knot_node_t **nsec3_previous);
-/*!
- * \brief Returns the apex node of the zone.
- *
- * \param zone Zone to get the apex of.
- *
- * \return Zone apex node.
- */
-const knot_node_t *knot_zone_contents_apex(
-	const knot_zone_contents_t *contents);
 
 const knot_node_t *knot_zone_contents_find_wildcard_child(
                const knot_zone_contents_t *contents, const knot_node_t *parent);
diff --git a/src/knot/zone/zone-create.c b/src/knot/zone/zone-create.c
index 938e5da0d4f5028f1d6b5122d232081581202f3d..af66692faa6105c9e32254d2ede4c7d8a66deb8f 100644
--- a/src/knot/zone/zone-create.c
+++ b/src/knot/zone/zone-create.c
@@ -78,7 +78,7 @@ static bool handle_err(zcreator_t *zc,
 
 int zcreator_step(zcreator_t *zc, const knot_rrset_t *rr)
 {
-	if (zc == NULL || rr == NULL || knot_rrset_rr_count(rr) != 1) {
+	if (zc == NULL || rr == NULL || rr->rrs.rr_count != 1) {
 		return KNOT_EINVAL;
 	}
 
diff --git a/src/knot/zone/zone-diff.c b/src/knot/zone/zone-diff.c
index 93411c70c9e3fa6be5cffb1a24a060eea9ee56bc..9390fc9bb434e6a96094be898970347f14719b1a 100644
--- a/src/knot/zone/zone-diff.c
+++ b/src/knot/zone/zone-diff.c
@@ -43,8 +43,8 @@ static int knot_zone_diff_load_soas(const knot_zone_contents_t *zone1,
 		return KNOT_EINVAL;
 	}
 
-	const knot_node_t *apex1 = knot_zone_contents_apex(zone1);
-	const knot_node_t *apex2 = knot_zone_contents_apex(zone2);
+	const knot_node_t *apex1 = zone1->apex;
+	const knot_node_t *apex2 = zone2->apex;
 	if (apex1 == NULL || apex2 == NULL) {
 		return KNOT_EINVAL;
 	}
@@ -55,8 +55,8 @@ static int knot_zone_diff_load_soas(const knot_zone_contents_t *zone1,
 		return KNOT_EINVAL;
 	}
 
-	if (knot_rrset_rr_count(&soa_rrset1) == 0 ||
-	    knot_rrset_rr_count(&soa_rrset2) == 0) {
+	if (soa_rrset1.rrs.rr_count == 0 ||
+	    soa_rrset2.rrs.rr_count == 0) {
 		return KNOT_EINVAL;
 	}
 
@@ -103,7 +103,7 @@ static int knot_zone_diff_changeset_add_rrset(knot_changeset_t *changeset,
 		return KNOT_EINVAL;
 	}
 
-	if (knot_rrset_rr_count(rrset) == 0) {
+	if (rrset->rrs.rr_count == 0) {
 		dbg_zonediff_detail("zone_diff: Nothing to add.\n");
 		return KNOT_EOK;
 	}
@@ -140,7 +140,7 @@ static int knot_zone_diff_changeset_remove_rrset(knot_changeset_t *changeset,
 		return KNOT_EOK;
 	}
 
-	if (knot_rrset_rr_count(rrset) == 0) {
+	if (rrset->rrs.rr_count == 0) {
 		/* RDATA are the same, however*/
 		dbg_zonediff_detail("zone_diff: Nothing to remove.\n");
 		return KNOT_EOK;
@@ -169,7 +169,7 @@ static int knot_zone_diff_add_node(const knot_node_t *node,
                                    knot_changeset_t *changeset)
 {
 	/* Add all rrsets from node. */
-	for (uint i = 0; i < knot_node_rrset_count(node); i++) {
+	for (uint i = 0; i < node->rrset_count; i++) {
 		knot_rrset_t rrset = knot_node_rrset_at(node, i);
 		int ret = knot_zone_diff_changeset_add_rrset(changeset,
 		                                             &rrset);
@@ -187,7 +187,7 @@ static int knot_zone_diff_remove_node(knot_changeset_t *changeset,
                                                 const knot_node_t *node)
 {
 	/* Remove all the RRSets of the node. */
-	for (uint i = 0; i < knot_node_rrset_count(node); i++) {
+	for (uint i = 0; i < node->rrset_count; i++) {
 		knot_rrset_t rrset = knot_node_rrset_at(node, i);
 		int ret = knot_zone_diff_changeset_remove_rrset(changeset,
 		                                                &rrset);
@@ -241,7 +241,7 @@ static int knot_zone_diff_rdata_return_changes(const knot_rrset_t *rrset1,
 		get_rdata_descriptor(rrset1->type);
 	assert(desc);
 
-	uint16_t rr1_count = knot_rrset_rr_count(rrset1);
+	uint16_t rr1_count = rrset1->rrs.rr_count;
 	for (uint16_t i = 0; i < rr1_count; ++i) {
 		if (!rr_exists(rrset2, rrset1, i)) {
 			/*
@@ -352,7 +352,7 @@ static int knot_zone_diff_node(knot_node_t **node_ptr, void *data)
 	 * node, if not, the whole node has been removed.
 	 */
 	const knot_node_t *node_in_second_tree = NULL;
-	const knot_dname_t *node_owner = knot_node_owner(node);
+	const knot_dname_t *node_owner = node->owner;
 	assert(node_owner);
 
 	knot_zone_tree_find(param->nodes, node_owner, &node_in_second_tree);
@@ -390,7 +390,7 @@ static int knot_zone_diff_node(knot_node_t **node_ptr, void *data)
 		return ret;
 	}
 
-	for (uint i = 0; i < knot_node_rrset_count(node); i++) {
+	for (uint i = 0; i < node->rrset_count; i++) {
 		/* Search for the RRSet in the node from the second tree. */
 		knot_rrset_t rrset = knot_node_rrset_at(node, i);
 
@@ -423,7 +423,7 @@ static int knot_zone_diff_node(knot_node_t **node_ptr, void *data)
 		}
 	}
 
-	for (uint i = 0; i < knot_node_rrset_count(node_in_second_tree); i++) {
+	for (uint i = 0; i < node_in_second_tree->rrset_count; i++) {
 		/* Search for the RRSet in the node from the second tree. */
 		knot_rrset_t rrset = knot_node_rrset_at(node_in_second_tree, i);
 
@@ -474,7 +474,7 @@ static int knot_zone_diff_add_new_nodes(knot_node_t **node_ptr, void *data)
 	* already handled.
 	*/
 
-	const knot_dname_t *node_owner = knot_node_owner(node);
+	const knot_dname_t *node_owner = node->owner;
 	/*
 	 * Node should definitely have an owner, otherwise it would not be in
 	 * the tree.
diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c
index 4443ac2bc4930f0920b56604036ec9513342e41d..7ab6ed68f490a0e07855e3606db29c1ea9bea6d9 100644
--- a/src/knot/zone/zone-dump.c
+++ b/src/knot/zone/zone-dump.c
@@ -50,7 +50,7 @@ static int apex_node_dump_text(knot_node_t *node, dump_params_t *params)
 					&soa_style) < 0) {
 			return KNOT_ENOMEM;
 		}
-		params->rr_count += knot_rrset_rr_count(&soa);
+		params->rr_count += soa.rrs.rr_count;
 		fprintf(params->file, "%s", params->buf);
 		params->buf[0] = '\0';
 	}
@@ -73,7 +73,7 @@ static int apex_node_dump_text(knot_node_t *node, dump_params_t *params)
 		                        params->style) < 0) {
 			return KNOT_ENOMEM;
 		}
-		params->rr_count +=  knot_rrset_rr_count(&rrset);
+		params->rr_count +=  rrset.rrs.rr_count;
 		fprintf(params->file, "%s", params->buf);
 		params->buf[0] = '\0';
 	}
@@ -122,7 +122,7 @@ static int node_dump_text(knot_node_t *node, void *data)
 		                        params->style) < 0) {
 			return KNOT_ENOMEM;
 		}
-		params->rr_count += knot_rrset_rr_count(&rrset);
+		params->rr_count += rrset.rrs.rr_count;
 		fprintf(params->file, "%s", params->buf);
 		params->buf[0] = '\0';
 	}
@@ -152,7 +152,7 @@ int zone_dump_text(knot_zone_contents_t *zone, const struct sockaddr_storage *fr
 	params.buf = buf;
 	params.buflen = DUMP_BUF_LEN;
 	params.rr_count = 0;
-	params.origin = knot_node_owner(apex);
+	params.origin = apex->owner;
 	params.style = &KNOT_DUMP_STYLE_DEFAULT;
 
 	int ret;
diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c
index af36361e8c10ab567fc5441d6875800681924b3f..56cd0024a4e797c46bcad59cbc95a484599148fa 100644
--- a/src/knot/zone/zone-tree.c
+++ b/src/knot/zone/zone-tree.c
@@ -141,7 +141,7 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree,
 	if (fval) *found = (knot_node_t *)(*fval);
 	int exact_match = 0;
 	if (ret == 0) {
-		*previous = knot_node_get_previous(*found);
+		*previous = (*found)->prev;
 		exact_match = 1;
 	} else if (ret < 0) {
 		*previous = *found;
@@ -154,20 +154,20 @@ int knot_zone_tree_get_less_or_equal(knot_zone_tree_t *tree,
 		/*! \todo We could store rightmost node in zonetree probably. */
 		hattrie_iter_t *i = hattrie_iter_begin(tree, 1);
 		*previous = *(knot_node_t **)hattrie_iter_val(i); /* leftmost */
-		*previous = knot_node_get_previous(*previous); /* rightmost */
+		*previous = (*previous)->prev; /* rightmost */
 		*found = NULL;
 		hattrie_iter_free(i);
 	}
 
 	/* Previous node for proof must be non-empty and authoritative. */
-	if (knot_node_rrset_count(*previous) == 0 || knot_node_is_non_auth(*previous)) {
-		*previous = knot_node_get_previous(*previous);
+	if ((*previous)->rrset_count == 0 || (*previous)->flags & KNOT_NODE_FLAGS_NONAUTH) {
+		*previous = (*previous)->prev;
 	}
 
 dbg_zone_exec_detail(
 		char *name = knot_dname_to_str(owner);
 		char *name_f = (*found != NULL)
-			? knot_dname_to_str(knot_node_owner(*found))
+			? knot_dname_to_str((*found)->owner)
 			: "none";
 
 		dbg_zone_detail("Searched for owner %s in zone tree.\n",
diff --git a/src/libknot/dnssec/rrset-sign.c b/src/libknot/dnssec/rrset-sign.c
index eaa98a4565ff0353abca1df37eac0fc5644e6ee7..161cb4c6a25b620222d346469ac28790c912aaab 100644
--- a/src/libknot/dnssec/rrset-sign.c
+++ b/src/libknot/dnssec/rrset-sign.c
@@ -149,7 +149,7 @@ static int sign_ctx_add_records(knot_dnssec_sign_context_t *ctx,
 	uint16_t rr_count = 0;
 	result = knot_rrset_to_wire(covered, rrwf, &rr_wire_size,
 	                            MAX_RR_WIREFORMAT_SIZE, &rr_count, NULL);
-	if (result != KNOT_EOK || rr_count != knot_rrset_rr_count(covered)) {
+	if (result != KNOT_EOK || rr_count != covered->rrs.rr_count) {
 		free(rrwf);
 		return result;
 	}
diff --git a/src/libknot/edns.c b/src/libknot/edns.c
index b9d4eb744af05fbf81fb1c26cbb992845dbae298..855d51d54a32766b49c27283fcce7484af2caf04 100644
--- a/src/libknot/edns.c
+++ b/src/libknot/edns.c
@@ -55,7 +55,7 @@ int knot_edns_new_from_rr(knot_opt_rr_t *opt_rr, const knot_rrset_t *rrset)
 {
 	if (opt_rr == NULL || rrset == NULL
 	    || rrset->type != KNOT_RRTYPE_OPT ||
-	    knot_rrset_rr_count(rrset) == 0) {
+	    rrset->rrs.rr_count == 0) {
 		return KNOT_EINVAL;
 	}
 
diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c
index 929e22c114a5d1be54fcbaeb47c0cb675e890596..56d053c8fcc8e290c7609ad96fdf59853c518235 100644
--- a/src/libknot/packet/pkt.c
+++ b/src/libknot/packet/pkt.c
@@ -657,9 +657,6 @@ static int knot_pkt_rr_from_wire(const uint8_t *wire, size_t *pos,
 
 	*pos += KNOT_RR_HEADER_SIZE;
 
-	dbg_packet_verb("%s: read type %u, class %u, ttl %u, rdlength %u\n",
-	                __func__, rrset->type, rrset->rclass, ttl, rdlength);
-
 	if (size - *pos < rdlength) {
 		dbg_packet("%s: not enough data to parse RDATA\n", __func__);
 		knot_dname_free(&owner, mm);
diff --git a/src/libknot/rrset-dump.c b/src/libknot/rrset-dump.c
index ab98d68f2c4ca0bfd52b3f9fb1e51d73997df1f6..41e4c2071bb50388998cfaf4def56833cfd6b784 100644
--- a/src/libknot/rrset-dump.c
+++ b/src/libknot/rrset-dump.c
@@ -1961,7 +1961,7 @@ int knot_rrset_txt_dump_header(const knot_rrset_t      *rrset,
 	if (knot_rrtype_to_string(rrset->type, buf, sizeof(buf)) < 0) {
 		return KNOT_ESPACE;
 	}
-	if (knot_rrset_rr_count(rrset) > 0) {
+	if (rrset->rrs.rr_count > 0) {
 		ret = snprintf(dst + len, maxlen - len, "%s%c", buf, sep);
 	} else {
 		ret = snprintf(dst + len, maxlen - len, "%s", buf);
@@ -1985,7 +1985,7 @@ int knot_rrset_txt_dump(const knot_rrset_t      *rrset,
 	int    ret;
 
 	// UPDATE delete may have empty RDATA => dump header.
-	if (knot_rrset_rr_count(rrset) == 0) {
+	if (rrset->rrs.rr_count == 0) {
 		// Dump rdata owner, class, ttl and type.
 		ret = knot_rrset_txt_dump_header(rrset, 0, dst + len,
 		                                 maxlen - len, style);
@@ -2003,7 +2003,7 @@ int knot_rrset_txt_dump(const knot_rrset_t      *rrset,
 	}
 
 	// Loop over rdata in rrset.
-	uint16_t rr_count = knot_rrset_rr_count(rrset);
+	uint16_t rr_count = rrset->rrs.rr_count;
 	for (uint16_t i = 0; i < rr_count; i++) {
 		// Dump rdata owner, class, ttl and type.
 		ret = knot_rrset_txt_dump_header(rrset,
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
index 421afcda94af4a35812006e66d371bb206b1c3f6..fea075576533023085375cdb9e39104ea842d933 100644
--- a/src/libknot/rrset.c
+++ b/src/libknot/rrset.c
@@ -36,7 +36,7 @@
 static uint16_t rrset_rdata_naptr_bin_chunk_size(const knot_rrset_t *rrset,
                                                size_t pos)
 {
-	if (rrset == NULL || pos >= knot_rrset_rr_count(rrset)) {
+	if (rrset == NULL || pos >= rrset->rrs.rr_count) {
 		return 0;
 	}
 
@@ -277,7 +277,7 @@ static int knot_rrset_to_wire_aux(const knot_rrset_t *rrset, uint8_t **pos,
 	assert(*pos != NULL);
 
 	// No RDATA, just save header and 0 RDLENGTH.
-	if (knot_rrset_rr_count(rrset) == 0) {
+	if (rrset->rrs.rr_count == 0) {
 		size_t header_size = 0;
 		int ret = knot_rrset_header_to_wire(rrset, 0, pos, max_size, comp,
 		                                    &header_size);
@@ -294,7 +294,7 @@ static int knot_rrset_to_wire_aux(const knot_rrset_t *rrset, uint8_t **pos,
 	}
 
 	// Save rrset records.
-	for (uint16_t i = 0; i < knot_rrset_rr_count(rrset); ++i) {
+	for (uint16_t i = 0; i < rrset->rrs.rr_count; ++i) {
 		dbg_rrset_detail("rrset: to_wire: Current max_size=%zu\n",
 			         max_size);
 		size_t knot_rr_size = 0;
@@ -454,15 +454,6 @@ void knot_rrset_rr_set_ttl(const knot_rrset_t *rrset, size_t pos, uint32_t ttl)
 	}
 }
 
-uint16_t knot_rrset_rr_count(const knot_rrset_t *rrset)
-{
-	if (rrset == NULL) {
-		return 0;
-	}
-
-	return rrset->rrs.rr_count;
-}
-
 int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size,
                        size_t max_size, uint16_t *rr_count, knot_compr_t *compr)
 {
@@ -488,7 +479,7 @@ int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size,
 	dbg_rrset_detail("Size after: %zu\n", *size);
 
 	// If the rrset is empty set record counter to 1.
-	*rr_count = knot_rrset_rr_count(rrset) > 0 ? knot_rrset_rr_count(rrset) : 1;
+	*rr_count = rrset->rrs.rr_count > 0 ? rrset->rrs.rr_count : 1;
 
 	return KNOT_EOK;
 }
@@ -632,7 +623,11 @@ bool knot_rrset_equal(const knot_rrset_t *r1,
 
 bool knot_rrset_empty(const knot_rrset_t *rrset)
 {
-	uint16_t rr_count = knot_rrset_rr_count(rrset);
-	return rr_count == 0;
+	if (rrset) {
+		uint16_t rr_count = rrset->rrs.rr_count;
+		return rr_count == 0;
+	} else {
+		return true;
+	}
 }
 
diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h
index 4cc4f77bc35edec876e7263cf87a2d463c03d903..17356ebb0f65bbac1dc26f51c5afd3a6c1331a08 100644
--- a/src/libknot/rrset.h
+++ b/src/libknot/rrset.h
@@ -167,15 +167,6 @@ uint32_t knot_rrset_rr_ttl(const knot_rrset_t *rrset, size_t pos);
  */
 void knot_rrset_rr_set_ttl(const knot_rrset_t *rrset, size_t pos, uint32_t ttl);
 
-/*!
- * \brief Returns count of RRs in RRSet.
- *
- * \param rrset  RRSet.
- *
- * \return RR count.
- */
-uint16_t knot_rrset_rr_count(const knot_rrset_t *rrset);
-
 /* ---------- Wire conversions (legacy, to be done in knot_pkt_t) ----------- */
 
 /*!
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
index 8922b10cbaafe1a2ca5c3d7facbb52ba19d6d4a9..86c45e941fe5f961c5a35285842eaa1f6c7f5955 100644
--- a/src/libknot/tsig-op.c
+++ b/src/libknot/tsig-op.c
@@ -700,7 +700,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr,
 
 	uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
 	size_t digest_tmp_len = 0;
-	assert(knot_rrset_rr_count(tsig_rr) > 0);
+	assert(tsig_rr->rrs.rr_count > 0);
 
 	if (use_times) {
 		/* Wire is not a single packet, TSIG RRs must be stripped already. */
@@ -715,7 +715,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr,
 		                                 tsig_rr, tsig_key);
 	}
 
-	assert(knot_rrset_rr_count(tsig_rr) > 0);
+	assert(tsig_rr->rrs.rr_count > 0);
 	free(wire_to_sign);
 
 	if (ret != KNOT_EOK) {
diff --git a/src/utils/common/exec.c b/src/utils/common/exec.c
index a336fc489ac96a96999b59d2968bd7560aabaf21..92af2dfe537110110ba374d620b7a49164609df5 100644
--- a/src/utils/common/exec.c
+++ b/src/utils/common/exec.c
@@ -255,7 +255,7 @@ static void print_section_dig(const knot_rrset_t *rrsets,
 
 	for (size_t i = 0; i < count; i++) {
 		const knot_rrset_t *rrset = &rrsets[i];
-		uint16_t rrset_rdata_count = knot_rrset_rr_count(rrset);
+		uint16_t rrset_rdata_count = rrset->rrs.rr_count;
 		for (uint16_t j = 0; j < rrset_rdata_count; j++) {
 			while (knot_rrset_txt_dump_data(rrset, j, buf, buflen,
 			                                &(style->style)) < 0) {
@@ -299,7 +299,7 @@ static void print_section_host(const knot_rrset_t *rrsets,
 		}
 		descr = knot_lookup_by_id(rtypes, rrset->type);
 
-		uint16_t rrset_rdata_count = knot_rrset_rr_count(rrset);
+		uint16_t rrset_rdata_count = rrset->rrs.rr_count;
 		for (uint16_t j = 0; j < rrset_rdata_count; j++) {
 			if (rrset->type == KNOT_RRTYPE_CNAME &&
 			    style->hide_cname) {