diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 00000000..02369289
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,5 @@
+[source.crates-io]
+replace-with = "vendored-sources"
+
+[source.vendored-sources]
+directory = "vendor"
diff --git a/.github/workflows/cargo-build.yml b/.github/workflows/cargo-build.yml
index 6d97b5cd..e08035fb 100644
--- a/.github/workflows/cargo-build.yml
+++ b/.github/workflows/cargo-build.yml
@@ -1,4 +1,4 @@
-name: ubuntu-matrix
+name: cargo-build-matrix
# Controls when the action will run.
on:
diff --git a/.gitignore b/.gitignore
index d56fce3e..be765b71 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ node_modules
# will have compiled files and executables
debug/
target/
+vendor/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
diff --git a/BQS97/BQS97.pdf b/BQS97/BQS97.pdf
new file mode 100644
index 00000000..23ce5d5c
Binary files /dev/null and b/BQS97/BQS97.pdf differ
diff --git a/BQS97/Byzantine_Quorum_Systems.md b/BQS97/Byzantine_Quorum_Systems.md
new file mode 100644
index 00000000..1e447353
--- /dev/null
+++ b/BQS97/Byzantine_Quorum_Systems.md
@@ -0,0 +1,447 @@
+
+
+##
Byzantine Quorum Systems
+####
Dahlia Malkhi Michael Reiter
+
+######
AT&T Labs—Research, Murray Hill, NJ USA {dalia,reiter}@research.att.com
+
+### Abstract
+
+Quorum Bystems are well-known tools for ensuring the con-
+sistency and availability of replicated data despite the be- nign failure of data repositones. In this paper we consider the arbitrary (Byzantine) failure of data repositories and present the first study of quorum system requirements and construct ions that ensure data availabNit y and consistence y despite these failures. We also consider the load associated with our quorum systems, i.e., the minimal access probabil- ity of the busiest server. For services subject to arbitrary failures, we demonstrate quorum systems over n servers with a load of `O(1/(sqrt(n))`, thus meeting the lower bound on load for
+benignly fault-tolerant quorum systems. We explore several variations of our quorum systems and extend our construc- tions to cope with arbitrary client failures.
+
+#### 1. Introduction
+
+A well known way to enhance the availability and performance of a replicated service is by using quorums. A quorum system for a universe of servers is a collection of subsets of servers, each pair of which intersect. Intuitively, each quorum can operate on behalf of the system, thus increasing its availability and performance, while the intersection property guarantees that operations done on distinct quorums preserve consistency.
+
+ In this paper we consider the arbitrary (Byzantine) failure of clients and servers, and initiate the study of quorum systems in this model. Intuitively, a quomm system tolerant of Byzantine failures is a collection of subsets of servers, each pair of which intersect in a set containing sufficiently many correct servers to guarantee consistencey of the replicated data as seen by clients. We provide the following contributions.
+
+`1.` We define the class of manking quorum systems, with which data can be consistently replicated in a way that is resiiient to the arbhmy fsilure of data repositories. We present several example constructions of such systems and show necessary and sufficient conditions for the existence of masking quorum systems under different failure assumptions.
+
+`2.` We explore two variations of masking quorum systems. The first, called dimernination quorum syatema, is suited for services that receive and distribute sel~-ueri.fyirtg information from correct clients (e.g., digitally signed values) that faulty servers can fail to redistribute but cannot undetectable alter. The second variation, called opaque masking quorum systems, is similar to regular masking quorums in that it makes no assumption of self verifying data, but it differs in that clients do not need to know the failure scenarios for which the service was designed. This somewhat simplifies the client protocol and, in the case that the failures are maliciously induced, reveals less information to clients that could guide an attack attempting to compromise the system.
+
+`3.` We explore the load of each type of quorum system, where the load of a quorum system is the minimal access prob- ability of the busiest server, minimizing over all strate- gies for picking quorums. We present a masking quorum system with the property that its load over a total of n Servem is 0(~), thereby meeting the lower bound for the load of benignly-fault-tolerant quorum systems. For opaque masking quorum systems, we prove a lower bound of ~ on the load, and present a construction that meets this lower bound and proves it tight.
+
+ For services that use masking quorums (opaque or not), we show how to deal with faulty clients in addition to faulty servers. The primary challenge raised by client fail- ures is that there is no guarantee that clients will update quorums according to any specified protocol. Thus, a faulty client could leave the service in an inconsistent and irrecoverable state. We develop an update protocol, by which clients access the replicated service, that prevents clients from leaving the service in an inconsistent state. The protocol has the desirable property that it involves only the quorum at which an access is attempted, while providing system-wide consistency properties.
+569
+
+`4.` In our treatment, we express assumptions about possi- ble failures in the system in the form of a fail-prone system B={ BI,..., Bh ) of servers, such that some Bi cent sins all the faulty servers. This formulation ineludes typical fail- ure assumptions that at most a threshold ~ of servers fail (e.g., the sets B1,..., Bk could be ~ sets of ~ servers), but it also generalizes to allow less uniform failure scenar- ios. Our motivation for exploring this generalization stems from our experience in constructing secure distributed ser- vices [34, 27], i.e., distributed services that can tolerate the malicious corruption of some (typically, up to a threshold number of) component servers by an attacker. A criticism to assuming a simple threshold of corrupted servers is that server penetrations may not be independent. For exam- ple, servers in physical proximity to each other or in the same administrative domain may exhibit correlated proba- bilities of being captured, or servers with identical hardware and software platforms may have correlated probabilities of electronic penetration. By exploiting such correlations (i.e., knowledge of the collection B), we can design quorum sys- tems that more effectively mask faulty servers.
+Our quorum systems, if used in conjunction with ap- propriate protocols and synchronization mechanisms, can be used to implement a wide range of data semantics. In this paper, however, we choose to demonstrate a variable supporting read and write operations with relatively weak semantics, in order to maintain focus on our quorum con- structions. These semantics imply a sate variable [24] in the caae of a single reader and single writer, which a set of correct clients can use to build other abstractions, e.g., atomic, multi-writ er multi-reader registem [24, 21, 25], con- current timestamp systems [12, 19], l-exclusion [11, 2], and atomit snapshot scars [1, 5]. Our quorum constructions can also be directly exploited in algorithms that employ “uni- form” quorums for fault tolerance (by involving a threshold of processes), in order to improve efficiency or tolerate non- uniform failure scenarios. Examples include algorithms for shared memory emulation [6], randomized Byzantine agree- ment [39], reliable Byzantine multicast [8, 33, 27], and secure replicated data [18].
+
+The rest of this paper is structured as follows. We begin in Section 2 with a description of related work.
+
+In Section 3 we present our system model and definitions. We present quorum systems for the replication of arbitrary data subject to arbltrarv server failures in
+
+Section 4. and in Section 5 “we present two variations of these systems. We then detail an access protocol for replicated services that tolerate faulty clients in addition to faulty servers in Section 6. We conclude in Section 7.
+
+### 2 Related work
+
+Our work was influenced by the substantial body of literature on quorum systems for benign failures and applications that make use of them, e.g., [15, 38, 26, 14, 17, 13, 9, 4, 30]. In particular, our grid construction of Section 4 was influ- enced by grid-like constructions for benign failures (e.g., [9]), and we borrow our definition of load from [30].
+Quorum systems have been previously employed in the implementation of security mechanisms. Naor and Wool [31] described methods to construct an access-control service us- ing quorums. Their constructions use cryptographic tech- niques to ensure that out-of-date (but correct) servers can- not grant access to unauthorized users. Agrawal and El Abbadi [3] and Mukkamala [29] considered the confiden- tiality of replicated data despite the disclosure of the con- tents of a threshold of the (otherwise correct) repositories. Their constructions used quorums with increased intersec- tion, combined with Rabin’s dispersal scheme [32], to en- hance the confidentiality and availability of the data despite some servers crashing or their contents being observed. Our work differs from all of the above by considering arbitrarily faulty servers, and accommodating failure scenarios beyond a simpIe threshold of servers.
+
+Herlihy and Tygar [18] applied quorums with increased intersection to the problem of protecting the confidential- ity and integrity of replicated data against a threshold of arbitrarily faulty servers. In their constructions, replicated data is stored encrypted under a key that is shared among the servers using a threshold secret-sharing scheme [36], and each client accesses a threshold number of servers to recon- struct the key prior to performing (encrypted) reads and writes. This construction exhibits one approach to make replicated data self-verifying via encryption, and thus the quorum system they develop is a special case of our dis- semination quorum systems, i.e., for a threshold of faulty servers.
+570
+
+### 3 Preliminaries
+
+### 3.1 Preliminaries System model
+
+We assume a universe .?Jof servers, IIYI= n, and an arbi- trary number of clients that are distinct from the servera. A quorum system ~ ~ 2U is a set of subsets of U, any pair of which ht ersect. Each Q c Q is called a quorum.
+
+Servers (and clients) that obey their specifications are correct. A faulty server, however, may deviate from its spec- ification arbitrarily. A fail-prone system B c 2U is a set of subsets of U, none of which is contained in another, such that some B E B contains all the faulty servers. The fail- prone system represents an assumption characterizing the failure scenarios that can occur, and could express typical assumptions that up to a threshold of servers fail, as well as less uniform assumptions.
+
+In the remainder of this section, and throughout Sec- tions 4 and 5, we assume that clients behave correctly. In Section 6 we will relax this assumption (and will be explicit when we do so).
+
+We assume that any two correct processes (clients or servers) can communicate over an authenticated, reliable channel. That is, a correct process receives a message from another correct process if and only if the other correct pro- cess sent it. However, we do not assume known bounds on message transmission times; i.e., communication is asyn- chronous.
+
+### 3.2 Access protocol
+
+We consider a problem in which the clients perform read and write operations on a variable z that is replicated at each server in the universe U. A copy of the variable z is stored at each server, along with a timestamp value t.Timestamps are assigned by a client to each replica of the variable when the client writes the replica. Our protocols require that differ- ent clients choose different timestamps, and thus each client c chooses its timestamps from some set T. that does not intersect T,, for any other client c’. The timestamps in T. can be formed, e.g., as integers appended with the name of c in the low-order bits. The read and write operations are implement ed as follows.
+Write: For a client c to write the value u, it queries each server in some quorum Q to obtain a set of value/timestamp pairs A = {}ti~Q; chooses a timestamp t E Tc greater than the highest timestamp value in A end greater than any timestamp it has chosen in the past; and updates z and the associated timestamp at each server in Q to v and t, respectively.
+
+Read: For a client to read x, it queries each server in some quorum Q to obtain a set of value/ timestamp pairs A = {}U~Q. The client then applies a deterministic function Restdto to A to obtain the result Result(A) of the read operation.
+In the case of a write operation, each server updates its local variable and timestamp to the received values only if t is greater than the timestamp currently associated with the variable.
+Two points about this description deserve further dis-
+cussion. First, the nature of the quorum sets Q and the function Result () are intentionally left unspecified; further clarification of these are the point of this paper. Second, this descrbtion is intended to reauire a client to obtain a set A containing value/timestamp pairs from every server in some quorum Q. That is, if a client is unable to gather a complete set A for a quorum, e.g., because some server in the quorum appears unresponsive, the client must try to perform the operation with a different quorum. This re- quirement stems from our lack of synchrony assumptions on the network: in general, the only way that a client can know that it has accessed every correct server in a quorum is to (apparently successfully) access every server in the quorum. Our framework guarantees the availability of a quorum at any moment, and thus by attempting the operation at mul- tiple quorums, a client can eventually make progress. In some cases, the client can achieve progress by incrementally accessing servers until it obtains responses from a quorum of them.
+
+In Sections 4 and 5, we will argue the correctness of the above protocol—instantiated with quorums and a Resul to function that we will define according to the following semantics; a more formal treatment of these concepts can be found in [24]. We say that a read operation begins when the client initiates the operation and ends when the client obtains the read value; an operation to write value `u` with timestamp tbegins when the client initiates it and ends when all correct servers in some quorum have received the update `v, t`. An operation OPI precedes an operation o~ if opI ends before opa begins (in real time). If opI does not precede opa and opz does not precede opl, then they are called concurrent. Given a set of operations, a aertalization of those operations is a total ordering on them that extends the precedence ordering among them. Then, for the above protocol to be correct, we require that any read that is con- current with no writes returns the last value written in some serialization of the preceding writes. In the case of a single reader, single writer variable, this will immediately imply safe semantics [24].
+
+### 3.3 Load
+
+A measure of the inherent performance of a quorum system is its ioad. Naor and Wool [30] define the load of a quorum system as the probability of accessing the busiest server in the best case. More precisely, given a quorum system Q, an access strategu w is a probability distribution on the element 5 of Q; i.e.; ‘~QEQ w(Q) = 1: w(Q) is the probability
+that quorum Q will be chosen when the service is accessed. Load is then defined as follows:
+Definition 3.1 Let a strategy w be given for a quorum system Q={ Ql, ..., Q~} over a universe U. For an element u E U, the load induced by w on u is l~(u) = ~Q~3U w(Qi).
+
+The load induced by a strategy w on a quorum system Q is `L(Q) = rnm{L(u)}`. The system load (or just load) on a quorum system Q is `L(Q) = m~{LW(Q)}`, where the minimum is taken over all strategies. ❑ We reiterate that the load is a best case definition. The load of the quorum system will be achieved only if an op- timal access strategy is used, and only in the case that no failures occur. A strength of this deilnition is that load is a property of a quorum system, and not of the protocol using it. A comparison of the definition of load to other seemingly plausible definitions is given in [30].
+
+### 4 Masking quorum systems
+571
+
+In this section we introduce masking quorum systems,
+can be used to mask the arbitrarily faulty behavior of data repositories. To motivate our definition, suppose that the replicated variable z is written with quorum QI, and that subsequently z is read using quorum Qz.
+
+If 13 is the set of arbitrarily faulty servers, then (QI n Qz ) \ 1? is the set of correct servers that possess the latest value for z. In order for the client to obtain this value, the client must be able to locate a value/timestamp pair returned by a set of servers that could not all be faulty. In addition, for availability we require that there be no set of faulty servers that can disable all quorums.
+
+`4.1` A quorum system Q is a masking quorum aystern for a fail-prone system B if the following properties are satisfied.
+Definition
+M2, vBET33QEQ:
+—
+BnQ=O
+It is not difficult to verify that a masking quorum sys- tem enables a client to obtain the correct answer from the service. The write operation is implemented as described in Section 3, and the read operation becomes:
+Read: For a client to read a variable z, it queries each server
+in some quorum Q to obtain a set of value/timestamp
+A = {}@Q. The client computes the set A’ = { : 3B+c _ Q[ VBEZ3[B+~B]A
+pairs
+Vu EB+[vu=v Atti=t] ]}.
+The client then chooses the pair in A’ with the highest timestamp, and chooses v as the result of the read operation; if A’ is empty, the client returns 1 (a null value).
+Lemma 4.2 A read operation that is concurrent with no write operations returns the value written by the last pre- ceding write operation in some serialization of all preceding write operations.
+which
+
+ `Proof`. Let W denote the set of write operations preceding the read. The read operation will return the value written in the write operation in W with the highest timestamp, since, by the construction of masking quorum systems, this value/timestamp pair will appear in A’ and will have the highest timestamp in A’ (any pair with a higher timestamp will be returned only by servers in some B c B). So, it suf- fices to argue that there is a serialization of the writes in W in which this write operation appears last, or in other words, that this write operation precedes no other write operation in W. This is immediate, however, as if it did precede an- other write operation in W, that write operation would have a higher timest amp. ❑
+This lemma implies that the protocol above implements a single-writer single-reader safe variable [24]. From these, multi- writ er multi-reader at omit variables can be built using well-known constructions [24, 21, 25].
+A necessary and sufficient condition for the existence of a masking quorum system (and a construction for one, if it exists) for any given fail-prone system B is given in the following theorem:
+Theorem 4.3 Let B be a fail-prone system for a universe U. Then there exists a masking quomm system for B iff 4? = {U\ B : B ~ f3} is a masking quorum system for B.
+Proof. Obviously, if Q is a masking quorum system for B, then one exists. To show the converse, assume that Q is not a masking quorum. Since M2 holds in Q by construction, there exist QI, QZ E Q and B’, B“ ●B, such that (Ql n Qz)\B’ c B”. Let Bl=U\Qland BZ=U\QZ. By the construction of Q, we know that BI, Bz E f?. By M2, any masking quorum system for B must contain quorums Q; ~ Q,, Q~ G Qz. However, for any such Q~, Q:, it is the case that (Q{ nQ:)\B’ ~ (Ql nQa)\B’ g B“, violating Ml. Therefore, there does not exist a masking quorum system for B under the assumption that Q is not a masking quorum system for B. ❑
+Corollary 4.4 Let B be a fail-prone system for a universe U. Then there exists a masking quorum system for B iff for d B1,BZ,BS,B4 ~ B,U ~ B1UBZUB3UB4. hp=ticd~, suppose that B = {B G U : IBI = j}. Then, there exists a masking quorum system for B iff n > 4f.
+Proof. By Theorem 4.3, there is a masking quorum for B iff Q = {U \ B : B E B} is a masking quorum for B. By construction, Q is a masking quorum iff M 1 holds for Q, i.e.,
+Proof. Let w be any strategy for the quorum system Q, and fix Q1 E Q such that [QI I = C(Q). Summing the loads induced by w on all the elements of Q1 we obtain:
+Q;
+=1
+Therefore, there exists some element in QI that stiers a
+10a‘dfalteMat“
+Similarly, summing the total load induced by w on all of
+the elements of the universe, we get:
+ifffOr& B1,B1,BS,B4
+EB:
+Bl)~(u\B2))\&g B4
+B2)~&ui?4
+B2u B3u B4.
+(Here, the inequality results from the minimality of c(Q).) Therefore, there exists some element in U that sfiere a load
+of at least *. ❑
+Since any masking quorum system is a quorum system, we
+have, a fortiorfi
+Corollary 4.6 If Q is a masking quorum system over a
+@} ~d universe of n elements, then L(Q) > max{ ~, ~
+thus L(Q) > ~.
+Below we give several examples of masking quorum sys- tems and describe their properties.
+Example 4.7 (Threshold) Suppose that B = {B ~ U :
+IBI = f}, n > 4f. Note that this corresponds to the usual
+threshold assumption that up to ~ servers may fail. Then,
+the quorum system Q = {Q ~ U : IQI = [~1} is
+a masking quorum system for B. M1 is satisfied because
+~Y Q1~QZ E Q wi~ intersect in at l==t zf + 1 dernents. M2 holds because [~ 1 ~ n – ~. A strategy that as-
+signs equal probability to each quorum induces a load of
+1 on the system. By Corollary 4.6, this load is in fact the load of the system. ❑
+The following example is interesting since its load de- creases as a function of n, and since it demonstrates a method for ensuring system-wide consistency in the face of Byzan- tine failures while requiring the involvement of fewer than a majority of the correct servers.
+Example 4.8 (Grid quorums) Suppose that the universe of servers is of size n = kz for some integer k and that B = {B ~ U : IBI = f}, 3j+ 1< X. Arrange the universe into a W x W grid, as shown in F@re 1. Denote the rows
+E!
+((u\ - u\(&u
+* ugB1u
+The following theorem was proved in [30] for benign- failure quorum systems, and holds for masking quorums as well (as a result of Ml). Let c(Q) denote the size of the smallest quorum of Q.
+`Theorem 4.5` If Q is a quorum system over a universe of n &l}. elements, then L(Q) ~ max{ -&j, .
+The proof of this theorem in [30] employs rather complex methods. Here we present a simpler proof of their theorem.
+572
+:[+
+
+ and columns of the grid by R; and C;, respectively, where
+
+##### 5 Variations
+
+##### 5.1 Dissemination quorum systems
+
+As a special case of services that can employ quorums in a Byzantine environment, we now consider applications in which the service is a repository for self verifying information, i.e., information that only clients can create and to which clients can detect any attempted modification by a faulty server. A natural example is a database of public key certificates as found in many public key distribution systems (e.g., [10, 37, 23]). A public key certificate is a structure con- taining a name for a user and a public key, and represents the assertion that the indicated public key can be used to au- thenticate messages from the indicated user. This structure is digitally signed (e.g., [35]) by a certification authority so that anyone with the public key of this authority can verify this assertion and, providing it trusts the authority, use the indicated public key to authenticate the indicated user. Due to this signature, it is not possible for a faulty server to undetectable modify a certificate it stores. However, a faulty server can undetectable suppress a change from propagating to clients, simply by ignoring an update from a certification authority. This could have the effect, e.g., of suppressing the revocation of a key that has been compromised.
+
+As can be expected, the use of digital signatures to verify data improves the cost of accessing replicated data. To support such a service, we employ a dissemination quorum system, which has weaker requirements than masking quo- rums, but which nevertheless ensures that in applications like those above, self verifying writes will be propagated to all subsequent read operations despite the arbitrary failure of some servers. To achieve this, it suffices for the inter- section of every two quorums to not be contained in any set of potentially faulty servers (so that a written value can propagate to a read). And, supposing that operations are required to continue in the face of failures, there should be quorums that a faulty set cannot disable.
+
+Definition 5.1 A quorum system Q is a dissemination
+
+```
+guo-
+1< z < X. Q=
+{
+Then, the quorum system
+cjuu
+Ri:~,{j}C{l... fi},l~l=2f+ 11
+icI
+```
+
+is a masking quorum system for B. M 1 holds since every pair of quorums intersect in at least 2f + 1 elements (the column of one quorum intersects the 2~ + 1 rows of the other), and M2 holds since for any choice of ~ faulty elements in the grid, 2f + 1 full rows and a column remain available. A strategy that assigns equal probabdit y to each quorum induces a load of (2f+2)fi-(2f+l
+~, and again by Corollary 4.6, this is the load of the”system. ❑
+Note that by choosing B = {O} (i.e., f = O) in the exam- ple above, the resulting construction has a load of 0( $=),
+which asymptotically meets the bounds given in Corollary 4.6. In general, however, this construction yields a load of 0(~), which is not optimal: Malkhi et al. [28] show a lower
+bound of ~ ~ on the load of any masking quorum sYs- r
+tern for B = {B ~ U : lB/ = f}, and provide a construction whose load matches that bound.
+Figure 1: Grid construction, k.x k = n, ~ = 1 (one quorum shaded).
+Example 4.9 (Partition) Suppose that B = {131,..., B-},
+m > 4, is a partition of U where Bi # 0 for all i, 1 < i < m. This choice of B could arise, for example, in a wide area network composed of multiple local clusters, each containing some Bi, and expresses the assumption that at any time, at most one cluster is faulty. Then, any collection of nonempty sets B1 ~ E1, 1 ~ i < m, can be thought of as ‘super-elements’ in a universe of ~lze m, with a threshold assumption ~ = 1. Therefore, the following is a masking quorum system for B:
+rurn sys tern for a fail-prone erties are satisfied.
+Dl:vQ,, QzEQVBEB:
+D2:VBEB3QEQ:
+❑
+system B if the following prop- QlnQ~qB
+Q= uEi { i~I
+: IC{l,...,
+m}l,Il=(~l 1
+
+A dissemination quorum system will suffice for propagat- ing self-verifying information as in the application described above. The write operation is implemented as described in Section 3, and the read operation becomes:
+
+Read: For a client to read a variable z, it queries each server in some quorum Q to obtain a set of value/timestamp pairs A = {}uEQ. The client then discards those pairs that are not verifiable (e.g., using an appropriate e digital signature verification algorithm) and chooses from the re- maining pairs the pair with the largest timestamp. u is the result of the read operation.
+
+It is important to note that timestamps must be included as part of the self-verifying information, so they cannot be undet ect ably altered by faulty servers. In the case of the ap- plication described above, existing standards for public key certificates (e.g., [10]) already require a real-time timestamp in the certificate.
+
+Ml is satisfied because the intersection of any two quorums contains elements from at least three sets in B. M2 holds since thereis no B E B thatintersects all quorums. A strat- egy that assigns equal probability to each quorum induces a load of ~ ~WI on the system regardless of the size of each
+~i, and again Corollary 4.6 implies that this is the load of the system.
+
+If m = k2 for some k. then a more efficient construction can be achieved by forming the grid construction from Ex- ample 4.8 on the ‘super elements’ {~i }, achieving a load of *.m ❑
+573
+BnQ=O
+
+ The following lemma proves correctness of the above pro- tocol using dissemination quorum systems. The proof is al- most identical to that for masking quorum systems.
+
+Lemma 5.2 A read operation that is concurrent with no write operations returns the value written by the last pre- ceding write operation in some serialization of all preceding write operations.
+Due to the assumption of self-verifying data, we can also prove in this case the following property.
+Lemma 5.3 A read operation that is concurrent with one or more write operations returns either the value written by the last preceding write operation in some serialization of all preceding write operations, or any of the values being written in the concurrent write operations.
+
+The above lemmata imply that the protocol above im- plements a single-writer single-reader regular variable [24]. Theorems analogous to the ones given for masking quorum systems above are easily derived for disseminateion quorums. Below, we list these results without proof.
+
+`Theorem 5.4` Let B be a fail-prone system for a universe U. Then there exists a dissemination quorum system for B iff Q = {U \ 13 : B E B} is a dissemination quorum system for B.
+
+`5.2` Opaque masking quorum systems
+Masking quorums impose a requirement that clients know the fail-prone system t?, while there may be reasons that clients should not be required to know this. First, it some- what complicates the client’s read protocol. Second, by re- vealing the failure scenarios for which the system was de- signed, the system also reveals the failure scenarios to which it is vulnerable, which could be exploited by an attacker to guide an active attack against the system. By not reveal- ing the fail-prone system to clients, and indeed giving each client only a small fraction of the possible quorums, the sys- tem can somewhat obscure (though perhaps not secure in any formal sense) the failure scenarios to which it is vulner- able, especially in the absence of client collusion.
+In this section we describe one way to modify the mask- ing quorum definition of Section 4 to be opaque, i.e., to elim- inate the need for clients to know 1?. In the absence of the client knowing B, the only method of which we are aware for the client to reduce a set of replies from servers to a single reply from the service is via voting, i.e., choosing the reply that occurs most often. In order for this reply to be the cor- rect one, however, we must strengthen the requirements on our quorum systems. Specifically, suppose that the variable z is written with quorum Q1, and that subsequently x is read with quorum Q2. If 1? is the set of arbitrarily faulty servers, then (Ql n Q2 ) \ B is the set of correct servers that possess the latest value for z (see Figure 2). In order for the client to obtain this value by vote, this set must be larger than the set of faulty servers that are allowed to respond, i.e., Q2 n B. Moreover, since these faulty servers can “team up” with the out-of-date but correct servers in an effort to suppress the write operation, the number of correct, up-to-date servers that reply must be no less than the number of faulty or out-of-date servers that can reply, i.e., (Qz fl B) U (Qz \ Q1 ).
+
+`Definition 5.10` A quorum system Q is an opaque masking quorum system for a fail-prone system B if the following properties are satisfied.
+01: VQI, Q2EQVBEZ3:
+l(Qln QZ)\Bl z l(Qzn B) U(Qz\Ql)l
+Corollary
+U. Then there exists a dissemination quorum system for B iff for all B1,B2,Bs E B, U ~ B1 Ul?Z uB3. Inparticukm, suppose that B = {B ~ U :IBI = f}. Then, there exists a dissemination quorum system for B iff n > 3f.
+Corollary 5.6 If Q is a dissemination quorum system over
+Q}, a universe of n elements, then L(Q) z max{ ~, .
+and thus also L(Q) ~ -&.
+Below, we provide several example constructions of dissem- inateion quorum systems.
+Example 5.7 (Threshold) Suppose that B = {B Q U : IBl = f}, n > 3f. Note that this corresponds to the usual threshold assumption that up to f servers may fail. Then, the quorum system Q = {Q G U : IQI = [~1} is a
+dissemination quorum system for B with load ~ [-l. •l
+Example 5.I3 ( Grid) Let the universe be arranged in a grid as in Example 4.8 above, and let B = {B G U : IBI = f}, 2j + I < W. Then, the quorum system
+5.5 Let B be a fail-prone system for a universe
+Q= cjuu Ri:I, {j}~{l...fi},lI[=f+l { ieI
+}
+B
+Q2
+01:
+02:
+
+is a dissemination quorum system for B. The load of this system is “+a)~-(’+l]. ❑
+Example 5.9 (Partition) Suppose that B = {Bl, . . . . B~}, m > ~, is a partition of U. For any collection of nonempt y sets B; ~ B;, 1 < i < m, the Threshold construction of Example 5.7 on the ‘super-elements’ Bi ~ Bi (as in Example 4.9) yields a dissemination quorum system with a load of ~ [*1. If m = k’ for some k, the Grid construction of
+Example 5.8 achieves a load of %. ❑
+Note that 01 admits the possibility of equality in size be- tween (Q1 n Qz) \B and (Q2 fl II) U (Qa \ Ql). Equality is
+574
+❑
+02: VQ,, Q2EQVBEB:
+l(Q~nQz)\Bl>lQ,f7Bl
+BnQ=O
+03, vB~B3Qc
+Q:
+
+ sufficient since, in the case that the faulty servers “t earn up” with the correct but out-of-date servers in QZ, the value re- turned from (QI fI Q2 ) \ El will have a higher timestamp than that returned by (Qz n B) u (Qz \ Q1). Therefore, in the case of a tie, a reader can choose the value with the higher times- tamp. It is intcresting to note that a strong inequality in 01 would permit a correct implementation of a single-reader singer-writer safe variable that does not use timestamps (by taking the majority value in a read operation).
+
+It is not difficult to verify that an opaque masking quo- rum system enables a client to obtain the correct answer from the service. The write operation is implemented as de- scribed in Section 1, and the read operation becomes:
+
+Read: For a client to read a variable z, it queries each server in some quorum Q to obtain a set of value/timestamp pairs A = {}.~Q. The client chooses the pair that appears most often in A, and if there are multiple such val-
+Example 5.14 (Partition) Suppose that B = {Bl, . . . . Bs~}, k>1, isapartitionofUwhereBi#0foralli,1< i<3k. Choose any collection of sets fii ~ B;, 1< i< 3k, such that l~i I = c for a fixed constant c >0. Then, the Threshold construction of Example 5.12 on the ‘super-elements’ {A;} (as in Example 4.9), with universe size 3k and a threshold assumption ~ = 1, yields an opaque quorum system with load ~. ❑
+
+Unlike the case for regular masking quorum systems, an open problem is to find a technique for testing whether, given a fail-prone system 1?, there exists an opaque quorum system for 23(other than an exhaustive search of all subsets of 2~).
+
+In the constructions in Examples 5.12 and 5.13, the re- sulting quorum systems exhibited loads that at best were constant as a function of n. In the case of masking quorum systems, we were able to exhibit quorum systems whose load decreased as a function of n, namely the grid quorums. A natural question is whether there exists an opaque quorum system for any fail-prone system B that has load that de- creases as a fhnction of n. In this section, we answer this question in the negative: we show a lower bound of ~ on the load for any opaque quorum system construction, regardless of the fail-prone system.
+ues, the one with the highest timestamp. result of the read operation.
+
+The value v is the
+Opaque masking quorum systems, combined with the access protocol described previously, provide the same semantics as regular masking quorum systems. The proof is ahnost identical to that for regular masking quorums.
+
+Lemma 5.11 A read operation that is concurrent with no write operations returns the value written by the last preceding write operation in some serialization of all preceding write operations.
+
+Below we give several examples of opaque masking quo- rum systems (or just “opaque quorum systems”) and de- scribe their properties.
+
+`Example 5.12` (Threshold) Suppose that B = {B ~ U :
+Theorem at least *.
+5.15 The load of any opaque quorum system is
+IBI = }} where n z 5j and ~ >0. system Q = {Q ~ U : IQI= [~]} system for B, whose load is ~ [~
+Then, the quorum is an opaque quorum
+Proof. 01 implies that for any Q1, Q2 E Q, IQ1 fl QzI >
+IQ1\Qzl, ~d th~ IQ1n Qzl z ~. Let w be any strategy for the quorum system Q, and flx any QI E Q. Then, the total load induced by w on the elements of Q1 is:
+.IQJ1 2
+Therefore, there must be some server in Q1 that sufTers a load at least ~. ❑
+We now present a generic construction of an opaque quo- rum system for B = {0} and increasingly large universe sizes n, that has a load that tends to ~ as n grows. We give this construction primarily to show that the lower bound of ~ is tight; due to the requirement that B = {0}, this con- struction is not of practical use for coping with Byzantine failures.
+Example 5.16 Suppose that the universe of servers is U =
+{u,,..., u.} where n = 24 for some .f > 2, and that B =
+{0}. Consider the n x n Hadamard matrix H(t), constmcted ..
+1. ❑
+The next theorem proves a resilience bound for opaque quo-
+rum systems.
+Theorem 5,13 Suppose that B = {B ~ U : IBI = f}. There exists an opaque quorum system for B iff n z 5f.
+Proof. That n ~ 5f is sufficient is already demonstrated in Example 5.12 above. Now suppose that Q is an opaque quorum system for B. Fm any Q1 E Q SUChthat IQ1[ < n–f (QI exists by 03); note that IQ, I > ~ by 02. Choose B1 ~ Q,, IBII = f, and some Q, E Qsuch that Q, C U\Bl (Qz exists by 03). Then IQ1n Qzl < n – 2~. By 02,
+IQ1nQZI2 f, =d therefore there is some B, E B such that Bz G Q1 n Qz. Then
+n–3~ z
+= l(Q~nQl)\Bal
+> I(Q1 \Q2)u(Ql = lQl\Qzl+lBzl ~ IB11+IB21
+= 2f
+lQ~nQ1l– IBz I
+Where (1) holds by 01. Therefore, we have n ~ 5f. ❑
+nBz)l (1)
+575
+recursively as follows:
+H(l) = _l ~
+H(k) =
+[
+H(k – 1) H(k – 1)
+H(k – 1) –H(k – 1)
+[1
+–1 –1
+
+ H(t) has the property that HAT = nl, where Z is the n x n identity matrix. Using well-known inductive ar- guments [16, Ch. 14], it can be shown that (i) the fist row and column consist entirely of – 1‘s, (ii) the i-th row and i-th column, for each i z 2, has 1’s in ~ positions (and simi- larly for –l’s), and (iii) any two rows (and any two columns) i, j z 2 have identical elements in ~ positions, i.e., 1’s in ~ common positions and —1‘s in ~ common positions.
+We treat the rows of H(t) as indicators of subsets of U. That is, let Qi = {uj : H(t)[i, j] = 1} be the set defined bythei-throw,1}.cQ; chooses a timestamp t E T=greater than the highest timestamp value in A and greater than any timestamp it has chosen in the paat; and performs Init(Q, v, t).
+Note that writing the pair to the quorum Q is performed by executing the operation lnit(Q, u, t).Servers ex- ecute corresponding events ~eliver(u, t).If a correct server executes Deli ver(u, t),and if t is greater than the timest amp currently stored with the variable, then the server updates
+the value of the variable and its timestamp to v and t, re- spectively. Regardless of whether it updates the variable, it sends an acknowledgment message to c where Tc 3 t.
+The correctness of this protocol depends on the following relationships among hit executions at clients and Deliver events at servers. How to implement kit and DeJiver to satisfy these relationships is the tepic of Section 6.2.
+Integrity: If c is correct, then a correct server executes Deliver(u, t)where t ~ T. only if c executed lnit(Q, u,t)for some Q E Q.
+Agreement: If a correct server executes Deliver(u, t)and a correct server executes Deliver(u’, t), then w = u’.
+
+`Propagation:` If a correct server executes Deliver(u, t), then eventually there exists a quorum Q E Q such that every correct server in Q executes Deliver(u, t).
+Validity: If a correct client executes Init(Q, v,t)and all servers in Q are correct, then eventually a correct server ex- ecutes Deli ver(v, t).
+
+Note that by Validity, if a correct client executes lnit(Q, v, t) but Q contains a faulty server, then there is no guarantee that Deliver (u,t)will occur at any correct server; i.e., the write operation may have no effect. A correct server ac- knowledges each Deliver (v, t) execution as described above to inform the client that Deliver (o, t) was indeed executed. If the client receives acknowledgments from a set B+ of servers, such that VB ~ B : B+ ~ B, then it is certain that its write will be applied at all correct servers in some quorum Q (by Propagation). If the client receives acknowledgments from no such set B+ of servers, then it must attempt the Init operation again with a different quorum. As before, M2 guarantees the availability of some quomm.
+
+In order to argue correctness for this protocol, we have to adapt the definition of operation precedence to allow for the behavior of a faulty client. The reason is that it is unclear how to define when an operation by a faulty client begins or ends, as the client can behave outside the specification of LWIYprotocol. We now say that a write operation that writes v with timestamp tE T., where c is faulty, begins when the first correct server executes Deliver(v, t) and ends when all correct servers in some quorum have executed Deli ver(v, t). Write operations by correct clients begin as before and end when all the correct servers in some quomm have delivered the update. We do not define or make use of the duration of a read by a faulty client; reads by faulty clients are not ordered with respect to other operations. Carrying over the remainder of the precedence definition, a proof very similar
+to that of Lemma 4.2 suffices to prove the following:
+Lemma 6.1 A correct process’ read operation that is con- current with no write operations returns the value written by the preceding write operation with the highest timestamp among all preceding write operations.
+
+We are not aware of any common definition of variable semantics in the case of possibly faulty clients with whit% to compare Lemma 6.1. However, note that if all the write operations preceding the read are done by correct clients, the highest timestamp value among them will belong to the last write in some serialization of them, and therefore the read will return that value.
+576
+
+### 6.2 The update operation
+
+The remaining protocol to describe is the update protocol for masking quorum systems that satisfies Integrity, Agree- ment, Propagation, and Validity. We present such an update protocol in F@re 3.
+
+1. If a client executes lnit(Q, v, t),then it sends to each member of Q.
+
+2. If a server receives from a client c, if tE Tc, and if the server has not previously received from c a message where either t’ = t and V’ # v or t’ > t, then the server sends to each member of Q.
+
+3. If a server receives identical echo messages from every server in Q, then it sends to each member of Q.
+
+4. If a server receives identical ready messages from a set B+ of servers, such that B+ ~ B for all B E B, then it sends to every member of Q if it has not done so already.
+
+5. If a server receives identical ready messages from a set Q– of servers, such that for some B ~ B, Q- = Q \B, it executes Deliver(v, t).
+F@re 3: An update protocol
+Lemma 6.2( Integrity) If c is correct, then a correct server executes Ile]i ver (v, t) where t E Z’c ordy if c executed lnit(Q, u, t) for some Q.
+
+`Proof.` The first message from a correct server is sent only after it receives from each member of Q. Moreover, a correct member sends where t E Tc only if it receives from c over an authenticated channel, i.e., only if c executed lnit(Q, u, t). ❑
+Lemma 6.3( Agreement) If a correct server executes Deliver(v, t)and a correct server executes Deliver(v’, t), then v = v’.
+Proof. As argued in the previous lemma, for a correct server to execute Ileliver(u, t), must have been sent by all servers in Q. Similarly, must have been sent by all servers in Q’. Since every two quorums intersect in (at least) one correct member, and since any correct server sends for at most one value 0, v must be identical to v’. ❑
+
+`Lemma 6.4` If Q is a masking quorum system over a universe U with respect to a fail-prone system B, then VQ c QVB,, B,, B,~B, Q~B, uB, uB,.
+Proof. Assume otherwise for a contradiction, i.e., that there isa Q6Qand Bl, Bl, B9~f3 such that Q~BIUBIUBs.
+By M2, there exists Q’ E Q, Q’ n B, = 0. Then, Q n Q’ c Ba U Bs and thus (Q n Q’) \Ba ~ Bs, contradicting Ml. ❑
+
+`Lemma 6.5`( Propagation) If a correct server executes Deliver (v, t), then eventually there exists a quorum Q E Q such that every correct server in Q executes Deli ver(v, t).
+Proof According to the protocol, the correct server that executed Deli ver(v, t) received a message from each server in Q- =Q\Bforsome Q~Qand B~B. Since, for some B’ E B, (at least) all the members in Q-\ B’ are correct, every correct member of Q receives from each of the members of B+ = Q– \ B’. Since, VB” E B, Q– \B’ ~ B“ (by Lemma 6.4), the ready messages from B+ cause each correct member of Q to send such a ready message. Consequently, Deliver(v, t) is executed by all of the correct members of Q. ❑
+Lemma 6.6( Validity) If a correct client c executes lnit(Q, v, t) and all servers in Q are correct, then eventually a correct server executes Deli ver(u, t).
+Proof. Since both the client and all of the members of Q are correct, will be received and echoed by every member in Q. Consequently, all the servers in Q will send messages to the members of Q, and will eventually execute Deliver (v, t). •I
+
+### 7 Conclusions
+
+The literature contains an abundance of protocols that use quorums for accessing replicated data. This approach is ap- pealing for constructing replicated services as it allows for increasing the availability and efficiency of the service while maintaining its consistency. Our work extends this success- ful approach to environments where both the servers and the clients of a service may deviate from their prescribed behavior in arbitrary ways. We introduced a new class of quorum systems, namely masking quorum systems, and devised pro- tocols that use these quorums to enhance the availability of systems prone to Byzantine failures. We also explored two variations of our quorum syst ems, namely dissemination and opaque masking quorums, and for all of these classes of quo- rums we provided various constructions and analyzed the load they impose on the system.
+Our work leaves a number of intriguing open challenges and directions for future work. One is to characterize the average performance of our quorum constructions and their load in less-than-ideal scenarios, e.g., when failures occur. Also, in this work we described only quorum systems that are uniform, in the sense that any quorum is possible for both read and write operations. In practice it may be ben- eficial to employ quorum systems with distinguished read quorums and write quorums, with consistency requirements imposed only between pairs consisting of at least one write quorum. Although this does not seem to improve our lower bounds on the overall load that can be achieved, it may al- low greater flexibility in trading between the availability of reads and writes.
+Acknowledgments
+
+We are grateful to Andrew Odlyzko for suggesting the use of Hadamard matrices to construct opaque masking quo- rum systems with an asymptotic load of ~. We also thank Yehuda Afek and Mk.hael Merritt for he1pful discussions, and Rebecca Wright for many helpful comments on earlier versions of this paper. An insightful comment by Rida Bazzi led to a substantial improvement over a previous version of this paper.
+577
+
+
diff --git a/Cargo.lock b/Cargo.lock
index 5050e6c9..b61efc16 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -203,7 +203,7 @@ dependencies = [
"futures-lite 2.1.0",
"parking",
"polling 3.3.1",
- "rustix 0.38.26",
+ "rustix 0.38.27",
"slab",
"tracing",
"windows-sys 0.52.0",
@@ -242,7 +242,7 @@ dependencies = [
"cfg-if",
"event-listener 3.1.0",
"futures-lite 1.13.0",
- "rustix 0.38.26",
+ "rustix 0.38.27",
"windows-sys 0.48.0",
]
@@ -258,7 +258,7 @@ dependencies = [
"cfg-if",
"futures-core",
"futures-io",
- "rustix 0.38.26",
+ "rustix 0.38.27",
"signal-hook-registry",
"slab",
"windows-sys 0.48.0",
@@ -1933,9 +1933,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.18.0"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "oorandom"
@@ -2128,7 +2128,7 @@ dependencies = [
"cfg-if",
"concurrent-queue",
"pin-project-lite 0.2.13",
- "rustix 0.38.26",
+ "rustix 0.38.27",
"tracing",
"windows-sys 0.52.0",
]
@@ -2532,9 +2532,9 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.38.26"
+version = "0.38.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a"
+checksum = "bfeae074e687625746172d639330f1de242a178bf3189b51e35a7a21573513ac"
dependencies = [
"bitflags 2.4.1",
"errno",
@@ -2545,9 +2545,9 @@ dependencies = [
[[package]]
name = "rustls"
-version = "0.21.9"
+version = "0.21.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9"
+checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
"log",
"ring",
@@ -2908,7 +2908,7 @@ dependencies = [
"cfg-if",
"fastrand 2.0.1",
"redox_syscall",
- "rustix 0.38.26",
+ "rustix 0.38.27",
"windows-sys 0.48.0",
]
@@ -2923,9 +2923,19 @@ dependencies = [
[[package]]
name = "test-log"
-version = "0.2.13"
+version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f66edd6b6cd810743c0c71e1d085e92b01ce6a72782032e3f794c8284fe4bcdd"
+checksum = "6159ab4116165c99fc88cce31f99fa2c9dbe08d3691cb38da02fc3b45f357d2b"
+dependencies = [
+ "test-log-macros",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "test-log-macros"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d"
dependencies = [
"proc-macro2",
"quote",
@@ -3159,9 +3169,9 @@ checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3"
[[package]]
name = "try-lock"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tungstenite"
@@ -3200,9 +3210,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
+checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
[[package]]
name = "unicode-ident"
diff --git a/Cargo.toml b/Cargo.toml
index 8341382f..f9d69bbd 100755
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -53,7 +53,7 @@ curve25519-dalek = "4"
crypto_secretstream = "0.2"
rust-crypto = "0.2.36"
git2 = "0.9.1"
-argparse = "0.2.2"
+argparse = "0.2.2"
time = "0.1.42"
chrono = "0"
nostr = "0.24.0"
diff --git a/cargo.mk b/cargo.mk
index ddb37ad7..3a88e465 100755
--- a/cargo.mk
+++ b/cargo.mk
@@ -49,5 +49,18 @@ cargo-doc:### cargo-doc
cargo-b-wasm-tokio:
@. $(HOME)/.cargo/env && cargo clean && cargo build --target=wasm32-unknown-emscripten --no-default-features #--features wasm-bindgen,tokio
+node-examples-nodejs-run-js-node:### node-examples-nodejs-run-js-node
+## node-examples-nodejs-run-js-node
+ node examples-nodejs/run.js node
+node-examples-nodejs-run-js-node-6102:### node-examples-nodejs-run-js-node-6102
+## node-examples-nodejs-run-js-node-6102
+ node examples-nodejs/run.js node 6102
+node-examples-nodejs-run-js-rust:### node-examples-nodejs-run-js-rust
+## node-examples-nodejs-run-js-rust
+ node examples-nodejs/run.js rust
+node-examples-nodejs-run-js-rust-2106:### node-examples-nodejs-run-js-rust-2106
+## node-examples-nodejs-run-js-rust-2106
+ node examples-nodejs/run.js rust 2106
+
# vim: set noexpandtab:
# vim: set setfiletype make
diff --git a/examples-nodejs/replicate.js b/examples-nodejs/replicate.js
index 6425b199..39fe2992 100644
--- a/examples-nodejs/replicate.js
+++ b/examples-nodejs/replicate.js
@@ -12,7 +12,7 @@ hypercore.info().then((_info) => {
console.log('KEY=' + hypercore.key.toString('hex'))
console.log()
if (hypercore.writable && !key) {
- hypercore.append(['hi\n', 'ola\n', 'hello\n', 'mundo\n'])
+ hypercore.append(['hi\n', 'ola\n', 'hello\n', 'mundo\n', hypercore.key.toString('hex')])
}
})
@@ -58,7 +58,7 @@ function onconnection (opts) {
console.log("");
console.log("### Results (Press Ctrl-C to exit)");
console.log("");
- console.log("Replication succeeded if you see '0: hi', '1: ola', '2: hello' and '3: mundo' (not necessarily in that order)")
+ console.log("Replication succeeded if you see '0: hi', '1: ola', '2: hello', '3: mundo', '4: key', (not necessarily in that order)")
console.log("");
for (let i = 0; i < hypercore.length; i++) {
hypercore.get(i).then(value => {
diff --git a/examples-nodejs/run.js b/examples-nodejs/run.js
index c96541fd..5db978e5 100644
--- a/examples-nodejs/run.js
+++ b/examples-nodejs/run.js
@@ -3,11 +3,11 @@ const p = require('path')
const chalk = require('chalk')
const split = require('split2')
-const PORT = 8000
-
const EXAMPLE_NODE = p.join(__dirname, 'replicate.js')
const EXAMPLE_RUST = 'replication'
const MODE = process.argv[2]
+const PORT = process.argv[3] || 8000
+
if (!MODE) {
usage()
}
diff --git a/examples/replication.rs b/examples/replication.rs
index 542925c1..4f15dba5 100644
--- a/examples/replication.rs
+++ b/examples/replication.rs
@@ -38,8 +38,11 @@ fn main() {
});
task::block_on(async move {
+
let mut hypercore_store: HypercoreStore = HypercoreStore::new();
+
let storage = Storage::new_memory().await.unwrap();
+
// Create a hypercore.
let hypercore = if let Some(key) = key {
let public_key = VerifyingKey::from_bytes(&key).unwrap();
@@ -53,7 +56,7 @@ fn main() {
.unwrap()
} else {
let mut hypercore = HypercoreBuilder::new(storage).build().await.unwrap();
- let batch: &[&[u8]] = &[b"hi\n", b"ola\n", b"hello\n", b"mundo\n"];
+ let batch: &[&[u8]] = &[b"hi\n", b"ola\n", b"hello\n", b"mundo\n", b"key\n"];
hypercore.append_batch(batch).await.unwrap();
hypercore
};
@@ -388,7 +391,7 @@ where
println!();
println!("### Results");
println!();
- println!("Replication succeeded if this prints '0: hi', '1: ola', '2: hello' and '3: mundo':");
+ println!("Replication succeeded if this prints '0: hi', '1: ola', '2: hello', '3: mundo', '4: key':");
println!();
for i in 0..new_info.contiguous_length {
println!(
diff --git a/vendor/hypercore/.cargo-checksum.json b/vendor/hypercore/.cargo-checksum.json
new file mode 100644
index 00000000..db9604ec
--- /dev/null
+++ b/vendor/hypercore/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CERTIFICATE":"53a0a460f8eccb279580aa16013c5f98936eba73554d267632f5ea83d8e890b1","CHANGELOG.md":"8a4836a83337941142be6b379a079fe7575dc43c72a4708880c77906d4168f5d","Cargo.lock":"f20c29c9f5177c0a4fdf1130739aba95853588fdcee6689884b4551cb834f7df","Cargo.toml":"b80a9f1e01fb34ae1df211fb22dbe252f789de9b5686dd8e83bb5e225a7179db","LICENSE-APACHE":"40b135370517318ee023f4553b49453ab716f4277ccc7801beb3a44ec481c9fb","LICENSE-MIT":"a06326997c80661a79a99f66af7417f3420640323952c92afae69d5a4b7537ee","README.md":"db19ee440a805365a53ca973e374eb46eb794142290f8da2c90f3a284a873918","benches/disk.rs":"5a6c5d2b5a30a519464dec175c37b4ff1245065323cef5c35b1dca47af607c94","benches/memory.rs":"3f84f98a50017389b539d2f4c2208f4430e35bf5dc6af4ed7d6e49e29980c8ec","examples/disk.rs":"62974fe304dfbb6284c92df1a5cb6375058f1d359f5f9d78a6fd6a300f663b0c","examples/memory.rs":"f4ddc81bed815ed63625a5ca5ce67beaa16fc12f841c324eef316e032d94ef27","examples/replication.rs":"161139858c741ac9277564af52b40b2df44c870061fb3acfa939a9f3618d0e61","src/bitfield/dynamic.rs":"6003a197ce52d0aa605ba17bbae66e695771e9900dd68e984dd17c2208294e4d","src/bitfield/fixed.rs":"2dbaac2d56b56f78af2793a6b7e883951a1bae02944f63ee92fa2faae6e4539e","src/bitfield/mod.rs":"76f1555e6389a73e73f7fdee470ed3d51ebfcebbd1d94d5c5731f8c8683dab4a","src/builder.rs":"0411b6ffc73a1cda42075ce987e6ae3e85666f03c5259c968d42da5427c5a75b","src/common/cache.rs":"ed25e719612092fb943099eb07bc8a787cc7a7df650c1371f5a6dc3d0ef0181c","src/common/error.rs":"ac4f5658d8b874f5affde1fe8c51576d6ad8eaf8208b42999319691208c5c133","src/common/mod.rs":"426f30f05ab8ebb178e064370f457b45ccebd824f5505908b6d729024ca6194e","src/common/node.rs":"08ab19770804f4e5ce61d3595b06062af2cc1068f4176af16ccb52cc548d3ee0","src/common/peer.rs":"aa096218932eda26927f3c27a22a583c0b52a4cd8c54a2abc604469209917ebe","src/common/store.rs":"e0490b59ec68dea1f0519727f6f3a3d993bf3f9b8d5fefdf6fad3e66d549e17c","src/core.rs":"43026192ee19ba3b61dd39bbf263911b889659aa8246fd89d60246c549941e31","src/crypto/hash.rs":"0011d7326968c6072d2d416eb31a83afa271d1256517914914bf2371ceef369c","src/crypto/key_pair.rs":"262939ca4da120491308e7de734fc2e41f3fc4d9b916a90a0b0525db98f0b5a0","src/crypto/manifest.rs":"7f0dca0127bcf0290ebb8c385acf6f3add7a6df9987acf883dfcf1a3066262f4","src/crypto/mod.rs":"d227ef04204ac64d5136dbfc6dc5fbd6833ae40e13412dde8c712138898a7c15","src/data/mod.rs":"af89c77f5b45a48b860935f1ea6761afc25847df4f5a7327d9642d515f761363","src/encoding.rs":"725501e6f36cf4548220d1ab3d564670dacf947a53ac974246f8c4acca32a4c4","src/lib.rs":"3799aad86cd033ce830660fd7329c9be00db076d6bea9e6ac5126847f12b3298","src/oplog/entry.rs":"df13ac9985cecbd4e057c0375beadf5296186352024b5b01aec9e3c1a41f2bd0","src/oplog/header.rs":"d2a2779b7b8ded5627b834ce0de87abc759de80c579b621ee217cb6ebb3cf1ec","src/oplog/mod.rs":"8404515befe41225055daa5b6499d1495316368e799cc62251b88f52cf09e998","src/prelude.rs":"254cc894b75d1181a8b677a904da441cc64fe44c4a0aac050f46c9c69c2bb855","src/storage/mod.rs":"0a84af3d6b76dd4afec03374d1ef556c069c48dbeab0c23f13cbe40ed61199f9","src/tree/merkle_tree.rs":"439807c4f46c484223a800a83716570ec24fd0bdde0d3bfd8f629deb85b28fa1","src/tree/merkle_tree_changeset.rs":"9da5e8cbaea13cdd537b979e7e470b387a8811510966fbe6ee826ef3e64f11e1","src/tree/mod.rs":"787b1877ce05197191aa7381752707b0f7a9e14f276bb8ddc5466b14db1e5ea9","tests/common/mod.rs":"5de5296507c1633e21ee63280da79c21cc6572fa8191cdd5da8d993177722a3b","tests/core.rs":"851d32f8149c140fb260cfe58d838e22f24d971c25f9008448981dfa1f633b82","tests/js/interop.js":"6cfde323aab89db0548898e0a0e8c93921cc9e684cc6f7343fb9df9c96a8ab8a","tests/js/mod.rs":"b741ad5f4bedbd482dd423d7b8d5e1248f11e1f9c8dc312666b92dc07c2e7c67","tests/js/package.json":"3fb483760615ba5e27b80bb340c593c90f6a7e2b95a4b895174a9e786c75c715","tests/js_interop.rs":"d4f44309aeda77286e4a5bd13fb74647d807c2abb9094a09dcef18907bf43158","tests/model.rs":"d1ef5bea900f87bd7cb2e72d4df70a8d92bb6291f6f5e85b36afea397254307c"},"package":"f58caa4fc81bfac2b018eda14b81cadbfc5cdd88fcee81c5b37532144027cde8"}
\ No newline at end of file
diff --git a/vendor/hypercore/CERTIFICATE b/vendor/hypercore/CERTIFICATE
new file mode 100644
index 00000000..8201f992
--- /dev/null
+++ b/vendor/hypercore/CERTIFICATE
@@ -0,0 +1,37 @@
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+1 Letterman Drive
+Suite D4700
+San Francisco, CA, 94129
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
diff --git a/vendor/hypercore/CHANGELOG.md b/vendor/hypercore/CHANGELOG.md
new file mode 100644
index 00000000..5b57c6d3
--- /dev/null
+++ b/vendor/hypercore/CHANGELOG.md
@@ -0,0 +1,409 @@
+## 2023-10-28, Version v0.12.1
+### Commits
+- [[`60d50a5e76`](https://github.com/datrs/hypercore/commit/60d50a5e7638c60047c722b6cfb7c50e29ecd502)] Fix Oplog decoding failing on bitfied update (Timo Tiuraniemi)
+
+### Stats
+```diff
+ src/oplog/entry.rs | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+```
+
+
+## 2023-10-12, Version v0.12.0
+### Commits
+- [[`fa7d487758`](https://github.com/datrs/hypercore/commit/fa7d4877582023e310a7129b11ebd55eb877a75f)] Merge pull request #138 from datrs/v10 (Timo Tiuraniemi)
+
+### Stats
+```diff
+ .github/workflows/ci.yml | 142 ++++
+ .gitignore | 2 +
+ CHANGELOG.md | 31 +
+ Cargo.toml | 83 +-
+ README.md | 81 +-
+ benches/bench.rs | 58 --
+ benches/disk.rs | 140 ++++
+ benches/memory.rs | 128 +++
+ examples/async.rs | 29 -
+ examples/disk.rs | 88 ++
+ examples/iter.rs | 80 --
+ examples/main.rs | 29 -
+ examples/memory.rs | 59 ++
+ examples/replication.rs | 116 +++
+ src/audit.rs | 20 -
+ src/bitfield/dynamic.rs | 403 +++++++++
+ src/bitfield/fixed.rs | 228 ++++++
+ src/bitfield/iterator.rs | 158 ----
+ src/bitfield/masks.rs | 108 ---
+ src/bitfield/mod.rs | 379 +--------
+ src/builder.rs | 100 +++
+ src/common/cache.rs | 58 ++
+ src/common/error.rs | 78 ++
+ src/common/mod.rs | 23 +
+ src/{storage => common}/node.rs | 77 +-
+ src/common/peer.rs | 117 +++
+ src/common/store.rs | 155 ++++
+ src/core.rs | 1136 ++++++++++++++++++++++++++
+ src/crypto/hash.rs | 227 +++++-
+ src/crypto/key_pair.rs | 56 +-
+ src/crypto/manifest.rs | 43 +
+ src/crypto/merkle.rs | 74 --
+ src/crypto/mod.rs | 10 +-
+ src/crypto/root.rs | 52 --
+ src/data/mod.rs | 46 ++
+ src/encoding.rs | 370 +++++++++
+ src/event.rs | 3 -
+ src/feed.rs | 676 ----------------
+ src/feed_builder.rs | 89 --
+ src/lib.rs | 112 ++-
+ src/oplog/entry.rs | 164 ++++
+ src/oplog/header.rs | 325 ++++++++
+ src/oplog/mod.rs | 495 ++++++++++++
+ src/prelude.rs | 16 +-
+ src/proof.rs | 30 -
+ src/replicate/message.rs | 6 -
+ src/replicate/mod.rs | 5 -
+ src/replicate/peer.rs | 40 -
+ src/storage/mod.rs | 578 +++++--------
+ src/storage/persist.rs | 19 -
+ src/tree/merkle_tree.rs | 1616 +++++++++++++++++++++++++++++++++++++
+ src/tree/merkle_tree_changeset.rs | 131 +++
+ src/tree/mod.rs | 5 +
+ tests/bitfield.rs | 195 -----
+ tests/common/mod.rs | 108 ++-
+ tests/compat.rs | 178 ----
+ tests/core.rs | 79 ++
+ tests/feed.rs | 340 --------
+ tests/js/interop.js | 128 +++
+ tests/js/mod.rs | 50 ++
+ tests/js/package.json | 10 +
+ tests/js_interop.rs | 192 +++++
+ tests/model.rs | 175 ++--
+ tests/regression.rs | 18 -
+ tests/storage.rs | 51 --
+ 65 files changed, 7558 insertions(+), 3260 deletions(-)
+```
+
+
+## 2020-07-19, Version v0.11.1-beta.10
+### Commits
+- [[`084f00dd3c`](https://github.com/datrs/hypercore/commit/084f00dd3cd9d201315e43eef44352317f9f9b8b)] (cargo-release) version 0.11.1-beta.10 (Bruno Tavares)
+- [[`99eff3db3c`](https://github.com/datrs/hypercore/commit/99eff3db3c0f70aeda8e31594c9e2c401743e4b9)] Fix travis errors - clippy warnings and fmt (Bruno Tavares)
+- [[`d6f2c5522f`](https://github.com/datrs/hypercore/commit/d6f2c5522f62dbc1f4df303bbaa199f621e3ab70)] Merge pull request #121 from khodzha/append_fix (Bruno Tavares)
+- [[`57bd16444e`](https://github.com/datrs/hypercore/commit/57bd16444e3c4e5576e51ac7787851a145d371e9)] Avoid calling unwrap or expect inside fn that returns Result (Bruno Tavares)
+- [[`de9ebae3ce`](https://github.com/datrs/hypercore/commit/de9ebae3ce4b0a1f0e76ee17b710c70475f5c33f)] Pin ed25519-dalek to a version with compatible signature methods (Bruno Tavares)
+- [[`f7676d530a`](https://github.com/datrs/hypercore/commit/f7676d530a3f6d4ef18f3c92989cccac1c40c131)] Fix clippy errors (Bruno Tavares)
+- [[`cf251468e9`](https://github.com/datrs/hypercore/commit/cf251468e9194500cb3b900cc0bb3c9b4a8bfa84)] fixed saving feed to disk (Shamir Khodzha)
+- [[`2c260b1b51`](https://github.com/datrs/hypercore/commit/2c260b1b51a5e2ea48bf806fefbfc3705e7dcef1)] Update changelog (Bruno Tavares)
+
+### Stats
+```diff
+ .gitignore | 1 +-
+ CHANGELOG.md | 24 +++++++++++++-
+ Cargo.toml | 4 +-
+ benches/bench.rs | 7 ++--
+ examples/main.rs | 23 +++++++++++--
+ src/bitfield/mod.rs | 97 +++++++++++++++++++++++++++++++++++++++++++++--------
+ src/crypto/merkle.rs | 11 ++++++-
+ src/feed.rs | 16 +++++++--
+ src/feed_builder.rs | 42 +++++++++++++++++++----
+ src/storage/mod.rs | 93 ++++++++++++++++++++++++++++++++++++---------------
+ tests/bitfield.rs | 18 ++++------
+ tests/common/mod.rs | 2 +-
+ tests/compat.rs | 12 ++++---
+ tests/feed.rs | 24 +++++++++----
+ 14 files changed, 295 insertions(+), 79 deletions(-)
+```
+
+
+## 2020-07-09, Version v0.11.1-beta.9
+### Commits
+- [[`8589bd17a6`](https://github.com/datrs/hypercore/commit/8589bd17a6ed323a3c48844a6ef13d40937899df)] (cargo-release) version 0.11.1-beta.9 (Bruno Tavares)
+- [[`2765a010ea`](https://github.com/datrs/hypercore/commit/2765a010ea176190be4aa36c265de1d2f8cb78c0)] Merge pull request #120 from khodzha/path_check (Bruno Tavares)
+- [[`8ee485bf62`](https://github.com/datrs/hypercore/commit/8ee485bf62da4ae6d6a57a8a691db448fa87a3b1)] added path is a dir check in Feed::open (Shamir Khodzha)
+- [[`62a411ee66`](https://github.com/datrs/hypercore/commit/62a411ee660701927884c5276032fc94dc7bc952)] Merge branch 'dependabot/cargo/bitfield-rle-0.2.0' (Bruno Tavares)
+- [[`bac9ba4905`](https://github.com/datrs/hypercore/commit/bac9ba4905b339c3f79408b2f7ac6fe4bfeb8ad8)] Fix cargofmt (Bruno Tavares)
+- [[`2a6563b46f`](https://github.com/datrs/hypercore/commit/2a6563b46f7e67efcd3551403ed300e10d822891)] Update bitfield-rle requirement from 0.1.1 to 0.2.0 (dependabot-preview[bot])
+- [[`37d2a9cf24`](https://github.com/datrs/hypercore/commit/37d2a9cf24502988ec3ad2108b9ae37c5c1f82f2)] Merge branch 'fix-mask-note' (Bruno Tavares)
+- [[`e53afb8d92`](https://github.com/datrs/hypercore/commit/e53afb8d92da4a8f55f54c3ed6f987a3b4bde1bf)] Merge branch 'master' into fix-mask-note (Bruno Tavares)
+- [[`999ff75213`](https://github.com/datrs/hypercore/commit/999ff75213cdf4246c096bfb3c7bb6fefc666860)] Merge branch 'FreddieRidell-document-src-feed-rs' (Bruno Tavares)
+- [[`6be4441404`](https://github.com/datrs/hypercore/commit/6be44414046a5cb801f2985d381e932c9c06075b)] Merge branch 'document-src-feed-rs' of git://github.com/FreddieRidell/hypercore into FreddieRidell-document-src-feed-rs (Bruno Tavares)
+
+### Stats
+```diff
+ Cargo.toml | 4 +--
+ src/bitfield/masks.rs | 2 +-
+ src/crypto/mod.rs | 4 ++-
+ src/feed.rs | 73 +++++++++++++++++++++++++++++++++++++++++-----------
+ tests/feed.rs | 30 +++++++++++++++++++++-
+ 5 files changed, 94 insertions(+), 19 deletions(-)
+```
+
+
+## 2020-03-03, Version 0.11.1-beta.3
+### Commits
+- [[`b555606bd6`](https://github.com/datrs/hypercore/commit/b555606bd626ae39f338bd6aef4f8976ff0c055e)] (cargo-release) version 0.11.1-beta.3 (Bruno Tavares)
+- [[`aaf265b8b8`](https://github.com/datrs/hypercore/commit/aaf265b8b84ee5ba6b975a5503db262e154c14eb)] Fix requirements on ram crates to compile (Bruno Tavares)
+- [[`10448df561`](https://github.com/datrs/hypercore/commit/10448df56163c1f2917d4508f57713d635fa2d24)] Update changelog (Bruno Tavares)
+
+### Stats
+```diff
+ CHANGELOG.md | 24 ++++++++++++++++++++++++
+ Cargo.toml | 6 +++---
+ 2 files changed, 27 insertions(+), 3 deletions(-)
+```
+
+
+## 2020-03-03, Version 0.11.1-beta.2
+### Commits
+- [[`3dfd5c8c71`](https://github.com/datrs/hypercore/commit/3dfd5c8c716a439131cf7b9a2b360ef737969335)] (cargo-release) version 0.11.1-beta.2 (Bruno Tavares)
+- [[`4136866e01`](https://github.com/datrs/hypercore/commit/4136866e01259825944cff099e59ffa4c8df081c)] Merge pull request #96 from bltavares/bitfield-compress (Bruno Tavares)
+- [[`d8beadbbfb`](https://github.com/datrs/hypercore/commit/d8beadbbfb0ff7d2d79e52abc14ffb570570b101)] GH Feedback: add comments on the optional fields (Bruno Tavares)
+- [[`9c6812d901`](https://github.com/datrs/hypercore/commit/9c6812d901454a383bee9802e0f5828c3224b515)] Use literals for floats (Bruno Tavares)
+- [[`356c90e915`](https://github.com/datrs/hypercore/commit/356c90e915a9a5dcc4edb5bf0fa61eda200f6b9b)] Make test with bigger ranges than page size (Bruno Tavares)
+- [[`390e13f9b5`](https://github.com/datrs/hypercore/commit/390e13f9b527845f281b24071bbf579f9a6232eb)] WIP: JS has float numbers on math (Bruno Tavares)
+- [[`bd333ba68d`](https://github.com/datrs/hypercore/commit/bd333ba68dc50f6e8bc581d39169ae64f6cba9de)] Compress bitfield and expose it to network code (Bruno Tavares)
+- [[`0bdbf6207a`](https://github.com/datrs/hypercore/commit/0bdbf6207af26ca3e3516956db7fa3140679e56e)] Bump dalek and rand (Bruno Tavares)
+- [[`ac0f3b6a74`](https://github.com/datrs/hypercore/commit/ac0f3b6a743cae1a8c1b51cabfd5a542ef34361b)] Update changelog (Bruno Tavares)
+
+### Stats
+```diff
+ CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++
+ Cargo.toml | 3 ++-
+ src/bitfield/mod.rs | 32 ++++++++++++++++++++++++++++++++
+ src/feed.rs | 5 +++++
+ tests/bitfield.rs | 22 ++++++++++++++++++++++
+ tests/model.rs | 7 +------
+ 6 files changed, 102 insertions(+), 7 deletions(-)
+```
+
+
+## 2020-03-03, Version 0.11.1-beta.1
+### Commits
+- [[`e5f071766c`](https://github.com/datrs/hypercore/commit/e5f071766c8b32c875df4872abe89ebb43700f31)] (cargo-release) version 0.11.1-beta.1 (Bruno Tavares)
+- [[`f7af79a3c2`](https://github.com/datrs/hypercore/commit/f7af79a3c271b426d0d6638872b0420a341d025e)] Merge pull request #100 from bltavares/bumps (Bruno Tavares)
+- [[`51c35d8f42`](https://github.com/datrs/hypercore/commit/51c35d8f42c42e111f2c207f1901288aaee7e500)] Point deps to crates versions (Bruno Tavares)
+- [[`f3b421c6ca`](https://github.com/datrs/hypercore/commit/f3b421c6ca76a0b5c5acb267988d97ba97e8a77a)] Fix clippy: rename func to adhere to conventions (Bruno Tavares)
+- [[`ba09c27336`](https://github.com/datrs/hypercore/commit/ba09c2733684f0320a7f99ebfa3ec8aae31334fd)] Fix travis: include checks on benchmarks (Bruno Tavares)
+- [[`173bc3fda2`](https://github.com/datrs/hypercore/commit/173bc3fda2f079994a38577030142b97c3143b4f)] Move from usize to u64 (Bruno Tavares)
+- [[`0678d06687`](https://github.com/datrs/hypercore/commit/0678d066875b7cef8cde3628f7ef91658a40f8c1)] Fix changes on ed25519_dalek and rand (Bruno Tavares)
+- [[`7fd467d928`](https://github.com/datrs/hypercore/commit/7fd467d92800e00cff7600fe6e68fbb474c899be)] Fix Travis config (Bruno Tavares)
+- [[`c4dc33a69a`](https://github.com/datrs/hypercore/commit/c4dc33a69aeead974d7dbd35d8414016ea3e421b)] Bump versions to latest versions (Bruno Tavares)
+- [[`ac3790dd4d`](https://github.com/datrs/hypercore/commit/ac3790dd4da0c72341944f29a75a8bf1fefcae00)] Bump versions to latest versions (Bruno Tavares)
+- [[`a3aa858b61`](https://github.com/datrs/hypercore/commit/a3aa858b61f36b30d02f06976eebbb37d823aa81)] Update sparse-bitfield requirement from 0.10.0 to 0.11.0 (dependabot-preview[bot])
+- [[`97cf996831`](https://github.com/datrs/hypercore/commit/97cf996831d00626a6ea75cc5267d5974bbca573)] Update changelog (Bruno Tavares)
+
+### Stats
+```diff
+ .travis.yml | 8 ++--
+ CHANGELOG.md | 28 +++++++++++++-
+ Cargo.toml | 34 ++++++++--------
+ examples/iter.rs | 6 +--
+ src/audit.rs | 8 ++--
+ src/bitfield/iterator.rs | 37 +++++++++---------
+ src/bitfield/mod.rs | 100 ++++++++++++++++++++++++------------------------
+ src/crypto/hash.rs | 12 +++---
+ src/crypto/key_pair.rs | 13 +++---
+ src/crypto/root.rs | 62 +++++++++++++++---------------
+ src/feed.rs | 48 +++++++++++------------
+ src/proof.rs | 4 +-
+ src/replicate/message.rs | 4 +-
+ src/replicate/peer.rs | 4 +-
+ src/storage/mod.rs | 42 ++++++++++----------
+ src/storage/node.rs | 16 ++++----
+ src/storage/persist.rs | 4 +-
+ tests/bitfield.rs | 8 ++--
+ tests/model.rs | 12 +++---
+ 19 files changed, 243 insertions(+), 207 deletions(-)
+```
+
+
+## 2020-02-19, Version 0.11.0
+### Commits
+- [[`f2baf805d5`](https://github.com/datrs/hypercore/commit/f2baf805d5477c768f32ca2cf7faae4d9d284686)] (cargo-release) version 0.11.0 (Bruno Tavares)
+- [[`31dfdd15f2`](https://github.com/datrs/hypercore/commit/31dfdd15f27356780d75fa126bd8a8d464fefc39)] Merge pull request #95 from bltavares/send (Bruno Tavares)
+- [[`46be5197a2`](https://github.com/datrs/hypercore/commit/46be5197a2398e04d413ebfa65fcb6f830dedf0f)] Use published version (Bruno Tavares)
+- [[`d4905b11cf`](https://github.com/datrs/hypercore/commit/d4905b11cf83871db98c118c373d52626e6b1c78)] Point to merkle-tree-stream that is Send while new version is to be released (Bruno Tavares)
+- [[`40caf92ec2`](https://github.com/datrs/hypercore/commit/40caf92ec2c357a08ddeec03f9d4ba34a723eeaf)] Replace all Rc with Arc in code. Needs to update dependencies (Bruno Tavares)
+- [[`2dc8008a55`](https://github.com/datrs/hypercore/commit/2dc8008a5542713a2569cfb115a006dee34bbca6)] example to ensure structs are send (Bruno Tavares)
+- [[`f77fe7b025`](https://github.com/datrs/hypercore/commit/f77fe7b0257bd5f0e7007c012bc68bc1d75eda05)] fix readme link (#88) (nasa)
+- [[`82e48f0c7d`](https://github.com/datrs/hypercore/commit/82e48f0c7d2330f0ed845dac30db46a02d5f7c48)] Update memory-pager requirement from 0.8.0 to 0.9.0 (dependabot-preview[bot])
+- [[`580dff64c5`](https://github.com/datrs/hypercore/commit/580dff64c50377e6fc51dbed701c2dc26a2693a2)] Update sparse-bitfield requirement from 0.8.1 to 0.10.0 (dependabot-preview[bot])
+- [[`7eda3504d6`](https://github.com/datrs/hypercore/commit/7eda3504d61de0f1423d0efa272587fe8b0a1650)] Merge pull request #81 from bltavares/discovery-key-hash (Szabolcs Berecz)
+- [[`1edf42f790`](https://github.com/datrs/hypercore/commit/1edf42f79007924b79e7b1b99a7e9d66abc3b4e9)] Implements discoveryKey from hypercore-crypto (Bruno Tavares)
+- [[`aedef0b149`](https://github.com/datrs/hypercore/commit/aedef0b149de042313245c2baab0948da3390aef)] Update changelog (Yoshua Wuyts)
+
+### Stats
+```diff
+ CHANGELOG.md | 26 ++++++++++++++++++++++++++
+ Cargo.toml | 9 +++++----
+ README.md | 2 +-
+ examples/async.rs | 30 ++++++++++++++++++++++++++++++
+ src/crypto/hash.rs | 42 +++++++++++++++++++++++++++++-------------
+ src/crypto/merkle.rs | 10 +++++-----
+ src/feed.rs | 4 ++--
+ 7 files changed, 98 insertions(+), 25 deletions(-)
+```
+
+
+## 2018-12-22, Version 0.9.0
+### Commits
+- [[`9c2b07fca6`](https://github.com/datrs/hypercore/commit/9c2b07fca68bb34046551f0fd152aa7f97a33fb6)] (cargo-release) version 0.9.0 (Yoshua Wuyts)
+- [[`86e241f9e0`](https://github.com/datrs/hypercore/commit/86e241f9e02e3583445fcb43fcc28295eae1cd31)] 🙋 Implement feed auditing (#55) (Tim Deeb-Swihart)
+- [[`5840a3a6a9`](https://github.com/datrs/hypercore/commit/5840a3a6a90f47ba89662687a374f070f3172c69)] Update rand requirement from 0.5.5 to 0.6.0 (#49) (dependabot[bot])
+- [[`1628057868`](https://github.com/datrs/hypercore/commit/162805786831866ea611cfe97e85def690614fa6)] use tree_index functions (#48) (Yoshua Wuyts)
+- [[`f66fbb3543`](https://github.com/datrs/hypercore/commit/f66fbb354376681062697ffd2be18da2224cb1b9)] Update merkle-tree-stream requirement from 0.7.0 to 0.8.0 (#46) (dependabot[bot])
+- [[`343df6f991`](https://github.com/datrs/hypercore/commit/343df6f991b0fbe5f50a7d95b632b3c60e5dfa54)] Update changelog (Yoshua Wuyts)
+
+### Stats
+```diff
+ CHANGELOG.md | 26 +++++++++++++++++++-
+ Cargo.toml | 6 ++--
+ src/audit.rs | 20 +++++++++++++++-
+ src/bitfield/mod.rs | 21 ++++++++++------
+ src/crypto/key_pair.rs | 2 +-
+ src/crypto/merkle.rs | 14 ++++++----
+ src/feed.rs | 46 ++++++++++++++++++++++++++++------
+ src/lib.rs | 1 +-
+ src/storage/mod.rs | 10 +++++--
+ src/storage/node.rs | 2 +-
+ tests/feed.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 11 files changed, 191 insertions(+), 26 deletions(-)
+```
+
+
+## 2018-12-22, Version 0.9.0
+### Commits
+- [[`9c2b07fca6`](https://github.com/datrs/hypercore/commit/9c2b07fca68bb34046551f0fd152aa7f97a33fb6)] (cargo-release) version 0.9.0 (Yoshua Wuyts)
+- [[`86e241f9e0`](https://github.com/datrs/hypercore/commit/86e241f9e02e3583445fcb43fcc28295eae1cd31)] 🙋 Implement feed auditing (#55) (Tim Deeb-Swihart)
+- [[`5840a3a6a9`](https://github.com/datrs/hypercore/commit/5840a3a6a90f47ba89662687a374f070f3172c69)] Update rand requirement from 0.5.5 to 0.6.0 (#49) (dependabot[bot])
+- [[`1628057868`](https://github.com/datrs/hypercore/commit/162805786831866ea611cfe97e85def690614fa6)] use tree_index functions (#48) (Yoshua Wuyts)
+- [[`f66fbb3543`](https://github.com/datrs/hypercore/commit/f66fbb354376681062697ffd2be18da2224cb1b9)] Update merkle-tree-stream requirement from 0.7.0 to 0.8.0 (#46) (dependabot[bot])
+- [[`343df6f991`](https://github.com/datrs/hypercore/commit/343df6f991b0fbe5f50a7d95b632b3c60e5dfa54)] Update changelog (Yoshua Wuyts)
+
+### Stats
+```diff
+ CHANGELOG.md | 26 +++++++++++++++++++-
+ Cargo.toml | 6 ++--
+ src/audit.rs | 20 +++++++++++++++-
+ src/bitfield/mod.rs | 21 ++++++++++------
+ src/crypto/key_pair.rs | 2 +-
+ src/crypto/merkle.rs | 14 ++++++----
+ src/feed.rs | 46 ++++++++++++++++++++++++++++------
+ src/lib.rs | 1 +-
+ src/storage/mod.rs | 10 +++++--
+ src/storage/node.rs | 2 +-
+ tests/feed.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 11 files changed, 191 insertions(+), 26 deletions(-)
+```
+
+
+## 2018-10-28, Version 0.8.1
+### Commits
+- [[`938d2816cc`](https://github.com/datrs/hypercore/commit/938d2816cc63e4dd8964139baa56be2dd28e72d5)] (cargo-release) version 0.8.1 (Yoshua Wuyts)
+- [[`79fd7a8141`](https://github.com/datrs/hypercore/commit/79fd7a8141096606b4124c7d59dede2a4021b3fb)] Stricter lints (#45) (Yoshua Wuyts)
+- [[`96b3af825d`](https://github.com/datrs/hypercore/commit/96b3af825ddc5c69364fe92c71d8498f4a00a2dc)] use spec compatible constants (#44) (Yoshua Wuyts)
+- [[`ac8ef53b0c`](https://github.com/datrs/hypercore/commit/ac8ef53b0cd45f0b935ab83dde4f750eb91a07e8)] Update changelog (Yoshua Wuyts)
+
+### Stats
+```diff
+ CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++
+ Cargo.toml | 10 +++++++++-
+ src/crypto/hash.rs | 8 ++++----
+ src/crypto/key_pair.rs | 2 +-
+ src/crypto/merkle.rs | 4 ++--
+ src/feed.rs | 20 ++++++++++----------
+ src/feed_builder.rs | 10 +++++-----
+ src/lib.rs | 19 +++++++++++--------
+ src/prelude.rs | 4 ++--
+ src/proof.rs | 4 ++--
+ src/storage/mod.rs | 2 +-
+ src/storage/node.rs | 4 ++--
+ src/storage/persist.rs | 2 +-
+ 13 files changed, 83 insertions(+), 39 deletions(-)
+```
+
+
+## 2018-10-18, Version 0.8.0
+### Commits
+- [[`048921b077`](https://github.com/datrs/hypercore/commit/048921b077d02963e70a881fa780e6e96c347d50)] (cargo-release) version 0.8.0 (Yoshua Wuyts)
+- [[`54ceb55e7b`](https://github.com/datrs/hypercore/commit/54ceb55e7bf6c5c037b3849c53bc082bc57e0ee4)] travis master only builds (Yoshua Wuyts)
+- [[`1a06b5862d`](https://github.com/datrs/hypercore/commit/1a06b5862d371120dc2e1695e5d1764721707e29)] upgrade (#43) (Yoshua Wuyts)
+- [[`2fda376767`](https://github.com/datrs/hypercore/commit/2fda376767efe3b61fe2f3bc46a431340cf984a2)] tests/helpers -> tests/common (#38) (Yoshua Wuyts)
+- [[`d48e5570fa`](https://github.com/datrs/hypercore/commit/d48e5570fa659b38519a54288b6019205cb48276)] Keep up with modern times in clippy invocation (#35) (Szabolcs Berecz)
+- [[`a62a21b249`](https://github.com/datrs/hypercore/commit/a62a21b24953f6b1da5cfc902abef6914f0b7950)] Update quickcheck requirement from 0.6.2 to 0.7.1 (#33) (Szabolcs Berecz)
+- [[`3bbe87db8d`](https://github.com/datrs/hypercore/commit/3bbe87db8d448e8fbc7a73a99b07ff39ec09c1e9)] Update changelog (Yoshua Wuyts)
+
+### Stats
+```diff
+ .github/ISSUE_TEMPLATE.md | 40 +++---------------------------
+ .github/ISSUE_TEMPLATE/bug_report.md | 23 +++++++++++++++++-
+ .github/ISSUE_TEMPLATE/feature_request.md | 43 ++++++++++++++++++++++++++++++++-
+ .github/ISSUE_TEMPLATE/question.md | 18 +++++++++++++-
+ .travis.yml | 24 +++++++++---------
+ CHANGELOG.md | 25 +++++++++++++++++++-
+ Cargo.toml | 28 ++++++++++-----------
+ README.md | 23 +++++++++++++++--
+ src/feed.rs | 2 +-
+ src/lib.rs | 23 +++++++++++++----
+ src/replicate/peer.rs | 2 +-
+ src/storage/mod.rs | 2 +-
+ tests/common/mod.rs | 15 +++++++++++-
+ tests/feed.rs | 29 +++++++++++++++++++---
+ tests/helpers.rs | 34 +-------------------------
+ tests/model.rs | 6 ++--
+ tests/regression.rs | 4 +--
+ 17 files changed, 232 insertions(+), 109 deletions(-)
+```
+
+
+## 2018-09-03, Version 0.7.1
+### Commits
+- [[`43ad5d3c9a`](https://github.com/datrs/hypercore/commit/43ad5d3c9accd9e4faa63fc5fe35b5c74997d503)] (cargo-release) version 0.7.1 (Yoshua Wuyts)
+- [[`cb2cfac275`](https://github.com/datrs/hypercore/commit/cb2cfac2757a50600886251b608ab349bdc6daf4)] Update ed25519_dalek to 0.8 and rand to 0.5 (#30) (Luiz Irber)
+- [[`ade97ddfe3`](https://github.com/datrs/hypercore/commit/ade97ddfe3310edbff11057740ebd03ed73075b4)] Update memory-pager requirement from 0.7.0 to 0.8.0 (dependabot[bot])
+- [[`420a3b19b0`](https://github.com/datrs/hypercore/commit/420a3b19b0daa7d32d96c3c67045adab10c0f38d)] Upgrade random-access-storage (#26) (Szabolcs Berecz)
+- [[`7421f677eb`](https://github.com/datrs/hypercore/commit/7421f677eb200cfa2cceb98c027408e29cc526ee)] update changelog (Yoshua Wuyts)
+
+### Stats
+```diff
+ CHANGELOG.md | 26 ++++++++++++++++++++++++++
+ Cargo.toml | 14 +++++++-------
+ benches/bench.rs | 8 +++-----
+ src/crypto/key_pair.rs | 4 ++--
+ src/feed.rs | 16 ++++++++--------
+ src/feed_builder.rs | 6 +++---
+ src/storage/mod.rs | 40 ++++++++++++++++++++--------------------
+ src/storage/persist.rs | 4 ++--
+ tests/compat.rs | 6 +++---
+ tests/feed.rs | 10 +++++-----
+ tests/helpers.rs | 8 ++++----
+ 11 files changed, 83 insertions(+), 59 deletions(-)
+```
+
+
+## 2018-08-25, Version 0.7.0
+### Commits
+- [[`c4c5986191`](https://github.com/datrs/hypercore/commits/c4c5986191ab9dc07443264c65d0f2edc6971439)] (cargo-release) version 0.7.0 (Yoshua Wuyts)
+- [[`7d6bde061c`](https://github.com/datrs/hypercore/commits/7d6bde061c6724a216f59ecd90970722b0c0f118)] Storage: implement keypair read/write (#18)
+- [[`d027f37ed8`](https://github.com/datrs/hypercore/commits/d027f37ed8aa5c9a487a7e0260fa1ca0cd089011)] Update sparse-bitfield requirement from 0.4.0 to 0.8.0 (#20)
+- [[`5d9b05f029`](https://github.com/datrs/hypercore/commits/5d9b05f029f2e1427770c4169794ce1cccd70ec5)] Update memory-pager requirement from 0.4.5 to 0.7.0
+- [[`73a3f28e26`](https://github.com/datrs/hypercore/commits/73a3f28e26957c627254ed024092df7ae057d277)] Update sleep-parser requirement from 0.4.0 to 0.6.0
+- [[`566b7a1021`](https://github.com/datrs/hypercore/commits/566b7a1021a36e7dc82ca22091ee21df88870d57)] Upgrade to latest random-access-storage (#17)
+- [[`e086e60942`](https://github.com/datrs/hypercore/commits/e086e609428d015bc831384ff3e16a8c9a295bc7)] Add rustfmt back to travis (#19)
+- [[`eb5edfba43`](https://github.com/datrs/hypercore/commits/eb5edfba438f8617d076f3a3f95636dfd3cc29ad)] (cargo-release) start next development iteration 0.6.1-alpha.0 (Yoshua Wuyts)
+
+### Stats
+```diff
+ .travis.yml | 1 +-
+ Cargo.toml | 14 ++++++------
+ src/bitfield/mod.rs | 9 +++-----
+ src/feed.rs | 49 +++++++++++++++++++++++++++++--------------
+ src/feed_builder.rs | 3 ++-
+ src/lib.rs | 2 +-
+ src/storage/mod.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++++-----
+ tests/compat.rs | 7 +++---
+ tests/feed.rs | 32 ++++++++++++++++++++++++++++-
+ tests/helpers.rs | 2 +-
+ tests/storage.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++-
+ 11 files changed, 197 insertions(+), 38 deletions(-)
+```
diff --git a/vendor/hypercore/Cargo.toml b/vendor/hypercore/Cargo.toml
new file mode 100644
index 00000000..d85ae45e
--- /dev/null
+++ b/vendor/hypercore/Cargo.toml
@@ -0,0 +1,175 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+name = "hypercore"
+version = "0.12.1"
+authors = [
+ "Yoshua Wuyts ",
+ "Timo Tiuraniemi ",
+]
+description = "Secure, distributed, append-only log"
+documentation = "https://docs.rs/hypercore"
+readme = "README.md"
+keywords = [
+ "dat",
+ "p2p",
+ "stream",
+ "feed",
+ "merkle",
+]
+categories = [
+ "asynchronous",
+ "concurrency",
+ "cryptography",
+ "data-structures",
+ "encoding",
+]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/datrs/hypercore"
+
+[[bench]]
+name = "memory"
+harness = false
+
+[[bench]]
+name = "disk"
+harness = false
+
+[dependencies.blake2]
+version = "0.10"
+
+[dependencies.byteorder]
+version = "1"
+
+[dependencies.compact-encoding]
+version = "1"
+
+[dependencies.crc32fast]
+version = "1"
+
+[dependencies.ed25519-dalek]
+version = "2"
+features = ["rand_core"]
+
+[dependencies.flat-tree]
+version = "6"
+
+[dependencies.futures]
+version = "0.3"
+
+[dependencies.getrandom]
+version = "0.2"
+features = ["js"]
+
+[dependencies.intmap]
+version = "2"
+
+[dependencies.merkle-tree-stream]
+version = "0.12"
+
+[dependencies.moka]
+version = "0.12"
+features = ["sync"]
+optional = true
+
+[dependencies.pretty-hash]
+version = "0.4"
+
+[dependencies.rand]
+version = "0.8"
+
+[dependencies.random-access-memory]
+version = "3"
+
+[dependencies.random-access-storage]
+version = "5"
+
+[dependencies.sha2]
+version = "0.10"
+
+[dependencies.thiserror]
+version = "1"
+
+[dependencies.tracing]
+version = "0.1"
+
+[dev-dependencies.anyhow]
+version = "1.0.70"
+
+[dev-dependencies.async-std]
+version = "1.12.0"
+features = ["attributes"]
+
+[dev-dependencies.criterion]
+version = "0.4"
+features = [
+ "async_std",
+ "async_tokio",
+]
+
+[dev-dependencies.data-encoding]
+version = "2.2.0"
+
+[dev-dependencies.proptest]
+version = "1.1.0"
+
+[dev-dependencies.proptest-derive]
+version = "0.2.0"
+
+[dev-dependencies.remove_dir_all]
+version = "0.7.0"
+
+[dev-dependencies.sha2]
+version = "0.10"
+
+[dev-dependencies.tempfile]
+version = "3.1.0"
+
+[dev-dependencies.test-log]
+version = "0.2.11"
+features = ["trace"]
+default-features = false
+
+[dev-dependencies.tokio]
+version = "1.27.0"
+features = [
+ "macros",
+ "rt",
+ "rt-multi-thread",
+]
+default-features = false
+
+[dev-dependencies.tokio-test]
+version = "0.4"
+
+[dev-dependencies.tracing-subscriber]
+version = "0.3.16"
+features = [
+ "env-filter",
+ "fmt",
+]
+
+[features]
+async-std = ["random-access-disk/async-std"]
+cache = ["moka"]
+default = [
+ "async-std",
+ "sparse",
+]
+js_interop_tests = []
+sparse = ["random-access-disk/sparse"]
+tokio = ["random-access-disk/tokio"]
+
+[target."cfg(not(target_arch = \"wasm32\"))".dependencies.random-access-disk]
+version = "3"
+default-features = false
diff --git a/vendor/hypercore/LICENSE-APACHE b/vendor/hypercore/LICENSE-APACHE
new file mode 100644
index 00000000..6ab06963
--- /dev/null
+++ b/vendor/hypercore/LICENSE-APACHE
@@ -0,0 +1,190 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2018 Yoshua Wuyts
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/hypercore/LICENSE-MIT b/vendor/hypercore/LICENSE-MIT
new file mode 100644
index 00000000..c7509bad
--- /dev/null
+++ b/vendor/hypercore/LICENSE-MIT
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Yoshua Wuyts
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/hypercore/README.md b/vendor/hypercore/README.md
new file mode 100644
index 00000000..a95afaeb
--- /dev/null
+++ b/vendor/hypercore/README.md
@@ -0,0 +1,105 @@
+# Hypercore
+[![crates.io version][1]][2] [![build status][3]][4]
+[![downloads][5]][6] [![docs.rs docs][7]][8]
+
+Hypercore is a secure, distributed append-only log. This crate is a limited Rust
+port of the original Javascript
+[holepunchto/hypercore](https://github.com/holepunchto/hypercore). The goal is to
+maintain binary compatibility with the LTS version with regards to disk storage.
+
+See [hypercore-protocol-rs](https://github.com/datrs/hypercore-protocol-rs) for the
+corresponding wire protocol implementation.
+
+- [Documentation][8]
+- [Crates.io][2]
+
+## Features
+
+- [x] Create [in-memory](https://github.com/datrs/random-access-memory) and [disk](https://github.com/datrs/random-access-disk) hypercores
+- [x] Append to hypercore either a single entry or a batch of entries
+- [x] Get entries from hypercore
+- [x] Clear range from hypercore, with optional support for sparse files
+- [x] Support basic replication by creating proofs in a source hypercore and verifying and applying them to a destination hypercore
+- [x] Support `tokio` or `async-std` runtimes
+- [x] Support WASM for in-memory storage
+- [x] Test Javascript interoperability for supported features
+- [x] Add optional read cache
+- [ ] Support the new [manifest](https://github.com/holepunchto/hypercore/blob/main/lib/manifest.js) in the wire protocol to remain compatible with upcoming v11
+- [ ] Finalize documentation and release v1.0.0
+
+## Usage
+
+```rust
+// Create an in-memory hypercore using a builder
+let mut hypercore = HypercoreBuilder::new(Storage::new_memory().await.unwrap())
+ .build()
+ .await
+ .unwrap();
+
+// Append entries to the log
+hypercore.append(b"Hello, ").await.unwrap();
+hypercore.append(b"world!").await.unwrap();
+
+// Read entries from the log
+assert_eq!(hypercore.get(0).await.unwrap().unwrap(), b"Hello, ");
+assert_eq!(hypercore.get(1).await.unwrap().unwrap(), b"world!");
+```
+
+Find more examples in the [examples](./examples) folder, and/or run:
+
+```bash
+cargo run --example memory
+cargo run --example disk
+cargo run --example replication
+```
+
+## Installation
+
+```bash
+cargo add hypercore
+```
+
+## Safety
+
+This crate uses ``#![forbid(unsafe_code)]`` to ensure everythong is implemented in
+100% Safe Rust.
+
+## Development
+
+To test interoperability with Javascript, enable the `js_interop_tests` feature:
+
+```bash
+cargo test --features js_interop_tests
+```
+
+Run benches with:
+
+```bash
+cargo bench
+```
+
+## Contributing
+
+Want to join us? Check out our ["Contributing" guide][contributing] and take a
+look at some of these issues:
+
+- [Issues labeled "good first issue"][good-first-issue]
+- [Issues labeled "help wanted"][help-wanted]
+
+## License
+
+[MIT](./LICENSE-MIT) OR [Apache-2.0](./LICENSE-APACHE)
+
+[1]: https://img.shields.io/crates/v/hypercore.svg?style=flat-square
+[2]: https://crates.io/crates/hypercore
+[3]: https://github.com/datrs/hypercore/actions/workflows/ci.yml/badge.svg
+[4]: https://github.com/datrs/hypercore/actions
+[5]: https://img.shields.io/crates/d/hypercore.svg?style=flat-square
+[6]: https://crates.io/crates/hypercore
+[7]: https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square
+[8]: https://docs.rs/hypercore
+
+[releases]: https://github.com/datrs/hypercore/releases
+[contributing]: https://github.com/datrs/hypercore/blob/master/.github/CONTRIBUTING.md
+[good-first-issue]: https://github.com/datrs/hypercore/labels/good%20first%20issue
+[help-wanted]: https://github.com/datrs/hypercore/labels/help%20wanted
diff --git a/vendor/hypercore/benches/disk.rs b/vendor/hypercore/benches/disk.rs
new file mode 100644
index 00000000..326f57b3
--- /dev/null
+++ b/vendor/hypercore/benches/disk.rs
@@ -0,0 +1,140 @@
+use std::time::{Duration, Instant};
+
+#[cfg(feature = "async-std")]
+use criterion::async_executor::AsyncStdExecutor;
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+use hypercore::{Hypercore, HypercoreBuilder, HypercoreError, Storage};
+use random_access_disk::RandomAccessDisk;
+use tempfile::Builder as TempfileBuilder;
+
+fn bench_create_disk(c: &mut Criterion) {
+ let mut group = c.benchmark_group("slow_call");
+ group.measurement_time(Duration::from_secs(20));
+
+ #[cfg(feature = "async-std")]
+ group.bench_function("create_disk", move |b| {
+ b.to_async(AsyncStdExecutor)
+ .iter(|| create_hypercore("create"));
+ });
+ #[cfg(feature = "tokio")]
+ group.bench_function("create_disk", move |b| {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ b.to_async(&rt).iter(|| create_hypercore("create"));
+ });
+}
+
+#[cfg(feature = "cache")]
+async fn create_hypercore(name: &str) -> Result, HypercoreError> {
+ let dir = TempfileBuilder::new()
+ .prefix(name)
+ .tempdir()
+ .unwrap()
+ .into_path();
+ let storage = Storage::new_disk(&dir, true).await?;
+ HypercoreBuilder::new(storage)
+ .node_cache_options(hypercore::CacheOptionsBuilder::new())
+ .build()
+ .await
+}
+
+#[cfg(not(feature = "cache"))]
+async fn create_hypercore(name: &str) -> Result, HypercoreError> {
+ let dir = TempfileBuilder::new()
+ .prefix(name)
+ .tempdir()
+ .unwrap()
+ .into_path();
+ let storage = Storage::new_disk(&dir, true).await?;
+ HypercoreBuilder::new(storage).build().await
+}
+
+fn bench_write_disk(c: &mut Criterion) {
+ let mut group = c.benchmark_group("slow_call");
+ group.measurement_time(Duration::from_secs(20));
+
+ #[cfg(feature = "async-std")]
+ group.bench_function("write disk", |b| {
+ b.to_async(AsyncStdExecutor).iter_custom(write_disk);
+ });
+ #[cfg(feature = "tokio")]
+ group.bench_function("write disk", |b| {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ b.to_async(&rt).iter_custom(write_disk);
+ });
+}
+
+async fn write_disk(iters: u64) -> Duration {
+ let mut hypercore = create_hypercore("write").await.unwrap();
+ let data = Vec::from("hello");
+ let start = Instant::now();
+ for _ in 0..iters {
+ black_box(hypercore.append(&data).await.unwrap());
+ }
+ start.elapsed()
+}
+
+fn bench_read_disk(c: &mut Criterion) {
+ let mut group = c.benchmark_group("slow_call");
+ group.measurement_time(Duration::from_secs(20));
+
+ #[cfg(feature = "async-std")]
+ group.bench_function("read disk", |b| {
+ b.to_async(AsyncStdExecutor).iter_custom(read_disk);
+ });
+ #[cfg(feature = "tokio")]
+ group.bench_function("read disk", |b| {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ b.to_async(&rt).iter_custom(read_disk);
+ });
+}
+
+async fn read_disk(iters: u64) -> Duration {
+ let mut hypercore = create_hypercore("read").await.unwrap();
+ let data = Vec::from("hello");
+ for _ in 0..iters {
+ hypercore.append(&data).await.unwrap();
+ }
+ let start = Instant::now();
+ for i in 0..iters {
+ black_box(hypercore.get(i).await.unwrap());
+ }
+ start.elapsed()
+}
+
+fn bench_clear_disk(c: &mut Criterion) {
+ let mut group = c.benchmark_group("slow_call");
+ group.measurement_time(Duration::from_secs(20));
+
+ #[cfg(feature = "async-std")]
+ group.bench_function("clear disk", |b| {
+ b.to_async(AsyncStdExecutor).iter_custom(clear_disk);
+ });
+ #[cfg(feature = "tokio")]
+ group.bench_function("clear disk", |b| {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ b.to_async(&rt).iter_custom(clear_disk);
+ });
+}
+
+#[allow(clippy::unit_arg)]
+async fn clear_disk(iters: u64) -> Duration {
+ let mut hypercore = create_hypercore("clear").await.unwrap();
+ let data = Vec::from("hello");
+ for _ in 0..iters {
+ hypercore.append(&data).await.unwrap();
+ }
+ let start = Instant::now();
+ for i in 0..iters {
+ black_box(hypercore.clear(i, 1).await.unwrap());
+ }
+ start.elapsed()
+}
+
+criterion_group!(
+ benches,
+ bench_create_disk,
+ bench_write_disk,
+ bench_read_disk,
+ bench_clear_disk
+);
+criterion_main!(benches);
diff --git a/vendor/hypercore/benches/memory.rs b/vendor/hypercore/benches/memory.rs
new file mode 100644
index 00000000..b439b1e1
--- /dev/null
+++ b/vendor/hypercore/benches/memory.rs
@@ -0,0 +1,128 @@
+use std::time::{Duration, Instant};
+
+#[cfg(feature = "async-std")]
+use criterion::async_executor::AsyncStdExecutor;
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+use hypercore::{Hypercore, HypercoreBuilder, HypercoreError, Storage};
+use random_access_memory::RandomAccessMemory;
+
+fn bench_create_memory(c: &mut Criterion) {
+ #[cfg(feature = "async-std")]
+ c.bench_function("create memory", |b| {
+ b.to_async(AsyncStdExecutor).iter(|| create_hypercore(1024));
+ });
+ #[cfg(feature = "tokio")]
+ c.bench_function("create memory", |b| {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ b.to_async(&rt).iter(|| create_hypercore(1024));
+ });
+}
+
+#[cfg(feature = "cache")]
+async fn create_hypercore(
+ page_size: usize,
+) -> Result, HypercoreError> {
+ let storage = Storage::open(
+ |_| Box::pin(async move { Ok(RandomAccessMemory::new(page_size)) }),
+ false,
+ )
+ .await?;
+ HypercoreBuilder::new(storage)
+ .node_cache_options(hypercore::CacheOptionsBuilder::new())
+ .build()
+ .await
+}
+
+#[cfg(not(feature = "cache"))]
+async fn create_hypercore(
+ page_size: usize,
+) -> Result, HypercoreError> {
+ let storage = Storage::open(
+ |_| Box::pin(async move { Ok(RandomAccessMemory::new(page_size)) }),
+ false,
+ )
+ .await?;
+ HypercoreBuilder::new(storage).build().await
+}
+
+fn bench_write_memory(c: &mut Criterion) {
+ #[cfg(feature = "async-std")]
+ c.bench_function("write memory", |b| {
+ b.to_async(AsyncStdExecutor).iter_custom(write_memory);
+ });
+ #[cfg(feature = "tokio")]
+ c.bench_function("write memory", |b| {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ b.to_async(&rt).iter_custom(write_memory);
+ });
+}
+
+async fn write_memory(iters: u64) -> Duration {
+ let mut hypercore = create_hypercore(1024).await.unwrap();
+ let data = Vec::from("hello");
+ let start = Instant::now();
+ for _ in 0..iters {
+ black_box(hypercore.append(&data).await.unwrap());
+ }
+ start.elapsed()
+}
+
+fn bench_read_memory(c: &mut Criterion) {
+ #[cfg(feature = "async-std")]
+ c.bench_function("read memory", |b| {
+ b.to_async(AsyncStdExecutor).iter_custom(read_memory);
+ });
+ #[cfg(feature = "tokio")]
+ c.bench_function("read memory", |b| {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ b.to_async(&rt).iter_custom(read_memory);
+ });
+}
+
+async fn read_memory(iters: u64) -> Duration {
+ let mut hypercore = create_hypercore(1024).await.unwrap();
+ let data = Vec::from("hello");
+ for _ in 0..iters {
+ hypercore.append(&data).await.unwrap();
+ }
+ let start = Instant::now();
+ for i in 0..iters {
+ black_box(hypercore.get(i).await.unwrap());
+ }
+ start.elapsed()
+}
+
+fn bench_clear_memory(c: &mut Criterion) {
+ #[cfg(feature = "async-std")]
+ c.bench_function("clear memory", |b| {
+ b.to_async(AsyncStdExecutor).iter_custom(clear_memory);
+ });
+ #[cfg(feature = "tokio")]
+ c.bench_function("clear memory", |b| {
+ let rt = tokio::runtime::Runtime::new().unwrap();
+ b.to_async(&rt).iter_custom(clear_memory);
+ });
+}
+
+#[allow(clippy::unit_arg)]
+async fn clear_memory(iters: u64) -> Duration {
+ let mut hypercore = create_hypercore(1024).await.unwrap();
+ let data = Vec::from("hello");
+ for _ in 0..iters {
+ hypercore.append(&data).await.unwrap();
+ }
+ let start = Instant::now();
+ for i in 0..iters {
+ black_box(hypercore.clear(i, 1).await.unwrap());
+ }
+ start.elapsed()
+}
+
+criterion_group!(
+ benches,
+ bench_create_memory,
+ bench_write_memory,
+ bench_read_memory,
+ bench_clear_memory
+);
+criterion_main!(benches);
diff --git a/vendor/hypercore/examples/disk.rs b/vendor/hypercore/examples/disk.rs
new file mode 100644
index 00000000..99990897
--- /dev/null
+++ b/vendor/hypercore/examples/disk.rs
@@ -0,0 +1,88 @@
+#[cfg(feature = "async-std")]
+use async_std::main as async_main;
+use hypercore::{HypercoreBuilder, HypercoreError, Storage};
+use tempfile::Builder;
+#[cfg(feature = "tokio")]
+use tokio::main as async_main;
+
+/// Example about using an in-memory hypercore.
+#[async_main]
+async fn main() {
+ // For the purposes of this example, first create a
+ // temporary directory to hold hypercore.
+ let dir = Builder::new()
+ .prefix("examples_disk")
+ .tempdir()
+ .unwrap()
+ .into_path();
+
+ // Create a disk storage, overwriting existing values.
+ let overwrite = true;
+ let storage = Storage::new_disk(&dir, overwrite)
+ .await
+ .expect("Could not create disk storage");
+
+ // Build a new disk hypercore
+ let mut hypercore = HypercoreBuilder::new(storage)
+ .build()
+ .await
+ .expect("Could not create disk hypercore");
+
+ // Append values to the hypercore
+ hypercore.append(b"Hello, ").await.unwrap();
+ hypercore.append(b"from ").await.unwrap();
+
+ // Close hypercore
+ drop(hypercore);
+
+ // Open hypercore again from same directory, not
+ // overwriting.
+ let overwrite = false;
+ let storage = Storage::new_disk(&dir, overwrite)
+ .await
+ .expect("Could not open existing disk storage");
+ let mut hypercore = HypercoreBuilder::new(storage)
+ .open(true)
+ .build()
+ .await
+ .expect("Could not open disk hypercore");
+
+ // Append new values to the hypercore
+ hypercore.append(b"disk hypercore!").await.unwrap();
+
+ // Add three values and clear the first two
+ let batch: &[&[u8]] = &[
+ b"first value to clear",
+ b"second value to clear",
+ b"third value to keep",
+ ];
+ let new_length = hypercore.append_batch(batch).await.unwrap().length;
+ hypercore
+ .clear(new_length - 3, new_length - 1)
+ .await
+ .unwrap();
+
+ // The two values return None, but the last one returns correctly
+ assert!(hypercore.get(3).await.unwrap().is_none());
+ assert!(hypercore.get(4).await.unwrap().is_none());
+ assert_eq!(
+ hypercore.get(5).await.unwrap().unwrap(),
+ b"third value to keep"
+ );
+
+ // Print the first three values, converting binary back to string
+ println!(
+ "{}{}{}",
+ format_res(hypercore.get(0).await),
+ format_res(hypercore.get(1).await),
+ format_res(hypercore.get(2).await)
+ ); // prints "Hello, from disk hypercore!"
+}
+
+fn format_res(res: Result