diff --git a/component/cache_requestor.cc b/component/cache_requestor.cc index 026633ba..d82e5b5e 100644 --- a/component/cache_requestor.cc +++ b/component/cache_requestor.cc @@ -47,7 +47,7 @@ void Self::Assign(dc::BackendResult res) { } } auto Self::handle(RequestPtr req) -> HandleOutcome { - if (startup_pending_) { + if (startup_pending_ || !(req->cachable())) { return HandleOutcome::NOT_HANDLED; } Task task; @@ -132,19 +132,20 @@ void Self::OnBodyRead(Task task, int code) { task.body.assign(task.buf->data(), static_cast(code)); if (task.request) { task.SetHeaders(name()); - if (task.request->RespondSuccessfully(task.body, api_)) { - VLOG(2) << "Cache hit on " << task.key << " for " - << task.request->debug_string(); + bool valid = false; + task.request->RespondSuccessfully(task.body, api_, &valid); + if (valid) { + LOG(INFO) << "Cache hit for " << task.key; } else { - LOG(ERROR) << "Had a BAD cached response for " << task.key; + LOG(ERROR) << "Had a bad or expired cached response for " << task.key; Expire(task.key); Miss(task); } } } void Self::Store(std::string key, std::string headers, std::string body) { - VLOG(2) << "Store(" << name() << ',' << key << ',' << headers.size() << ',' - << body.size() << ')'; + LOG(INFO) << "Store(" << name() << ',' << key << ',' << headers.size() << ',' + << body.size() << ')'; auto bound = base::BindOnce(&Self::OnEntryCreated, base::Unretained(this), key, headers, body); auto res = cache_->OpenOrCreateEntry(key, net::LOW, std::move(bound)); diff --git a/library/include/ipfs_client/gw/gateway_request.h b/library/include/ipfs_client/gw/gateway_request.h index a3801a94..f9e15f04 100644 --- a/library/include/ipfs_client/gw/gateway_request.h +++ b/library/include/ipfs_client/gw/gateway_request.h @@ -61,9 +61,11 @@ class GatewayRequest { std::optional describe_http(std::string_view) const; std::string debug_string() const; void orchestrator(std::shared_ptr const&); + bool cachable() const; bool RespondSuccessfully(std::string_view, - std::shared_ptr const& api); + std::shared_ptr const& api, + bool* valid = nullptr); void Hook(std::function); bool PartiallyRedundant() const; std::string Key() const; diff --git a/library/include/ipfs_client/gw/requestor.h b/library/include/ipfs_client/gw/requestor.h index 634c3673..0aba88b5 100644 --- a/library/include/ipfs_client/gw/requestor.h +++ b/library/include/ipfs_client/gw/requestor.h @@ -18,10 +18,7 @@ class GatewayRequest; using RequestPtr = std::shared_ptr; class Requestor : public std::enable_shared_from_this { - protected: - Requestor() {} - - friend class RequestorPool; + public: enum class HandleOutcome : char { NOT_HANDLED = 'N', PENDING = 'P', @@ -29,6 +26,10 @@ class Requestor : public std::enable_shared_from_this { PARALLEL = 'L', MAYBE_LATER = 'M' }; + + protected: + Requestor() {} + virtual HandleOutcome handle(RequestPtr) = 0; void definitive_failure(RequestPtr) const; diff --git a/library/include/ipfs_client/ipld/dag_node.h b/library/include/ipfs_client/ipld/dag_node.h index f91532e3..bda11b0e 100644 --- a/library/include/ipfs_client/ipld/dag_node.h +++ b/library/include/ipfs_client/ipld/dag_node.h @@ -30,6 +30,8 @@ namespace ipfs::ipld { using NodePtr = std::shared_ptr; class DirShard; +class DnsLinkName; +class IpnsName; struct MoreDataNeeded { MoreDataNeeded(std::string one) : ipfs_abs_paths_{{one}} {} @@ -90,7 +92,14 @@ class DagNode : public std::enable_shared_from_this { virtual NodePtr rooted(); virtual NodePtr deroot(); - virtual DirShard* as_hamt(); // Wish I had access to dynamic_cast + + // Wish I had access to dynamic_cast + virtual DnsLinkName const* as_dnslink() const { return nullptr; } + virtual DirShard* as_hamt() { return nullptr; } + virtual IpnsName const* as_ipns() const { return nullptr; } + + virtual bool expired() const; + virtual bool PreferOver(DagNode const& another) const; void set_api(std::shared_ptr); }; diff --git a/library/src/ipfs_client/gw/dnslink_requestor.cc b/library/src/ipfs_client/gw/dnslink_requestor.cc index 7249ce80..07ad79c7 100644 --- a/library/src/ipfs_client/gw/dnslink_requestor.cc +++ b/library/src/ipfs_client/gw/dnslink_requestor.cc @@ -1,6 +1,6 @@ #include -#include "ipfs_client/ipld/ipns_name.h" +#include "ipfs_client/ipld/dnslink_name.h" #include #include diff --git a/library/src/ipfs_client/gw/gateway_request.cc b/library/src/ipfs_client/gw/gateway_request.cc index f5b1a839..39759943 100644 --- a/library/src/ipfs_client/gw/gateway_request.cc +++ b/library/src/ipfs_client/gw/gateway_request.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -219,6 +220,23 @@ std::string_view ipfs::gw::name(ipfs::gw::Type t) { std::sprintf(buf.data(), "InvalidType %d", static_cast(t)); return buf.data(); } +bool Self::cachable() const { + using ipfs::gw::Type; + switch (type) { + case Type::Car: + return path.find("/ipns/") == std::string::npos; + case Type::Block: + case Type::Ipns: + return true; + case Type::DnsLink: + case Type::Providers: + case Type::Identity: + case Type::Zombie: + return false; + } + LOG(ERROR) << "Unhandled request type: " << debug_string(); + return false; +} std::string Self::debug_string() const { std::ostringstream oss; oss << "Request{Type=" << type << ' ' << main_param; @@ -237,9 +255,13 @@ std::string Self::Key() const { return rv; } bool Self::RespondSuccessfully(std::string_view bytes, - std::shared_ptr const& api) { + std::shared_ptr const& api, + bool* valid) { using namespace ipfs::ipld; bool success = false; + if (valid) { + *valid = false; + } switch (type) { case Type::Block: { DCHECK(cid.has_value()); @@ -249,11 +271,19 @@ bool Self::RespondSuccessfully(std::string_view bytes, } DCHECK(api); auto node = DagNode::fromBytes(api, cid.value(), bytes); + if (!node) { + return false; + } else if (valid) { + *valid = true; + } success = orchestrator_->add_node(main_param, node); } break; case Type::Identity: success = orchestrator_->add_node( main_param, std::make_shared(std::string{bytes})); + if (valid) { + *valid = true; + } break; case Type::Ipns: if (cid.has_value()) { @@ -262,43 +292,55 @@ bool Self::RespondSuccessfully(std::string_view bytes, auto rec = ipfs::ValidateIpnsRecord({byte_ptr, bytes.size()}, cid.value(), *api); if (rec.has_value()) { - auto node = DagNode::fromIpnsRecord(rec.value()); + auto node = std::make_shared(rec.value()); success = orchestrator_->add_node(main_param, node); + if (valid) { + *valid = !node->expired(); + LOG(INFO) << "IPNS node created " << main_param << ' ' << success + << " vs. " << *valid; + } } else { LOG(ERROR) << "IPNS record failed to validate!"; return false; } } break; - case Type::DnsLink: + case Type::DnsLink: { LOG(INFO) << "Resolved " << debug_string() << " to " << bytes; + auto node = std::make_shared(bytes); if (orchestrator_) { - success = orchestrator_->add_node( - main_param, std::make_shared(bytes)); + success = orchestrator_->add_node(main_param, node); } else { LOG(FATAL) << "I have no orchestrator!!"; } - break; + if (valid) { + *valid = !node->expired(); + } + } break; case Type::Car: { DCHECK(api); Car car(as_bytes(bytes), *api); - auto added = 0; while (auto block = car.NextBlock()) { auto cid_s = block->cid.to_string(); auto n = DagNode::fromBytes(api, block->cid, block->bytes); if (!n) { LOG(ERROR) << "Unable to handle block from CAR: " << cid_s; - } else if (orchestrator_->add_node(cid_s, n)) { - ++added; - } else { - LOG(INFO) << "Did not add node from CAR: " << cid_s; + continue; + } + if (valid) { + *valid = true; + } + if (orchestrator_->add_node(cid_s, n)) { + success = true; } } - success = added > 0; break; } case Type::Providers: success = providers::ProcessResponse(bytes, *api); + if (valid) { + *valid = success; + } break; case Type::Zombie: LOG(WARNING) << "Responding to a zombie is ill-advised."; diff --git a/library/src/ipfs_client/gw/multi_gateway_requestor.cc b/library/src/ipfs_client/gw/multi_gateway_requestor.cc index e1de2464..6d3c12a9 100644 --- a/library/src/ipfs_client/gw/multi_gateway_requestor.cc +++ b/library/src/ipfs_client/gw/multi_gateway_requestor.cc @@ -15,6 +15,9 @@ std::string_view Self::name() const { return "multi-gateway requestor"; } auto Self::handle(RequestPtr r) -> HandleOutcome { + if (!r || !api_) { + return HandleOutcome::DONE; + } if (!r->is_http()) { LOG(INFO) << r->debug_string() << " is not an HTTP request."; return HandleOutcome::NOT_HANDLED; diff --git a/library/src/ipfs_client/gw/multi_gateway_requestor_unittest.cc b/library/src/ipfs_client/gw/multi_gateway_requestor_unittest.cc new file mode 100644 index 00000000..c57140db --- /dev/null +++ b/library/src/ipfs_client/gw/multi_gateway_requestor_unittest.cc @@ -0,0 +1,21 @@ +#include "multi_gateway_requestor.h" + +#include + +#include + +namespace { +ig::RequestPtr block_req() { + auto rv = std::make_shared(); + rv->type = ig::Type::Block; + rv->main_param = + "bafybeid4dzlxm6h4r6kfvx6jp6vj4nteplmbve224lx2s3lgjubyufsuo4"; + return rv; +} +} // namespace + +TEST(MultiGatewayRequestor, FailsWithoutApi) { + ig::MultiGatewayRequestor t; + auto o = t.handle(block_req()); + EXPECT_TRUE(o == ig::Requestor::HandleOutcome::DONE); +} \ No newline at end of file diff --git a/library/src/ipfs_client/ipld/dag_node.cc b/library/src/ipfs_client/ipld/dag_node.cc index d6ffd400..a6abf57e 100644 --- a/library/src/ipfs_client/ipld/dag_node.cc +++ b/library/src/ipfs_client/ipld/dag_node.cc @@ -4,7 +4,7 @@ #include "dag_cbor_node.h" #include "dag_json_node.h" #include "directory_shard.h" -#include "ipns_name.h" +#include "dnslink_name.h" #include "root.h" #include "small_directory.h" #include "symlink.h" @@ -144,7 +144,7 @@ std::shared_ptr Node::fromBlock(ipfs::PbDag const& block) { } auto Node::fromIpnsRecord(ipfs::ValidatedIpns const& v) -> NodePtr { - return std::make_shared(v.value); + return std::make_shared(v.value); } std::shared_ptr Node::deroot() { @@ -153,9 +153,6 @@ std::shared_ptr Node::deroot() { std::shared_ptr Node::rooted() { return std::make_shared(shared_from_this()); } -auto Node::as_hamt() -> DirShard* { - return nullptr; -} void Node::set_api(std::shared_ptr api) { api_ = api; } @@ -229,6 +226,12 @@ auto Node::FindChild(std::string_view link_key) -> Link* { } return nullptr; } +bool Node::expired() const { + return false; +} +bool Node::PreferOver(Node const&) const { + return false; +} std::ostream& operator<<(std::ostream& s, ipfs::ipld::PathChange const& c) { return s << "PathChange{" << c.new_path << '}'; diff --git a/library/src/ipfs_client/ipld/dnslink_name.cc b/library/src/ipfs_client/ipld/dnslink_name.cc new file mode 100644 index 00000000..d838d3e6 --- /dev/null +++ b/library/src/ipfs_client/ipld/dnslink_name.cc @@ -0,0 +1,53 @@ +#include "dnslink_name.h" + +#include "log_macros.h" + +using Self = ipfs::ipld::DnsLinkName; +namespace ch = std::chrono; + +Self::DnsLinkName(std::string_view target_abs_path) + : expiration_(ch::system_clock::now() + ch::minutes(5)) { + SlashDelimited target{target_abs_path}; + target_namespace_ = target.pop(); + target_root_ = target.pop(); + links_.emplace_back("", Link{target_root_, nullptr}); + target_path_.assign(target.to_string()); +} + +auto Self::resolve(ResolutionState& params) -> ResolveResult { + auto& node = links_.at(0).second.node; + if (!node) { + node = params.GetBlock(target_root_); + } + if (!node) { + return MoreDataNeeded(target_namespace_ + "/" + target_root_); + } + if (target_path_.empty()) { + return node->resolve(params); + } + auto path = target_path_; + path.append("/").append(params.PathToResolve().to_view()); + auto altered = params.WithPath(path); + LOG(WARNING) << "Odd case: name points at /ns/root/MORE/PATH (" + << target_namespace_ << '/' << target_root_ << '/' + << target_path_ << "): " << params.MyPath() + << " will be resolved as " << path; + auto lower = node->resolve(params); + if (auto* mdn = std::get_if(&lower)) { + if (expired()) { + auto refresh_path = "/ipns/" + params.MyPath().pop_back(); + mdn->ipfs_abs_paths_.push_back(refresh_path); + } + } + return lower; +} +bool Self::expired() const { + return expiration_ < ch::system_clock::now(); +} +bool Self::PreferOver(DagNode const& another) const { + auto* other = another.as_dnslink(); + if (!other) { + return true; + } + return expiration_ > other->expiration_ + ch::seconds(1); +} diff --git a/library/src/ipfs_client/ipld/dnslink_name.h b/library/src/ipfs_client/ipld/dnslink_name.h new file mode 100644 index 00000000..8dbeb89d --- /dev/null +++ b/library/src/ipfs_client/ipld/dnslink_name.h @@ -0,0 +1,27 @@ +#ifndef IPFS_IPLD_DNSLINK_NAME_H_ +#define IPFS_IPLD_DNSLINK_NAME_H_ + +#include "ipfs_client/ipld/dag_node.h" + +#include + +namespace ipfs::ipld { +class DnsLinkName : public DagNode { + std::string target_namespace_; + std::string target_root_; + std::string target_path_; + std::chrono::system_clock::time_point expiration_; + + ResolveResult resolve(ResolutionState& params) override; + bool PreferOver(DagNode const& another) const override; + DnsLinkName const* as_dnslink() const override { return this; } + + public: + DnsLinkName(std::string_view target_abs_path); + virtual ~DnsLinkName() noexcept {} + + bool expired() const override; +}; +} // namespace ipfs::ipld + +#endif // IPFS_IPLD_DNSLINK_NAME_H_ diff --git a/library/src/ipfs_client/ipld/ipns_name.cc b/library/src/ipfs_client/ipld/ipns_name.cc index e3ad0271..c5a32382 100644 --- a/library/src/ipfs_client/ipld/ipns_name.cc +++ b/library/src/ipfs_client/ipld/ipns_name.cc @@ -1,11 +1,17 @@ #include "ipns_name.h" +#include + #include "log_macros.h" using Self = ipfs::ipld::IpnsName; +namespace ch = std::chrono; -Self::IpnsName(std::string_view target_abs_path) { - SlashDelimited target{target_abs_path}; +Self::IpnsName(ValidatedIpns const& record) + : expiration_{ch::system_clock::from_time_t( + std::min(record.use_until, record.cache_until))}, + serial_{record.sequence} { + SlashDelimited target{record.value}; target_namespace_ = target.pop(); target_root_ = target.pop(); links_.emplace_back("", Link{target_root_, nullptr}); @@ -30,5 +36,22 @@ auto Self::resolve(ResolutionState& params) -> ResolveResult { << target_namespace_ << '/' << target_root_ << '/' << target_path_ << "): " << params.MyPath() << " will be resolved as " << path; - return node->resolve(params); + auto lower = node->resolve(params); + if (auto* mdn = std::get_if(&lower)) { + if (expired()) { + auto refresh_path = "/ipns/" + params.MyPath().pop_back(); + mdn->ipfs_abs_paths_.push_back(refresh_path); + } + } + return lower; +} +bool Self::expired() const { + return expiration_ < ch::system_clock::now(); +} +bool Self::PreferOver(DagNode const& another) const { + auto other = another.as_ipns(); + if (!other) { + return true; + } + return serial_ > other->serial_; } diff --git a/library/src/ipfs_client/ipld/ipns_name.h b/library/src/ipfs_client/ipld/ipns_name.h index b27025bd..35462f7c 100644 --- a/library/src/ipfs_client/ipld/ipns_name.h +++ b/library/src/ipfs_client/ipld/ipns_name.h @@ -3,18 +3,29 @@ #include "ipfs_client/ipld/dag_node.h" -namespace ipfs::ipld { +#include + +namespace ipfs { +struct ValidatedIpns; +namespace ipld { class IpnsName : public DagNode { std::string target_namespace_; std::string target_root_; std::string target_path_; + std::chrono::system_clock::time_point expiration_; + std::size_t serial_; ResolveResult resolve(ResolutionState& params) override; + bool PreferOver(DagNode const& another) const override; + IpnsName const* as_ipns() const override { return this; } public: - IpnsName(std::string_view target_abs_path); + IpnsName(ValidatedIpns const&); virtual ~IpnsName() noexcept {} + + bool expired() const override; }; -} // namespace ipfs::ipld +} // namespace ipld +} // namespace ipfs #endif // IPFS_IPLD_IPNS_NAME_H_ diff --git a/library/src/ipfs_client/ipld/root.cc b/library/src/ipfs_client/ipld/root.cc index fd5af1b2..308c0081 100644 --- a/library/src/ipfs_client/ipld/root.cc +++ b/library/src/ipfs_client/ipld/root.cc @@ -18,6 +18,10 @@ Ptr Self::deroot() { Ptr Self::rooted() { return shared_from_this(); } +bool Self::expired() const { + auto n = links_.at(0).second.node; + return n ? n->expired() : true; +} auto Self::resolve(ResolutionState& params) -> ResolveResult { auto location = params.PathToResolve().to_string(); diff --git a/library/src/ipfs_client/ipld/root.h b/library/src/ipfs_client/ipld/root.h index b57951b4..d603e433 100644 --- a/library/src/ipfs_client/ipld/root.h +++ b/library/src/ipfs_client/ipld/root.h @@ -13,6 +13,7 @@ class Root : public DagNode { ResolveResult resolve(ResolutionState& params) override; std::shared_ptr rooted() override; std::shared_ptr deroot() override; + bool expired() const override; public: Root(std::shared_ptr); diff --git a/library/src/ipfs_client/ipns_record.cc b/library/src/ipfs_client/ipns_record.cc index 81e52065..808bf94a 100644 --- a/library/src/ipfs_client/ipns_record.cc +++ b/library/src/ipfs_client/ipns_record.cc @@ -223,6 +223,7 @@ ipfs::ValidatedIpns::ValidatedIpns(IpnsCborEntry const& e) #else use_until = timegm(&t); #endif + LOG(INFO) << "use_until=" << use_until << " based on " << e.validity; cache_until = std::time(nullptr) + ttl; } diff --git a/library/src/ipfs_client/orchestrator.cc b/library/src/ipfs_client/orchestrator.cc index 33964621..53cfb796 100644 --- a/library/src/ipfs_client/orchestrator.cc +++ b/library/src/ipfs_client/orchestrator.cc @@ -24,7 +24,7 @@ void Self::build_response(std::shared_ptr req) { return; } auto req_path = req->path(); - req_path.pop(); // namespace + req_path.pop(); // discard namespace ipfs or ipns std::string affinity{req_path.pop()}; auto it = dags_.find(affinity); if (dags_.end() == it) { @@ -82,6 +82,9 @@ void Self::from_tree(std::shared_ptr req, response->location_.clear(); } req->finish(*response); + if (node->expired()) { + dags_.erase(affinity); + } } else if (auto* pc = std::get_if(&result)) { LOG(ERROR) << "Should not be getting a PathChange in orchestrator - " "should've been handled in the root, but got " @@ -118,15 +121,22 @@ bool Self::gw_request(std::shared_ptr ir, } bool Self::add_node(std::string key, ipfs::ipld::NodePtr p) { - if (p) { - if (dags_.insert({key, p}).second) { - p->set_api(api_); - } - return true; - } else { + if (!p) { LOG(INFO) << "NULL block attempted to be added for " << key; + return false; } - return false; + auto [it, first] = dags_.insert({key, p}); + if (first) { + LOG(INFO) << "First node showed up for [" << key << "]."; + } else if (p->PreferOver(*it->second)) { + it->second = p; + } else { + LOG(INFO) << "Already had a [" << key + << "] node that was at least as good."; + return false; + } + p->set_api(api_); + return true; } std::string Self::sniff(ipfs::SlashDelimited p, std::string const& body) const { diff --git a/library/src/ipfs_client/orchestrator_unittest.cc b/library/src/ipfs_client/orchestrator_unittest.cc index d2d87db8..be63a5b6 100644 --- a/library/src/ipfs_client/orchestrator_unittest.cc +++ b/library/src/ipfs_client/orchestrator_unittest.cc @@ -9,7 +9,7 @@ #include #include -#include "ipld/ipns_name.h" +#include "ipld/dnslink_name.h" #include #include @@ -96,6 +96,7 @@ struct TestRequestor final : public ig::Requestor { if (!is_regular_file(f)) { auto cmd = "ipfs routing get /ipns/" + cid + " > " + f.generic_string(); + std::cout << cmd << std::endl; auto ec = std::system(cmd.c_str()); EXPECT_EQ(ec, 0); } @@ -285,6 +286,7 @@ TEST_F(OrchestratingRealData, examples_articles_generates_list) { )"); } TEST_F(OrchestratingRealData, dirshard_immediate_hit) { + i::log::SetLevel(i::log::Level::TRACE); dorequest( "/ipfs/bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze/" "index.html"); diff --git a/test_data/blocks/QmTdiGirysKeuHGBZa4Jypf7P8VGVnQ6YTEGfcRkZsDKe4 b/test_data/blocks/QmTdiGirysKeuHGBZa4Jypf7P8VGVnQ6YTEGfcRkZsDKe4 deleted file mode 100644 index 4bc445ab..00000000 --- a/test_data/blocks/QmTdiGirysKeuHGBZa4Jypf7P8VGVnQ6YTEGfcRkZsDKe4 +++ /dev/null @@ -1,2 +0,0 @@ - -˜Tg4 Tg5 Tg6 Tg7 Tg8 Tg9 Th0 Th1 Th2 Th3 Th4 Th5 Th6 Th7 Th8 Th9 Ti0 Ti1 Ti2 Ti3 Ti4 Ti5 Ti6 Ti7 Ti8 Ti9 Tj0 Tj1 Tj2 Tj3 Tj4 Tj5 Tj6 Tj7 Tj8 Tj9  \ No newline at end of file diff --git a/test_data/blocks/QmU9HH6fsfUiy7isXZ8J6YEkkw3M1u11rD7TxjyY35keF1 b/test_data/blocks/QmU9HH6fsfUiy7isXZ8J6YEkkw3M1u11rD7TxjyY35keF1 deleted file mode 100644 index 7eb16a2d..00000000 --- a/test_data/blocks/QmU9HH6fsfUiy7isXZ8J6YEkkw3M1u11rD7TxjyY35keF1 +++ /dev/null @@ -1,2 +0,0 @@ - -˜Lu0 Lu1 Lu2 Lu3 Lu4 Lu5 Lu6 Lu7 Lu8 Lu9 Lv0 Lv1 Lv2 Lv3 Lv4 Lv5 Lv6 Lv7 Lv8 Lv9 Lw0 Lw1 Lw2 Lw3 Lw4 Lw5 Lw6 Lw7 Lw8 Lw9 Lx0 Lx1 Lx2 Lx3 Lx4 Lx5  \ No newline at end of file diff --git a/test_data/blocks/QmU9pWH3wBhM9RWMTpAqYj73NfJLK9ugTZMMy6VVUwAzQf b/test_data/blocks/QmU9pWH3wBhM9RWMTpAqYj73NfJLK9ugTZMMy6VVUwAzQf deleted file mode 100644 index a2fa4e06..00000000 Binary files a/test_data/blocks/QmU9pWH3wBhM9RWMTpAqYj73NfJLK9ugTZMMy6VVUwAzQf and /dev/null differ diff --git a/test_data/blocks/QmUBNwaYgAkSaMTAPG2JjyijrSETrZt7MPqjNd9gsADSCc b/test_data/blocks/QmUBNwaYgAkSaMTAPG2JjyijrSETrZt7MPqjNd9gsADSCc deleted file mode 100644 index 302ec134..00000000 --- a/test_data/blocks/QmUBNwaYgAkSaMTAPG2JjyijrSETrZt7MPqjNd9gsADSCc +++ /dev/null @@ -1,2 +0,0 @@ - -˜Um8 Um9 Un0 Un1 Un2 Un3 Un4 Un5 Un6 Un7 Un8 Un9 Uo0 Uo1 Uo2 Uo3 Uo4 Uo5 Uo6 Uo7 Uo8 Uo9 Up0 Up1 Up2 Up3 Up4 Up5 Up6 Up7 Up8 Up9 Uq0 Uq1 Uq2 Uq3  \ No newline at end of file diff --git a/test_data/blocks/bafkreibthyfb4j4blugo5zk4i476hxet2vwghy564kz3jlxi53lnoamrum b/test_data/blocks/bafkreibthyfb4j4blugo5zk4i476hxet2vwghy564kz3jlxi53lnoamrum deleted file mode 100644 index 4fc3fe1c..00000000 --- a/test_data/blocks/bafkreibthyfb4j4blugo5zk4i476hxet2vwghy564kz3jlxi53lnoamrum +++ /dev/null @@ -1 +0,0 @@ -G \ No newline at end of file diff --git a/test_data/blocks/bafkreic4mlqjdogakzprxl5nbwwvsnbhmfb24lgo66stqhuk3jnrvdjg2i b/test_data/blocks/bafkreic4mlqjdogakzprxl5nbwwvsnbhmfb24lgo66stqhuk3jnrvdjg2i deleted file mode 100644 index 675f43ab..00000000 --- a/test_data/blocks/bafkreic4mlqjdogakzprxl5nbwwvsnbhmfb24lgo66stqhuk3jnrvdjg2i +++ /dev/null @@ -1 +0,0 @@ -P \ No newline at end of file