From f097f6473095fa04ff52ac7ee33a8dc435144a6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Roman=20Smr=C5=BE?= <roman.smrz@seznam.cz>
Date: Wed, 29 Nov 2023 20:27:38 +0100
Subject: Avoid storing zero references and objects

---
 src/network/protocol.cpp |  2 +-
 src/storage.cpp          | 29 +++++++++++++++++++++++++----
 2 files changed, 26 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp
index 8e0de61..02c3dae 100644
--- a/src/network/protocol.cpp
+++ b/src/network/protocol.cpp
@@ -134,7 +134,7 @@ NetworkProtocol::Connection NetworkProtocol::connect(sockaddr_in6 addr)
 		connections.push_back(conn.get());
 
 		vector<Header::Item> header {
-			Header::Initiation { Digest(array<uint8_t, Digest::size> {}) },
+			Header::Initiation { Digest::of(Object(Record())) },
 			Header::AnnounceSelf { self->ref()->digest() },
 			Header::Version { defaultVersion },
 		};
diff --git a/src/storage.cpp b/src/storage.cpp
index 366fe71..19f35a9 100644
--- a/src/storage.cpp
+++ b/src/storage.cpp
@@ -746,7 +746,11 @@ optional<PartialObject> PartialStorage::loadObject(const Digest & digest) const
 }
 
 PartialRef PartialStorage::storeObject(const PartialObject & obj) const
-{ return ref(p->storeBytes(obj.encode())); }
+{
+	if (not obj)
+		return PartialRef::zcreate(*this);
+	return ref(p->storeBytes(obj.encode()));
+}
 
 PartialRef PartialStorage::storeObject(const PartialRecord & val) const
 { return storeObject(PartialObject(val)); }
@@ -775,6 +779,8 @@ Ref Storage::storeObject(const Blob & val) const
 template<class S>
 optional<Digest> Storage::Priv::copy(const typename S::Ref & pref, vector<Digest> * missing) const
 {
+	if (pref.digest().isZero())
+		return pref.digest();
 	if (backend->contains(pref.digest()))
 		return pref.digest();
 	if (pref)
@@ -787,6 +793,9 @@ optional<Digest> Storage::Priv::copy(const typename S::Ref & pref, vector<Digest
 template<class S>
 optional<Digest> Storage::Priv::copy(const ObjectT<S> & pobj, vector<Digest> * missing) const
 {
+	if (not pobj)
+		return Digest(array<uint8_t, Digest::size> {});
+
 	bool fail = false;
 	if (auto rec = pobj.asRecord())
 		for (const auto & r : rec->items().asRef())
@@ -948,6 +957,11 @@ PartialRef PartialRef::create(const PartialStorage & st, const Digest & digest)
 	return PartialRef(shared_ptr<Priv>(p));
 }
 
+PartialRef PartialRef::zcreate(const PartialStorage & st)
+{
+	return create(st, Digest(array<uint8_t, Digest::size> {}));
+}
+
 const Digest & PartialRef::digest() const
 {
 	return p->digest;
@@ -1421,9 +1435,6 @@ vector<uint8_t> RecordT<S>::encodeInner() const
 	vector<uint8_t> res;
 	auto inserter = std::back_inserter(res);
 	for (const auto & item : *ptr) {
-		copy(item.name.begin(), item.name.end(), inserter);
-		inserter = ':';
-
 		string type;
 		string value;
 
@@ -1451,6 +1462,8 @@ vector<uint8_t> RecordT<S>::encodeInner() const
 			value = string(*x);
 		} else if (auto x = item.asRef()) {
 			type = "r";
+			if (x->digest().isZero())
+				continue;
 			value = string(x->digest());
 		} else if (auto x = item.asUnknown()) {
 			type = x->type;
@@ -1459,6 +1472,8 @@ vector<uint8_t> RecordT<S>::encodeInner() const
 			throw runtime_error("unhandeled record item type");
 		}
 
+		copy(item.name.begin(), item.name.end(), inserter);
+		inserter = ':';
 		copy(type.begin(), type.end(), inserter);
 		inserter = ' ';
 
@@ -1598,6 +1613,12 @@ ObjectT<S> ObjectT<S>::load(const typename S::Ref & ref)
 	return *ref;
 }
 
+template<class S>
+ObjectT<S>::operator bool() const
+{
+	return not holds_alternative<monostate>(content);
+}
+
 template<class S>
 optional<RecordT<S>> ObjectT<S>::asRecord() const
 {
-- 
cgit v1.2.3