<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title></title>
    <description>Documentation for the high-throughput yielding distributed ledger built upon scale-centric design principles to democratize and decentralize computation.
</description>
    <link>https://blog.expolab.org</link>
    <atom:link href="https://blog.expolab.org/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Implementing Raft Consensus Protocol for ResilientDB</title>
        <description>&lt;p&gt;Distributed systems are powerful and prevalent tools in today’s computing landscape. Properly coordinating these systems requires some mechanism to do so, that being a consensus protocol. Because many consensus protocols exist to target different use cases, it is beneficial for a distributed database to support different protocols. While ResilientDB already contains multiple Byzantine Fault Tolerant algorithms, it has not contained a Crash Fault Tolerant algorithm until now. ResilientDB’s Raft implementation fills this gap, allowing for a more favorable asymptotic message complexity compared to Byzantine Fault Tolerant protocols at the cost of no longer tolerating malicious behavior.&lt;/p&gt;

&lt;h1 id=&quot;background&quot;&gt;Background&lt;/h1&gt;

&lt;h2 id=&quot;consensus&quot;&gt;Consensus&lt;/h2&gt;

&lt;p&gt;Oftentimes, it can be beneficial to leverage the power of multiple computers in multiple locations to solve a computational problem. This may be useful to enable lower latency for users in different locations, handle a higher load, and allow for operations to continue even if individual machines stop working. However, there is one large problem with computation on a distributed system: how do the machines agree on which data values to use during computation? This is the problem of consensus in distributed systems.&lt;/p&gt;

&lt;p&gt;Solving this problem is non-trivial. The &lt;a href=&quot;https://dl.acm.org/doi/10.1145/564585.564601&quot;&gt;CAP theorem&lt;/a&gt; shows that no matter what algorithm or design is used, if messages are allowed to be arbitrarily delayed or dropped, it cannot be guaranteed that all clients will receive the same response to the same request. Tradeoffs have to be made based on the needs of the system and the users.&lt;/p&gt;

&lt;h2 id=&quot;fault-tolerance&quot;&gt;Fault Tolerance&lt;/h2&gt;

&lt;p&gt;One consideration when designing a consensus protocol is the kinds of faults that are tolerated in the system. Crash Fault Tolerant (CFT) protocols tolerate machines crashing or stopping. Byzantine Fault Tolerant (BFT) protocols allow for faults as well as malicious (Byzantine) behavior. A Byzantine machine may lie or actively act against the goal of the group. If a cluster has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; faulty nodes, a CFT algorithm must have at least &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2f + 1&lt;/code&gt; nodes in total (less than half of the nodes can be faulty). A BFT algorithm must have at least &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3f + 1&lt;/code&gt; nodes in total (less than one third of the nodes can be faulty or Byzantine). One well-known BFT algorithm is Practical Byzantine Fault Tolerance (PBFT).&lt;/p&gt;

&lt;h2 id=&quot;what-is-raft&quot;&gt;What is Raft?&lt;/h2&gt;

&lt;p&gt;Raft is a consensus protocol used in many existing software systems, including etcd (used by Kubernetes), Kafka, and MongoDB. It has been battle-tested in production since it was first published in 2014. The ResilientDB project on GitHub has had an open issue since October 2023 requesting that Raft be added to its portfolio of available consensus protocols. This Raft implementation aims to fulfill this feature request.&lt;/p&gt;

&lt;p&gt;Raft is the first CFT protocol available within ResilientDB. This comes with several benefits: a ResilientDB Raft deployment can function with only 3 replicas instead of the current minimum of 4, and transaction throughput should, in theory, degrade less sharply than PBFT as the number of replicas increases, thanks to Raft’s more favorable asymptotic message complexity (O(n)) compared to the PBFT family of protocols (O(n&lt;sup&gt;2&lt;/sup&gt;)). The performance overhead of cryptography in BFT protocols is also fairly high, so latency improvements can be expected with Raft as well.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/Raft.gif&quot; alt=&quot;Raft Protocol Diagram&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Animation of the Flow of the Raft Consensus Protocol
    &lt;/em&gt;
    &lt;br /&gt;
    &lt;strong&gt; &lt;em&gt;c&lt;/em&gt;: client | &lt;em&gt;T&lt;/em&gt;: Transaction | &lt;em&gt;L&lt;/em&gt;: leader | &lt;em&gt;F&lt;/em&gt;: follower &lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;In Raft, a leader receives transactions from the client, adds them to its log, and forwards them to followers in an AppendEntries Remote Procedure Call (RPC). The followers execute that procedure to add the entry to their log, and respond to the leader to inform them if the RPC succeeded or failed. The leader waits until it has reached quorum on that transaction, requiring responses from at least &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f + 1&lt;/code&gt; nodes, before committing the transaction to be executed. Then the client is informed, and in future AppendEntries RPCs, the commit index is updated so followers know to commit and execute the transaction.&lt;/p&gt;

&lt;h2 id=&quot;raft-leader-elections&quot;&gt;Raft Leader Elections&lt;/h2&gt;

&lt;p&gt;In Raft, leaders are supposed to send out heartbeats periodically to maintain their leadership status. All followers maintain a timeout window, and randomly pick a time to wait within that window. Without the follower receiving an AppendEntries RPC from the leader within the time window, it is assumed that the leader is no longer available. The follower will transition to a candidate, increment its term, and send out RequestVote RPCs to all other computers. A computer will respond with a yes vote if:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The replica has not already voted for another computer this term&lt;/li&gt;
  &lt;li&gt;The candidate’s term and log are at least as up to date as the replica’s own.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Replicas decide if a follower’s log is more recent based upon the index and the term of the last entry in their logs. If the terms of the last entries are different, then the more up-to-date log is the one with the most recent term. If the terms of the last entries are the same, then the more up-to-date log is the one with the highest last log index.&lt;/p&gt;

&lt;p&gt;Because at least &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f + 1&lt;/code&gt; nodes are required to win an election, and entries are committed once &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f + 1&lt;/code&gt; machines have replicated them, a node can only be elected as leader if its log contains every committed entry.&lt;/p&gt;

&lt;h1 id=&quot;initial-raft-implementation&quot;&gt;Initial Raft Implementation&lt;/h1&gt;

&lt;h2 id=&quot;implementation-strategy-and-architecture&quot;&gt;Implementation Strategy and Architecture&lt;/h2&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/Architecture1.svg&quot; alt=&quot;How Raft fits into ResilientDB&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. How Raft Fits into ResilientDB
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;Raft needs to fit into ResilientDB’s existing codebase. It interacts with the TransactionExecutor to execute transactions and add them to the database, the ReplicaCommunicator for replica messaging, and the Recovery class. Raft also will have access to built-in benchmarking support through PerformanceManager, to easily measure throughput and latency.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/Architecture2.svg&quot; alt=&quot;Raft Architecture&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. Raft Architecture
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;The Raft implementation consists of several core components. The consensus object receives messages from the ReplicaCommunicator, and depending on what type of message it is, calls the appropriate Raft function to handle it. Messages can be transactions from a client, or RPCs and RPC responses. These RPCs include AppendEntries, RequestVote, and InstallSnapshot. Raft requires certain data to be durably stored on disk, necessitating the use of RaftRecovery. Specific details on RaftRecovery and the InstallSnapshot RPC are discussed in &lt;a href=&quot;#persistence&quot;&gt;Persistence&lt;/a&gt; and &lt;a href=&quot;#snapshots&quot;&gt;Snapshots&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Raft object has the logic to send heartbeats and start leader elections, but it needs these events to be triggered at appropriate times. This is handled by the LeaderElectionManager.&lt;/p&gt;

&lt;p&gt;The LeaderElectionManager operates in two different modes, leader mode and follower mode. The LeaderElectionManager keeps a timer to invoke certain functions when the timer has elapsed. For leaders, the Raft object tells the LeaderElectionManager every time a message is broadcast to all replicas, which refreshes the duration of the timer. If the LeaderElectionManager times out for a leader, then it forces a heartbeat to be sent.&lt;/p&gt;

&lt;p&gt;For followers, the Raft object tells the LeaderElectionManager every time an RPC is received, which refreshes the duration of the timer. If the LeaderElectionManager times out for a follower, then it forces the follower to transition to a candidate and start an election, requesting votes from all other replicas.&lt;/p&gt;

&lt;h3 id=&quot;leader-in-flight-message-throttling&quot;&gt;Leader In-Flight Message Throttling&lt;/h3&gt;

&lt;p&gt;The network can become overwhelmed if too many messages are sent unnecessarily. To help mitigate this, there are multiple ways to limit the number of messages sent at once. The first is a cap on message size and the number of entries in a single message. Once that cap would be exceeded, the current message is sent as-is and the remaining entries are sent in one or more additional messages. Additionally, there is a limit on the number of messages allowed to be in flight (from the &lt;strong&gt;leader&lt;/strong&gt; to &lt;strong&gt;followers&lt;/strong&gt;), meaning sent but not yet acknowledged by a follower. Once that limit is reached, no messages other than heartbeats are sent to that follower until it responds or a timeout is reached.&lt;/p&gt;

&lt;p&gt;If a timeout occurs, all in-flight messages are presumed lost, and the follower’s next index is reset to its match index (the index of the last entry the follower is known to have).&lt;/p&gt;

&lt;h1 id=&quot;follow-up-raft-improvements&quot;&gt;Follow-up Raft Improvements&lt;/h1&gt;

&lt;p&gt;The initial implementation included basic log replication, heartbeats, timeouts, and leader elections. However, it was missing several key features described in &lt;a href=&quot;https://raft.github.io/raft.pdf&quot;&gt;Diego Ongaro and John Ousterhout’s Raft Paper&lt;/a&gt;. The main omissions were persisting each server’s state to disk, and the ability to create and send snapshots to followers that have fallen behind.&lt;/p&gt;

&lt;p&gt;In addition to these required features, the implementation had no tests, and the initial benchmarking was performed on a single local machine. After testing on multiple remote machines, throughput issues surfaced, which are addressed in &lt;a href=&quot;#throughput-improvements&quot;&gt;Throughput Improvements&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;persistence&quot;&gt;Persistence&lt;/h2&gt;

&lt;p&gt;To guarantee the safety of the protocol, Raft requires certain information to be persisted to disk on stable storage before responding to RPCs. This includes the log entries themselves, as well as some extra metadata. ResilientDB’s Recovery class was expanded to support Raft’s needs while maintaining existing behavior for PBFT.&lt;/p&gt;

&lt;p&gt;Since the log information that needs to be stored differs between Raft and PBFT, the Recovery class was split into a RecoveryBase and two derived classes, PBFTRecovery and RaftRecovery. Most of the required work was the same, but since different data needs to be stored, different function arguments need to be used. This led to the use of the Curiously Recurring Template Pattern (CRTP), which is well suited to this case since the object type is known at compile time. The base class takes the derived class, as well as the argument types of some functions, as template parameters. This lets the code that reads and writes the individual elements of the Write-Ahead Log (WAL) live entirely in the base class, while the derived classes define which elements are written and in what order.&lt;/p&gt;

&lt;p&gt;The extra metadata is stored separately from RecoveryBase’s WAL in RaftRecovery’s own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata.dat&lt;/code&gt; file. This metadata includes the current term, the replica that was voted for in the current term (if any), and the index and term of the last log entry included in any snapshot. Unlike a log, this data doesn’t need to retain history. It only needs to reflect the current state, so it can be overwritten any time it changes. The data is first written to a temporary file, then renamed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata.dat&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;snapshots&quot;&gt;Snapshots&lt;/h2&gt;

&lt;p&gt;In a Raft instance, since a follower can be arbitrarily far behind the leader, the entire state of the log must be kept if no precautions have been taken. Without some way to compact this information, the log can grow indefinitely. This problem can be solved by using snapshots to enable log compaction. Snapshots also speed up catching up a follower that has fallen far behind the leader’s log.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/RaftSnapshotFlow.svg&quot; alt=&quot;Raft Snapshot Flow&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. Raft Snapshot Flow
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;In Raft, snapshots contain the current state of the state machine as is, without retaining all of the instructions to get to that point. For ResilientDB, this state is effectively just the database already being used (such as LevelDB). To decide when a checkpoint is to be taken, ResilientDB uses a timer as well as a “checkpoint sequence.” Every 60 seconds (a customizable amount), a thread checks to see if the checkpoint sequence has been updated. This checkpoint sequence is updated after every 1,000 transactions executed, based on a function callback in TransactionExecutor. When the check occurs, if the checkpoint sequence is different from the cached value from the last time it was checked, that triggers the database to be flushed to disk, and the WAL rotates to a new file. Then, the Raft class is notified and truncates the prefix of the log corresponding to that snapshot. Rather than immediately removing every snapshotted entry from the log, a configurable buffer keeps some of them in place.&lt;/p&gt;

&lt;p&gt;When a leader knows a follower has fallen behind, it queues a snapshot for that follower. A separate snapshot queue thread reads the queue and sends the InstallSnapshot RPC out. Each snapshot is serialized to a byte string, stored to disk, and then sent to the follower in chunks. The leader waits for the follower to receive and respond to each chunk before sending the next.&lt;/p&gt;

&lt;p&gt;During the period between a follower being sent its first chunk of a snapshot and the leader receiving confirmation that the follower has received the last chunk of the snapshot, the leader does not initiate new checkpoints, which pauses prefix truncation until the snapshot completes. This prevents a follower from finishing one snapshot only to immediately need another, because the entry it needs next has already been truncated from the log.&lt;/p&gt;

&lt;h2 id=&quot;no-op-entries&quot;&gt;NO-OP Entries&lt;/h2&gt;

&lt;p&gt;As part of Raft’s safety guarantees, a leader can only directly commit entries from its own term. The specification for Raft addresses this by having the leader submit a blank no-operation (NO-OP) entry at the start of its term. While this was originally described as a step toward supporting read-only transactions, it also solved a specific issue in ResilientDB’s testing harness, where the client can only have a finite number of transactions in flight that have not yet been committed. If all of these transactions have been sent out and a leader election then occurs, no new transactions would be added to the log or committed. Without a NO-OP entry at the start of each term, this would cause progress to stall indefinitely.&lt;/p&gt;

&lt;h2 id=&quot;raft-transaction-batching&quot;&gt;Raft Transaction Batching&lt;/h2&gt;

&lt;p&gt;Another mechanism that was tested to try to address network congestion was to have the leader batch transactions before sending them to followers. When batching is enabled, the leader waits until a set time threshold elapses before sending newly received transactions to followers. In practice, this only helped when transaction bandwidth was not already saturated, so it is currently disabled.&lt;/p&gt;

&lt;h2 id=&quot;tests&quot;&gt;Tests&lt;/h2&gt;

&lt;p&gt;Around 100 test cases were added for the Raft implementation. This includes tests for Raft and RaftRecovery, as well as for existing components touched by the new Recovery class, such as MemoryDB and LevelDB. Most of the tests are unit tests written for the sending and receiving of each RPC (AppendEntries, RequestVote, and InstallSnapshot) as well as their responses. Additionally, there are some integration tests to verify how Raft and RaftRecovery work together. These tests write to the WAL and metadata file, let the Raft object go out of scope, and then verify that data is restored properly.&lt;/p&gt;

&lt;h2 id=&quot;throughput-improvements&quot;&gt;Throughput Improvements&lt;/h2&gt;

&lt;p&gt;Benchmarking began after the initial implementation was fully complete. However, throughput was significantly lower than expected. The following changes address this:&lt;/p&gt;

&lt;h3 id=&quot;follower-state&quot;&gt;Follower State&lt;/h3&gt;

&lt;p&gt;Sending a single message at a time and waiting for a response before sending the next is far too slow, so pipelining was added to achieve reasonable throughput. The leader continues sending new transactions as they arrive, without waiting for acknowledgment of previous messages. However, this can overwhelm the network, and the problem compounds whenever a follower fails to add entries to its log for any reason. For example, a single message received out of order causes all subsequent messages to be rejected until the missing entry is resent. The in-flight limits discussed previously mitigate this somewhat, but not completely.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/FollowerState.svg&quot; alt=&quot;Raft Follower State&quot; style=&quot;display:block; margin:0 auto; max-width:100%; height:auto;&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Follower State
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;To help solve this, the design borrows an approach inspired by the follower progress tracking in &lt;a href=&quot;https://github.com/etcd-io/raft&quot;&gt;etcd’s Raft implementation&lt;/a&gt;. For each follower, the leader tracks which of three states it is in: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REPLICATE&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PROBE&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SNAPSHOT&lt;/code&gt;. While a follower is in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REPLICATE&lt;/code&gt; state, the leader continues to forward that follower new log entries up to the in-flight limit, assuming everything is being received correctly. If the leader gets a failure response, it sets the follower’s state to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PROBE&lt;/code&gt;, assumes all in-flight messages were lost, and waits for a response before trying to catch the follower up again. No messages other than heartbeats are sent to a follower while it is in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PROBE&lt;/code&gt; state. Once the follower responds, the leader does one of two things: if the missing entry has not been truncated, it sets the follower’s state back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REPLICATE&lt;/code&gt; and sends the missing entry. If the entry has been truncated, it sets the state to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SNAPSHOT&lt;/code&gt; and queues a snapshot for that follower.&lt;/p&gt;

&lt;p&gt;This lets the leader use pipelined log replication normally when there are no issues, while avoiding overwhelming the network once a failure occurs. Once the leader has confirmed the follower’s log state, it can resume normal operations.&lt;/p&gt;

&lt;h3 id=&quot;asynchronous-wal-writing&quot;&gt;Asynchronous WAL Writing&lt;/h3&gt;

&lt;p&gt;Because the log must be persisted to disk before responding to an AppendEntries RPC, the WAL needs to be flushed to disk regularly, which can be expensive. Initially, writes were done every time a leader received a transaction from a client, or every time a follower received an AppendEntries RPC with one or more log entries. This proved prohibitively expensive, especially with multiple threads receiving transactions.&lt;/p&gt;

&lt;p&gt;A separate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WalWriterLoop&lt;/code&gt; thread solves this by batching records and performing one &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fsync&lt;/code&gt; per batch. This request to add a log entry to the WAL returns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::future&lt;/code&gt; that the Raft implementation waits on before responding to an AppendEntries RPC. When a leader receives a transaction from the client, it will add it to its log and then forward the transaction to followers immediately. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::future&lt;/code&gt; it receives from RaftRecovery will be waited on after forwarding. Logically, the transaction is only required to be persisted to disk before committing it. Instead, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::future&lt;/code&gt; is checked after the messages have been sent to the ReplicaCommunicator, which is sufficient to hide the latency from the required disk I/O.&lt;/p&gt;

&lt;h3 id=&quot;fast-log-backtracking&quot;&gt;Fast Log Backtracking&lt;/h3&gt;

&lt;p&gt;If a follower cannot accept a leader’s AppendEntries RPC, one option is for the leader to decrement its index one entry at a time and try again. Unfortunately, this is impractical with pipelining, since the point where a message was dropped or received out of order may be many thousands of log entries back during periods of high bandwidth. To address this, the Raft paper describes an optional optimization that lets the leader and follower back up one term at a time instead of one entry at a time, allowing for much faster backtracking to the correct log index at which to resume replication. This accelerated log backtracking, while not very well specified in the original Raft paper, can be found in more detail in &lt;a href=&quot;https://thesquareplanet.com/blog/students-guide-to-raft/#an-aside-on-optimizations&quot;&gt;Jon Gjengset’s Students’ Guide to Raft&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Raft, when a leader sends an AppendEntries RPC, it includes the index and term of the entry directly preceding the first log entry sent in the RPC. For example, if the log only contains entries from term 1, when the leader sends entries beginning at index 6, the previous log index is 5, and the previous log term is 1. If the follower contains an entry at that index at that term, it is guaranteed the follower’s log is identical to the leader’s up until that point.&lt;/p&gt;

&lt;p&gt;If the follower’s log contains an entry at that index from a different term, the follower must reject that message and reply with the first log index of that term (the one in its log). For example, say that a follower’s log only contains entries from term 1, and it receives an AppendEntries RPC with a previous log index of 5 and previous log term of 2. At index 5 in the follower’s log, the follower has a conflicting term of 1. So, it will reverse through its log and return the first index from the conflicting term, which is index 1. If the leader’s log does not contain any entries from the conflicting term, it will begin sending entries at the conflicting index. If the leader’s log does have entries with that conflicting term, the leader will begin sending entries at the index after the last entry in its log that matches the conflicting term.&lt;/p&gt;

&lt;p&gt;If the follower’s log is simply too short, then it can return the conflicting index as the length of its log, and the leader can try to continue from there. This will either lead to successful replication or one of the previous cases with a conflicting term.&lt;/p&gt;

&lt;h3 id=&quot;performance-manager-changes&quot;&gt;Performance Manager Changes&lt;/h3&gt;

&lt;p&gt;Additionally, changes were made to the client’s PerformanceManager to allow multiple threads to generate transactions for the consensus cluster. This is not a change to the Raft implementation itself, but part of the benchmarking infrastructure within ResilientDB. While benchmarking the Raft implementation, one client using one thread did not generate enough transactions to saturate bandwidth. Previously, multiple threads could be created to send out transactions, but generating them was still done by only one thread. Additionally, a semaphore class was added to prevent the threads generating transactions from getting too far ahead of the threads sending them out.&lt;/p&gt;

&lt;h1 id=&quot;evaluation&quot;&gt;Evaluation&lt;/h1&gt;

&lt;p&gt;The evaluation was performed remotely on CloudLab using four d430 machines for the Raft nodes. These computers have an Intel Xeon Processor E5-2630v3 2.4 GHz CPU, and 64 GB RAM. Experiments were run for 120 seconds. For all experiments, 3 runs were done, and the average throughput and average latency were recorded for each run. Only the run with the median average throughput was used. In these experiments, the client computer requests transactions to be added to the database, and the leader responds to the client once a transaction has been committed to being executed. For the evaluation, no leader elections occurred. The following config file was used for these runs, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_process_txn&lt;/code&gt; being varied across the different runs:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;client_batch_num&quot;: 100,
  &quot;enable_viewchange&quot;: false,
  &quot;recovery_enabled&quot;: false,
  &quot;not_need_signature&quot;: true,
  &quot;max_client_complaint_num&quot;: 10,
  &quot;max_process_txn&quot;: 2048,
  &quot;worker_num&quot;: 8,
  &quot;input_worker_num&quot;: 5,
  &quot;output_worker_num&quot;: 5,
  &quot;recovery_ckpt_time_s&quot;: 60,
  &quot;min_client_receive_num&quot;: 1,
  &quot;raft_follower_batch_timeout_ms&quot;: 0
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that in the following tables, the in-flight Transaction limit (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_process_txn&lt;/code&gt; in the config file) is different from the discussion on in-flight messages previously. The previous limit was on the number of unacknowledged messages sent from a &lt;strong&gt;leader&lt;/strong&gt; to a &lt;strong&gt;follower&lt;/strong&gt;. This in-flight limit is on the number of unacknowledged messages, each message being a batch of 100 transactions, from a &lt;strong&gt;client&lt;/strong&gt; to the Raft cluster. This second type of in-flight limit is to prevent the client from overwhelming the Raft cluster.&lt;/p&gt;

&lt;h2 id=&quot;comparison-vs-hotstuff-1&quot;&gt;Comparison vs HotStuff-1&lt;/h2&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;td align=&quot;center&quot;&gt;
      &lt;img src=&quot;/assets/images/raft/ThroughputByMaxInFlight.png&quot; alt=&quot;Throughput vs. Maximum In-Flight Transactions&quot; /&gt;
      &lt;br /&gt;
      &lt;em&gt;(a) Throughput vs. maximum in-flight transactions&lt;/em&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align=&quot;center&quot;&gt;
      &lt;img src=&quot;/assets/images/raft/LatencyByMaxInFlight.png&quot; alt=&quot;Latency by Maximum In-Flight Transactions&quot; /&gt;
      &lt;br /&gt;
      &lt;em&gt;(b) Latency vs. maximum in-flight transactions&lt;/em&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td align=&quot;center&quot;&gt;
      &lt;img src=&quot;/assets/images/raft/ThroughputByLatency.png&quot; alt=&quot;Throughput by Latency&quot; /&gt;
      &lt;br /&gt;
      &lt;em&gt;(c) Throughput vs. latency&lt;/em&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;em&gt;Figure 6. Performance evaluation of the Raft implementation.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;Here, we can see that Raft appears to reach its saturation point around 2,048 maximum in-flight transactions. At this point, the bandwidth of the Raft cluster is fully saturated. As the number of transactions in the system increases, latency increases dramatically, and throughput drops.&lt;/p&gt;

&lt;p&gt;Comparisons were run against HotStuff-1, another BFT protocol available in ResilientDB. Setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recovery_enabled&lt;/code&gt; set to false disables writing the WAL and metadata to stable storage, as well as snapshotting. As a result, the prefix of the log is not truncated. The choices to use 4 nodes and no recovery (no WAL, no storing of metadata) were made to compare to HotStuff-1, which requires a minimum of 4 nodes, and also operates fully in memory. Both protocols have their own saturation point due to their own bottlenecks. &lt;a href=&quot;#table-raft-hotstuff&quot;&gt;Table 1&lt;/a&gt; shows that, when bandwidth is fully saturated for both protocols, Raft achieves almost 6x higher throughput with just over 9x better latency.&lt;/p&gt;

&lt;table id=&quot;table-raft-hotstuff&quot; style=&quot;margin-left:auto; margin-right:auto; width:fit-content;&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Metric&lt;/th&gt;
    &lt;th&gt;Raft&lt;/th&gt;
    &lt;th&gt;HotStuff-1&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Maximum in-flight transactions from client&lt;/td&gt;
    &lt;td&gt;2048&lt;/td&gt;
    &lt;td&gt;3&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Average throughput (transactions/second)&lt;/td&gt;
    &lt;td&gt;588,596&lt;/td&gt;
    &lt;td&gt;104,080&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Average latency (ms)&lt;/td&gt;
    &lt;td&gt;0.288&lt;/td&gt;
    &lt;td&gt;2.611&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;em&gt;Table 1. Comparison between Raft and HotStuff-1 at their saturation point&lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;effect-of-persistence&quot;&gt;Effect of Persistence&lt;/h2&gt;

&lt;table id=&quot;figure-7&quot;&gt;
  &lt;tr&gt;
    &lt;td align=&quot;center&quot;&gt;
      &lt;img src=&quot;/assets/images/raft/RecoveryThroughputVsLatency.png&quot; alt=&quot;RecoveryGraph&quot; /&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;em&gt;Figure 7. Raft evaluation with Snapshotting and Persistence enabled.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;However, even with recovery enabled, Raft achieves nearly identical throughput and latency for values of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_process_txn&lt;/code&gt; around the saturation point. While this extra bookkeeping does have some overhead, the current settings do not fully utilize the available CPU threads, and the batching of WAL writes has minimized the effect of this overhead.&lt;/p&gt;

&lt;h2 id=&quot;scalability&quot;&gt;Scalability&lt;/h2&gt;
&lt;table id=&quot;figure-8&quot;&gt;
  &lt;tr&gt;
    &lt;td align=&quot;center&quot;&gt;
      &lt;img src=&quot;/assets/images/raft/Scalability.png&quot; alt=&quot;Scalability&quot; /&gt;
    &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;em&gt;Figure 8. Raft Scalability with different numbers of replicas (n).&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;#figure-8&quot;&gt;Figure 8&lt;/a&gt; illustrates the impact that the number of replicas has on the performance of Raft. An increase in the number of replicas leads to an increase in latency and an overall decrease in throughput. In Raft, the latency is generally bottlenecked by the leader. The leader needs to forward all transactions, and keep track of when quorum is reached for each transaction. This work grows linearly with respect to the number of replicas. However, there is also a constant component of the work that runs concurrently with the previous work, like disk I/O and network round-trip time. Since the system is saturated with client transactions, throughput decreases as latency increases. This causes the shape of the curve to be flatter at lower replica counts and steeper as the number of replicas increases.&lt;/p&gt;

&lt;h2 id=&quot;commands-to-execute&quot;&gt;Commands to Execute&lt;/h2&gt;
&lt;p&gt;Here are the commands to download ResilientDB and prepare all requirements:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt update&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt install git psmisc&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git clone https://github.com/apache/incubator-resilientdb.git&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd incubator-resilientdb/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./INSTALL.sh&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./service/tools/kv/server_tools/start_kv_service.sh&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bazel build service/tools/kv/api_tools/kv_service_tools&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd scripts/deploy/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;touch config/key.conf&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To run the Raft performance script locally on only a single machine, use:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./performance_local/raft_performance.sh config/kv_performance_server_local.conf&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To run the evaluation remotely, several changes will need to be made:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Make sure the machine you are running the performance evaluation script on is able to connect via ssh key to the remote machines.&lt;/li&gt;
  &lt;li&gt;Change the contents of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/config/key.conf&lt;/code&gt; to point to the directory of the ssh key on the machine running the performance evaluation script, as shown in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/config/key_example.conf&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;(Optional) Change the existing file in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/config/raft.config&lt;/code&gt; to match the desired config, or pass the separate config file as the second argument to raft_performance.sh&lt;/li&gt;
  &lt;li&gt;Change the IP addresses in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/config/kv_performance_server.conf&lt;/code&gt; to the IP addresses of the remote machines.&lt;/li&gt;
  &lt;li&gt;Change the user and home directory in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/script/env.sh&lt;/code&gt; to match the user and home directory on all of the machines you will ssh into.&lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/&lt;/code&gt;, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./performance/raft_performance.sh config/kv_performance_server.conf &amp;lt;optional_config_file&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This script will build the needed binaries on the current machine and scp them to the other machines, so no setup should be needed on them.&lt;/p&gt;

&lt;p&gt;In order to view more detailed log information, the following steps can be taken:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;(Optional) If you would like to examine the individual log files, go to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/performance/run_performance.sh&lt;/code&gt; and uncomment the line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#rm -rf result_*_log&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;(Optional) If you would like to see the more verbose VLOG lines, on the line where the server binary is actually run underneath the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;# Start server&lt;/code&gt; comment in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/script/deploy.sh&lt;/code&gt;, change &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./${server_bin} server.config&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./${server_bin} --v=3 server.config&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want to view detailed log information for the local version, instead modify the files &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/performance_local/run_performance.sh&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripts/deploy/script/deploy_local.sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Raft and RaftRecovery tests can be run with:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bazel test //platform/consensus/ordering/raft/algorithm:all --test_timeout=20&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bazel test //platform/consensus/recovery:raft_recovery_test --test_timeout=60&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Raft is a well-known and well-tested consensus algorithm used in many real-world applications. While the specification for Raft does describe the protocol, many implementation details are left to the reader. This is especially true for an implementation that integrates with a large existing codebase while maintaining compatibility and sharing code with other consensus protocols. On top of needing to ensure correctness, engineering and design effort had to be put in for several different components. Decisions had to be made to decide how to share RecoveryBase code with PBFT, to minimize lock contention in a multi-threaded environment through techniques like batching the WAL writes, and to add extra tracking of individual follower state to allow for more effective usage of pipelining AppendEntries RPCs.&lt;/p&gt;

&lt;p&gt;Now, ResilientDB contains a CFT protocol with a different trust model than the BFT protocols. When the situation calls for a protocol where all involved computers can be trusted, this allows for better asymptotic complexity for messages sent as well as no need for cryptographic signatures. However, there is still work to be done for the Raft implementation.&lt;/p&gt;

&lt;h2 id=&quot;future-work&quot;&gt;Future Work&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Further Throughput Improvements&lt;/strong&gt;: When runs are done past Raft’s saturation point at 2,048 maximum in-flight transactions, the latency spikes as expected, but throughput goes down. One plausible explanation for this is that once a leader’s capacity to receive more transactions from the client is full, the buffer holding these transactions before they get added to the log becomes overwhelmed and degrades performance. It is future work to investigate this in more detail.&lt;/p&gt;

    &lt;p&gt;Additionally, others have implemented optimizations to increase Raft throughput in various scenarios, such as &lt;a href=&quot;https://tikv.org/deep-dive/scalability/multi-raft/&quot;&gt;Multi-Raft&lt;/a&gt; or &lt;a href=&quot;https://arxiv.org/abs/2506.17793v1&quot;&gt;Fast Raft&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Membership Changes&lt;/strong&gt;: Enable the safe addition or removal of servers from the cluster dynamically, without shutting down the system or halting operations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Read-Only Operations&lt;/strong&gt;: Allow read-only operations without writing anything to the log. Some groundwork has already been laid by having leaders commit a blank NO-OP entry at the start of their term, as described in the Raft paper, which is a step toward this.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;/h3&gt;

&lt;p&gt;The initial development of the Raft implementation was accomplished through the combined effort of five ResilientDB community members: Josh Hutton, Jim Brower, Nachiket Subbaraman, Vinoth Gopikrishnan, and Yuhua Huang. The engineering effort described in &lt;a href=&quot;#initial-raft-implementation&quot;&gt;Initial Raft Implementation&lt;/a&gt; contains work done by the group. Additionally, initial versions of the written sections in &lt;a href=&quot;#background&quot;&gt;Background&lt;/a&gt; and &lt;a href=&quot;#initial-raft-implementation&quot;&gt;Initial Raft Implementation&lt;/a&gt; were created by the group. The second section, &lt;a href=&quot;#follow-up-raft-improvements&quot;&gt;Follow-up Raft Improvements&lt;/a&gt;, and the &lt;a href=&quot;#evaluation&quot;&gt;Evaluation&lt;/a&gt; document the additional work Josh Hutton completed individually afterward.&lt;/p&gt;

&lt;h1 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h1&gt;

&lt;p&gt;S. Gilbert and N. Lynch, “Brewer’s conjecture and the feasibility of consistent, available, partition-tolerant web services,” SIGACT News, vol. 33, no. 2, pp. 51–59, Jun. 2002, doi: 10.1145/564585.564601.&lt;/p&gt;

&lt;p&gt;etcd-io/raft. Go. etcd-io. [Online]. Available: &lt;a href=&quot;https://github.com/etcd-io/raft&quot;&gt;https://github.com/etcd-io/raft&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A. Melnychuk and B. SebaRaj, “Implementation and Evaluation of Fast Raft for Hierarchical Consensus,” Jun. 21, 2025, arXiv: arXiv:2506.17793. doi: 10.48550/arXiv.2506.17793.&lt;/p&gt;

&lt;p&gt;D. Ongaro and J. Ousterhout, “In search of an understandable consensus algorithm,” in Proceedings of the 2014 USENIX conference on USENIX Annual Technical Conference. USA: USENIX Association, Jun. 2014, pp. 305–320.&lt;/p&gt;

&lt;p&gt;“Multi-raft.” [Online]. Available: &lt;a href=&quot;https://tikv.org/deep-dive/scalability/multi-raft/&quot;&gt;https://tikv.org/deep-dive/scalability/multi-raft/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;J. Gjengset &lt;a href=&quot;mailto:jon@thesquareplanet.com&quot;&gt;jon@thesquareplanet.com&lt;/a&gt;, “Students’ Guide to Raft.” [Online]. Available: &lt;a href=&quot;https://thesquareplanet.com/blog/students-guide-to-raft/&quot;&gt;https://thesquareplanet.com/blog/students-guide-to-raft/&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 26 Aug 2026 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2026/08/26/RaftProtocol.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2026/08/26/RaftProtocol.html</guid>
      </item>
    
      <item>
        <title>The World’s First Blockchain-Backed Drawing App? Introducing ResCanvas.</title>
        <description>&lt;h1 id=&quot;the-existing-problem&quot;&gt;The Existing Problem&lt;/h1&gt;
&lt;p&gt;Drawing is an important aspect of art and free expression within a variety of domains to express new ideas and valuable works of creativity. Tools such as MS Paint allow for drawing to be achievable on the computer, with online tools extending that functionality over the cloud where users can share and collaborate on drawings and other digital works of art. Both Google’s Drawing and Canva’s Draw application have a sharable canvas page where registered users can draw, and Figma has also been quite popular due to its wide array of features and ease of use.&lt;/p&gt;

&lt;p&gt;As you can see, drawing tools are everywhere, from quick doodle apps running on your computer to full fledged cloud design suites hosted over the cloud. &lt;strong&gt;But beneath the convenience lies a hidden cost: centralization.&lt;/strong&gt; When you draw on a typical web platform, your work and your identity, are stored on a server you don’t control. Your art can be censored, your actions monitored, your data analyzed or sold.&lt;/p&gt;

&lt;p&gt;At the same time, creativity has never been more collaborative. Artists sketch together, communities brainstorm visually, and teams rely on whiteboards to communicate ideas.&lt;/p&gt;

&lt;p&gt;But existing online platforms store the drawing and user data centrally, making personal data easily trackable by their respective companies, and easily sharable to other third parties such as advertisers. The drawings can be censored by both private and public entities, including government agencies. Privacy is important, yet online collaboration is an essential part of many user’s daily workflow.&lt;/p&gt;

&lt;p&gt;Even the famous Reddit &lt;em&gt;r/place&lt;/em&gt; board, while being massively collaborative as a pixel based canvas, relies on fully centralized state and exposes all user activity to the platform.&lt;/p&gt;

&lt;p&gt;Creativity thrives only when ideas can be freely expressed. But freedom requires autonomy, and autonomy requires decentralization.&lt;/p&gt;

&lt;p&gt;So we asked a simple question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why can’t collaborative creativity be both expressive and decentralized?&lt;/strong&gt;&lt;/p&gt;

&lt;h1 id=&quot;our-solution-rescanvas&quot;&gt;Our Solution: ResCanvas&lt;/h1&gt;
&lt;p&gt;That question led to ResCanvas - a fully decentralized, real-time drawing platform powered by ResilientDB, a high performance blockchain database engineered for trust on a global scale. The canvas drawing board is the core feature of ResCanvas, designed to allow users to perform drawings all while being censorship resistant. It is simple to use, yet it allows for infinite possibilities. &lt;strong&gt;To our knowledge, ResCanvas is the world’s first drawing and creativity platform that combines the key breakthroughs in database decentralization brought forth by a blockchain based database, ResilientDB, with the power of expression that comes with art, bridging the gap between the arts and the sciences.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ResCanvas is designed to seamlessly integrate drawings with the familiarity of online contribution between users using effective synchronization of each user’s canvas drawing page. This allows for error-free consistency even when multiple users are drawing all at the same time.&lt;/p&gt;

&lt;p&gt;Multiple users are able to collaborate on a single canvas, and just as many things in life have strength in numbers, so too are the users on a canvas. One user could be working on one key part of a drawing while other users can finish the remaining parts in a collaborative manner.&lt;/p&gt;

&lt;p&gt;The key feature of ResCanvas is defined by having all drawings stored persistently within ResilientDB in a stroke by stroke manner. Each stroke is individually cached via in-memory data store using Redis serving as the frontend cache, hosted on a trusted node of your choice. This ensures that the end user is able to receive all the strokes from the other users regardless of the response latency of ResilientDB, which greatly enhances performance for the end user.&lt;/p&gt;

&lt;p&gt;In essence, all users will see each other’s strokes under a decentralized context and without any reliance on a centralized server for processing requests and storing data.&lt;/p&gt;

&lt;p&gt;ResCanvas works seamlessly, with the familiarity of the drawing tools you already use, without the issues of surveillance, control, or central ownership.&lt;/p&gt;

&lt;h2 id=&quot;detailed-architecture-and-concepts&quot;&gt;Detailed Architecture and Concepts&lt;/h2&gt;
&lt;p&gt;To turn decentralized creativity into a reality, our application consists of several major components.&lt;/p&gt;

&lt;p&gt;The first one is the &lt;strong&gt;frontend (React)&lt;/strong&gt;, which handles drawing input, local smoothing/coalescing of strokes, UI state (tools, color, thickness), optimistic local rendering, and Socket.IO for real-time updates. Thus the frontend handles the user facing side of ResCanvas and ensures a smooth UX while ensuring communication between this frontend layer and the backend. This layer also handles the storage of auth tokens in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localStorage&lt;/code&gt; and its API wrappers (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;frontend/src/api/&lt;/code&gt;) automatically attach JWT access tokens to all protected requests as well. The most important aspect of this layer in terms of security is that the frontend does not perform authentication or authorization logic, since it simply presents credentials and tokens to the backend.&lt;/p&gt;

&lt;p&gt;This brings us to the &lt;strong&gt;backend (Flask + Flask-SocketIO)&lt;/strong&gt;, which serves as the authoritative security boundary and data handler for the application. The backend validates all JWT tokens server-side using middleware, enforces room membership and permissions, verifies client-side signatures for secure rooms, encrypts/decrypts strokes for private/secure rooms, commits transactions to ResilientDB via GraphQL, and also retrieves data as needed according to the frontend’s request. All protected API routes and Socket.IO connections require valid JWT access tokens sent via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; header. Since the backend performs all security checks, clients cannot bypass authentication or authorization and must go through the backend for all sensitive requests. Furthermore, when working with private or secure rooms, the backend handles encryption/decryption and room key management as well.&lt;/p&gt;

&lt;p&gt;Going into deeper detail with regards to the backend, it interacts with several other key components.&lt;/p&gt;

&lt;p&gt;The first one is &lt;strong&gt;ResilientDB&lt;/strong&gt;, the persistent, decentralized, immutable transaction log where strokes are ultimately stored, and the core essence of this application. Strokes are written as transactions so the full history is auditable and censorship-resistant. Through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resilient-python-cache&lt;/code&gt; library, ResilientDB synchronizes data blocks with &lt;strong&gt;MongoDB (canvasCache)&lt;/strong&gt;. MongoDB is a warm persistent cache and queryable replica of strokes so the backend can serve reads without contacting ResilientDB directly for every request, and can be hosted on any node that users trust. This essentially serves as a secure sync bridge that mirrors ResilientDB into MongoDB.&lt;/p&gt;

&lt;p&gt;From MongoDB, our backend handles the syncronization of data with &lt;strong&gt;Redis&lt;/strong&gt;, which is a short-lived, in-memory store keyed by room for fast read/write and undo/redo operations. Redis is intentionally ephemeral as it allows quick synchronization of live sessions while ResilientDB acts as the long-term durable store. Just like MongoDB, this Redis cache can be hosted by any trusted node, and thus ensures that security and privacy guarantees of ResilientDB are still preserved while ensuring fast performance. It can be said that our backend is also another sync bridge layer, that of between MongoDB and Redis.&lt;/p&gt;

&lt;h3 id=&quot;data-model-and-stroke-format&quot;&gt;Data Model and Stroke Format&lt;/h3&gt;
&lt;p&gt;ResCanvas uses a simple, compact stroke model that is end-to-end friendly for network transport and decentralized commits. A typical base stroke data payload (JSON) contains the following data:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;drawingId: unique per-user or per-drawing session&lt;/li&gt;
  &lt;li&gt;userId: author id (when available/allowed)&lt;/li&gt;
  &lt;li&gt;color: hex or named value&lt;/li&gt;
  &lt;li&gt;lineWidth: numeric stroke thickness&lt;/li&gt;
  &lt;li&gt;pathData: an array of (x,y) points, optionally compressed (delta-encoded)&lt;/li&gt;
  &lt;li&gt;timestamp: client-side timestamp for ordering and replay&lt;/li&gt;
  &lt;li&gt;metadata: optional fields for signing, encryption info, transform/offsets, custom brush styles, .etc&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;undoredo-and-edit-history&quot;&gt;Undo/Redo and Edit History&lt;/h3&gt;
&lt;p&gt;Despite the decentralized, blockchain backed nature of ResCanvas, users can still leverage the functionality they know and love, including undoing and redoing operations. Undo/redo is implemented through per-room, per-user stacks stored in Redis. Each user action that mutates the canvas pushes an entry to the user’s undo stack and updates the live room state in Redis. Redo pops from a redo stack and applies the strokes again via the same commit flow (including related signing and encryption rules).&lt;/p&gt;

&lt;p&gt;Because ResilientDB is immutable, undo/redo on the client is implemented as additional strokes that semantically represent an “undo” (for example, through a delta or a tombstone stroke) by using a separate metadata layer that signals removal in replay. The visible client behavior is immediate, while the authoritative history in ResilientDB preserves the full append only log.&lt;/p&gt;

&lt;h3 id=&quot;consistency-concurrency-and-ordering&quot;&gt;Consistency, Concurrency and Ordering&lt;/h3&gt;
&lt;p&gt;Multiple users can draw simultaneously since the system is designed for eventual consistency with low-latency broadcast, where each stroke is broadcast immediately via Socket.IO to all connected room participants. This allows the application to provide near real-time feedback. The backend attempts to persist strokes to ResilientDB and caches (Redis/MongoDB). If ResilientDB write is delayed, clients still see strokes from the Socket.IO broadcast and from Redis while waiting for the backend to finishing writing the stroke data.&lt;/p&gt;

&lt;p&gt;Ordering is primarily guided by timestamps and the sequence of commits in ResilientDB. When replaying history, the authoritative order comes from the ResilientDB transaction log so all data and their ordering is preserved even if the canvas itself is cleared, strokes are undone, or even if the entire canvas room is deleted by the user.&lt;/p&gt;

&lt;h3 id=&quot;resilientdb-theory&quot;&gt;ResilientDB Theory&lt;/h3&gt;
&lt;p&gt;ResilientDB is used as an immutable, decentralized transaction log. There are several key properties that we rely on.&lt;/p&gt;

&lt;p&gt;The first one is that of &lt;strong&gt;immutability&lt;/strong&gt;, where once a stroke is committed, it cannot be altered silently. This increases trust and accountability. The second one is &lt;strong&gt;decentralization&lt;/strong&gt;, since no single host controls the persistent copy of strokes, reducing censorship and central data harvesting. The third key property that we rely on is &lt;strong&gt;auditability&lt;/strong&gt; as the entire canvas history can be inspected and verified against the ResilientDB ledger. This ensures transparency as anyone can view and verify the user’s drawing history and actions taken on the application, and serves as a key deterrent against malicious activity on the canvas.&lt;/p&gt;

&lt;p&gt;By treating each stroke as a transaction, we now achieve a chronological, tamper-evident history of canvas changes. Anyone can verify and review the changes to the canvas as the ground truth source of information. The sync bridge mirrors transactions into MongoDB so read queries don’t need to hit ResilientDB for every request, while Redis caching further enhances the performance from the UX standpoint by caching the data from MongoDB on an in-memory basis within a trusted node. Removal operations such as undo and redo, as well as clear canvas/room deletions are simulated using time stamp markers to achieve the same effects without altering the historical backend data as well.&lt;/p&gt;

&lt;p&gt;This hierarchical relationship between ResilientDB, MongoDB, and Redis essentially serves as an unique balance between user experience, security, and privacy.&lt;/p&gt;

&lt;h3 id=&quot;public-rooms-vs-private-rooms-vs-secure-rooms&quot;&gt;Public Rooms vs Private Rooms vs Secure Rooms&lt;/h3&gt;
&lt;p&gt;In ResCanvas, options are provided to meet the diverse needs of users. One way we achieve this is through the three different types of canvas rooms that users can create.&lt;/p&gt;

&lt;p&gt;The first kind is &lt;strong&gt;public rooms&lt;/strong&gt;, which allow anyone to access and draw in them, and so all the data is publically accessible by all registered users without needing to perform decryption and obtaining an access key to the room.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;private rooms&lt;/strong&gt;, access is restricted as only invited users or those with the room key can join such rooms. Strokes are encrypted so only members with the room key can decrypt and access them. The backend participates in wrapping/unwrapping room keys using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ROOM_MASTER_KEY_B64&lt;/code&gt;. This allows users who want additional privacy while drawing contents containing sensitive or personal information to be able to do so without the risk of exposing all their raw drawings to the general public.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secure rooms&lt;/strong&gt; go further and expand upon the protections of private rooms by requiring client-side signing of strokes with a cryptographic wallet (such as &lt;a href=&quot;https://chromewebstore.google.com/detail/resvault/ejlihnefafcgfajaomeeogdhdhhajamf?pli=1&quot;&gt;ResVault&lt;/a&gt;). Each stroke is signed by the user’s wallet private key and the signature is stored with the stroke. This enables verifiable authorship since anyone can confirm a stroke was created by the owner of a given wallet address.&lt;/p&gt;

&lt;h4 id=&quot;putting-cryptographic-signatures-into-use-secure-rooms-work-as-follows-assuming-resvault-is-used&quot;&gt;Putting cryptographic signatures into use, secure rooms work as follows (assuming ResVault is used):&lt;/h4&gt;
&lt;ol&gt;
  &lt;li&gt;User connects cryptographic wallet via the frontend UI and grants signing permissions.&lt;/li&gt;
  &lt;li&gt;When drawing in a secure room, the frontend prepares the stroke payload and asks ResVault to sign the serialized stroke or a deterministic hash of it.&lt;/li&gt;
  &lt;li&gt;The signed payload (signature + public key or address) is sent to the backend along with the stroke.&lt;/li&gt;
  &lt;li&gt;The backend verifies the signature before accepting and committing the stroke to persistent storage.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;security-privacy-and-threat-model&quot;&gt;Security, Privacy and Threat Model&lt;/h2&gt;
&lt;p&gt;ResCanvas aims to improve user privacy and resist centralized censorship, and so we mitigated several threats in our application.&lt;/p&gt;

&lt;p&gt;One of the most significant threats that many web based applications face today is the danger of &lt;strong&gt;central server compromise&lt;/strong&gt;, since many existing applications are based on a centralized sever and store important data there. However, in ResCanvas, persistent data is stored on ResilientDB and mirrored to MongoDB, which reduces a single point of failure due to the decentralized nature of ResilientDB.&lt;/p&gt;

&lt;p&gt;We also prevent &lt;strong&gt;data harvesting by a platform operator&lt;/strong&gt; from occurring in the first place as decentralized storage and client-side signing for secure rooms reduce linkability and provide verifiability. This ensures that user’s data is not being collected for third party usage, for instance, which could result in data being leveraged for commercial purposes and malicious intent. This assurance in user’s data security is also guaranteed through our prevention of &lt;strong&gt;client-side authentication bypasses&lt;/strong&gt;. All authentication, authorization, and access control logic runs server-side, rather on the client’s front end. The backend middleware validates tokens, checks permissions, and enforces room access rules. Even the most malicious of clients cannot manipulate or circumvent security checks because of this middleware.&lt;/p&gt;

&lt;p&gt;Other security protections that ResCanvas offers includes handling the situation where there could be &lt;strong&gt;token theft via XSS&lt;/strong&gt;. We manage this risk by having refresh tokens be stored in HttpOnly cookies that cannot be accessed by JavaScript, protecting long-lived sessions from cross-site scripting attacks. Additionally, we prevent &lt;strong&gt;CSRF attacks&lt;/strong&gt; by having refresh cookies use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SameSite&lt;/code&gt; attribute. Using this kind of attribute prevents cross-site request forgery from occurring. We also prevent &lt;strong&gt;signature forgery&lt;/strong&gt; for secure rooms since the backend verifies cryptographic signatures server-side. This protection ensures that strokes cannot be attributed to users who didn’t create them in the first place.&lt;/p&gt;

&lt;p&gt;Despite these significant protections that ResCanvas offers, there are several key trade-offs and assumptions that are worth mentioning.&lt;/p&gt;

&lt;p&gt;For instance, there is still a risk that the application can suffer from &lt;strong&gt;frontend device compromise&lt;/strong&gt;. While the backend enforces all security decisions, if a user’s device or browser is compromised, attackers could steal access tokens from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localStorage&lt;/code&gt; or wallet keys before signing. So access tokens are short-lived (15 minutes by default) to minimize exposure and refresh tokens in HttpOnly cookies are protected from JavaScript access.&lt;/p&gt;

&lt;p&gt;The core functionality of ResCanvas also depends on the &lt;strong&gt;availability of ResilientDB&lt;/strong&gt;. ResilientDB endpoints and GraphQL commit endpoints used by the backend must remain available and trusted by backend operators. If those services are compromised, ledger inclusion or availability may be affected. However, the probability of this occurring is extremely low due to the decentralized, blockchain nature of ResilientDB.&lt;/p&gt;

&lt;p&gt;Furthermore, certain backend layers and services, such as Redis and MongoDB, rely on the user’s level of &lt;strong&gt;backend trust&lt;/strong&gt;. Users must trust the backend operators to correctly implement and enforce security policies, and also ensure that those backend layers and services are running on trusted nodes. Having nodes that are trustworthy to the user is essential as the backend has access to certain data such as unencrypted strokes for public rooms.&lt;/p&gt;

&lt;h2 id=&quot;frontend-design-and-user-experience&quot;&gt;Frontend Design and User Experience&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/rescanvas/frontend_demo.png&quot; alt=&quot;Image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;While ResCanvas is powered by a decentralized backend architecture, the user experience is intentionally designed to feel &lt;strong&gt;familiar and approachable&lt;/strong&gt;. The frontend serves as the main interaction layer between users and the underlying ResilientDB-powered system. Instead of exposing users directly to blockchain transactions, caching layers, or synchronization logic, the interface presents ResCanvas as a clean collaborative drawing workspace.&lt;/p&gt;

&lt;p&gt;The ResCanvas frontend is organized around a &lt;strong&gt;canvas-first layout&lt;/strong&gt;. The central canvas workspace occupies the majority of the screen so that drawing remains the primary user activity. This design choice helps users focus on creative expression while keeping supporting controls available around the workspace. Drawing input is captured directly from the canvas area and converted into structured stroke data that can later be submitted to the backend, cached, synchronized, and persisted through the system.&lt;/p&gt;

&lt;p&gt;On the left side of the interface, ResCanvas provides a &lt;strong&gt;compact vertical toolbar&lt;/strong&gt; for drawing controls and canvas operations. This toolbar maintains important UI state such as the selected tool, brush size, and color. It also exposes drawing-related actions such as tool selection, undo/redo operations, and other canvas controls. By keeping these controls compact and visually separated from the main drawing area, the interface reduces clutter and preserves more usable space for the canvas itself.&lt;/p&gt;

&lt;p&gt;At the top of the interface, the application displays &lt;strong&gt;navigation and user context&lt;/strong&gt;. The breadcrumb-style room information helps users understand which canvas room they are currently working in, while the account area fetches and displays user information after login or registration. This connects the authentication flow with the main drawing experience and gives users a clear sense of where they are inside the application.&lt;/p&gt;

&lt;p&gt;On the right side, the interface includes a &lt;strong&gt;drawing history panel&lt;/strong&gt;. This panel helps surface the historical nature of ResCanvas by showing previous drawing activity associated with the current room. While the backend and ResilientDB preserve the deeper operation history, the frontend presents this concept in a way that users can understand visually. This supports one of the core ideas of ResCanvas: the canvas is not just a final image, but an evolving history of user contributions.&lt;/p&gt;

&lt;p&gt;The bottom navigation bar connects ResCanvas to broader &lt;strong&gt;project resources&lt;/strong&gt;, including help pages, blog content, metrics, analytics, benchmark dashboards, and overview statistics. These links help present ResCanvas as a more complete application rather than a standalone drawing prototype. They also make it easier for users, developers, and evaluators to explore the surrounding ResilientDB ecosystem.&lt;/p&gt;

&lt;p&gt;Overall, the frontend design bridges the gap between a technically complex decentralized backend and a simple user-facing drawing experience. Users interact with familiar concepts such as a canvas, toolbar, room navigation, drawing history, and account controls, while the system behind the interface handles authentication, real-time synchronization, caching, persistent storage, and blockchain-backed operation history.&lt;/p&gt;

&lt;h1 id=&quot;rescanvas-setup-guide&quot;&gt;ResCanvas Setup Guide&lt;/h1&gt;
&lt;p&gt;Want to deploy and run ResCanvas locally right on your own machine? This guide provides complete instructions to deploy ResCanvas locally, including setup for the cache layer, backend, and frontend.&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Before starting, ensure the following dependencies are installed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; ≥ 3.10 and ≤ 3.12&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Node.js&lt;/strong&gt; (LTS version via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nvm install --lts&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;npm&lt;/strong&gt; (latest version)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MongoDB Atlas&lt;/strong&gt; account with a working connection URI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;step-0-mongodb-account-setup&quot;&gt;Step 0: MongoDB Account Setup&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Go to &lt;a href=&quot;https://account.mongodb.com/account/login&quot;&gt;https://account.mongodb.com/account/login&lt;/a&gt; and &lt;strong&gt;log in or register&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Create a &lt;strong&gt;project&lt;/strong&gt; and &lt;strong&gt;cluster&lt;/strong&gt; (if not already existing).&lt;/li&gt;
  &lt;li&gt;Within your cluster, click &lt;strong&gt;Connect → Drivers&lt;/strong&gt; and copy the connection string from &lt;strong&gt;Step 3&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Keep this MongoDB connection URI handy. You will use it in later &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; files.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;step-1-clone-the-repository&quot;&gt;Step 1: Clone the Repository&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/ResilientApp/ResCanvas.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ResCanvas
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check your Python installation:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3 &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-2-resilient-python-cache-first-terminal-window&quot;&gt;Step 2: Resilient Python Cache (First Terminal Window)&lt;/h2&gt;

&lt;p&gt;This cache layer synchronizes strokes between MongoDB and ResilientDB.&lt;/p&gt;

&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;backend/incubator-resilientdb-resilient-python-cache/
pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;resilient-python-cache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file in this directory with the following content
(replace everything between brackets):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MONGO_URL = &quot;[URI_COPIED_FROM_MONGODB_CONNECTION]&quot;
MONGO_DB = &quot;canvasCache&quot;
MONGO_COLLECTION = &quot;strokes&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;start-the-cache-service&quot;&gt;Start the Cache Service&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3 example.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This starts a MongoDB caching service that syncs data with ResilientDB via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resilientdb://crow.resilientdb.com&lt;/code&gt; endpoint defined in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cache.py&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;step-3-backend-setup-second-terminal-window&quot;&gt;Step 3: Backend Setup (Second Terminal Window)&lt;/h2&gt;

&lt;p&gt;The backend handles authentication, REST APIs, and interfaces with ResilientDB.&lt;/p&gt;

&lt;h3 id=&quot;create-virtual-environment--install-dependencies&quot;&gt;Create Virtual Environment &amp;amp; Install Dependencies&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;backend/
python3 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; venv venv
&lt;span class=&quot;nb&quot;&gt;source &lt;/span&gt;venv/bin/activate
pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;generate-keys&quot;&gt;Generate Keys&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python gen_keys.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Copy the printed public and private keys.&lt;/p&gt;

&lt;h3 id=&quot;create-env-file&quot;&gt;Create .env File&lt;/h3&gt;

&lt;p&gt;Create a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; under the backend/ folder with the following contents
(replace values between brackets):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MONGO_ATLAS_URI=[URI_COPIED_FROM_MONGODB_CONNECTION]
SIGNER_PUBLIC_KEY=[PUBLIC_KEY_COPIED_FROM_GEN_KEYS_PY]
SIGNER_PRIVATE_KEY=[PRIVATE_KEY_COPIED_FROM_GEN_KEYS_PY]
RESILIENTDB_BASE_URI=https://crow.resilientdb.com
RESILIENTDB_GRAPHQL_URI=https://cloud.resilientdb.com/graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-4-redis-setup&quot;&gt;Step 4: Redis Setup&lt;/h2&gt;

&lt;p&gt;Redis is required for caching and backend operations.&lt;/p&gt;

&lt;h3 id=&quot;macos-homebrew&quot;&gt;macOS (Homebrew)&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;redis
brew services start redis
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ubuntu-apt&quot;&gt;Ubuntu (APT)&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; redis-server
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl restart redis.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;verify-redis&quot;&gt;Verify Redis&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;redis-cli ping
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Expected output: PONG&lt;/p&gt;

&lt;h3 id=&quot;optional-fix-bcrypt-error&quot;&gt;Optional Fix (bcrypt Error)&lt;/h3&gt;

&lt;p&gt;If you encounter bcrypt issues, run:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;passlib&amp;gt;=1.7.4&apos;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;bcrypt&amp;gt;=4.1.2,&amp;lt;5&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;start-the-backend&quot;&gt;Start the Backend&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python app.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;step-5-frontend-setup-third-terminal-window&quot;&gt;Step 5: Frontend Setup (Third Terminal Window)&lt;/h2&gt;

&lt;p&gt;The frontend provides the ResCanvas web UI.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;frontend/
nvm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--lts&lt;/span&gt;
nvm use &lt;span class=&quot;nt&quot;&gt;--lts&lt;/span&gt;
npm i &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; npm
npm &lt;span class=&quot;nb&quot;&gt;install
&lt;/span&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The app should now be running at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:[...]&lt;/code&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2026/06/05/ResCanvas.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2026/06/05/ResCanvas.html</guid>
      </item>
    
      <item>
        <title>ResTier: A Tiered Storage Engine for ResilientDB using IPFS</title>
        <description>&lt;h1 id=&quot;restier-a-tiered-storage-engine-with-ipfs-cold-storage-for-resilientdb&quot;&gt;ResTier: A Tiered Storage Engine with IPFS Cold Storage for ResilientDB&lt;/h1&gt;

&lt;p&gt;Exploratory Systems Lab
Jun 02, 2026&lt;/p&gt;

&lt;p&gt;ResTier is a tiered storage engine for ResilientDB that extends the permissioned blockchain fabric with hot/warm/cold storage tiers, using IPFS as a scalable cold-storage backend. The engine transparently migrates historical data from local storage (MemoryDB or LevelDB) to IPFS, providing unbounded storage growth with zero write-path latency overhead and O(1) cold-read performance via an in-memory secondary index.&lt;/p&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;ResilientDB is a high-throughput permissioned blockchain fabric that orders and executes client transactions through PBFT consensus. By default, all blockchain state, i.e. every key-value pair, every version, is persisted indefinitely in local LevelDB storage. As the ledger accumulates history, storage grows unboundedly: every transaction, every checkpoint, every version remains on disk. For production deployments that process millions of transactions, this increases the costs multifold to vertically scale the number of SSDs for all resilientdb nodes.&lt;/p&gt;

&lt;p&gt;Existing storage backends offer no mechanism to offload cold or archival data. Operators face a choice between expensive vertical scaling (larger disks) or manual data pruning, which breaks the blockchain’s immutability guarantees. What is needed is a storage system that can seamlessly migrate historical data to cheaper, scalable storage while keeping recent data on fast local storage—all without changing the application’s query interface or the consensus protocol.&lt;/p&gt;

&lt;p&gt;IPFS (InterPlanetary File System) is a natural fit for the cold tier. It is decentralized, content-addressed (CIDs are cryptographic hashes of the data), trustless (content is mathematically verified), provides built-in deduplication, replicates across nodes via peer-to-peer gossip, and carries no vendor lock-in. By combining IPFS with ResilientDB’s existing MemoryDB and LevelDB tiers, we can build a storage engine that is both scalable and transparent.&lt;/p&gt;

&lt;p&gt;The key goals of ResTier are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Unbounded storage growth&lt;/strong&gt;: Historical data automatically migrates to IPFS, freeing local disk space.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Zero write-path overhead&lt;/strong&gt;: The hot write path is untouched; migration runs asynchronously.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transparent cold reads&lt;/strong&gt;: Applications use the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetValue&lt;/code&gt; API; cold data is fetched from IPFS automatically.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No consensus changes&lt;/strong&gt;: Each PBFT replica migrates independently; no cross-replica coordination is needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h2&gt;

&lt;p&gt;ResTier organizes storage into two data storage tiers and one index manifest tier that form a hierarchy of decreasing performance and increasing capacity:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/restier/restier-node-sidecar-arch.png&quot; alt=&quot;Image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Each PBFT replica runs its own IPFS sidecar and maintains its own manifest index. There is no cross-node coordination for migration—each replica independently decides when and what to migrate. Consensus guarantees that all replicas converge to the same application state regardless of the storage backend.&lt;/p&gt;

&lt;h3 id=&quot;four-storage-modes&quot;&gt;Four Storage Modes&lt;/h3&gt;

&lt;p&gt;ResTier supports four deployment modes to accommodate different use cases:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Mode&lt;/th&gt;
      &lt;th&gt;Backend&lt;/th&gt;
      &lt;th&gt;Hot Tier&lt;/th&gt;
      &lt;th&gt;Warm Tier&lt;/th&gt;
      &lt;th&gt;Cold Tier&lt;/th&gt;
      &lt;th&gt;Use Case&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;MEMORYDB&lt;/td&gt;
      &lt;td&gt;MemoryDB&lt;/td&gt;
      &lt;td&gt;—&lt;/td&gt;
      &lt;td&gt;—&lt;/td&gt;
      &lt;td&gt;Dev/testing, fastest access&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;LEVELDB&lt;/td&gt;
      &lt;td&gt;LevelDB&lt;/td&gt;
      &lt;td&gt;—&lt;/td&gt;
      &lt;td&gt;—&lt;/td&gt;
      &lt;td&gt;Production, small datasets&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;TIERED&lt;/td&gt;
      &lt;td&gt;LevelDB&lt;/td&gt;
      &lt;td&gt;LevelDB (manifest)&lt;/td&gt;
      &lt;td&gt;IPFS&lt;/td&gt;
      &lt;td&gt;Production, large data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;TIERED&lt;/td&gt;
      &lt;td&gt;MemoryDB&lt;/td&gt;
      &lt;td&gt;LevelDB (manifest)&lt;/td&gt;
      &lt;td&gt;IPFS&lt;/td&gt;
      &lt;td&gt;High-throughput, crash-tolerant&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Modes 2 and 3 are the primary focus. They enable unbounded storage growth by offloading cold data to IPFS while keeping hot data on fast local storage.&lt;/p&gt;

&lt;h2 id=&quot;write-path-zero-overhead-by-design&quot;&gt;Write Path: Zero Overhead by Design&lt;/h2&gt;

&lt;p&gt;The write path is deliberately kept simple. When a client submits a transaction through PBFT consensus, the execution layer calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TieredStorage::SetValueWithSeq(key, value, seq)&lt;/code&gt;. This method writes &lt;strong&gt;only&lt;/strong&gt; to the hot storage tier:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Client → PBFT Consensus → KVExecutor → TieredStorage::SetValueWithSeq
                                              │
                                              ▼
                                       hot_storage_.SetValueWithSeq
                                              │
                                              ▼
                                    MemoryDB or LevelDB (immediate)
                                              │
                                              ▼
                                     max_seq_ updated (atomically)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The warm LevelDB (which stores the manifest index) is &lt;strong&gt;not&lt;/strong&gt; touched on the write path. This is a deliberate design decision: writing to LevelDB on every transaction would add 20–50µs of latency. By deferring all manifest updates to the asynchronous migration thread, ResTier ensures that the write-path latency is identical to the underlying hot storage when the tiering were not enabled (memorydb or leveldb).&lt;/p&gt;

&lt;p&gt;Checkpoint tracking differs by hot tier:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;LevelDB hot tier&lt;/strong&gt;: Uses LevelDB’s native &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UpdateLastCkpt(seq)&lt;/code&gt; mechanism, which fires on every write via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetValueWithSeq&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MemoryDB hot tier&lt;/strong&gt;: Tracks &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_seq_&lt;/code&gt; atomically as a simple counter. There is no warm-write overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;read-path-transparent-auto-fallback&quot;&gt;Read Path: Transparent Auto-Fallback&lt;/h2&gt;

&lt;p&gt;The read path implements a three-level cascade: hot storage is checked first, then warm (LevelDB manifest), and finally cold (IPFS). The fallback is completely transparent to the application:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GetValue(key)
    │
    ├── HOT (MemoryDB/LevelDB) ─── found? ──► Return value
    │
    └── not found ──► COLD (IPFS)
                        │
                        ▼
                InMemoryHashIndex.Get(key) or WARM (LevelDB Manifest Index) → CID
                        │
                        ▼
                    IPFS::Cat(CID)
                        │
                        ▼
                    Return value
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The cold-read path uses an in-memory secondary index (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryHashIndex&lt;/code&gt;, backed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unordered_map&lt;/code&gt;) to map keys to their IPFS CIDs. Lookups are O(1) here. This is extremely faster than any IPFS network operation, so the index is never the bottleneck.&lt;/p&gt;

&lt;p&gt;Benchmark measurements confirm this:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Hot read (MemoryDB): 2µs p50&lt;/li&gt;
  &lt;li&gt;Hot read (LevelDB): 15µs p50&lt;/li&gt;
  &lt;li&gt;Index lookup: 1µs p50&lt;/li&gt;
  &lt;li&gt;Cold read (IPFS Cat, loopback): 4ms p50 (This latency for historical reads is the tradeoff for cheaper storage. But from the client’s perspective this latency might get hidden because of higher network latency between client -&amp;gt; resilientdb client proxy -&amp;gt; resilientdb nodes)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;migration-flow-asynchronous-background-thread&quot;&gt;Migration Flow: Asynchronous Background Thread&lt;/h2&gt;

&lt;p&gt;Data migration from hot storage to IPFS runs in a background thread inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TieredStorage&lt;/code&gt;. This design was chosen over a separate sidecar process because LevelDB’s LOCK file prevents concurrent access from multiple processes.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;TieredStorage constructor → StartMigration()
    │
    ▼
If tiering enabled + IPFS available:
    ├── 1. Create InMemoryHashIndex
    ├── 2. Load Manifest from warm LevelDB → populate index
Background thread: MigrationLoop() ─ poll every N seconds
    │
    ▼
MigrateColdData()
    │
    ├── 1. Get checkpoint from hot storage
    ├── 2. Calculate cold threshold: seq &amp;lt;= (checkpoint - watermark × threshold)
    ├── 3. Scan hot storage via GetAllItemsWithSeq()
    ├── 4. For each eligible key:
    │       ├── Upload to IPFS via POST /api/v0/add → get CID
    │       ├── Add CID to InMemoryHashIndex
    │       ├── Save manifest to warm LevelDB
    │       ├── Delete key from hot storage
    │       │   └── (LRU cache invalidated for LevelDB hot tier)
    │       └── Unpin stale CID in case of value updates to existing key to prevent bloating in IPFS due to stale data
    │
    └── 5. Sleep until next poll interval
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;key-design-decisions&quot;&gt;Key Design Decisions&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cursor optimization (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;last_migrated_seq_&lt;/code&gt;):&lt;/strong&gt; On each migration cycle, only keys with sequence numbers between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;last_migrated_seq_&lt;/code&gt; and the cold threshold are eligible. This avoids a full scan of the hot storage on every cycle. The cursor is persisted to warm storage after each successful cycle, so crash recovery resumes from the last saved position rather than scanning from seq 0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Safe delete with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DeletableStorage&lt;/code&gt; interface:&lt;/strong&gt; Deletion from the hot tier is mediated through a pure virtual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DeletableStorage&lt;/code&gt; interface. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TieredStorage&lt;/code&gt; uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dynamic_cast&amp;lt;DeletableStorage*&amp;gt;&lt;/code&gt; to check whether the hot storage backend supports deletion at runtime. This avoids &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;friend class&lt;/code&gt; coupling and remains extensible to future backends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LRU cache invalidation:&lt;/strong&gt; When operating in LevelDB→IPFS mode (Mode 2), the hot tier has an LRU block cache. After &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DeleteKey&lt;/code&gt; removes a key from LevelDB, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;block_cache_-&amp;gt;Remove(key)&lt;/code&gt; is called to ensure stale cache entries don’t serve pre-migration values. This bug was caught and fixed during testing.&lt;/p&gt;

&lt;h3 id=&quot;race-condition-safety-concurrent-reads-during-migration&quot;&gt;Race Condition Safety (Concurrent Reads During Migration)&lt;/h3&gt;

&lt;p&gt;The migration thread operates concurrently with read requests. Four possible race windows were analyzed:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Window&lt;/th&gt;
      &lt;th&gt;State&lt;/th&gt;
      &lt;th&gt;GET Behavior&lt;/th&gt;
      &lt;th&gt;Safe?&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;After IPFS upload, before index add&lt;/td&gt;
      &lt;td&gt;Data in IPFS + hot, NOT in index&lt;/td&gt;
      &lt;td&gt;Hits hot → correct&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;After index add, before hot delete&lt;/td&gt;
      &lt;td&gt;Data in IPFS + index + hot&lt;/td&gt;
      &lt;td&gt;Hits hot → correct&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;After hot delete&lt;/td&gt;
      &lt;td&gt;Data in IPFS + index only&lt;/td&gt;
      &lt;td&gt;Index lookup → CID → IPFS Cat&lt;/td&gt;
      &lt;td&gt;✅&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;A stress test with 10 concurrent readers, 100 keys, and 60 seconds of continuous reads during active migration cycles confirmed &lt;strong&gt;zero mismatches&lt;/strong&gt; in both Mode 2 and Mode 3.&lt;/p&gt;

&lt;h2 id=&quot;secondary-index-design&quot;&gt;Secondary Index Design&lt;/h2&gt;

&lt;p&gt;The secondary index (manifest) tracks where each key resides in IPFS and provides the CID needed for cold-data retrieval. It is stored in two places:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;In-memory&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryHashIndex&lt;/code&gt; backed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unordered_map&lt;/code&gt; for O(1) lookups.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Persisted&lt;/strong&gt;: A LevelDB manifest database (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;db_path&amp;gt;_manifest_db&lt;/code&gt;) that is written after each successful migration cycle and loaded on startup.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The manifest maintains range mappings for efficient range queries:&lt;/p&gt;

&lt;div class=&quot;language-protobuf highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IndexManifest&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RangeMapping&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;start_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;end_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ipfs_cid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;min_checkpoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;max_checkpoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;repeated&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RangeMapping&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;range_mappings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;total_keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;cold_keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int64&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;last_updated_timestamp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The index is stored in the warm LevelDB using reserved key patterns:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Key Pattern&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_tiered_manifest&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;IndexManifest proto with range mappings&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_last_migrated_seq&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Persisted migration cursor for crash recovery&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_migration_status&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Last migration timestamp&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;crash-recovery&quot;&gt;Crash Recovery&lt;/h2&gt;

&lt;p&gt;On restart, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TieredStorage&lt;/code&gt; rebuilds the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryHashIndex&lt;/code&gt; from the persisted manifest in warm LevelDB. This ensures that all previously migrated keys remain accessible via IPFS even though the in-memory index was lost.&lt;/p&gt;

&lt;p&gt;Four crash scenarios are handled:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Crash before manifest save&lt;/strong&gt;: The orphan CID in IPFS is harmless (pinned data with no index entry). On restart, the key is re-migrated—the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetIndexCID&lt;/code&gt; check prevents re-upload since the old CID is not in the rebuilt index.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Crash after manifest save, before hot delete&lt;/strong&gt;: The key exists in both hot storage and IPFS. On restart, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetIndexCID(key)&lt;/code&gt; returns the CID, so migration skips this key. GET returns the value from hot storage (correct, same value exists in both tiers).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Crash after hot delete&lt;/strong&gt;: The key exists only in IPFS. The manifest is intact, so cold reads work normally.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Crash during migration, LevelDB block cache&lt;/strong&gt;: The block cache is process-local and lost on crash. No stale entries survive restart.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In all cases, &lt;strong&gt;zero data loss is guaranteed&lt;/strong&gt;. At worst, a key exists in multiple tiers (safe duplicate).&lt;/p&gt;

&lt;h2 id=&quot;benchmark-results&quot;&gt;Benchmark Results&lt;/h2&gt;

&lt;p&gt;All benchmarks were run with 4 PBFT replicas and 1 client proxy on localhost, with IPFS daemon on loopback (127.0.0.1:5001). Timers are inserted at the storage layer using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::chrono::high_resolution_clock&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All values in &lt;strong&gt;microseconds (µs)&lt;/strong&gt; unless noted:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Mode&lt;/th&gt;
      &lt;th&gt;Metric&lt;/th&gt;
      &lt;th&gt;100 Keys (p50/p95/p99)&lt;/th&gt;
      &lt;th&gt;1000 Keys (p50/p95/p99)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt; MemoryDB&lt;/td&gt;
      &lt;td&gt;Write&lt;/td&gt;
      &lt;td&gt;1 / 3 / 6&lt;/td&gt;
      &lt;td&gt;1 / 3 / 5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Read&lt;/td&gt;
      &lt;td&gt;2 / 2 / 3&lt;/td&gt;
      &lt;td&gt;2 / 3 / 4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt; LevelDB&lt;/td&gt;
      &lt;td&gt;Write&lt;/td&gt;
      &lt;td&gt;23 / 39 / 185&lt;/td&gt;
      &lt;td&gt;23 / 43 / 64&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Read&lt;/td&gt;
      &lt;td&gt;15 / 30 / 42&lt;/td&gt;
      &lt;td&gt;17 / 30 / 47&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;2&lt;/strong&gt; LevelDB→IPFS&lt;/td&gt;
      &lt;td&gt;Hot write&lt;/td&gt;
      &lt;td&gt;24 / 71 / 141&lt;/td&gt;
      &lt;td&gt;26 / 62 / 106&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Hot read&lt;/td&gt;
      &lt;td&gt;15 / 31 / 42&lt;/td&gt;
      &lt;td&gt;18 / 30 / 50&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Index lookup&lt;/td&gt;
      &lt;td&gt;1 / 3 / 4&lt;/td&gt;
      &lt;td&gt;1 / 3 / 4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;IPFS Add&lt;/td&gt;
      &lt;td&gt;36752 / 60610 / 74283&lt;/td&gt;
      &lt;td&gt;33586 / 56612 / 67585&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Cold read&lt;/td&gt;
      &lt;td&gt;4212 / 11257 / 12525&lt;/td&gt;
      &lt;td&gt;3878 / 5351 / 5668&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;3&lt;/strong&gt; MemoryDB→IPFS&lt;/td&gt;
      &lt;td&gt;Hot write&lt;/td&gt;
      &lt;td&gt;1 / 2 / 5&lt;/td&gt;
      &lt;td&gt;1 / 3 / 6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Hot read&lt;/td&gt;
      &lt;td&gt;2 / 2 / 3&lt;/td&gt;
      &lt;td&gt;2 / 3 / 4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Index lookup&lt;/td&gt;
      &lt;td&gt;1 / 3 / 4&lt;/td&gt;
      &lt;td&gt;1 / 3 / 4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;IPFS Add&lt;/td&gt;
      &lt;td&gt;35241 / 58970 / 78638&lt;/td&gt;
      &lt;td&gt;35074 / 38556 / 55948&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;Cold read&lt;/td&gt;
      &lt;td&gt;4341 / 5932 / 6106&lt;/td&gt;
      &lt;td&gt;4135 / 5537 / 6639&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;key-findings&quot;&gt;Key Findings&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Tiering adds zero hot-path overhead&lt;/strong&gt;: Mode 0 vs Mode 3 and Mode 1 vs Mode 2 show identical hot write and read latencies. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TieredStorage&lt;/code&gt; wrapper delegates directly to the underlying hot storage with no measurable overhead.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Index lookup is not a bottleneck&lt;/strong&gt;: At 1µs p50, index lookups are 1000–37000× faster than any IPFS operation. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::unordered_map&lt;/code&gt; provides O(1) lookups regardless of key count.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;IPFS Add dominates migration&lt;/strong&gt;: At ~35ms per key, IPFS upload is the bottleneck by two orders of magnitude. This is expected—IPFS is a content-addressed storage network, not a local filesystem. For bulk migration, batching and parallelism would improve throughput.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Cold reads are viable for archival&lt;/strong&gt;: At ~4ms on loopback IPFS, cold reads are acceptable for infrequent access to historical data. In geo-distributed deployments, expect 50–200ms depending on network topology.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;MemoryDB is 23× faster than LevelDB for writes&lt;/strong&gt;: 1µs vs 24µs p50. Mode 3 (MemoryDB→IPFS) provides the best write throughput while retaining the ability to offload cold data.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;

&lt;p&gt;ResTier is configured via JSON protobuf messages in the server config file. Here is an example for Mode 3 (MemoryDB→IPFS):&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;storage_config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;backend&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ipfs_info&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;api_endpoint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;127.0.0.1:5001&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;gateway_endpoint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;127.0.0.1:8080&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timeout_ms&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max_retries&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tiered_info&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cold_threshold_checkpoint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;enabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;poll_interval_seconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;batch_size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;auto_migration_enabled&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hot_backend&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;configuration-parameters&quot;&gt;Configuration Parameters&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Parameter&lt;/th&gt;
      &lt;th&gt;Default&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;backend&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;0 (MEMORYDB)&lt;/td&gt;
      &lt;td&gt;Storage mode: 0=MEMORYDB, 1=LEVELDB, 2=TIERED&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hot_backend&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;0 (MEMORYDB)&lt;/td&gt;
      &lt;td&gt;Hot tier when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;backend=TIERED&lt;/code&gt;: 0=MEMORYDB, 1=LEVELDB&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cold_threshold_checkpoint&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;Checkpoints to wait before data becomes eligible for migration&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;poll_interval_seconds&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;60&lt;/td&gt;
      &lt;td&gt;How often the migration thread checks for eligible data&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;batch_size&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;1000&lt;/td&gt;
      &lt;td&gt;Maximum keys migrated per cycle&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;auto_migration_enabled&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;false&lt;/td&gt;
      &lt;td&gt;Enables the background migration thread&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api_endpoint&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;—&lt;/td&gt;
      &lt;td&gt;IPFS Kubo API endpoint (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1:5001&lt;/code&gt;)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;how-to-build-and-run&quot;&gt;How to Build and Run&lt;/h2&gt;

&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Ubuntu 20+ with Bazel installed&lt;/li&gt;
  &lt;li&gt;Docker (for IPFS Kubo container)&lt;/li&gt;
  &lt;li&gt;LevelDB support: build with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--define enable_leveldb=True&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;step-1-start-ipfs-daemon&quot;&gt;Step 1: Start IPFS Daemon&lt;/h3&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; ipfs-test &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 5001:5001 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 8080:8080 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 4001:4001 ipfs/kubo:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-2-build&quot;&gt;Step 2: Build&lt;/h3&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build //service/kv:kv_service //service/tools/kv/api_tools:kv_service_tools &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--define&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;enable_leveldb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-3-generate-certificates&quot;&gt;Step 3: Generate Certificates&lt;/h3&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./service/tools/kv/server_tools/generate_keys_and_certs.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-4-start-the-cluster&quot;&gt;Step 4: Start the Cluster&lt;/h3&gt;
&lt;p&gt;The checkpoint watermark is hardcoded to 5 (every 5 transactions triggers a checkpoint). With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cold_threshold_checkpoint: 1&lt;/code&gt;, data becomes eligible for migration after ~10 transactions.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Start 4 replicas + 1 client proxy&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;nohup &lt;/span&gt;bazel-bin/service/kv/kv_service service/tools/config/server/server_tiered.config &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    service/tools/data/cert/node1.key.pri service/tools/data/cert/cert_1.cert &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; server0.log 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;span class=&quot;c&quot;&gt;# ... repeat for nodes 2-4 and client proxy (node 5)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-5-write-and-verify&quot;&gt;Step 5: Write and Verify&lt;/h3&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Write data&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;seq &lt;/span&gt;1 15&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
    &lt;/span&gt;bazel-bin/service/tools/kv/api_tools/kv_service_tools &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; service/tools/config/interface/service.config &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--cmd&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--key&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;test_&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--value&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;val_&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Wait for migration (sleep 10 seconds), then read cold data&lt;/span&gt;
bazel-bin/service/tools/kv/api_tools/kv_service_tools &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; service/tools/config/interface/service.config &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--cmd&lt;/span&gt; get &lt;span class=&quot;nt&quot;&gt;--key&lt;/span&gt; test_1
&lt;span class=&quot;c&quot;&gt;# → returns &quot;val_1&quot; (served from IPFS after migration)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h2&gt;

&lt;p&gt;ResTier is fully functional and validated for small-to-medium (100k) key counts. The following enhancements are planned:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Configurable checkpoint watermark&lt;/strong&gt;: Currently hardcoded to 5 in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;platform/config/resdb_config.h&lt;/code&gt;. Making it configurable via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TieredStorageConfig&lt;/code&gt; will allow predictable migration behavior across deployment environments.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Access-based tiering&lt;/strong&gt;: Evict based on LRU access patterns instead of checkpoint age.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Compression&lt;/strong&gt;: Compress data before IPFS upload to reduce cold storage costs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Multi-node consistency verification&lt;/strong&gt;: Validate that all PBFT replicas converge to identical state after independent migration.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;ResTier demonstrates that tiered storage with IPFS cold storage can be integrated into a PBFT-based permissioned blockchain with zero write-path overhead and transparent read-path fallback. The architecture—background migration thread, O(1) in-memory secondary index, four storage modes, and interface-based hot eviction—provides a solid foundation for unbounded storage growth in ResilientDB deployments.&lt;/p&gt;

&lt;p&gt;The system has been validated through extensive testing: end-to-end migration cycles, cold and hot reads, concurrent reads during migration (zero mismatches), crash recovery, LRU cache invalidation, stale-CID deduplication on key updates, and latency benchmarks across all four modes. ResTier is ready for production evaluation in large-scale ResilientDB deployments.&lt;/p&gt;

&lt;hr /&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;*Built on Apache ResilientDB&lt;/td&gt;
      &lt;td&gt;IPFS Kubo&lt;/td&gt;
      &lt;td&gt;PBFT Consensus*&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;em&gt;This work is licensed under a &lt;a href=&quot;https://creativecommons.org/licenses/by-nc/4.0/&quot;&gt;Attribution-NonCommercial 4.0 International&lt;/a&gt; license.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2026/06/02/ResTier.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2026/06/02/ResTier.html</guid>
      </item>
    
      <item>
        <title>Deep Observe: Building AI Assisted Observability for Consensus Protocols</title>
        <description>&lt;p&gt;Distributed databases and blockchain systems depend on consensus protocols to maintain consistency, yet few tools exist for observing protocol behavior in live deployments. Existing approaches typically rely on static simulation, offline trace replay, or intrusive instrumentation—each of which is costly and falls short of capturing runtime execution.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/harish876/DeepObserve&quot;&gt;&lt;strong&gt;DeepObserve&lt;/strong&gt;&lt;/a&gt; addresses this gap as an observability framework for &lt;a href=&quot;https://resilientdb.incubator.apache.org/&quot;&gt;Apache ResilientDB&lt;/a&gt;. As part of the DeepObserve project, we present two &lt;a href=&quot;https://ebpf.io/&quot;&gt;eBPF&lt;/a&gt;-based applications—&lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer&quot;&gt;ResView&lt;/a&gt; and &lt;a href=&quot;https://reslens.resilientdb.com/cpu&quot;&gt;ResLens&lt;/a&gt;—that instrument running systems with minimal code changes. Each runs as a sidecar, decoupling telemetry from the database execution path and providing low-code, language-agnostic instrumentation. DeepObserve also exposes these tools through MCP servers, enabling AI agents to connect, query runtime behavior, visualize subprotocol execution, and inspect call-stack flamegraphs.&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;Observability is defined as the degree to which the internal state of a system can be inferred from its external outputs. These outputs—logs, metrics, and traces—enable operators to gauge system health, measure performance, and evaluate compliance with service-level objectives (SLOs).&lt;/p&gt;

&lt;p&gt;Despite its importance, achieving effective observability in production distributed systems remains challenging. Conventional instrumentation relies on language-specific SDKs that embed telemetry logic directly alongside application logic. Each observability goal typically requires a dedicated toolchain: consensus visualization may depend on high-volume log ingestion through systems such as Loki or Elasticsearch, while continuous profiling requires Grafana Pyroscope or language-specific profilers. This fragmentation increases operational complexity and often forces trade-offs between visibility and performance.&lt;/p&gt;

&lt;h2 id=&quot;approach&quot;&gt;Approach&lt;/h2&gt;

&lt;p&gt;DeepObserve is built on two core design decisions: running observability as a &lt;strong&gt;&lt;a href=&quot;https://ujjwal18.hashnode.dev/understanding-the-sidecar-pattern-how-atlassian-reduced-latency-by-70&quot;&gt;sidecar&lt;/a&gt;&lt;/strong&gt;, and using &lt;strong&gt;&lt;a href=&quot;https://ebpf.io/&quot;&gt;eBPF&lt;/a&gt;&lt;/strong&gt; for instrumentation. Together, they keep telemetry out of the database hot path while still providing protocol-aware visibility at runtime.&lt;/p&gt;

&lt;h3 id=&quot;why-a-sidecar-pattern&quot;&gt;Why a Sidecar Pattern&lt;/h3&gt;

&lt;p&gt;In conventional observability setups, telemetry logic lives inside the application—timestamps are recorded in consensus handlers, statistics are serialized and pushed over websockets, and profiling hooks are woven through storage and execution code. This co-location creates several problems. Instrumentation competes with consensus logic for CPU and memory on the critical path, changes to observability require modifying and redeploying the database itself, and enabling or disabling telemetry often means recompilation or runtime configuration deep inside the system.&lt;/p&gt;

&lt;p&gt;DeepObserve moves all of this into a sidecar process that runs alongside ResilientDB without sharing its execution context. The database exposes lightweight trace dispatch points; the sidecar attaches externally, collects events, and serves them to visualization frontends and MCP servers. When observability is not needed, the sidecar can be stopped entirely—the database continues running unaffected. This separation also means each observability concern (consensus tracing, continuous profiling) can evolve independently, as its own deployable unit, without destabilizing the core system.&lt;/p&gt;

&lt;h3 id=&quot;how-ebpf-enables-low-code-instrumentation&quot;&gt;How eBPF Enables Low-Code Instrumentation&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://ebpf.io/&quot;&gt;eBPF&lt;/a&gt; (extended Berkeley Packet Filter) is a Linux kernel technology that allows sandboxed programs to attach dynamically to kernel and user-space execution points. For DeepObserve, the key capability is &lt;strong&gt;uprobes&lt;/strong&gt;—probes that fire when specific user-space functions are invoked. We define minimal trace dispatch functions at consensus and storage boundaries in ResilientDB. When a probe is attached, eBPF captures function arguments, timestamps, and thread metadata at the point of execution. When no probe is attached, these dispatch points compile down to near-zero overhead.&lt;/p&gt;

&lt;p&gt;This model replaces large amounts of hand-written instrumentation. The original ResView data collection path required over 600 lines of in-process telemetry code embedded across the consensus layer. The eBPF-based approach reduces this to lightweight hooks under 250 lines, with the sidecar handling collection, aggregation, and export. Because probes attach at the binary level rather than through language-specific SDKs, the same pattern extends to other subsystems and, in principle, to other consensus implementations—without rewriting application logic for each observability goal.&lt;/p&gt;

&lt;h3 id=&quot;applications&quot;&gt;Applications&lt;/h3&gt;

&lt;p&gt;As part of the DeepObserve project, we present two applications:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer&quot;&gt;ResView&lt;/a&gt;&lt;/strong&gt; — traces and visualizes client requests through consensus protocol stages in real time.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://reslens.resilientdb.com/cpu&quot;&gt;ResLens&lt;/a&gt;&lt;/strong&gt; — provides continuous CPU and memory profiling with call-stack flamegraphs for ResilientDB runtime analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both run as eBPF sidecars and are accessible to AI agents through MCP servers.&lt;/p&gt;

&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;

&lt;p&gt;The diagram below shows the general DeepObserve architecture: trace dispatch hooks in ResilientDB, eBPF probe attachment in the sidecar, and export to visualization frontends and MCP servers.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/architecture.png&quot; alt=&quot;DeepObserve architecture diagram&quot; style=&quot;width: 80%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. DeepObserve pipeline—ResilientDB trace hooks feed eBPF sidecars, which export telemetry to visualization frontends and MCP-connected agents.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;At a high level, a client request enters ResilientDB and flows through the consensus layer. At each instrumented stage, a trace dispatch function emits metadata (sequence number, message type, sender, timestamp). The eBPF sidecar captures these events via uprobes, correlates them by request, and forwards structured traces to the ResView frontend. ResLens follows the same sidecar model but attaches profiling probes to capture CPU and call-stack samples, which are aggregated into flamegraphs. Both applications are exposed to AI agents through the DeepObserve MCP server, described below.&lt;/p&gt;

&lt;h2 id=&quot;resview&quot;&gt;ResView&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer&quot;&gt;ResView&lt;/a&gt; is DeepObserve’s consensus visualization application. It traces individual client requests through the full lifecycle of a consensus protocol and renders protocol-aware diagrams from live execution data.&lt;/p&gt;

&lt;h3 id=&quot;features&quot;&gt;Features&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Traces and visualizes requests through any consensus algorithm; our primary focus is &lt;strong&gt;PBFT&lt;/strong&gt; (Practical Byzantine Fault Tolerance).&lt;/li&gt;
  &lt;li&gt;Visualizes each protocol stage—PRE-PREPARE, PREPARE, COMMIT, and others.&lt;/li&gt;
  &lt;li&gt;Visualizes PBFT sub-protocols such as commitment and view change.&lt;/li&gt;
  &lt;li&gt;Displays real-time message flow and timing information between replicas and clients.&lt;/li&gt;
  &lt;li&gt;Measures latency across consensus stages and quorum formation.&lt;/li&gt;
  &lt;li&gt;Helps observe leader changes and faulty replica behavior.&lt;/li&gt;
  &lt;li&gt;MCP-enabled interface allows AI agents to autonomously trigger workloads and visualize PBFT execution flows.&lt;/li&gt;
  &lt;li&gt;Migrates a manually instrumented visualization module (600+ LOC) to extensible eBPF hooks (&amp;lt;250 LOC).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;design&quot;&gt;Design&lt;/h3&gt;

&lt;p&gt;ResView’s instrumentation pipeline has three layers: lightweight hooks in the consensus code, modular eBPF probe programs in the sidecar, and consumers that render or query the parsed output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why hooks are needed.&lt;/strong&gt; ResilientDB’s consensus layer is written in C++, where function names are mangled at compile time. eBPF uprobes cannot reliably attach to mangled symbols in a portable way, so we add a thin layer of trace dispatch hooks—just a few lines of formatting code per consensus stage. These hooks are called directly from the consensus logic (e.g., pre-prepare, prepare, commit, view change) and expose stable, unmangled entry points for the sidecar to attach to.&lt;/p&gt;

&lt;p&gt;A trace hook is a minimal &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extern &quot;C&quot;&lt;/code&gt; function marked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;noinline&lt;/code&gt;, with arguments passed through inline assembly so eBPF uprobes can read them from registers:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noinline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resdb_trace_pbft_commit_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proxy_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;epoch_ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;asm&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;volatile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proxy_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
               &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;epoch_ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
               &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;memory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The hook is invoked from consensus logic at the point of interest. Metadata—message type, sender, and replica ID—is packed into a single 64-bit value before the call:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Commitment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessCommitMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req_ptr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;reinterpret_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meta_commit_recv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResdbTracePackMeta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()));&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;resdb_trace_pbft_commit_recv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;req_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meta_commit_recv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proxy_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResdbTraceEpochNs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;CollectorResultCode&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;message_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddConsensusMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CollectorResultCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STATE_CHANGED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meta_commit_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResdbTracePackMeta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/*sender_id=*/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;resdb_trace_pbft_commit_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req_ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meta_commit_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proxy_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;n&quot;&gt;ResdbTraceEpochNs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CollectorResultCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INVALID&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Sidecar and bpftrace modules.&lt;/strong&gt; When ResView starts, the sidecar spawns a &lt;a href=&quot;https://bpftrace.org/&quot;&gt;bpftrace&lt;/a&gt; listener for the running ResilientDB process. We define separate bpf programs for each module, each targeting a specific sub-protocol or consensus stage—commitment, view change, request intake, and others. Each module registers an uprobe on the corresponding trace dispatch hook. For example, the commitment module attaches to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resdb_trace_pbft_commit_state&lt;/code&gt; and unpacks the packed metadata at probe time:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;uprobe:/home/ubuntu/production/incubator-resilientdb/bazel-bin/service/kv/kv_service:resdb_trace_pbft_commit_state
{
  $meta = arg2;
  $type = $meta &amp;amp; 0xffffffff;
  $sender = ($meta &amp;gt;&amp;gt; 32) &amp;amp; 0xffff;
  $self = ($meta &amp;gt;&amp;gt; 48) &amp;amp; 0xffff;
  printf(&quot;%llu %lld %d %d commit_state %lu sender=%u self=%u proxy=%lu req=0x%lx type=%u\n&quot;,
         nsecs, arg4, pid, tid, arg1, $sender, $self, arg3, arg0, $type);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;From probe to consumer.&lt;/strong&gt; When a hook is invoked, the attached uprobe captures the event metadata (sequence number, message type, sender and replica IDs, timestamp) and emits it as structured log output. The sidecar parses these events, correlates them by request and replica, and reconstructs the per-request consensus timeline. The parsed traces are then exposed to downstream consumers—the ResView UI, MCP servers, and AI agents—without the database process handling any of the collection or serialization logic.&lt;/p&gt;

&lt;p&gt;The previous ResView implementation collected statistics in-process: a data structure inside the consensus layer recorded stage timestamps and message arrivals, then pushed JSON over a websocket to the frontend. This required over 600 lines of telemetry code embedded across the consensus hot path. The eBPF redesign reduces the in-process footprint to under 250 lines of lightweight hooks—the database only declares &lt;em&gt;where&lt;/em&gt; to trace; the sidecar and bpftrace modules decide &lt;em&gt;what&lt;/em&gt; to capture and &lt;em&gt;how&lt;/em&gt; to present it.&lt;/p&gt;

&lt;h3 id=&quot;screenshots&quot;&gt;Screenshots&lt;/h3&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/all-replicas-good.png&quot; alt=&quot;ResView consensus visualizer&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Normal-case PBFT message flow with Replica 3 as primary. All four replicas are healthy and participate across every protocol phase.&lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer?seq=4393&quot;&gt;View in ResView&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/replica-timing.png&quot; alt=&quot;Message flow information as observed by Replica 1&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. Consensus timeline for Transaction #4391 as observed by Replica 1, with per-stage latencies across pre-prepare, prepare, commit, and execution.&lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer?seq=4391&quot;&gt;View in ResView&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/faulty-replica.png&quot; alt=&quot;PBFT message flow with faulty Replica 3&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. PBFT execution under replica failure—Replica 3 is faulty while Replica 4 serves as primary and the remaining replicas continue toward quorum.&lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer?seq=4395&quot;&gt;View in ResView&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/view-change.png&quot; alt=&quot;View change triggered after Replica 3 becomes faulty&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. View change triggered by Replica 3&apos;s failure. Replicas run leader election and elect Replica 4 as the new primary before broadcasting a new view.&lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer&quot;&gt;View in ResView&lt;/a&gt;
&lt;/p&gt;

&lt;div style=&quot;display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;&quot;&gt;
    &lt;div style=&quot;flex: 1; min-width: 300px;&quot;&gt;
        &lt;img src=&quot;/assets/images/deepobserve/resview-mcp-1.jpg&quot; alt=&quot;MCP commit and trace workflow in ResView&quot; style=&quot;width: 100%&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Commit a transaction, then trace the resulting PBFT flow (seq 4027)&lt;/em&gt;
        &lt;br /&gt;
        &lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer?seq=4027&quot;&gt;View in ResView&lt;/a&gt;
    &lt;/div&gt;
    &lt;div style=&quot;flex: 1; min-width: 300px;&quot;&gt;
        &lt;img src=&quot;/assets/images/deepobserve/resview-mcp-2.png&quot; alt=&quot;MCP trace after view change in ResView&quot; style=&quot;width: 100%&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Retry after stopping the primary—trace captures view change (seq 4029)&lt;/em&gt;
        &lt;br /&gt;
        &lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer?seq=4029&quot;&gt;View in ResView&lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
    &lt;em&gt;Figure 6. The MCP &lt;code&gt;trace_request&lt;/code&gt; tool runs after &lt;code&gt;commit_key_value&lt;/code&gt; and opens the ResView UI for user visualization.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;reslens&quot;&gt;ResLens&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://reslens.resilientdb.com/cpu&quot;&gt;ResLens&lt;/a&gt; is DeepObserve’s continuous profiling application. It captures CPU and memory behavior of a running ResilientDB deployment and presents call-stack flamegraphs and performance metrics through a web-based dashboard.&lt;/p&gt;

&lt;h3 id=&quot;features-1&quot;&gt;Features&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Continuous CPU and memory profiling of ResilientDB processes with minimal overhead.&lt;/li&gt;
  &lt;li&gt;Real-time flamegraph generation for identifying hot paths in consensus and storage code.&lt;/li&gt;
  &lt;li&gt;Call-stack–level visibility into execution, correlated with request activity.&lt;/li&gt;
  &lt;li&gt;eBPF-based sampling that avoids intrusive in-process profilers.&lt;/li&gt;
  &lt;li&gt;Sidecar deployment—profiling can be enabled or disabled without restarting the database.&lt;/li&gt;
  &lt;li&gt;MCP-enabled interface allows AI agents to fetch flamegraphs and query performance data at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;design-1&quot;&gt;Design&lt;/h3&gt;

&lt;p&gt;ResLens follows the same sidecar architecture as ResView, but targets continuous profiling rather than consensus tracing. Profiling runs externally from the ResilientDB process—the database does not need to embed profilers or expose custom hooks beyond being a target process for the sidecar to attach to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pyroscope and eBPF profiling.&lt;/strong&gt; ResLens builds on &lt;a href=&quot;https://pyroscope.io/&quot;&gt;Pyroscope&lt;/a&gt;, an open-source continuous profiling platform. We use an older version of Pyroscope specifically for its ad-hoc eBPF profiler, which supports attaching to a process that is already running without restart or recompilation. The sidecar configures Pyroscope’s eBPF spy tool to attach to the live ResilientDB process and sample CPU call stacks at runtime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server and client.&lt;/strong&gt; Pyroscope provides two components that ResLens orchestrates as part of the sidecar. The &lt;strong&gt;server&lt;/strong&gt; runs locally and exposes interactive flamegraphs on port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4040&lt;/code&gt;. The &lt;strong&gt;client&lt;/strong&gt; is configured to target the ResilientDB process—when attached, it continuously collects stack samples and forwards them to the server for aggregation and visualization. The ResLens frontend reads from this Pyroscope server to render flamegraphs and profiling metrics in the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-accessible flamegraph analysis.&lt;/strong&gt; To enable AI agents to reason over profiling data, ResLens converts flamegraphs into a structured text representation using &lt;a href=&quot;https://github.com/google/pprof&quot;&gt;pprof&lt;/a&gt;. The exported markdown captures the call-stack hierarchy and sample counts in a format that MCP-connected agents can parse and query—allowing natural-language questions such as which functions dominate CPU time during consensus execution, without requiring the agent to interpret raw binary profile data or interact with the Pyroscope UI directly.&lt;/p&gt;

&lt;h3 id=&quot;screenshots-1&quot;&gt;Screenshots&lt;/h3&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/reslens-split-view.png&quot; alt=&quot;ResLens split view with execution time table and flamegraph&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 7. Split view pairing a ranked execution-time table with an interactive flamegraph, where each bar&apos;s width reflects CPU time spent in that function.&lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://reslens.resilientdb.com/cpu&quot;&gt;View in ResLens&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/reslens-sandwich.png&quot; alt=&quot;ResLens sandwich mode showing callers and callees&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 8. Sandwich view centered on &lt;code&gt;InternalConsensusCommit&lt;/code&gt;, with callers above and callees below—useful for tracing which functions a hot path invokes and what invokes it.&lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://reslens.resilientdb.com/cpu&quot;&gt;View in ResLens&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/reslens-view-code.png&quot; alt=&quot;View Code option on a flamegraph span&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;img src=&quot;/assets/images/deepobserve/reslens-view-code-1.png&quot; alt=&quot;Source code search results from a flamegraph span&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 9. From profile to source code—selecting &lt;strong&gt;View Code&lt;/strong&gt; on a flamegraph span (top) opens a GitHub search for that function&apos;s definition in the ResilientDB repository (bottom).&lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://reslens.resilientdb.com/cpu&quot;&gt;View in ResLens&lt;/a&gt;
&lt;/p&gt;

&lt;div style=&quot;display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;&quot;&gt;
    &lt;div style=&quot;flex: 1; min-width: 300px;&quot;&gt;
        &lt;img src=&quot;/assets/images/deepobserve/reslens-insights.png&quot; alt=&quot;Structured CPU profile summary in ResLens&quot; style=&quot;width: 100%&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Structured profile summary—flat and cumulative sample percentages per function&lt;/em&gt;
    &lt;/div&gt;
    &lt;div style=&quot;flex: 1; min-width: 300px;&quot;&gt;
        &lt;img src=&quot;/assets/images/deepobserve/reslens-ai-insights.png&quot; alt=&quot;AI-generated performance bottleneck analysis in ResLens&quot; style=&quot;width: 100%&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;AI-assisted analysis—bottlenecks grouped by network I/O, cryptography, and polling&lt;/em&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;
    &lt;em&gt;Figure 10. Two ways to interpret the same CPU profile: a deterministic summary when AI is unavailable (left), and an AI-generated breakdown that categorizes bottlenecks and suggests optimizations (right).
    &lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://reslens.resilientdb.com/cpu&quot;&gt;View in ResLens&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/deepobserve/reslens_copilot.png&quot; alt=&quot;MCP trace_profile tool querying ResLens flamegraph&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 11. The MCP &lt;code&gt;trace_profile&lt;/code&gt; tool opens a web browser and queries the flamegraph to answer user queries—in this case, identifying &lt;code&gt;SetValue&lt;/code&gt; as the function used to commit values in the PBFT flow.&lt;/em&gt;
    &lt;br /&gt;
    &lt;a href=&quot;https://reslens.resilientdb.com/flamegraph?searchQuery=SetValue&amp;amp;interval=now-30m&quot;&gt;View in ResLens&lt;/a&gt;
&lt;/p&gt;

&lt;h2 id=&quot;mcp-implementation&quot;&gt;MCP Implementation&lt;/h2&gt;

&lt;p&gt;AI agents interact with DeepObserve through an &lt;a href=&quot;https://github.com/harish876/DeepObserve&quot;&gt;MCP server&lt;/a&gt; built on &lt;a href=&quot;https://github.com/jlowin/fastmcp&quot;&gt;FastMCP&lt;/a&gt;. Rather than exposing ResView and ResLens as separate endpoints, the server acts as an &lt;strong&gt;MCP hub&lt;/strong&gt;—a single interface that combines database operations, observability UI tools, and proxied integrations with external MCP servers such as Prometheus and Grafana.&lt;/p&gt;

&lt;p&gt;The entry point is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;server.py&lt;/code&gt;, which registers three layers of capability:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Database tools&lt;/strong&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/database/tools.py&lt;/code&gt;) — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit_key_value&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_key_value&lt;/code&gt; submit and retrieve transactions against ResilientDB through a REST client, returning structured responses that include the sequence number assigned to each commit.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Observability UI tools&lt;/strong&gt; — tools such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace_request&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace_profile&lt;/code&gt; return &lt;a href=&quot;https://modelcontextprotocol.io/&quot;&gt;MCP UI resources&lt;/a&gt; that embed live ResView and ResLens URLs directly in the agent’s chat interface. When an agent calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace_request&lt;/code&gt; with a sequence number, the tool constructs a filtered ResView URL and returns it as an embeddable resource—the client opens the visualizer without the user navigating manually. Similarly, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace_profile&lt;/code&gt; opens ResLens with query parameters so the agent can inspect flamegraph data while answering performance questions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Proxied MCP servers&lt;/strong&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/mcp_hub/proxy.py&lt;/code&gt;) — external servers for Prometheus and Grafana are mounted with prefixed tool names (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prometheus_query&lt;/code&gt;), giving agents access to metrics and dashboards through the same hub.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This design enables multi-step agent workflows entirely through natural language. An agent can call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit_key_value&lt;/code&gt; to insert a transaction, read the returned sequence number, invoke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace_request&lt;/code&gt; to open the PBFT visualization for that request, and then call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trace_profile&lt;/code&gt; to inspect which functions dominated CPU time—all without leaving the conversation. The server runs over SSE transport on port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3500&lt;/code&gt; by default and can be deployed via Docker using the configuration in the repository.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;DeepObserve shows that observability for consensus protocols does not require heavy in-process instrumentation or protocol-agnostic trace pipelines. By combining eBPF sidecars with MCP-accessible tooling, ResView and ResLens provide protocol-aware visualization and continuous profiling for ResilientDB—with under 250 lines of lightweight hooks, decoupled sidecar deployment, and an interface that both developers and AI agents can use to understand runtime behavior at the granularity of individual requests and function calls.&lt;/p&gt;

&lt;p&gt;The demonstrations in this post cover the full path from motivation to implementation: normal and fault-tolerant PBFT execution, view change sub-protocols, flamegraph analysis across multiple view modes, and agent-driven workflows that commit transactions and immediately visualize the results. Together, these pieces form a practical observability stack for distributed consensus—one that stays out of the hot path while making live protocol behavior legible to humans and machines alike.&lt;/p&gt;

&lt;h2 id=&quot;source-code&quot;&gt;Source Code&lt;/h2&gt;

&lt;p&gt;The DeepObserve MCP server, deployment configuration, and tool implementations are available in the &lt;a href=&quot;https://github.com/harish876/DeepObserve&quot;&gt;DeepObserve repository&lt;/a&gt;. Live demos are available at &lt;a href=&quot;https://dev-res-view.vercel.app/pages/visualizer&quot;&gt;ResView&lt;/a&gt; and &lt;a href=&quot;https://reslens.resilientdb.com/cpu&quot;&gt;ResLens&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;demo-video&quot;&gt;Demo Video&lt;/h2&gt;

&lt;div class=&quot;extensions extensions--video&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/83JqM8qdENI?rel=0&amp;amp;showinfo=0&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Watch the full walkthrough on &lt;a href=&quot;https://youtu.be/83JqM8qdENI?si=7rBbP932qJMJr_p_&quot;&gt;YouTube&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Mon, 25 May 2026 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2026/05/25/DeepObserve.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2026/05/25/DeepObserve.html</guid>
      </item>
    
      <item>
        <title>ResPulse: Performance Regression Detection and Explanation for ResilientDB</title>
        <description>&lt;p&gt;In the world of distributed systems and blockchain infrastructure, performance monitoring isn’t just helpful, it’s essential. Today, we’re excited to introduce ResPulse: A comprehensive performance monitoring and regression detection system, a sophisticated tool designed specifically for monitoring PBFT consensus performance in real-world deployments.&lt;/p&gt;

&lt;h2 id=&quot;the-challenge-monitoring-pbft-consensus-performance&quot;&gt;The Challenge: Monitoring PBFT Consensus Performance&lt;/h2&gt;

&lt;p&gt;Modern blockchain systems like ResilientDB rely on complex consensus protocols that must maintain both security and performance under varying conditions. Traditional monitoring approaches often fall short when it comes to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Understanding consensus-specific metrics&lt;/strong&gt; like PBFT phase timing and replica coordination overhead&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Detecting performance regressions&lt;/strong&gt; before they impact production workloads&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Providing actionable insights&lt;/strong&gt; that help developers optimize consensus parameters&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Correlating performance degradation&lt;/strong&gt; with specific code changes or system conditions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ResPulse addresses these challenges head-on with a comprehensive solution built specifically for ResilientDB’s PBFT implementation.&lt;/p&gt;

&lt;h2 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h2&gt;

&lt;p&gt;ResPulse consists of four main components:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/ResPulse/Architecture.png&quot; alt=&quot;ResPulse Architecture&quot; /&gt;
&lt;em&gt;Figure 1: System architecture showing the main components and data flow&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;1-performance-testing-engine-perf_testsh&quot;&gt;1. Performance Testing Engine (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;perf_test.sh&lt;/code&gt;)&lt;/h3&gt;

&lt;p&gt;At the core of our system is a bash-based performance testing engine that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Executes realistic transaction workloads&lt;/strong&gt; against ResilientDB endpoints&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Captures detailed timing metrics&lt;/strong&gt; using curl’s built-in timing capabilities&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Measures end-to-end latency&lt;/strong&gt; including TCP connection time, server processing time, and response transfer time&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Supports configurable test parameters&lt;/strong&gt; for different workload patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The testing engine generates structured timing data that captures every aspect of request processing:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Example: Running 100 performance tests with version tagging&lt;/span&gt;
bash perf_test.sh 100 &lt;span class=&quot;s2&quot;&gt;&quot;v2.1.0-optimization-branch&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-advanced-metrics-analysis-analyzepy--analyze_recordpy&quot;&gt;2. Advanced Metrics Analysis (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;analyze.py&lt;/code&gt; &amp;amp; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;analyze_record.py&lt;/code&gt;)&lt;/h3&gt;

&lt;p&gt;Our analysis engine transforms raw timing data into meaningful performance insights:&lt;/p&gt;

&lt;h4 id=&quot;core-metrics-calculation&quot;&gt;Core Metrics Calculation&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Total Latency&lt;/strong&gt;: End-to-end request completion time&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Consensus Time&lt;/strong&gt;: Server-side processing time (PBFT phases, queuing, execution)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;TCP Connect Time&lt;/strong&gt;: Network connection establishment overhead&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transfer Time&lt;/strong&gt;: Response payload transmission time&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Throughput&lt;/strong&gt;: Requests per second under sequential load&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Success Rate&lt;/strong&gt;: Percentage of successfully completed transactions&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;statistical-analysis&quot;&gt;Statistical Analysis&lt;/h4&gt;
&lt;p&gt;The system computes comprehensive statistical summaries including:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Mean, median, min, max values&lt;/li&gt;
  &lt;li&gt;Standard deviation for variance analysis&lt;/li&gt;
  &lt;li&gt;P95 and P99 percentiles for tail latency detection&lt;/li&gt;
  &lt;li&gt;Historical baseline comparisons with percentage change calculations&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;ai-powered-analysis-integration&quot;&gt;AI-Powered Analysis Integration&lt;/h4&gt;
&lt;p&gt;A breakthrough feature of our system is its integration with &lt;strong&gt;Deepseek AI&lt;/strong&gt; for intelligent performance analysis:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# AI analysis replaces traditional pattern recognition
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ai_analysis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_ai_analysis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;baseline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;period_label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The AI system:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Analyzes complex performance patterns&lt;/strong&gt; that simple thresholds might miss&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Provides contextualized recommendations&lt;/strong&gt; specific to PBFT consensus optimization&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Generates human-readable reports&lt;/strong&gt; explaining performance bottlenecks&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Adapts analysis based on historical trends&lt;/strong&gt; and system behavior patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;3-real-time-dashboard-regression_ui&quot;&gt;3. Real-Time Dashboard (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;regression_UI&lt;/code&gt;)&lt;/h3&gt;

&lt;p&gt;Built with React and Recharts, our dashboard provides:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/ResPulse/dashboard.png&quot; alt=&quot;ResPulse Dashboard&quot; /&gt;
&lt;em&gt;Figure 2: Main dashboard showing real-time performance metrics and trends&lt;/em&gt;&lt;/p&gt;

&lt;h4 id=&quot;interactive-visualizations&quot;&gt;Interactive Visualizations&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Time-series charts&lt;/strong&gt; showing latency, throughput, and consensus timing trends&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Configurable time ranges&lt;/strong&gt; from 24 hours to all-time historical data&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Anomaly detection&lt;/strong&gt; highlighting unusual performance values&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Baseline comparison overlays&lt;/strong&gt; for regression identification&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;live-monitoring-features&quot;&gt;Live Monitoring Features&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Real-time status cards&lt;/strong&gt; displaying current system health&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Auto-refresh capabilities&lt;/strong&gt; with configurable intervals&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Detailed drill-down views&lt;/strong&gt; for individual test runs&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Performance trend analysis&lt;/strong&gt; with statistical summaries
&lt;img src=&quot;/assets/images/ResPulse/performance_overlay.png&quot; alt=&quot;Run Analysis&quot; /&gt;
&lt;em&gt;Figure 3: The system’s analysis of a test run&lt;/em&gt;
    &lt;h4 id=&quot;key-dashboard-components&quot;&gt;Key Dashboard Components&lt;/h4&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Main monitoring dashboard with comprehensive metrics&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ResilientDBMonitor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Features include:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// - Live connection status and performance metrics&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// - Interactive charts with anomaly detection&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// - Historical baseline comparison&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// - Auto-refresh with manual override capability&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;4-intelligent-alerting-system&quot;&gt;4. Intelligent Alerting System&lt;/h3&gt;

&lt;p&gt;Our alerting system provides proactive monitoring with:&lt;/p&gt;

&lt;h4 id=&quot;automated-regression-detection&quot;&gt;Automated Regression Detection&lt;/h4&gt;
&lt;p&gt;The system automatically:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Compares current performance&lt;/strong&gt; against historical baselines&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Detects statistical anomalies&lt;/strong&gt; using configurable thresholds&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Identifies performance degradation&lt;/strong&gt; across multiple metrics simultaneously&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Calculates regression severity&lt;/strong&gt; based on multiple warning signals&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;configurable-baseline-periods&quot;&gt;Configurable Baseline Periods&lt;/h4&gt;
&lt;p&gt;A key innovation in our alerting system is &lt;strong&gt;flexible baseline comparison periods&lt;/strong&gt; for scheduled tests. Instead of being locked to a fixed timeframe, users can now choose the most appropriate historical baseline:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;1 Week&lt;/strong&gt;: Ideal for detecting short-term performance changes and immediate impact assessment&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;1 Month&lt;/strong&gt;: Balances recent trends with sufficient statistical stability&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;3 Months&lt;/strong&gt;: Provides robust baseline for quarterly performance evaluation&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;6 Months&lt;/strong&gt;: Default option offering comprehensive long-term trend analysis&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;1 Year&lt;/strong&gt;: Maximum historical context for annual performance reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;intelligent-data-validation&quot;&gt;Intelligent Data Validation&lt;/h4&gt;
&lt;p&gt;The system automatically validates data availability for each baseline period:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Minimum threshold enforcement&lt;/strong&gt;: Requires at least 3 historical results for meaningful statistical comparison&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Real-time availability checking&lt;/strong&gt;: UI dynamically shows available vs. insufficient data periods&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Data count indicators&lt;/strong&gt;: Displays the exact number of historical results available for each timeframe&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Smart defaults&lt;/strong&gt;: Automatically selects the most appropriate available period if user’s choice lacks sufficient data&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;flexible-notification-system&quot;&gt;Flexible Notification System&lt;/h4&gt;
&lt;p&gt;Originally built with Resend, we’ve recently migrated to &lt;strong&gt;Nodemailer&lt;/strong&gt; for greater flexibility:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Multi-provider email support&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createTransporter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;EMAIL_PROVIDER&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;gmail&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;gmail&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nodemailerGmailTransport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;outlook&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nodemailerOutlookTransport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;smtp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nodemailerCustomSMTP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;scheduled-monitoring&quot;&gt;Scheduled Monitoring&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Configurable test schedules&lt;/strong&gt; (hourly, daily, weekly, monthly)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Automatic regression detection&lt;/strong&gt; after each scheduled test&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Email notifications&lt;/strong&gt; with detailed performance analysis&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rich HTML reports&lt;/strong&gt; showing performance trends and recommendations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/ResPulse/Alert_Setup.png&quot; alt=&quot;Scheduling Tests and Alert Setup&quot; /&gt;
&lt;em&gt;Figure 4: Scheduling Tests and Alert System&lt;/em&gt;
&lt;img src=&quot;/assets/images/ResPulse/example_email.png&quot; alt=&quot;Performance Regression Alert Email&quot; /&gt;
&lt;em&gt;Figure 5: Automated regression alert with detailed performance metrics&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;key-features-and-innovations&quot;&gt;Key Features and Innovations&lt;/h2&gt;

&lt;h3 id=&quot;1-pbft-specific-metrics&quot;&gt;1. PBFT-Specific Metrics&lt;/h3&gt;

&lt;p&gt;Our system is uniquely designed for PBFT consensus monitoring:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Consensus Phase Timing&lt;/strong&gt;: Distinguishes between network overhead and actual consensus processing&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Replica Coordination Analysis&lt;/strong&gt;: Identifies bottlenecks in multi-replica coordination&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Batch Processing Metrics&lt;/strong&gt;: Analyzes the impact of batching parameters on throughput&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tail Latency Detection&lt;/strong&gt;: Identifies consensus stalls and synchronization delays&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-ai-powered-analysis&quot;&gt;2. AI-Powered Analysis&lt;/h3&gt;

&lt;p&gt;The integration with Deepseek AI represents a significant advancement in performance analysis:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# AI generates contextualized performance insights
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prompt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;
You are a ResilientDB performance expert. Analyze these PBFT consensus metrics:
- Average Latency: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;avg_latency_ms&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ms
- Throughput: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;throughput_rps&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; req/s
- Server Wait Time: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;consensus_time_ms&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;mean&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ms

Provide specific technical recommendations for PBFT optimization.
&quot;&quot;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The AI system provides:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Context-aware recommendations&lt;/strong&gt; based on PBFT consensus theory&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Root cause analysis&lt;/strong&gt; for performance bottlenecks&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Optimization suggestions&lt;/strong&gt; for consensus parameters&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Performance trend interpretation&lt;/strong&gt; with actionable insights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/ResPulse/AI_Analysis.png&quot; alt=&quot;AI Performance Analysis Report&quot; /&gt;
&lt;em&gt;Figure 6: AI-generated performance analysis with actionable recommendations&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;3-comprehensive-regression-detection&quot;&gt;3. Comprehensive Regression Detection&lt;/h3&gt;

&lt;p&gt;Our regression detection algorithm analyzes multiple dimensions:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;METRICS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;latency&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;na&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;avg_latency_ms&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;na&quot;&gt;lowerBetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;consensus&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;na&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;consensus_ms_mean&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lowerBetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;throughput&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;throughput_rps&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;na&quot;&gt;lowerBetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;na&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;success_rate&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;na&quot;&gt;lowerBetter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The system:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Calculates dynamic baselines&lt;/strong&gt; from recent performance history&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Applies configurable thresholds&lt;/strong&gt; for each metric type&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Considers metric interdependencies&lt;/strong&gt; for holistic analysis&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Generates severity scores&lt;/strong&gt; based on multiple regression signals&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;4-developer-friendly-integration&quot;&gt;4. Developer-Friendly Integration&lt;/h3&gt;

&lt;p&gt;The system is designed for seamless integration into development workflows:&lt;/p&gt;

&lt;h4 id=&quot;easy-setup-and-configuration&quot;&gt;Easy Setup and Configuration&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Simple environment-based configuration&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;EMAIL_PROVIDER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;gmail
&lt;span class=&quot;nv&quot;&gt;EMAIL_USER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;your-email@gmail.com
&lt;span class=&quot;nv&quot;&gt;DEEPSEEK_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;your-deepseek-key

&lt;span class=&quot;c&quot;&gt;# Run performance tests&lt;/span&gt;
bash perf_test.sh 1000 &lt;span class=&quot;s2&quot;&gt;&quot;feature-branch-testing&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;mongodb-integration&quot;&gt;MongoDB Integration&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Persistent storage&lt;/strong&gt; of all performance data&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Efficient querying&lt;/strong&gt; for historical analysis&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scalable data architecture&lt;/strong&gt; supporting long-term trend analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;restful-api&quot;&gt;RESTful API&lt;/h4&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Express.js backend with comprehensive API endpoints&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/api/results&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getResults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// Historical data&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/api/results/:id/analyze&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;analyzeResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// AI analysis&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/api/schedule&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getScheduleConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// Monitoring configuration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;technical-architecture-decisions&quot;&gt;Technical Architecture Decisions&lt;/h2&gt;

&lt;h3 id=&quot;choice-of-technologies&quot;&gt;Choice of Technologies&lt;/h3&gt;

&lt;p&gt;Our technology stack reflects careful consideration of performance monitoring requirements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Python for analysis&lt;/strong&gt;: Leverages scientific computing libraries for statistical analysis&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Node.js for backend&lt;/strong&gt;: Provides excellent performance for real-time data processing&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;React for frontend&lt;/strong&gt;: Enables responsive, interactive data visualization&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MongoDB for storage&lt;/strong&gt;: Offers flexible schema for evolving metrics collection&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;performance-considerations&quot;&gt;Performance Considerations&lt;/h3&gt;

&lt;p&gt;The monitoring system itself is optimized for minimal overhead:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Efficient data collection&lt;/strong&gt; using curl’s native timing capabilities&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Asynchronous processing&lt;/strong&gt; to avoid blocking performance tests&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Intelligent caching&lt;/strong&gt; for dashboard responsiveness&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Configurable refresh intervals&lt;/strong&gt; balancing freshness with resource usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;scalability-design&quot;&gt;Scalability Design&lt;/h3&gt;

&lt;p&gt;The system architecture supports growing monitoring needs:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Horizontal scaling&lt;/strong&gt; of backend services&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Database sharding&lt;/strong&gt; for high-volume data storage&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Modular component design&lt;/strong&gt; enabling feature expansion&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;API-first architecture&lt;/strong&gt; supporting multiple frontend clients&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;

&lt;p&gt;Setting up ResPulse is straightforward:&lt;/p&gt;

&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;A ResilientDB GraphQL instance running locally. For setup instructions, see the &lt;a href=&quot;https://github.com/apache/incubator-resilientdb-graphql/blob/main/README.md&quot;&gt;ResilientDB GraphQL README&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Python 3.x with required packages&lt;/li&gt;
  &lt;li&gt;Node.js 18+ for backend services&lt;/li&gt;
  &lt;li&gt;MongoDB instance for data persistence&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;installation-steps&quot;&gt;Installation Steps&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Clone the repository&lt;/strong&gt;:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/resilientdb/incubator-resilientdb
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ecosystem/monitoring/resPulse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Configure environment variables&lt;/strong&gt;:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Backend configuration&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;backend/.env.example backend/.env
&lt;span class=&quot;c&quot;&gt;# Edit with your MongoDB URI, email settings, AI API keys&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Start the services&lt;/strong&gt;:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Backend API&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;backend &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm start

&lt;span class=&quot;c&quot;&gt;# Frontend dashboard&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resPulse_UI &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Run your first performance test&lt;/strong&gt;:
Open the dashboard in your browser and click the “Run Test” button to execute your first performance benchmark.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;configuration-options&quot;&gt;Configuration Options&lt;/h3&gt;

&lt;p&gt;The system supports extensive configuration:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Test parameters&lt;/strong&gt;: Request count, endpoint URLs, payload customization&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Analysis settings&lt;/strong&gt;: AI API configuration, statistical thresholds&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Alerting setup&lt;/strong&gt;: Email providers, notification schedules, regression thresholds&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dashboard preferences&lt;/strong&gt;: Time ranges, metrics display, refresh intervals&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;future-developments&quot;&gt;Future Developments&lt;/h2&gt;

&lt;p&gt;We’re continuously expanding the monitoring system’s capabilities:&lt;/p&gt;

&lt;h4 id=&quot;automated-pull-request-testing&quot;&gt;Automated Pull Request Testing&lt;/h4&gt;

&lt;p&gt;One of the most exciting planned features is automated performance testing triggered by code changes. This system will:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitor Repository Changes&lt;/strong&gt;: Using GitHub webhooks or CI/CD pipeline integration, automatically detect when Pull Requests are created or updated that modify ResilientDB core components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Triggered Testing&lt;/strong&gt;: Automatically execute performance benchmarks against the proposed changes, comparing results with baseline performance metrics from the main branch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance Impact Analysis&lt;/strong&gt;: Generate detailed reports showing whether code changes improve, degrade, or maintain performance across key metrics like consensus latency, throughput, and resource utilization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation Approach&lt;/strong&gt;: This can be implemented by integrating with GitHub Actions or similar CI/CD platforms, where the performance testing suite runs as part of the PR validation process. The system would deploy the proposed changes in a controlled environment, run the existing performance test suite, and automatically post results as PR comments.&lt;/p&gt;

&lt;p&gt;This automated approach ensures that performance regressions are caught early in the development cycle, maintaining ResilientDB’s performance standards while enabling rapid development iteration.&lt;/p&gt;

&lt;h2 id=&quot;other-developments&quot;&gt;Other Developments&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Custom metrics integration&lt;/strong&gt; for application-specific monitoring&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Enhanced AI analysis&lt;/strong&gt; with multi-model comparison capabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;contributing-and-community&quot;&gt;Contributing and Community&lt;/h2&gt;

&lt;p&gt;ResPulse is part of the Apache ResilientDB project and welcomes community contributions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Feature requests&lt;/strong&gt; and bug reports via GitHub Issues&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Code contributions&lt;/strong&gt; through pull requests with performance validation&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Documentation improvements&lt;/strong&gt; to support broader adoption&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Performance testing&lt;/strong&gt; across different deployment scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;ResPulse represents a significant advancement in blockchain infrastructure monitoring. By combining PBFT-specific metrics collection, AI-powered analysis, and comprehensive regression detection, it provides developers and operators with the tools they need to maintain optimal performance in distributed consensus systems.&lt;/p&gt;

&lt;p&gt;Whether you’re developing new features for ResilientDB, operating a production deployment, or researching consensus protocol optimizations, this monitoring system provides the insights and automation needed to ensure peak performance.&lt;/p&gt;

&lt;p&gt;The system’s modular architecture, comprehensive documentation, and active community support make it an ideal choice for organizations looking to implement robust performance monitoring for their ResilientDB infrastructure.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;Ready to get started? Visit our &lt;a href=&quot;https://github.com/resilientdb/incubator-resilientdb/tree/master/ecosystem/monitoring/resPulse&quot;&gt;GitHub repository&lt;/a&gt; for installation instructions and documentation. Join our community and help us build the future of blockchain performance monitoring.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;about-resilientdb&quot;&gt;About ResilientDB&lt;/h2&gt;

&lt;p&gt;ResilientDB is a high-performance permissioned blockchain fabric designed for modern distributed applications. With its focus on PBFT consensus and optimal performance, ResilientDB provides the foundation for secure, scalable blockchain solutions. Learn more at &lt;a href=&quot;https://resilientdb.com&quot;&gt;resilientdb.com&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2026/05/22/ResPulse.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2026/05/22/ResPulse.html</guid>
      </item>
    
      <item>
        <title>ResInsight: AI-Driven Developer Onboarding for ResilientDB</title>
        <description>&lt;h2 id=&quot;the-problem&quot;&gt;The Problem:&lt;/h2&gt;

&lt;p&gt;Today’s business applications are complex in nature with interleaved tech stacks with a mix of libs &amp;amp; frameworks, code bases are evolving rapidly on composable &amp;amp; interoperable stacks. E.g. code delivered 3-months back might look very different depending on the issues resolved or features built or new tech stack inclusion
For an unknown/new repo, there is no choice than to rely on README pages and manual code browsing.
For an existing repo, one must browse through the commit logs to understand changes in each file and the associated impact. Thus, code repositories (repo here onwards) have become increasingly difficult to build understanding on the functional dependencies. But you might be thinking that ChatGPT or Claude can do this so easily so why is this tool required? You are correct. Let us explore it through a story first and then deep dive:&lt;/p&gt;

&lt;h3 id=&quot;my-first-quarter-experience&quot;&gt;My First Quarter Experience&lt;/h3&gt;

&lt;p&gt;During my first quarter at UC Davis, I took ECS 265, a course focused on distributed database systems and blockchain technology using ResilientDB. Like many of my classmates, I came in with limited exposure to distributed systems. We were tasked with understanding ResilientDB’s architecture, its consensus protocols, and building projects using the existing applications.&lt;/p&gt;

&lt;p&gt;The learning curve was real. ResilientDB is a powerful, well-architected blockchain platform, its sophistication is one of its greatest strengths. But that same sophistication meant there was a lot to understand: from Byzantine fault tolerance theory to the practical aspects of getting a development environment running.&lt;/p&gt;

&lt;p&gt;Many of us found ourselves in a cycle: reading through documentation, trying to set things up, hitting errors we didn’t understand, and then relying on groupmates who had managed to get their environments working. Some students spent most of the quarter developing on their teammate’s setup rather than their own, not because they didn’t want to figure it out, but because troubleshooting took time away from actually learning the concepts and building projects.&lt;/p&gt;

&lt;p&gt;This wasn’t anyone’s fault. ResilientDB, as an active research platform, evolves quickly, which is excellent for pushing blockchain innovation forward. But it also means documentation and setup procedures are constantly catching up. The platform’s comprehensiveness is a feature, not a bug. However, for newcomers, this creates a genuine challenge.&lt;/p&gt;

&lt;h3 id=&quot;where-existing-ai-tools-failed-us&quot;&gt;Where Existing AI Tools Failed Us&lt;/h3&gt;

&lt;p&gt;Here’s what made this harder: we couldn’t just ask ChatGPT or Claude for help.&lt;/p&gt;

&lt;p&gt;When you ask ChatGPT about ResilientDB:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;It gives you generic blockchain advice that may or may not apply to our specific implementation&lt;/li&gt;
  &lt;li&gt;It hallucinates repository structures that don’t exist in ResilientDB&lt;/li&gt;
  &lt;li&gt;It can’t access actual code from our repositories to verify its suggestions&lt;/li&gt;
  &lt;li&gt;It provides outdated setup instructions based on whatever documentation it found during training&lt;/li&gt;
  &lt;li&gt;It doesn’t know about ResilientDB-specific applications like Debitable, Arrayán, or ResCounty&lt;/li&gt;
  &lt;li&gt;It can’t distinguish between theoretical PBFT and how ResilientDB actually implements it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The fundamental gap&lt;/strong&gt;: General-purpose AI tools lack context about your specific codebase. They’re trained on public data but have no connection to your actual repositories, your project’s conventions, or your domain-specific implementations.&lt;/p&gt;

&lt;p&gt;This gap becomes especially challenging for research platforms where:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Code evolves faster than public documentation can keep up&lt;/li&gt;
  &lt;li&gt;Internal applications and recent features aren’t well-represented in AI training data&lt;/li&gt;
  &lt;li&gt;Setup procedures vary based on specific use cases and environments&lt;/li&gt;
  &lt;li&gt;Understanding requires connecting theoretical concepts (like PBFT consensus) with their actual implementation in your codebase&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;but-cant-i-just-describe-what-i-need-to-an-ai-and-have-it-build-the-solution-heres-why-that-doesnt-solve-the-core-problem&quot;&gt;But can’t I just describe what I need to an AI and have it build the solution? Here’s why that doesn’t solve the core problem:&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Knowledge Problem&lt;/strong&gt;: ChatGPT doesn’t know about your specific codebase. It can’t tell you which files implement consensus in ResilientDB, where transaction processing actually happens, or how different modules connect, because it’s never analyzed your repositories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Access Problem&lt;/strong&gt;: AI chat tools can’t authenticate to your repositories, can’t make GitHub API calls on your behalf, and can’t maintain persistent indexes of your evolving code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Integration Problem&lt;/strong&gt;: Even if you copy-paste code snippets to ChatGPT, it processes them in isolation. It can’t build a knowledge graph of your entire repository, maintain vector embeddings for semantic search across your whole codebase, or track dependencies and relationships across files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Consistency Problem&lt;/strong&gt;: Every time you ask ChatGPT about your code, you need to provide context again. There’s no persistent memory of your codebase structure, previous analyses, or the specific questions you’ve already explored. ChatGPT has a memory which is limited and once its full you need to clear it. If you have any questions, you will have to give the entire context again and repeat the process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Verification Problem&lt;/strong&gt;: When ChatGPT suggests something about ResilientDB’s implementation, how do you know if it’s accurate? There’s no way to trace its answer back to actual code or verify it against current repository state.&lt;/p&gt;

&lt;p&gt;What we needed wasn’t just an AI tool that could answer questions, we needed a tool that’s &lt;strong&gt;connected to our actual codebase&lt;/strong&gt; and can retrieve, analyze, and verify information from our specific repositories and applications.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-solution-resinsight-mcp-server&quot;&gt;The Solution: ResInsight MCP Server&lt;/h2&gt;

&lt;p&gt;ResInsight bridges this gap by connecting AI agents directly to your GitHub repositories through the Model Context Protocol (MCP). Instead of asking ChatGPT general questions and getting generic answers, you can now ask questions like:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Show me all files related to transaction processing in ResilientDB”&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;“How does the PBFT consensus implementation connect to the executor layer?”&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;“What are the dependencies for the Debitable application?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And get answers based on your &lt;strong&gt;actual codebase&lt;/strong&gt;, not generic blockchain knowledge.&lt;/p&gt;

&lt;!-- ![ResInsight Architecture Overview](assets/images/resInsight/resinsight_architecture.png) --&gt;

&lt;h3 id=&quot;what-makes-resinsight-different&quot;&gt;What Makes ResInsight Different&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Repository-Aware Intelligence&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ResInsight doesn’t guess, it knows. When you ask about a feature, it:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Searches your actual codebase using semantic embeddings&lt;/li&gt;
  &lt;li&gt;Analyzes the real file structure from your GitHub repository&lt;/li&gt;
  &lt;li&gt;Provides answers based on current code, not outdated documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Hybrid Search Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional code search is limited to exact keyword matching. ResInsight combines:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;FAISS Vector Search&lt;/strong&gt;: Understands code semantically (“find Byzantine fault tolerance logic” finds relevant code even without exact keywords)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;NetworkX Knowledge Graphs&lt;/strong&gt;: Maps structural relationships between files, showing you how modules actually connect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means you can ask conceptual questions (“where does transaction validation happen?”) and get accurate results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Domain-Specific ResilientDB Knowledge&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ResInsight includes a curated knowledge base covering:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Setup procedures for all 14+ ResilientDB applications&lt;/li&gt;
  &lt;li&gt;Architectural explanations connecting theory to implementation&lt;/li&gt;
  &lt;li&gt;PBFT consensus mechanisms specific to ResilientDB&lt;/li&gt;
  &lt;li&gt;Performance benchmarks and optimization strategies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you ask about ResilientDB concepts, you get answers from expert-curated content, not generic blockchain information scraped from the internet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Private Repository Access&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unlike public AI tools that only work with open-source code, ResInsight:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Authenticates with GitHub to access your private repositories&lt;/li&gt;
  &lt;li&gt;Works with internal lab projects and course assignments using authentication&lt;/li&gt;
  &lt;li&gt;Respects your access permissions, you only see repos you have access to&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Tool-First Design&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every capability is exposed as a discrete tool that can be inspected, tested, and verified. Instead of opaque AI responses, you get:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Explicit tool calls showing what data was retrieved&lt;/li&gt;
  &lt;li&gt;Reproducible results, same query always returns same data&lt;/li&gt;
  &lt;li&gt;No hallucination, answers come from actual repository data, not AI imagination&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;core-capabilities&quot;&gt;Core Capabilities&lt;/h2&gt;

&lt;h3 id=&quot;repository-analysis&quot;&gt;Repository Analysis&lt;/h3&gt;

&lt;p&gt;ResInsight provides comprehensive repository analysis through specialized tools:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File Navigation&lt;/strong&gt;: Quickly understand repository structure without manually browsing hundreds of files. The system intelligently handles both small and large repositories, automatically switching between API strategies for optimal performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic Code Search&lt;/strong&gt;: Find code by &lt;em&gt;meaning&lt;/em&gt;, not just keywords. Using sentence transformers and FAISS indexing, ResInsight understands that “Byzantine fault tolerance handling” and “BFT consensus logic” refer to similar concepts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function Extraction&lt;/strong&gt;: Get instant overview of what a file does by extracting its function definitions, class structures, and key components, without reading hundreds of lines of code.&lt;/p&gt;

&lt;h3 id=&quot;setup-assistance&quot;&gt;Setup Assistance&lt;/h3&gt;

&lt;p&gt;One of the most time-consuming aspects of working with new codebases is getting your environment configured correctly. ResInsight automates this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile Analysis&lt;/strong&gt;: Instead of manually parsing Docker commands, ResInsight breaks down Dockerfile instructions step-by-step, explaining dependencies and configuration choices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interactive Troubleshooting&lt;/strong&gt;: When you hit setup errors, ResInsight can analyze error messages in the context of your specific repository and provide targeted solutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment Validation&lt;/strong&gt;: Verify that your setup matches repository requirements before you waste time debugging environment issues.&lt;/p&gt;

&lt;h3 id=&quot;dependency-visualization&quot;&gt;Dependency Visualization&lt;/h3&gt;

&lt;p&gt;Understanding how code is organized is crucial for effective development. ResInsight generates visual dependency graphs showing:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Module import relationships&lt;/li&gt;
  &lt;li&gt;Component interconnections&lt;/li&gt;
  &lt;li&gt;Architectural patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This visual representation helps you quickly grasp code organization that would take hours to piece together manually.&lt;/p&gt;

&lt;!-- ![Arrayán Dependency Graph Example](assets/images/resInsight/dependency_graph_arrayan.png) --&gt;

&lt;h3 id=&quot;resilientdb-knowledge-base&quot;&gt;ResilientDB Knowledge Base&lt;/h3&gt;

&lt;p&gt;The integrated knowledge base provides instant answers to common ResilientDB questions:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“How do I set up Debitable?”&lt;/em&gt; → Step-by-step guide with prerequisites and configuration
&lt;em&gt;“What is Arrayán?”&lt;/em&gt; → Application overview, use cases, and integration points
&lt;em&gt;“How does PBFT work in ResilientDB?”&lt;/em&gt; → Consensus mechanism explained with implementation details&lt;/p&gt;

&lt;p&gt;This eliminates the frustration of searching through multiple repositories and documentation sources.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;real-impact-before-and-after&quot;&gt;Real Impact: Before and After&lt;/h2&gt;

&lt;h3 id=&quot;scenario-first-time-repository-setup&quot;&gt;Scenario: First-Time Repository Setup&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Traditional Experience:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In ECS 265, getting ResilientDB running locally was often the first major hurdle. The process typically went like this:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Read through README files across multiple repositories&lt;/li&gt;
  &lt;li&gt;Try following setup instructions&lt;/li&gt;
  &lt;li&gt;Hit environment-specific errors that weren’t documented&lt;/li&gt;
  &lt;li&gt;Search for error messages online (often finding nothing ResilientDB-specific)&lt;/li&gt;
  &lt;li&gt;Ask classmates or wait for TA office hours&lt;/li&gt;
  &lt;li&gt;Eventually get it working through trial and error, or develop on a groupmate’s setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This could take 2-3 days of a student’s time, not learning distributed systems concepts, but wrestling with configuration issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With ResInsight:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The same student can now ask: &lt;em&gt;“How do I set up ResilientDB locally?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ResInsight:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Analyzes the actual Dockerfile from the repository&lt;/li&gt;
  &lt;li&gt;Breaks down each installation step with context&lt;/li&gt;
  &lt;li&gt;Explains what each dependency does and why it’s needed&lt;/li&gt;
  &lt;li&gt;Provides troubleshooting guidance for common environment issues&lt;/li&gt;
  &lt;li&gt;Answers follow-up questions as they arise during setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: 4-6 hours to a working environment, with the student understanding &lt;em&gt;why&lt;/em&gt; each step matters, not just following commands blindly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Real Impact:&lt;/strong&gt; More time spent learning distributed systems and building projects, less time fighting with Docker and dependency versions.&lt;/p&gt;

&lt;h3 id=&quot;scenario-understanding-code-architecture&quot;&gt;Scenario: Understanding Code Architecture&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Traditional Experience:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When tasked with understanding how a feature works in ResilientDB (say, transaction processing), students typically:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Manually browsed through repository files, trying to guess which ones were relevant&lt;/li&gt;
  &lt;li&gt;Attempted to piece together module relationships from import statements&lt;/li&gt;
  &lt;li&gt;Searched for specific implementations across multiple files&lt;/li&gt;
  &lt;li&gt;Asked senior developers or TAs to explain the architecture&lt;/li&gt;
  &lt;li&gt;Spent hours building mental models that could have been generated in minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For someone new to distributed systems, connecting these pieces, understanding both what the code does and why it’s structured that way, was genuinely challenging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With ResInsight:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A student can now ask: &lt;em&gt;“Show me files related to transaction processing in ResilientDB”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ResInsight:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Performs semantic search across the codebase&lt;/li&gt;
  &lt;li&gt;Returns relevant files ranked by actual relevance to the concept&lt;/li&gt;
  &lt;li&gt;Generates a dependency graph showing how components connect&lt;/li&gt;
  &lt;li&gt;Answers follow-ups like &lt;em&gt;“How does this connect to the consensus layer?”&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then ask: &lt;em&gt;“Explain how PBFT is implemented here”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ResInsight:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Pulls explanation from the ResilientDB-specific knowledge base&lt;/li&gt;
  &lt;li&gt;Shows which actual files implement different PBFT phases&lt;/li&gt;
  &lt;li&gt;Connects theoretical concepts to practical implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: Understanding in minutes instead of hours, with the ability to verify everything against actual code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Real Impact:&lt;/strong&gt; Students can explore the codebase independently, at their own pace, building understanding incrementally rather than waiting for explanations.&lt;/p&gt;

&lt;h3 id=&quot;scenario-exploring-resilientdb-applications&quot;&gt;Scenario: Exploring ResilientDB Applications&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The Traditional Experience:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When assigned to work with a ResilientDB application like Debitable or Arrayán:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Clone the repository and hope the README is current&lt;/li&gt;
  &lt;li&gt;Try to understand dependencies by reading package.json or requirements.txt&lt;/li&gt;
  &lt;li&gt;Look for example code or tutorials (often finding none)&lt;/li&gt;
  &lt;li&gt;Attempt setup following possibly outdated instructions&lt;/li&gt;
  &lt;li&gt;Debug environment issues specific to that application&lt;/li&gt;
  &lt;li&gt;Eventually piece together understanding through experimentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This exploration phase could consume significant time that should have been spent on project development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With ResInsight:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A student working on Debitable can ask: &lt;em&gt;“What is Debitable and how does it integrate with ResilientDB?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ResInsight:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Retrieves curated overview from the ResilientDB knowledge base&lt;/li&gt;
  &lt;li&gt;Explains Debitable’s purpose, architecture, and key features&lt;/li&gt;
  &lt;li&gt;Shows the file structure and identifies key components&lt;/li&gt;
  &lt;li&gt;Provides setup guidance specific to Debitable’s requirements&lt;/li&gt;
  &lt;li&gt;Answers follow-ups about GraphQL integration, data models, or specific features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then ask: &lt;em&gt;“Show me how Debitable handles data uploads”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ResInsight:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Uses semantic search to find relevant React components&lt;/li&gt;
  &lt;li&gt;Identifies files like DataUploader.jsx, InventoryPage.jsx&lt;/li&gt;
  &lt;li&gt;Shows how these connect to ResilientDB API calls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: From zero understanding to basic comprehension in 15-20 minutes, with confidence to start building.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Real Impact:&lt;/strong&gt; Students spend their time building features and experimenting with blockchain concepts, not deciphering project structure.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;technical-architecture&quot;&gt;Technical Architecture&lt;/h2&gt;

&lt;h3 id=&quot;model-context-protocol-mcp&quot;&gt;Model Context Protocol (MCP)&lt;/h3&gt;

&lt;p&gt;ResInsight is built on the Model Context Protocol, which provides a standardized way for AI applications to connect with external data sources. This architecture enables:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Persistent Context&lt;/strong&gt;: Repository data is indexed once and queried many times&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tool Composition&lt;/strong&gt;: Multiple specialized tools work together for complex queries&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;: New tools can be added without changing the core system&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vendor Agnostic&lt;/strong&gt;: Works with Claude, could support other LLMs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;search-and-retrieval-system&quot;&gt;Search and Retrieval System&lt;/h3&gt;

&lt;p&gt;The hybrid search architecture combines complementary approaches:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vector Embeddings (FAISS)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Code chunks converted to 768-dimensional embeddings&lt;/li&gt;
  &lt;li&gt;Semantic similarity search enables conceptual queries&lt;/li&gt;
  &lt;li&gt;Fast retrieval even with millions of code chunks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Knowledge Graphs (NetworkX)&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;File dependencies mapped as directed graphs&lt;/li&gt;
  &lt;li&gt;Import relationships explicitly modeled&lt;/li&gt;
  &lt;li&gt;Structural queries like “what imports this module?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Repository Indexing&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Intelligent chunking maintains context&lt;/li&gt;
  &lt;li&gt;Metadata tracking preserves file/line information&lt;/li&gt;
  &lt;li&gt;Incremental updates for large repositories&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;authentication-and-security&quot;&gt;Authentication and Security&lt;/h3&gt;

&lt;p&gt;Security is built into every layer:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;MCP Token Authentication&lt;/strong&gt;: All client requests require valid tokens&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GitHub PAT Authorization&lt;/strong&gt;: Read-only repository access&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Environment-Based Secrets&lt;/strong&gt;: No credentials in code&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Request Validation&lt;/strong&gt;: All inputs sanitized and validated&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;how-to-use-resinsight&quot;&gt;How to Use ResInsight&lt;/h2&gt;

&lt;p&gt;ResInsight can be used in two ways: connect to the hosted ResilientDB deployment, or run your own local copy if you want to self-host or modify the server.&lt;/p&gt;

&lt;h3 id=&quot;option-1-use-the-hosted-resilientdb-deployment&quot;&gt;Option 1: Use the hosted ResilientDB deployment&lt;/h3&gt;

&lt;p&gt;If you only want to use ResInsight, you do not need to clone the repository. Point your MCP client at the hosted HTTP endpoint:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://52.45.172.212:8005/mcp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Important details:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mcp&lt;/code&gt; endpoint directly.&lt;/li&gt;
  &lt;li&gt;The server is running in Docker as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resinsight&lt;/code&gt; with port mapping &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8005:8005&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Use an MCP client that supports HTTP transport, such as Cursor or Claude Desktop.&lt;/li&gt;
  &lt;li&gt;Add the Bearer token issued by the lab to your client configuration.&lt;/li&gt;
  &lt;li&gt;Do not rely on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mcp/tools&lt;/code&gt;; those paths are not the supported client entry point.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;option-2-run-it-locally&quot;&gt;Option 2: Run it locally&lt;/h3&gt;

&lt;p&gt;If you want to run your own instance, clone the repository and start the MCP server locally:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Clone the repo and move into the ResInsight directory.&lt;/li&gt;
  &lt;li&gt;Create and activate a Python virtual environment.&lt;/li&gt;
  &lt;li&gt;Install dependencies from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requirements.txt&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file with your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GITHUB_TOKEN&lt;/code&gt; and a locally chosen &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MCP_TOKEN&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Start the server with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python server.py&lt;/code&gt;, or build and run the Docker image if you prefer containers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For local use, your MCP client should send the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MCP_TOKEN&lt;/code&gt; value that the server reads from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt;. For cloud use, the client must send the Expo Lab team-issued token for the hosted endpoint.&lt;/p&gt;

&lt;h3 id=&quot;mcp-client-configuration&quot;&gt;MCP client configuration&lt;/h3&gt;
&lt;p&gt;Now, to configure an MCP client use one of the following two options depending on the option that you chose above to run the application:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Use command-based MCP configuration only when you are running ResInsight locally (self-hosted):&lt;/p&gt;

    &lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mcpServers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;resinsight&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;python&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;C:/path/to/incubator-resilientdb/ecosystem/ai-tools/mcp/ResInsight/server.py&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;env&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;GITHUB_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ghp_...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;MCP_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;your_local_secret_or_team_issued_token&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python + server.py&lt;/code&gt; setup, do not place the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mcp&lt;/code&gt; URL inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;args&lt;/code&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;args&lt;/code&gt; field is only the local script path.&lt;/p&gt;

&lt;h3 id=&quot;http-transport-clients-like-claude&quot;&gt;HTTP transport clients like Claude&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;If your application supports native remote HTTP MCP entries, configure the deployed endpoint like this:&lt;/p&gt;

    &lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://52.45.172.212:8005/mcp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;headers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Bearer MCP_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;For Claude use:&lt;/p&gt;

    &lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mcpServers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ResInsight: AI-driven developer onboarding ecosystem&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;npx&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;-y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mcp-remote&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://52.45.172.212:8005/mcp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;--header&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Authorization: Bearer MCP_TOKEN&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;env&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                 &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;MCP_REMOTE_CONFIG_DIR&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;C:/Users/your-user/.mcp-auth&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
             &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
         &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
     &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; `MCP_REMOTE_CONFIG_DIR` is optional. Keep it only if you want to control where bridge auth/session files are stored.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Important: keep a space after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bearer&lt;/code&gt; in the header value (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authorization: Bearer ...&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The direct Claude local setup (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;python + server.py&lt;/code&gt;) remains the preferred self-hosted option. The deployed endpoint should be configured with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mcp&lt;/code&gt; URL in the remote HTTP settings (or bridge argument), not in Python script args.&lt;/p&gt;

&lt;p&gt;For local self-hosted runs, replace the hosted URL with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:8005/mcp&lt;/code&gt; and use the token from your own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Note: command + args appears in both modes. For local mode, command launches `python server.py`. For deployed mode in some clients, command launches an HTTP bridge tool (such as `mcp-remote`) that forwards to the `/mcp` URL.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;measuring-success&quot;&gt;Measuring Success&lt;/h2&gt;

&lt;p&gt;The real measure of ResInsight’s impact isn’t in technical metrics, it’s in changed developer experiences:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time Savings&lt;/strong&gt;: Tasks that took days now take hours. Questions that required waiting for senior developers get answered immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Independence&lt;/strong&gt;: New developers can explore and learn at their own pace, without constantly interrupting others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confidence&lt;/strong&gt;: When setup actually works the first time, when you understand why code is structured a certain way, when you can find what you need, that confidence compounds over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Knowledge Access&lt;/strong&gt;: Information that was previously locked in senior developers’ experience is now available to everyone.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h2&gt;

&lt;p&gt;ResInsight represents a first step toward making sophisticated codebases more accessible. Future directions include:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automated PR Analysis&lt;/strong&gt;: Intelligent code review suggestions based on repository conventions and patterns&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interactive Learning Paths&lt;/strong&gt;: Guided tutorials that adapt based on your questions and progress&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team Knowledge Sharing&lt;/strong&gt;: Capture and share team-specific insights and best practices&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-Repository Understanding&lt;/strong&gt;: Answer questions that span multiple related repositories&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;a-note-on-scope&quot;&gt;A Note on Scope&lt;/h2&gt;

&lt;p&gt;ResInsight is designed for a specific problem: helping developers understand and work with existing codebases. It’s not trying to replace developers, automate all coding tasks, or solve every development challenge.&lt;/p&gt;

&lt;p&gt;What it does do is eliminate the frustrating parts of onboarding, the hours spent searching for the right file, the days debugging environment setup, the uncertainty about whether you’re understanding things correctly.&lt;/p&gt;

&lt;p&gt;By handling these mechanical tasks, ResInsight lets developers focus on what matters: understanding concepts, building features, and solving real problems.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;getting-involvedcontact&quot;&gt;Getting Involved/Contact&lt;/h2&gt;

&lt;p&gt;ResInsight is open source and available to the ResilientDB community. If you’re a student taking ECS 265, a lab member working on ResilientDB projects, or a researcher exploring the platform, you can start using ResInsight today.&lt;/p&gt;

&lt;p&gt;For access, contact kunjalagrawal2002@gmail.com or Prof. Sadoghi at msadoghi@expolab.org / msadoghi@ucdavis.edu.&lt;/p&gt;

&lt;p&gt;The code is available at: &lt;a href=&quot;https://github.com/apache/incubator-resilientdb/tree/master/ecosystem/ai-tools/mcp/ResInsight&quot;&gt;ResInsight&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contributions are welcome, whether it’s improving the knowledge base, adding new tools, or enhancing search capabilities.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;

&lt;p&gt;This project was inspired by the collaborative spirit of the ExpoLab community. Special thanks to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fellow ECS 265 students who helped me clearly understand what issues they faced when they took ECS 265 and when they started working with ResilientDB.&lt;/li&gt;
  &lt;li&gt;ExpoLab team for supporting this work&lt;/li&gt;
  &lt;li&gt;Professor Mohammad Sadoghi for his guidance throughout the project.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;ResInsight was born from a genuine need I experienced as a student learning distributed systems and blockchain technology. It’s not trying to replace the excellent work being done by the ResilientDB team, the growing documentation efforts, or the collaborative spirit of the ExpoLab community.&lt;/p&gt;

&lt;p&gt;Instead, ResInsight addresses a specific gap: the mechanical obstacles that slow down learning. It handles the frustrating parts, finding the right file, understanding repository structure, debugging setup issues, so developers can focus on what matters: grasping distributed systems concepts, understanding consensus mechanisms, and building innovative applications.&lt;/p&gt;

&lt;h3 id=&quot;what-this-changes&quot;&gt;What This Changes&lt;/h3&gt;

&lt;p&gt;For future ECS 265 students and new ResilientDB developers, ResInsight means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Independence&lt;/strong&gt;: Learn at your own pace without waiting for office hours or interrupting teammates
&lt;strong&gt;Confidence&lt;/strong&gt;: Verify your understanding against actual code, not guesses
&lt;strong&gt;Efficiency&lt;/strong&gt;: Spend time on concepts and projects, not configuration struggles&lt;br /&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Expert knowledge available 24/7, not locked in senior developers’ heads&lt;/p&gt;

&lt;h3 id=&quot;the-broader-picture&quot;&gt;The Broader Picture&lt;/h3&gt;

&lt;p&gt;As ResilientDB continues to grow, more applications, more features, more complexity,tools like ResInsight become increasingly valuable. They ensure that the platform’s sophistication enhances rather than hinders its accessibility.&lt;/p&gt;

&lt;p&gt;This is especially important for an academic research platform where:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;New students join each quarter with varying backgrounds&lt;/li&gt;
  &lt;li&gt;Code evolves rapidly with cutting-edge research&lt;/li&gt;
  &lt;li&gt;Learning happens alongside building&lt;/li&gt;
  &lt;li&gt;Time spent stuck on setup is time not spent learning&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Tags&lt;/strong&gt;: #ResilientDB #DeveloperExperience #AI #MCP #Onboarding #ExpoLab&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;ResInsight is part of the ResilientDB ecosystem. Learn more about ResilientDB at &lt;a href=&quot;https://expolab.resilientdb.com/&quot;&gt;expolab.resilientdb.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//developer%20tools/2026/04/15/ResInsight.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//developer%20tools/2026/04/15/ResInsight.html</guid>
      </item>
    
      <item>
        <title>Charitap: Transforming Spare Change into Social Impact</title>
        <description>&lt;h1 id=&quot;charitap-transforming-spare-change-into-social-impact&quot;&gt;Charitap: Transforming Spare Change into Social Impact&lt;/h1&gt;

&lt;p&gt;Giving back shouldn’t be difficult, yet many potential donors are held
back by a lack of transparency, and the friction of complicated donation
processes. Traditional models often pressure individuals to make large,
one-time contributions, which can feel overwhelming and lead to a total
deterrent from regular giving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Charitap&lt;/strong&gt; changes this narrative by making philanthropy effortless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Useful Links&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Website is live at:
&lt;a href=&quot;https://charitap-frontend.vercel.app&quot;&gt;https://charitap-frontend.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code Repository:
&lt;a href=&quot;https://github.com/ResilientApp/Charitap&quot;&gt;https://github.com/ResilientApp/Charitap&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Presentation Slides:
&lt;a href=&quot;https://github.com/ResilientApp/Charitap/blob/chrome-extension/Presentation%20-%20Charitap.pdf&quot;&gt;https://github.com/ResilientApp/Charitap/blob/chrome-extension/Presentation%20-%20Charitap.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo:
&lt;a href=&quot;https://drive.google.com/file/d/1hs5s6Y1NnB4djBBSIoU4bPaFRvC6t5Mp/view?usp=sharing&quot;&gt;https://drive.google.com/file/d/1hs5s6Y1NnB4djBBSIoU4bPaFRvC6t5Mp/view?usp=sharing&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-motivation-why-we-built-this&quot;&gt;&lt;strong&gt;The Motivation: Why We Built This&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Many people genuinely want to help but struggle to choose charities
wisely or track exactly where their funds go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &quot;Milk&quot; Use Case: Low-Pressure Philanthropy&lt;/strong&gt; Imagine the
simplicity of a routine trip to the grocery store. You buy a gallon of
milk for &lt;strong&gt;$3.60&lt;/strong&gt;. In a traditional setting, you might be asked to
donate $5 or $10 at the register, which feels like a &quot;pressure
point.&quot;&lt;/p&gt;

&lt;p&gt;With Charitap, you don’t even have to think about it. The system
automatically detects the purchase and &quot;rounds up&quot; the transaction to
&lt;strong&gt;$4.00&lt;/strong&gt;. That &lt;strong&gt;$0.40&lt;/strong&gt; difference, essentially just &quot;spare
change&quot; is quietly set aside. You walk away with your milk, knowing
you’ve contributed to a cause you love without it ever impacting your
daily budget or requiring a conscious decision at the checkout line. It
turns the act of living into an act of giving.&lt;/p&gt;

&lt;h3 id=&quot;the-charitap-journey-from-checkout-to-change&quot;&gt;&lt;strong&gt;The Charitap Journey: From Checkout to Change&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Step 1: Users sign up or log in to their personal impact portal. This is
where your journey of giving begins.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/charitap/image7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Seamless signup experience with Google OAuth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 2: Charitap works silently in the background. When you visit any of
the millions of supported e-commerce sites and reach the checkout, the
extension springs to life.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/charitap/image4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Charitap automatically detects your cart total on sites like Amazon or
Shopify and offers to round up your spare change.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 3: One-Click Impact &amp;amp; Celebration With a single click on the &quot;✓&quot;
button, your donation is processed. To celebrate your kindness, the
screen bursts with confetti, providing instant confirmation that you’ve
made a difference.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/charitap/image3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Making the world better, one cent at a time&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 4: Head back to the Charitap dashboard to see the big picture.
Here, you can track your total donations, see how many &quot;round-ups&quot;
you’ve completed, and view your impact trends over time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/charitap/image2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your personal command center for tracking the power of your collective
kindness.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 5: The Activity page provides a detailed Ledger of every
transaction. Each entry is linked to a ResilientDB blockchain ID,
providing 100% proof of your donation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/charitap/image5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every cent is logged on an immutable blockchain for you to verify.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Step 6: Nominate your favorite charities, update your profile, and
manage your account to ensure your philanthropy is as personal as it is
impactful.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/charitap/image1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customizing your experience to support the causes that matter most to
you.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;core-features-at-a-glance&quot;&gt;&lt;strong&gt;Core Features at a Glance&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Universal Compatibility:&lt;/strong&gt; Charitap is built with a sophisticated
  detection engine that automatically recognizes checkout and
  payment pages across millions of websites. Whether you are
  shopping on Amazon, Shopify-powered boutiques, or eBay, Charitap
  intelligently identifies the moment you’re about to pay and offers
  a way to give back.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Blockchain-Backed Trust:&lt;/strong&gt; In an era where trust is everything,
  Charitap leads with transparency. Every single donation is
  recorded on ResilientDB, a high-performance blockchain. This
  ensures that every cent you donate is immutable and traceable,
  providing total peace of mind that your contribution is reaching
  its intended destination.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Premium “Glassmorphic” UI/UX:&lt;/strong&gt; The extension features a premium
  floating widget designed with modern glassmorphism and vibrant
  gradients. It stays out of your way until it’s needed, appearing
  only during the final steps of your purchase with smooth, subtle
  animations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Privacy-First Filtering &amp;amp; Smart Cooldowns:&lt;/strong&gt; Charitap respects
  your digital space. It is programmed to exclude non-shopping sites
  like Instagram, Facebook, and Gmail to prevent intrusive popups.
  Furthermore, it features an intelligent cooldown system; if you
  choose to skip a donation, the widget politely stays hidden for an
  hour to avoid &quot;notification fatigue.&quot;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Real-Time Impact Dashboard:&lt;/strong&gt; Connected to a robust backend,
  Charitap tracks your lifetime impact. Users can see their total
  contributions, the number of &quot;round-ups&quot; completed, and their
  verified blockchain transaction history, allowing you to see the
  tangible weight of your collective kindness over time.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;technical-deep-dive-the-hybrid-architecture&quot;&gt;&lt;strong&gt;Technical Deep Dive: The Hybrid Architecture&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/charitap/image6.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Charitap is a multi-layered system designed to bridge the gap between
traditional finance (fiat) and decentralized ledgers.&lt;/p&gt;

&lt;h4 id=&quot;1-the-frontend-stack&quot;&gt;&lt;strong&gt;1. The Frontend Stack&lt;/strong&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;ReactJS &amp;amp; Tailwind CSS:&lt;/strong&gt; Powers the responsive dashboard for a
  modern, high-performance user experience.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Google OAuth &amp;amp; JWT:&lt;/strong&gt; Ensures secure, one-tap login for users.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Chrome Extension (Manifest v3):&lt;/strong&gt; Built to be lightweight and
  secure, monitoring DOM elements on specific retail sites to
  capture transaction totals.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;2-the-server-engine&quot;&gt;&lt;strong&gt;2. The Server Engine&lt;/strong&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Node.js &amp;amp; Express:&lt;/strong&gt; The central nervous system that coordinates
  between the extension, the database, and the blockchain.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Node-Cron:&lt;/strong&gt; A scheduled processor that &quot;collects&quot; the small
  round-up entries. To minimize transaction fees on the payment
  side, this job batches your change until it reaches a threshold
  before triggering a transfer.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;MongoDB:&lt;/strong&gt; Stores off-chain metadata like user preferences and
  charity profiles for lightning-fast retrieval on the dashboard.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;3-the-financial--blockchain-layer&quot;&gt;&lt;strong&gt;3. The Financial &amp;amp; Blockchain Layer&lt;/strong&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Stripe Connect:&lt;/strong&gt; We use Stripe’s enterprise-grade infrastructure
  to handle the actual movement of money from your bank to the
  charity.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;ResilientDB (The Truth Layer):&lt;/strong&gt; While Stripe handles the USD,
  ResilientDB provides the &lt;strong&gt;Proof&lt;/strong&gt;. Every donation is logged via a
  &lt;strong&gt;GraphQL&lt;/strong&gt; endpoint to an immutable KV store, creating a
  permanent audit trail.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;beyond-logging-smart-contracts--verification&quot;&gt;&lt;strong&gt;Beyond Logging: Smart Contracts &amp;amp; Verification&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;While ResilientDB provides an immutable log of &quot;what happened,&quot;
Charitap utilizes &lt;strong&gt;Smart Contracts&lt;/strong&gt; to add a layer of functional logic
and automated receipts.&lt;/p&gt;

&lt;h4 id=&quot;rescontract-the-digital-receipt-system&quot;&gt;&lt;strong&gt;ResContract: The Digital Receipt System&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;In the Charitap ecosystem, every donation isn’t just a number; it’s a
verifiable event. We use &lt;strong&gt;ResContract&lt;/strong&gt; to mint &lt;strong&gt;Digital Donation
Receipts&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Automated Minting:&lt;/strong&gt; The moment Stripe confirms a transfer, the
  server triggers a smart contract on the ResilientDB chain.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Mathematical Integrity:&lt;/strong&gt; The contract ensures that the total
  &quot;Impact&quot; displayed on your dashboard matches the actual state
  recorded on the blockchain. This prevents any central authority
  (including us) from altering your donation history or misreporting
  figures.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;steps-to-run-the-system&quot;&gt;&lt;strong&gt;Steps to Run the System&lt;/strong&gt;&lt;/h3&gt;

&lt;h4 id=&quot;prerequisites&quot;&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Node.js&lt;/strong&gt; (v16+)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;MongoDB&lt;/strong&gt; (Local or Atlas)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;ResilientDB instance&lt;/strong&gt; (Local or Remote)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Stripe Account&lt;/strong&gt; (Test mode keys)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;installation&quot;&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Clone the repository&lt;/strong&gt; git clone
  https://github.com/ResilientApp/Charitap.git&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Install Frontend Dependencies&lt;/strong&gt; cd src&lt;br /&gt;
  npm install&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Install Backend Dependencies&lt;/strong&gt; cd backend&lt;br /&gt;
  npm install&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;environment-setup&quot;&gt;&lt;strong&gt;Environment Setup&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Create .env files and add the necessary keys:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;MONGODB_URI&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;STRIPE_SECRET_KEY&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;RESILIENTDB_URL&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;(Other necessary environment variables, refer to the example env)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;run-the-application&quot;&gt;&lt;strong&gt;Run the Application&lt;/strong&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Backend:&lt;/strong&gt; cd backend &amp;amp;&amp;amp; npm run dev&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Frontend:&lt;/strong&gt; npm start (from root)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;contributions&quot;&gt;&lt;strong&gt;Contributions&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Aman Dwivedi:&lt;/strong&gt; Built the Chrome Extension and the roundup logic
  for logging user transactions into the database. Integrated Smart
  Contracts to mint donation receipts for user-charity transactions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Dhairye Gala:&lt;/strong&gt; Constructed the NodeJS server, providing API
  endpoints for the frontend and Chrome extension. Setup the payment
  flow from the user bank account to the charity’s account using
  Stripe Connect.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Himanshu Nimonkar:&lt;/strong&gt; Engineered the React/Tailwind dashboard with
  real-time Chart.js visualizations for tracking donation impact.
  Integrated Google OAuth, Stripe, and a GraphQL-powered ResilientDB
  public ledger for immutable transaction transparency.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;our-mission&quot;&gt;&lt;strong&gt;Our Mission&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Developed at the &lt;strong&gt;Expolab (UC Davis)&lt;/strong&gt; by Aman Dwivedi, Dhairye Gala,
and Himanshu Nimonkar, Charitap is a proof-of-concept for the future of
&quot;Resilient&quot; finance. Under the guidance of &lt;strong&gt;Professor Mohammad
Sadoghi&lt;/strong&gt;, we are proving that even the smallest change can change the
world when it is backed by a foundation of transparency and
high-performance distributed systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ready to turn your shopping into a force for good?&lt;/strong&gt; Start small, give
big with Charitap.&lt;/p&gt;
</description>
        <pubDate>Wed, 25 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2026/02/25/Charitap.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2026/02/25/Charitap.html</guid>
      </item>
    
      <item>
        <title>ResShare: A Decentralized File Sharing Network Built on ResilientDB and IPFS</title>
        <description>&lt;h1 id=&quot;resshare---decentralized-file-sharing-application-with-ai-chatbot&quot;&gt;ResShare - Decentralized File Sharing Application with AI Chatbot&lt;/h1&gt;

&lt;p&gt;ResShare is a decentralized file sharing application that allows users to securely store, share, and manage their files using Resilient DB technology. The application now features an &lt;strong&gt;AI-powered chatbot&lt;/strong&gt; that can answer questions about your uploaded documents using Retrieval-Augmented Generation (RAG).&lt;/p&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;With the rapid advancement of personal computing hardware, modern users now routinely own devices equipped with hundreds of gigabytes—or even multiple terabytes—of local storage. However, in practice, a significant portion of this storage capacity remains underutilized. For most users, less than half of their available disk space is actively used, leaving a vast amount of idle storage resources scattered across personal computers worldwide.&lt;/p&gt;

&lt;p&gt;At the same time, existing cloud storage solutions rely heavily on centralized infrastructures, which introduce concerns related to cost, scalability, data ownership, single points of failure, and long-term sustainability. Users are required to entrust their data to centralized providers, often with limited transparency or control over how their data is stored, replicated, or accessed.&lt;/p&gt;

&lt;p&gt;The core motivation behind ResShare is to bridge this gap by transforming unused local storage into a collectively shared, decentralized storage network. Instead of letting idle disk space go to waste, ResShare enables users to contribute their surplus storage capacity to a peer-to-peer ecosystem, where storage is shared, replicated, and managed in a decentralized and fault-tolerant manner.&lt;/p&gt;

&lt;p&gt;By building on ResilientDB for reliable metadata management and IPFS for content-addressed distributed storage, ResShare aims to create a storage system that is not only efficient and scalable, but also resilient to failures and censorship. In this model, storage becomes a shared community resource rather than a centralized service, aligning incentives across users while preserving data ownership and privacy.&lt;/p&gt;

&lt;p&gt;Ultimately, ResShare envisions a future where personal devices collaboratively form a decentralized storage backbone—leveraging existing, underutilized resources to provide a more sustainable, trustworthy, and user-centric alternative to traditional cloud storage systems.&lt;/p&gt;

&lt;h2 id=&quot;features&quot;&gt;Features&lt;/h2&gt;

&lt;h3 id=&quot;core-features&quot;&gt;Core Features&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;User Authentication (Sign up, Login, Logout)&lt;/li&gt;
  &lt;li&gt;File Upload and Download&lt;/li&gt;
  &lt;li&gt;Folder Creation and Management&lt;/li&gt;
  &lt;li&gt;File Sharing between Users&lt;/li&gt;
  &lt;li&gt;Secure File Storage using IPFS&lt;/li&gt;
  &lt;li&gt;User Account Management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;ai-document-assistant&quot;&gt;AI Document Assistant&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Intelligent Document Q&amp;amp;A&lt;/strong&gt;: Ask questions about your uploaded files&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Multi-format Support&lt;/strong&gt;: Works with PDF, DOCX, and TXT files&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Semantic Search&lt;/strong&gt;: Finds relevant information across all your documents&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Privacy-First&lt;/strong&gt;: Your data stays isolated and secure&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Source Attribution&lt;/strong&gt;: See which documents were used to answer your questions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;tech-stack&quot;&gt;Tech Stack&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: React.js with Material-UI&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Python Flask&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Storage&lt;/strong&gt;: ResilientDB for Metadata storage and IPFS for File Storage&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: Session-based authentication&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;AI/ML&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;Sentence Transformers for embeddings&lt;/li&gt;
      &lt;li&gt;FAISS for vector search&lt;/li&gt;
      &lt;li&gt;Gemini GPT (optional) or local models for response generation&lt;/li&gt;
      &lt;li&gt;LangChain for text processing&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Python 3.8+&lt;/li&gt;
  &lt;li&gt;Node.js 16+ and npm&lt;/li&gt;
  &lt;li&gt;IPFS daemon running locally&lt;/li&gt;
  &lt;li&gt;(Optional) Gemini API key for enhanced AI responses&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Clone the repository:&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/NoBugInMyCode/ResShareDeployable.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ResShareDeployable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Install backend dependencies:&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Install frontend dependencies:&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;frontend
npm &lt;span class=&quot;nb&quot;&gt;install
cd&lt;/span&gt; ..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Set up AI features (Optional but recommended):&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# For enhanced AI responses, set your Gemini API key&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GOOGLE_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;your-gemini-api-key-here&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;running-the-application&quot;&gt;Running the Application&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Start the IPFS daemon:&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ipfs daemon
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;&lt;em&gt;To install IPFS Cluster Service, please refer to &lt;a href=&quot;https://ipfscluster.io/download/&quot;&gt;this link&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Start the backend server:&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python app.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Start the frontend development server:&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;frontend
npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The application will be available at:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Frontend: http://localhost:3000&lt;/li&gt;
  &lt;li&gt;Backend API: http://localhost:5000&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;using-the-ai-chatbot&quot;&gt;Using the AI Chatbot&lt;/h2&gt;

&lt;h3 id=&quot;getting-started-with-ai&quot;&gt;Getting Started with AI&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Upload Documents&lt;/strong&gt;: Upload PDF, DOCX, or TXT files through the normal file upload process&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Navigate to AI Chat&lt;/strong&gt;: Click the “AI Chat” button in the navigation bar&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ask Questions&lt;/strong&gt;: Type questions about your documents and get intelligent responses&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;example-queries&quot;&gt;Example Queries&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;“What are the main findings in my research paper?”&lt;/li&gt;
  &lt;li&gt;“Summarize the key points from my meeting notes”&lt;/li&gt;
  &lt;li&gt;“What does my contract say about payment terms?”&lt;/li&gt;
  &lt;li&gt;“Find information about project deadlines”&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;supported-file-types-for-ai&quot;&gt;Supported File Types for AI&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;PDF&lt;/strong&gt;: Research papers, reports, contracts&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;DOCX&lt;/strong&gt;: Word documents, meeting notes, proposals&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;TXT&lt;/strong&gt;: Plain text files, code documentation, notes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;ai-features&quot;&gt;AI Features&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Smart Chunking&lt;/strong&gt;: Documents are intelligently split into semantic chunks&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vector Search&lt;/strong&gt;: Uses advanced embeddings to find relevant content&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Source Attribution&lt;/strong&gt;: Shows which files and sections were used for answers&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Privacy Preserved&lt;/strong&gt;: Each user’s AI data is completely isolated&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;

&lt;h3 id=&quot;basic-configuration-no-api-key-required&quot;&gt;Basic Configuration (No API key required)&lt;/h3&gt;
&lt;p&gt;The AI chatbot works out of the box with:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Local sentence transformer models for embeddings&lt;/li&gt;
  &lt;li&gt;FAISS for fast vector search&lt;/li&gt;
  &lt;li&gt;Simple extractive responses&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;enhanced-configuration-with-gemini&quot;&gt;Enhanced Configuration (With Gemini)&lt;/h3&gt;
&lt;p&gt;For higher quality responses, set up Gemini:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GOOGLE_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sk-your-key-here&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;

&lt;h3 id=&quot;standard-file-operations&quot;&gt;Standard File Operations&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;Create a new account using the sign-up feature&lt;/li&gt;
  &lt;li&gt;Log in to your account&lt;/li&gt;
  &lt;li&gt;Create folders to organize your files&lt;/li&gt;
  &lt;li&gt;Upload files to your folders&lt;/li&gt;
  &lt;li&gt;Share files with other users&lt;/li&gt;
  &lt;li&gt;Download shared files from other users&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;ai-powered-features&quot;&gt;AI-Powered Features&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Upload Text Documents&lt;/strong&gt;: Upload PDF, DOCX, or TXT files&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Wait for Processing&lt;/strong&gt;: Files are automatically processed for AI search&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ask Questions&lt;/strong&gt;: Use the AI Chat interface to query your documents&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Get Intelligent Answers&lt;/strong&gt;: Receive responses with source attribution&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Explore Knowledge Base&lt;/strong&gt;: View statistics about your indexed documents&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;

&lt;h3 id=&quot;rag-pipeline&quot;&gt;RAG Pipeline&lt;/h3&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;File Upload → Text Extraction → Chunking → Embedding → Vector DB Storage
                                                            ↓
User Query → Query Embedding → Vector Search → Context → LLM → Response
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/resshare/pipelineImage.png&quot; alt=&quot;Image&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;components&quot;&gt;Components&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Text Extractors&lt;/strong&gt;: PDF (PyPDF2), DOCX (python-docx), TXT (UTF-8)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Chunking&lt;/strong&gt;: LangChain RecursiveCharacterTextSplitter&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Embeddings&lt;/strong&gt;: Google Gemini API (gemini-embedding-001) with configurable dimensions (768/1536/3072)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vector DB&lt;/strong&gt;: FAISS with per-user isolation&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;LLM&lt;/strong&gt;: Gemini 2.5 Flash (optional) or extractive fallback&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Mon, 02 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2026/02/02/ResShare.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2026/02/02/ResShare.html</guid>
      </item>
    
      <item>
        <title>Implementing Raft Consensus Protocol for ResilientDB</title>
        <description>&lt;h1 id=&quot;what-is-raft&quot;&gt;What is Raft?&lt;/h1&gt;

&lt;p&gt;Raft is a consensus protocol used in many existing software systems including Kubernetes, Kafka, and MongoDB. It has been battle-tested in many circumstances since it was first described in 2013. The ResilientDB project on GitHub has had an open issue since October 2023 for Raft to be added to the portfolio of available consensus protocols. We aim to fulfill this feature request.&lt;/p&gt;

&lt;p&gt;Raft is a crash fault tolerant (CFT) protocol, and would be the first non-Byzantine fault tolerant (BFT) consensus protocol available within ResilientDB, which does come with benefits. A ResilientDB deployment would be able to function with only 3 replicas instead of the current minimum of 4 replicas. ResilientDB transaction throughput would scale far better with the number of replicas increases due to the preferable asymptotic message complexity of Raft (O(n)) compared to the PBFT family of protocols (O(n&lt;sup&gt;2&lt;/sup&gt;)). The performance overhead of cryptography in the BFT protocols is also quite high, so latency improvements can also be expected while using Raft.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/protocolOverview.png&quot; alt=&quot;Raft Protocol Diagram&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Picture describing Raft Protocol
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;how-it-differs-from-pbft&quot;&gt;How It Differs from PBFT&lt;/h2&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/RaftvsPBFT.png&quot; alt=&quot;PBFT vs Raft Table&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Table comparing Raft vs PBFT
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;useful-links&quot;&gt;Useful Links&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Official Raft consensus protocol paper: &lt;a href=&quot;https://raft.github.io/raft.pdf&quot;&gt;https://raft.github.io/raft.pdf&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Protocol is currently in this repo: &lt;a href=&quot;https://github.com/hammerface/incubator-resilientdb/tree/raft&quot;&gt;https://github.com/hammerface/incubator-resilientdb/tree/raft&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;our-implementation-strategy-and-architecture&quot;&gt;Our Implementation Strategy and Architecture&lt;/h1&gt;

&lt;p&gt;For our implementation, we chose to build on existing consensus protocol code, considering both PBFT and PoE, and ultimately selecting PoE for its simpler and more extensible design. The Consensus class exposes a ProcessCustomConsensus() method that lets us send custom message types through the RPC dispatcher, which in turn allows us to reuse existing components for database access and client notifications via TransactionManager, as well as replica messaging via ReplicaCommunicator. Our approach also benefits from built-in benchmarking support through the PerformanceManager module.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/Architecture.png&quot; alt=&quot;Implementation Architecture&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. Implementation Architecture
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;1-append-entries-rpc---log-replication&quot;&gt;1. Append Entries RPC - Log Replication&lt;/h2&gt;

&lt;p&gt;In Raft, log replication is driven by the leader: whenever a client sends a command, the leader appends it to its own log and then sends AppendEntries RPCs to followers to copy the new log entries. Followers accept an entry only if it follows a log prefix that matches the leader’s (same term and index), which keeps logs consistent across the cluster. Once a majority of followers have stored an entry, the leader commits it and applies it to the state machine, then notifies followers so they can commit it too. Catchup happens naturally for slow or rebooted followers: the leader keeps sending them AppendEntries starting from their nextIndex until their log matches the leader’s, filling in any missing or outdated entries along the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our Implementation Logs&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/AppendEntriesLogs.png&quot; alt=&quot;Append Entries Logs&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. Append Entries Logs
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;2-leader-election&quot;&gt;2. Leader Election&lt;/h2&gt;

&lt;p&gt;In Raft, leader elections occur when servers do not hear from the current leader within their timeout window. Each server starts as a follower. If a follower doesn’t receive a heartbeat or log entry from a leader within a timeout, it becomes a candidate, increments its term, and asks the other servers for votes. Servers will vote for at most one candidate per term, and they only vote for a candidate whose log is at least as up to date as their own. If a candidate receives votes from a majority, it becomes the new leader and immediately starts sending heartbeats to assert its authority and prevent new elections. If there’s a tie (no one gets a majority), everyone times out again with slightly randomized timers and the election is retried until a leader is chosen.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/LeaderElection.png&quot; alt=&quot;Leader Election Diagram&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Leader Election Diagram
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Our Implementation Logs&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/raft/LeaderElectionLogs.png&quot; alt=&quot;Leader Election Logs&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 6. Aggregated Excerpts about Leader Election from the Logs
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;commands-to-execute&quot;&gt;Commands to Execute&lt;/h2&gt;
&lt;p&gt;Here are the commands to download Resilient DB, build it, and run the RAFT and PBFT performance scripts:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt update&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt-get install git&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt install psmisc&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git clone https://github.com/apache/incubator-resilientdb.git&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd incubator-resilientdb/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./INSTALL.sh&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./service/tools/kv/server_tools/start_kv_service.sh&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bazel build service/tools/kv/api_tools/kv_service_tools&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd scripts/deploy/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;touch config/key.conf&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./performance_local/raft_performance.sh config/kv_performance_server_local.conf&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./performance_local/pbft_performance.sh config/kv_performance_server_local.conf&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;benchmarks&quot;&gt;Benchmarks&lt;/h2&gt;

&lt;p&gt;Here is our output after running both of the performance scripts, with PBFT results gathered using the main branch:&lt;/p&gt;

&lt;p&gt;Note, both configurations have the minimum number of nodes for f = 1 (the client is included as a node, so 4 replicas for PBFT and 3 replicas for Raft).&lt;/p&gt;

&lt;p&gt;PBFT:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;calculate results, number of nodes: 5
max throughput: 44660
average throughput: 20871.272727272728
max latency: 0.000144599
average latency: 0.000107366275
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Raft:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;calculate results, number of nodes: 4
max throughput: 104418
average throughput: 45385.2
max latency: 8.15001e-05
average latency: 6.7288925e-05
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Raft outperforms PBFT both in terms of throughput and latency, by roughly double. We ran into issues with the leader election with 4 Raft nodes, which we are still looking into.&lt;/p&gt;

&lt;h2 id=&quot;looking-ahead&quot;&gt;Looking Ahead&lt;/h2&gt;

&lt;p&gt;-&lt;strong&gt;Batching&lt;/strong&gt; - Groups multiple client transactions into a single Append Entry RPC to significantly boost throughput and reduce network overhead.&lt;/p&gt;

&lt;p&gt;-&lt;strong&gt;State Persistence&lt;/strong&gt; - Saves critical data (current term, vote, and log) related to the protocol itself to stable storage (in ResilientDB).&lt;/p&gt;

&lt;p&gt;-&lt;strong&gt;Snapshots&lt;/strong&gt; - Replaces old log entries with a compact file of the current state to prevent the log from consuming all available memory and to allow followers to catch up quicker.&lt;/p&gt;

&lt;p&gt;-&lt;strong&gt;Membership Changes&lt;/strong&gt; - Enables the safe addition or removal of servers from the cluster dynamically without shutting down the system or halting operations.&lt;/p&gt;

&lt;p&gt;-&lt;strong&gt;Inconsistent progress stalls&lt;/strong&gt; - We appear to have some inconsistencies with the leader elections where the leader is chosen but does not appear to make progress. How often this state occurs seems to vary based on the number of nodes. This needs to be investigated.&lt;/p&gt;
</description>
        <pubDate>Sat, 06 Dec 2025 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2025/12/06/RaftProtocol.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2025/12/06/RaftProtocol.html</guid>
      </item>
    
      <item>
        <title>GraphQ-LLM: AI Query Tutor for ResilientDB</title>
        <description>&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;GraphQ-LLM is an intelligent AI assistant that helps developers learn, understand, and optimize GraphQL queries for ResilientDB. Built with Retrieval-Augmented Generation (RAG) and integrated with the ResilientApp ecosystem, it provides real-time explanations, suggestions, and performance insights for your GraphQL queries.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/nexus.png&quot; alt=&quot;Homepage&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;-what-is-graphq-llm&quot;&gt;🎯 What is GraphQ-LLM?&lt;/h2&gt;

&lt;p&gt;GraphQ-LLM is a comprehensive AI tutor that transforms how developers interact with GraphQL APIs. Instead of searching through documentation or trial-and-error query writing, developers can ask questions in natural language or paste their queries to get:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Detailed Explanations&lt;/strong&gt;: Understand what each query does, how fields work, and what to expect in responses&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Efficiency Metrics&lt;/strong&gt;: See estimated execution time, resource usage, and complexity scores&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Documentation Context&lt;/strong&gt;: Access relevant ResilientDB and GraphQL documentation through semantic search&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;️-how-it-works&quot;&gt;🏗️ How It Works&lt;/h2&gt;

&lt;h3 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/architecture.png&quot; alt=&quot;Architecture&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;core-components&quot;&gt;Core Components&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;RAG System (Retrieval-Augmented Generation)&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Stores GraphQL documentation in ResilientDB with vector embeddings&lt;/li&gt;
      &lt;li&gt;Uses semantic search to find relevant documentation chunks&lt;/li&gt;
      &lt;li&gt;Combines retrieved context with LLM for accurate, contextual responses&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;AI Explanation Service&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Detects whether input is a GraphQL query or natural language question&lt;/li&gt;
      &lt;li&gt;For queries: Analyzes structure, fields, operations, and provides explanations&lt;/li&gt;
      &lt;li&gt;For questions: Retrieves relevant docs and generates comprehensive answers&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Efficiency Estimator&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Calculates query complexity scores&lt;/li&gt;
      &lt;li&gt;Estimates execution time and resource usage&lt;/li&gt;
      &lt;li&gt;Provides real-time metrics when ResLens is enabled&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;-key-features&quot;&gt;🚀 Key Features&lt;/h2&gt;

&lt;h3 id=&quot;1-intelligent-query-explanation&quot;&gt;1. &lt;strong&gt;Intelligent Query Explanation&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Paste any GraphQL query and get a detailed breakdown:&lt;/p&gt;

&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;123&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Response includes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;What the query does (in plain English)&lt;/li&gt;
  &lt;li&gt;How each field and operation works&lt;/li&gt;
  &lt;li&gt;Expected response format&lt;/li&gt;
  &lt;li&gt;Common use cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/explanation.jpeg&quot; alt=&quot;explanation&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;2-natural-language-qa&quot;&gt;2. &lt;strong&gt;Natural Language Q&amp;amp;A&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Ask questions like:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;“How do I retrieve a transaction by ID in GraphQL?”&lt;/li&gt;
  &lt;li&gt;“What is the difference between query and mutation?”&lt;/li&gt;
  &lt;li&gt;“How can I optimize my GraphQL queries?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system retrieves relevant documentation and provides comprehensive answers with examples.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/question.jpeg&quot; alt=&quot;question&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;3-query-optimization-suggestions&quot;&gt;3. &lt;strong&gt;Query Optimization Suggestions&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Get actionable recommendations:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Remove unused fields&lt;/li&gt;
  &lt;li&gt;Use field aliases for clarity&lt;/li&gt;
  &lt;li&gt;Add filters to reduce result size&lt;/li&gt;
  &lt;li&gt;Optimize nested queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/recommendations.png&quot; alt=&quot;recommendation&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;4-performance-metrics&quot;&gt;4. &lt;strong&gt;Performance Metrics&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;See efficiency scores, estimated execution times, and resource usage to understand query performance at a glance.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/llm-ui.png&quot; alt=&quot;UI&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/reslens.png&quot; alt=&quot;reslens&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;5-chatbot-interface&quot;&gt;5. &lt;strong&gt;Chatbot Interface&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Clean interface for interacting back and forth with the AI in a chat.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/chat.jpeg&quot; alt=&quot;chat&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;-setup-overview&quot;&gt;📦 Setup Overview&lt;/h2&gt;

&lt;p&gt;GraphQ-LLM is fully dockerized for easy deployment. Here’s what you need:&lt;/p&gt;

&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Docker &amp;amp; Docker Compose&lt;/strong&gt; - For running all services&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Node.js 18+&lt;/strong&gt; - For local development (optional)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Gemini API Key&lt;/strong&gt; - For LLM capabilities (get from &lt;a href=&quot;https://makersuite.google.com/app/apikey&quot;&gt;Google AI Studio&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Nexus Repository&lt;/strong&gt; - Separate Next.js frontend (use the forked version with GraphQ-LLM integration: &lt;a href=&quot;https://github.com/sophiequynn/nexus&quot;&gt;sophiequynn/nexus&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResLens Repositories&lt;/strong&gt; - Optional performance monitoring (use forked versions: &lt;a href=&quot;https://github.com/sophiequynn/incubator-resilientdb-ResLens&quot;&gt;sophiequynn/incubator-resilientdb-ResLens&lt;/a&gt; and &lt;a href=&quot;https://github.com/sophiequynn/incubator-resilientdb-ResLens-Middleware&quot;&gt;sophiequynn/incubator-resilientdb-ResLens-Middleware&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;quick-start&quot;&gt;Quick Start&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Clone and Install&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone &amp;lt;graphq-llm-repo&amp;gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;graphq-llm
npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Configure Environment&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Create .env file and add your Gemini API key&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;LLM_PROVIDER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;gemini
&lt;span class=&quot;nv&quot;&gt;LLM_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;your_gemini_api_key_here
&lt;span class=&quot;nv&quot;&gt;RESILIENTDB_GRAPHQL_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://localhost:5001/graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Clone ResLens Forks (Optional - for performance monitoring)&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Clone ResLens Frontend&lt;/span&gt;
git clone https://github.com/sophiequynn/incubator-resilientdb-ResLens.git ResLens
   
&lt;span class=&quot;c&quot;&gt;# Clone ResLens Middleware&lt;/span&gt;
git clone https://github.com/sophiequynn/incubator-resilientdb-ResLens-Middleware.git ResLens-Middleware
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; These forks include Dockerfile and configuration updates for GraphQ-LLM integration.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Start Services with Docker&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Start ResilientDB (database + GraphQL server)&lt;/span&gt;
docker-compose &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; docker-compose.dev.yml up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; resilientdb
   
&lt;span class=&quot;c&quot;&gt;# Start GraphQ-LLM Backend&lt;/span&gt;
docker-compose &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; docker-compose.dev.yml up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; graphq-llm-backend
   
&lt;span class=&quot;c&quot;&gt;# (Optional) Start ResLens for performance monitoring&lt;/span&gt;
docker-compose &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; docker-compose.dev.yml up &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; reslens-middleware reslens-frontend
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ingest Documentation&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm run ingest:graphql
&lt;span class=&quot;c&quot;&gt;# This loads all GraphQL docs into ResilientDB for RAG&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Set Up Nexus Frontend&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Clone the forked Nexus repository (includes GraphQ-LLM integration):
        &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/sophiequynn/nexus.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;nexus
npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Note:&lt;/strong&gt; This fork already includes all GraphQ-LLM integration files - no manual setup needed!&lt;/li&gt;
      &lt;li&gt;Start with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm run dev&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Access the Tool&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:3000/graphql-tutor&lt;/code&gt; in your browser&lt;/li&gt;
      &lt;li&gt;Start querying or asking questions!&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;service-architecture&quot;&gt;Service Architecture&lt;/h3&gt;

&lt;p&gt;All services run in Docker containers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;ResilientDB&lt;/strong&gt; (Port 18000, 5001) - Database with GraphQL server&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GraphQ-LLM Backend&lt;/strong&gt; (Port 3001) - HTTP API for Nexus integration&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GraphQ-LLM MCP Server&lt;/strong&gt; - For MCP client integration (stdio transport)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResLens Middleware&lt;/strong&gt; (Port 3003) - Performance monitoring API (optional)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResLens Frontend&lt;/strong&gt; (Port 5173) - Performance monitoring UI (optional)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/graphq-llm/docker.jpeg&quot; alt=&quot;docker&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;-how-it-helps-developers&quot;&gt;💡 How It Helps Developers&lt;/h2&gt;

&lt;h3 id=&quot;learning-graphql&quot;&gt;Learning GraphQL&lt;/h3&gt;

&lt;p&gt;New to GraphQL? GraphQ-LLM explains:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Query syntax and structure&lt;/li&gt;
  &lt;li&gt;Field selection and arguments&lt;/li&gt;
  &lt;li&gt;Mutations vs queries&lt;/li&gt;
  &lt;li&gt;Schema exploration&lt;/li&gt;
  &lt;li&gt;Best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;query-effeciency&quot;&gt;Query Effeciency&lt;/h3&gt;

&lt;p&gt;Working on performance? Get:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Complexity analysis&lt;/li&gt;
  &lt;li&gt;Field selection recommendations&lt;/li&gt;
  &lt;li&gt;Execution time estimates&lt;/li&gt;
  &lt;li&gt;Resource usage insights&lt;/li&gt;
  &lt;li&gt;Historical query comparisons (with ResLens)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;troubleshooting&quot;&gt;Troubleshooting&lt;/h3&gt;

&lt;p&gt;Stuck on an error? The system helps:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Understand query structure issues&lt;/li&gt;
  &lt;li&gt;Find relevant documentation&lt;/li&gt;
  &lt;li&gt;Compare with similar working queries&lt;/li&gt;
  &lt;li&gt;Get optimization suggestions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;-technology-stack&quot;&gt;🔧 Technology Stack&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Node.js/TypeScript with RAG architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;LLM&lt;/strong&gt;: Gemini 2.5 Flash Lite (configurable: DeepSeek, OpenAI, Anthropic, Hugging Face, local models)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Embeddings&lt;/strong&gt;: Local (Xenova/all-MiniLM-L6-v2) or Hugging Face API&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Database&lt;/strong&gt;: ResilientDB for vector storage and document chunks&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: Next.js (Nexus integration)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Monitoring&lt;/strong&gt;: ResLens for real-time performance metrics&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Protocol&lt;/strong&gt;: MCP (Model Context Protocol) for secure AI tool integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;-integration-with-resilientapp-ecosystem&quot;&gt;🌐 Integration with ResilientApp Ecosystem&lt;/h2&gt;

&lt;p&gt;GraphQ-LLM is designed to work seamlessly with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;ResilientDB&lt;/strong&gt;: The underlying blockchain database&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Nexus&lt;/strong&gt;: The ResilientApp frontend platform&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResLens&lt;/strong&gt;: Performance monitoring and profiling tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these tools provide a complete development and monitoring experience for ResilientDB applications.&lt;/p&gt;

&lt;h2 id=&quot;-documentation--resources&quot;&gt;📚 Documentation &amp;amp; Resources&lt;/h2&gt;

&lt;p&gt;Complete setup instructions are available in:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;TEAM_SETUP.md&lt;/strong&gt; - Step-by-step setup guide (includes Nexus fork setup)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;TEST_DOCKER_SERVICES.md&lt;/strong&gt; - Service verification guide&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;QUERY_TUTOR_EXAMPLES.md&lt;/strong&gt; - Example queries and questions&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;NEXUS_UI_EXTENSION_GUIDE.md&lt;/strong&gt; - Frontend integration guide (reference only - fork already includes integration)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;-fork-information&quot;&gt;📦 Fork Information&lt;/h3&gt;

&lt;p&gt;GraphQ-LLM uses forked versions of external repositories that include GraphQ-LLM-specific modifications:&lt;/p&gt;

&lt;h4 id=&quot;nexus-fork&quot;&gt;&lt;strong&gt;Nexus Fork&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Fork Repository:&lt;/strong&gt; &lt;a href=&quot;https://github.com/sophiequynn/nexus&quot;&gt;sophiequynn/nexus&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Original Repository:&lt;/strong&gt; &lt;a href=&quot;https://github.com/ResilientApp/nexus&quot;&gt;ResilientApp/nexus&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration Status:&lt;/strong&gt; The fork includes all GraphQ-LLM UI components and API routes&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Simply clone the fork - no additional modifications needed!&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;reslens-forks&quot;&gt;&lt;strong&gt;ResLens Forks&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;ResLens Frontend Fork:&lt;/strong&gt; &lt;a href=&quot;https://github.com/sophiequynn/incubator-resilientdb-ResLens&quot;&gt;sophiequynn/incubator-resilientdb-ResLens&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResLens Middleware Fork:&lt;/strong&gt; &lt;a href=&quot;https://github.com/sophiequynn/incubator-resilientdb-ResLens-Middleware&quot;&gt;sophiequynn/incubator-resilientdb-ResLens-Middleware&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Original Repository:&lt;/strong&gt; &lt;a href=&quot;https://github.com/apache/incubator-resilientdb-ResLens&quot;&gt;Apache ResLens&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration Status:&lt;/strong&gt; Forks include Dockerfile updates, additional routes (CpuPage, MemoryPage, QueryStats), and improved configuration&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Clone both forks - Docker Compose will use them automatically via absolute paths&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;-example-use-cases&quot;&gt;🎓 Example Use Cases&lt;/h2&gt;

&lt;h3 id=&quot;scenario-1-learning-graphql&quot;&gt;Scenario 1: Learning GraphQL&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;What is GraphQL and how do I write a basic query?&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;
Comprehensive explanation with examples, documentation references, and links to relevant guides.&lt;/p&gt;

&lt;h3 id=&quot;scenario-2-explaining-a-query&quot;&gt;Scenario 2: Explaining a Query&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;abc123&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Detailed breakdown of what this query does&lt;/li&gt;
  &lt;li&gt;Explanation of each field&lt;/li&gt;
  &lt;li&gt;Expected response format&lt;/li&gt;
  &lt;li&gt;Use cases and examples&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;scenario-3-optimizing-performance&quot;&gt;Scenario 3: Optimizing Performance&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signerPublicKey&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Efficiency score: 75/100&lt;/li&gt;
  &lt;li&gt;Optimization suggestions: “Consider selecting only needed fields”&lt;/li&gt;
  &lt;li&gt;Estimated execution time: 45ms&lt;/li&gt;
  &lt;li&gt;Complexity: Medium&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;-conclusion&quot;&gt;🎯 Conclusion&lt;/h2&gt;

&lt;p&gt;GraphQ-LLM bridges the gap between complex GraphQL documentation and practical query writing. By combining AI-powered explanations, semantic search, and performance monitoring, it provides developers with an intelligent assistant that makes learning and optimizing GraphQL queries effortless.&lt;/p&gt;

&lt;p&gt;Whether you’re a GraphQL beginner or an experienced developer looking to optimize queries, GraphQ-LLM offers the insights and recommendations you need to write better, faster, and more efficient queries for ResilientDB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ready to get started?&lt;/strong&gt; Follow the complete setup guide in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEAM_SETUP.md&lt;/code&gt; from our &lt;a href=&quot;https://github.com/sophiequynn/graphq-llm&quot;&gt;GitHub&lt;/a&gt; and begin exploring the power of AI-assisted GraphQL development in ResilientDB!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For detailed setup instructions, troubleshooting, and advanced configuration, see the complete documentation in the repository.&lt;/em&gt;&lt;/p&gt;
</description>
        <pubDate>Sat, 06 Dec 2025 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2025/12/06/GraphQ-LLM.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2025/12/06/GraphQ-LLM.html</guid>
      </item>
    
      <item>
        <title>Nexus: An Agentic Rag Assistant for ResilientDB and Distibuted Systems Research</title>
        <description>&lt;h2 id=&quot;nexus-an-agentic-rag-assistant-for-resilientdb-and-distributed-systems&quot;&gt;Nexus: An Agentic RAG Assistant for ResilientDB and Distributed Systems&lt;/h2&gt;

&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;
&lt;p&gt;Nexus is a Next.js-based agentic Retrieval-Augmented Generation (RAG) assistant tailored for Apache ResilientDB, blockchain, and distributed systems. It combines LlamaIndex (TypeScript) orchestration, DeepSeek for reasoning, Gemini Embedding 001 for retrieval, and Supabase (Postgres + pgvector) for persistent storage and memory, delivering grounded answers with clear citations.&lt;/p&gt;

&lt;h3 id=&quot;motivation&quot;&gt;Motivation&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;The research landscape is dense; answers must be verifiable and source-linked.&lt;/li&gt;
  &lt;li&gt;Traditional keyword tools don’t synthesize across documents.&lt;/li&gt;
  &lt;li&gt;Researchers need multi-document reasoning, persistent context, and the ability to pull in external updates when needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;key-features&quot;&gt;Key Features&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Research and Code modes:
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Research Mode&lt;/strong&gt;: Single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NexusAgent&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search_documents&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;search_web&lt;/code&gt; tools, streams tool usage transparently and surfaces source badges in the preview panel (inline footnotes are on the roadmap)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Code Mode&lt;/strong&gt; (experimental): Multi-agent workflow via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CodeAgent&lt;/code&gt; class:
        &lt;ul&gt;
          &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PlannerAgent&lt;/code&gt;: Retrieves document content and analyzes for implementation details&lt;/li&gt;
          &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PseudoCodeAgent&lt;/code&gt;: Creates structured pseudocode from research findings&lt;/li&gt;
          &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CodeAgent&lt;/code&gt;: Generates final production-ready code in selected language (TypeScript, Python, C++)&lt;/li&gt;
          &lt;li&gt;Features automatic handoffs between agents and live streaming of each phase&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Document selection:
    &lt;ul&gt;
      &lt;li&gt;Single-document focus for deep reading.&lt;/li&gt;
      &lt;li&gt;Multi-document selection for synthesis and comparison.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Tool-aware agent:
    &lt;ul&gt;
      &lt;li&gt;search_documents: semantic retrieval from Supabase pgvector (scoped to selected docs).&lt;/li&gt;
      &lt;li&gt;search_web: Tavily for up-to-date or out-of-corpus facts.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Session-scoped memory with short-term and long-term capabilities:
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Short-term memory&lt;/strong&gt;: FIFO queue of recent messages within token limits (30,000 tokens, 70% ratio for chat history)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Long-term memory&lt;/strong&gt;: Implemented via two memory blocks:
        &lt;ul&gt;
          &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robustFactExtractionBlock&lt;/code&gt;: Extracts and stores durable facts using DeepSeek (max 10 facts, priority 1)&lt;/li&gt;
          &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vectorBlock&lt;/code&gt;: Stores and retrieves session-scoped memory in Supabase pgvector (priority 2, top-k=3)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Streaming with tool transparency:
    &lt;ul&gt;
      &lt;li&gt;The API streams deltas and tool lifecycle events so the UI can interleave “thinking” steps and tool badges.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;system-architecture&quot;&gt;System Architecture&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/nexus/architecture.png&quot; alt=&quot;System Architecture&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;ingestion-pipeline&quot;&gt;Ingestion Pipeline&lt;/h3&gt;

&lt;p&gt;Nexus implements a sophisticated document ingestion pipeline using LlamaIndex’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IngestionPipeline&lt;/code&gt; with multiple transformation stages to prepare raw PDFs for efficient retrieval:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/nexus/ingestion.png&quot; alt=&quot;Ingestion Pipeline&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transformation Pipeline Details:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Document Parsing&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LlamaParseReader&lt;/code&gt; converts PDFs to structured JSON with page metadata, handling complex layouts, tables, and figures&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Node Parsing&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MarkdownNodeParser&lt;/code&gt; processes the markdown content from LlamaParse into structured document nodes&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Text Chunking&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SentenceSplitter&lt;/code&gt; with chunk size 768 tokens and 20-token overlap maintains semantic coherence while creating retrievable segments&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Metadata Extraction&lt;/strong&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SummaryExtractor&lt;/code&gt; automatically generates summaries and extracts key metadata for each chunk&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Embedding Generation&lt;/strong&gt;: Gemini Embedding 001 converts text chunks into high-dimensional vectors for semantic similarity search&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Vector Storage&lt;/strong&gt;: Embeddings and metadata are stored in Supabase pgvector with HNSW indexing for fast retrieval&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Caching Strategy&lt;/strong&gt;: The system maintains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;parsed_documents&lt;/code&gt; table in Supabase to track parsing status, avoiding re-processing of already ingested files and enabling incremental updates.&lt;/p&gt;

&lt;p&gt;This pipeline ensures that each PDF is transformed into semantically meaningful, searchable chunks with rich metadata and high-quality embeddings for precise retrieval.&lt;/p&gt;

&lt;h3 id=&quot;streaming-and-tooling&quot;&gt;Streaming and Tooling&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/nexus/streaming.png&quot; alt=&quot;Streaming and Tooling&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;stack&quot;&gt;Stack&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Frontend: Next.js (React) chat UI + PDF/source preview panel&lt;/li&gt;
  &lt;li&gt;API: Next.js Route Handlers under /api/research/*&lt;/li&gt;
  &lt;li&gt;Orchestration: LlamaIndex (TypeScript)&lt;/li&gt;
  &lt;li&gt;Vector Storage: Supabase (Postgres + pgvector) via @llamaindex/supabase&lt;/li&gt;
  &lt;li&gt;LLM: DeepSeek (deepseek-chat) via @llamaindex/deepseek&lt;/li&gt;
  &lt;li&gt;Embeddings: Gemini Embedding 001 via @llamaindex/google&lt;/li&gt;
  &lt;li&gt;Web Search: Tavily&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;how-it-works-at-a-glance&quot;&gt;How it Works (at a glance)&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Select documents (single or multiple).&lt;/li&gt;
  &lt;li&gt;The UI calls /api/research/prepare-index → PDFs parsed with LlamaParse → transformed and embedded → stored in pgvector.&lt;/li&gt;
  &lt;li&gt;Ask a question; the UI calls /api/research/chat → the agent chooses tools → streams tokens and events → UI displays content and source attributions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;research-agent&quot;&gt;Research Agent&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/nexus/research.png&quot; alt=&quot;Research Agent&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;code-composer-agent&quot;&gt;Code Composer Agent&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/nexus/agent.png&quot; alt=&quot;Code Composer Agent&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;run-locally&quot;&gt;Run Locally&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Prerequisites:
    &lt;ul&gt;
      &lt;li&gt;Node.js 18+&lt;/li&gt;
      &lt;li&gt;Supabase project with pgvector enabled&lt;/li&gt;
      &lt;li&gt;Create two tables (or reuse defaults):
        &lt;ul&gt;
          &lt;li&gt;llamaindex_vector_embeddings&lt;/li&gt;
          &lt;li&gt;llamaindex_memory_embeddings&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;API keys:
        &lt;ul&gt;
          &lt;li&gt;DEEPSEEK_API_KEY&lt;/li&gt;
          &lt;li&gt;GEMINI_API_KEY&lt;/li&gt;
          &lt;li&gt;LLAMA_CLOUD_API_KEY (for LlamaParse)&lt;/li&gt;
          &lt;li&gt;TAVILY_API_KEY&lt;/li&gt;
          &lt;li&gt;SUPABASE_URL and SUPABASE_ANON_KEY (or SUPABASE_SERVICE_ROLE_KEY)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI, GOOGLE_REFRESH_TOKEN (for Drive access)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Environment&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;.env.local&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;DEEPSEEK_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;DEEPSEEK_MODEL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;deepseek-chat

&lt;span class=&quot;nv&quot;&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;LLAMA_CLOUD_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;TAVILY_API_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...

&lt;span class=&quot;nv&quot;&gt;SUPABASE_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;SUPABASE_ANON_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...         or &lt;span class=&quot;nv&quot;&gt;SUPABASE_SERVICE_ROLE_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;SUPABASE_VECTOR_TABLE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;llamaindex_vector_embeddings
&lt;span class=&quot;nv&quot;&gt;SUPABASE_MEMORY_TABLE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;llamaindex_memory_embeddings

&lt;span class=&quot;nv&quot;&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;GOOGLE_CLIENT_SECRET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;GOOGLE_REDIRECT_URI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;span class=&quot;nv&quot;&gt;GOOGLE_REFRESH_TOKEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Install and run&lt;/strong&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install
&lt;/span&gt;npm run dev
open http://localhost:3000/research
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Connect document sources
    &lt;ul&gt;
      &lt;li&gt;Share the desired folders with the Google account tied to your refresh token.&lt;/li&gt;
      &lt;li&gt;Update the folder IDs inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/app/api/research/documents/route.ts&lt;/code&gt; if you need different collections.&lt;/li&gt;
      &lt;li&gt;Uploaded PDFs in those Drive folders appear automatically in the in-app library once credentials are configured.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Use the app
    &lt;ul&gt;
      &lt;li&gt;Select one or more documents in the sidebar.&lt;/li&gt;
      &lt;li&gt;Wait for “Preparing documents…” to complete (ingestion runs via /api/research/prepare-index).&lt;/li&gt;
      &lt;li&gt;Ask questions. The agent retrieves from your selected docs and lists sources within the preview panel.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;memory-design-session-scoped&quot;&gt;Memory Design (Session-Scoped)&lt;/h3&gt;
&lt;p&gt;Nexus implements the LlamaIndex Memory framework with both short-term and long-term memory capabilities:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short-term Memory:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Token-limited FIFO queue (30,000 tokens total, 70% allocated to chat history)&lt;/li&gt;
  &lt;li&gt;When chat history exceeds the ratio, the framework automatically trims the oldest short-term messages while leaving long-term memory blocks intact&lt;/li&gt;
  &lt;li&gt;Maintains recent conversational context within the session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Long-term Memory (via Memory Blocks):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;robustFactExtractionBlock&lt;/code&gt; (priority 1): Extracts durable, reusable facts using DeepSeek LLM, stores up to 10 facts with automatic summarization when limit is exceeded&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vectorBlock&lt;/code&gt; (priority 2): Stores and retrieves session-scoped memory batches in Supabase pgvector (keyed by sessionId), uses hybrid similarity search with top-k=3 retrieval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Coherence across turns and sessions without relying on raw chat transcripts&lt;/li&gt;
  &lt;li&gt;Scalable across instances via persistent vector storage&lt;/li&gt;
  &lt;li&gt;Automatic memory management with priority-based truncation when token limits are exceeded&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;current-limitations&quot;&gt;Current Limitations&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Code Mode is experimental and best for structured, implementation-focused prompts.&lt;/li&gt;
  &lt;li&gt;Corpus is intentionally scoped to ResilientDB and related systems to ensure high-quality retrieval.&lt;/li&gt;
  &lt;li&gt;Requires cloud APIs (DeepSeek, LlamaParse, Gemini, Tavily); offline mode is not supported out-of-the-box.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;future-work&quot;&gt;Future Work&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Inline citation markers and highlighting in the PDF preview panel
    &lt;ul&gt;
      &lt;li&gt;Add [^id]-style footnotes to responses and allow clicking to jump to the referenced passage/page range.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Custom selective context
    &lt;ul&gt;
      &lt;li&gt;Let users include/exclude sections (e.g., Methods only), set per-query filters, or re-rank top-k nodes.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Advanced reranking
    &lt;ul&gt;
      &lt;li&gt;Integrate implementation-aware reranking for code-generation workflows (leveraging the CodeComposer pipeline).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Multimodal parsing
    &lt;ul&gt;
      &lt;li&gt;Tables, figures, and chart-aware extraction for richer question answering.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Proactive discovery
    &lt;ul&gt;
      &lt;li&gt;Recommend relevant new papers based on ongoing sessions and research interests.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;closing&quot;&gt;Closing&lt;/h3&gt;
&lt;p&gt;Nexus brings together a modern TS-first stack, robust retrieval, transparent tool use, and session memory to create a reliable research copilot for distributed systems.&lt;/p&gt;
</description>
        <pubDate>Thu, 13 Nov 2025 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2025/11/13/Nexus.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2025/11/13/Nexus.html</guid>
      </item>
    
      <item>
        <title>Navigating ResilientDB&apos;s C++ Codebase: Empowering Contributors with Modern Tooling</title>
        <description>&lt;h2 id=&quot;navigating-resilientdbs-c-codebase-empowering-contributors-with-modern-tooling&quot;&gt;Navigating ResilientDB’s C++ Codebase: Empowering Contributors with Modern Tooling&lt;/h2&gt;

&lt;p&gt;ResilientDB is a high-performance blockchain platform written in modern C++17. If you’ve worked with C++ before, you know that managing large codebases can be challenging—not just because of the language’s complexity, but also due to the tools used to build and organize the project. In the C++ world, build systems play a crucial role: they take care of compiling source files, managing dependencies, and producing the final executable. While CMake is a popular choice for many open-source projects, ResilientDB uses Bazel—a powerful build tool developed at Google that excels at handling complex, multi-language codebases with many modules and dependencies.&lt;/p&gt;

&lt;p&gt;Understanding how a build system works is essential for any C++ developer. A build system automates the process of transforming source code into binaries, managing everything from compilation flags to linking libraries. This is especially important in large projects, where manual compilation would be error-prone and time-consuming. CMake is widely used for this purpose, but Bazel offers advanced features for scaling to very large codebases and supporting multiple languages.&lt;/p&gt;

&lt;p&gt;Modern development environments (IDEs) offer features like Intellisense, autocomplete, and code navigation, which are powered by language servers and configuration files that describe how the code is built. These features are not just conveniences—they are essential for stepping through code, debugging, and understanding how different parts of a project fit together. They make it much easier to dive into the details of an implementation, accelerate feature development, and lower the barrier for new contributors.&lt;/p&gt;

&lt;p&gt;However, Bazel doesn’t natively generate the configuration files (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile_commands.json&lt;/code&gt;) that many IDEs and language servers rely on for these features. This can make it difficult to get full code intelligence and navigation in editors like VSCode or CLion when working with Bazel-based projects.&lt;/p&gt;

&lt;p&gt;To solve this, we integrated a tool called &lt;a href=&quot;https://github.com/hedronvision/bazel-compile-commands-extractor&quot;&gt;Hedronvision’s Bazel Compile Commands Extractor&lt;/a&gt;. This tool generates a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile_commands.json&lt;/code&gt; file based on the current state of your Bazel build. This file is often called a &lt;em&gt;Compilation Database&lt;/em&gt; and helps tools to generate intellisense. With this file in place, you can use a Language Server Protocol (LSP) extension in your editor to unlock powerful, interactive code exploration—making it easy to step through functions, debug, and contribute to the core engine.&lt;/p&gt;

&lt;p&gt;In this post, I’ll show you how to set up your environment so you can:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Effortlessly navigate the ResilientDB codebase&lt;/li&gt;
  &lt;li&gt;Unlock powerful autocomplete and code exploration features&lt;/li&gt;
  &lt;li&gt;Lower the barrier for new contributors to jump into C++ development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s make contributing to ResilientDB accessible to everyone—because the more eyes and ideas we have, the stronger the project becomes.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-intellisense-for-resilientdbs-c-projects&quot;&gt;Setting up Intellisense for ResilientDB’s C++ Projects&lt;/h2&gt;

&lt;h3 id=&quot;setting-up-resilientdb-core&quot;&gt;Setting up ResilientDB Core&lt;/h3&gt;

&lt;p&gt;Follow the steps in the &lt;a href=&quot;https://github.com/apache/incubator-resilientdb?tab=readme-ov-file#build-and-deploy-resilientdb&quot;&gt;Build and Deploy ResilientDB&lt;/a&gt; to setup the resilientdb project.&lt;/p&gt;

&lt;h4 id=&quot;1-generate-compile_commandsjson-with-hedronvision&quot;&gt;1. Generate compile_commands.json with Hedronvision&lt;/h4&gt;

&lt;p&gt;Once your ResilientDB project is set up, you can generate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile_commands.json&lt;/code&gt; file by running the following command from your project root:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel run @hedron_compile_commands//:refresh_all
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will create or update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile_commands.json&lt;/code&gt; file, which is essential for enabling full-featured code navigation and autocomplete in your IDE.&lt;/p&gt;

&lt;h4 id=&quot;2-install-clangd-c-language-server&quot;&gt;2. Install clangd (C++ Language Server)&lt;/h4&gt;

&lt;p&gt;If you’re using VS Code, simply install the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd&quot;&gt;clangd extension&lt;/a&gt; from the Extensions marketplace. VS Code will handle the installation of clangd for you—no manual setup required.&lt;/p&gt;

&lt;h4 id=&quot;3-configure-your-editor-to-use-clangd&quot;&gt;3. Configure your editor to use clangd&lt;/h4&gt;

&lt;p&gt;Most modern editors (like VSCode, Neovim, or CLion) support clangd via extensions or built-in integration. For VSCode:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Install the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd&quot;&gt;clangd extension&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Open your ResilientDB project folder in VSCode.&lt;/li&gt;
  &lt;li&gt;The extension should automatically detect your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile_commands.json&lt;/code&gt; file and enable code navigation, autocomplete, and other features.&lt;/li&gt;
  &lt;li&gt;You will see a progress bar at the bottom of your screen displaying the progress of indexing. This step is essentially the LSP extension trying to crawl through your code and configuring the autocomplete.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;4-handling-missing-autocomplete-for-some-modules&quot;&gt;4. Handling Missing Autocomplete for Some Modules&lt;/h4&gt;

&lt;p&gt;While the steps above will enable autocomplete and code navigation for most of the codebase, you may occasionally notice that some modules or files are missing autocomplete or show errors. This usually happens when certain parts of the project haven’t been built yet, so their compilation information isn’t included in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile_commands.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;To resolve this:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Identify the module or target that’s missing autocomplete (for example, a storage engine or a smart contract library).&lt;/li&gt;
  &lt;li&gt;Navigate to the folder containing the relevant &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BUILD&lt;/code&gt; file.&lt;/li&gt;
  &lt;li&gt;Build the target using Bazel:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build //path/to/your/target
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For example, to build the storage engine module:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build chain/storage/leveldb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After building the target, restart the clangd extension in your editor. This will prompt clangd to re-index the codebase, and autocomplete should now work for the newly built modules.&lt;/p&gt;

&lt;p&gt;Now you’re ready to explore, debug, and contribute to ResilientDB with full code intelligence support!&lt;/p&gt;

&lt;h3 id=&quot;setting-up-resilientdb-graphql-proxy-server&quot;&gt;Setting up ResilientDB GraphQL Proxy Server&lt;/h3&gt;

&lt;p&gt;The same steps can be used for generating a &lt;em&gt;Compilation Database&lt;/em&gt;. Follow the instructions in the &lt;a href=&quot;https://github.com/apache/incubator-resilientdb-graphql/blob/main/README.md&quot;&gt;Build and Deploy GraphQL Proxy&lt;/a&gt;. Once the bazel build process is completed, use this command to generate the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile_commands.json&lt;/code&gt; file and start hacking.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel run @hedron_compile_commands//:refresh_all
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since the Proxy Server contains code written in both C++ and Python, we recommend installing the following VS Code extensions for full Intellisense support:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd&quot;&gt;clangd&lt;/a&gt; — for C++ code navigation and autocomplete&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-python.python&quot;&gt;Python&lt;/a&gt; — for Python code navigation and autocomplete&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;how-do-we-use-these-tools-internally&quot;&gt;How do we use these tools internally?&lt;/h3&gt;

&lt;p&gt;At ResilientDB, we rely heavily on Intellisense and advanced code navigation tools to work efficiently within our large and evolving codebase. By leveraging AI-powered editors like Cursor and GitHub Copilot, our team can quickly understand unfamiliar parts of the project, receive intelligent code suggestions, and even generate boilerplate or complex code snippets on the fly. This is especially valuable as we work on ambitious projects, such as developing a new storage engine and exploring ways to make our architecture pluggable for different storage backends to suit various use cases. Intellisense, combined with robust debugging and benchmarking workflows, enables us to iterate rapidly, catch issues early, and keep a sharp focus on both performance and developer productivity as we expand the capabilities of ResilientDB.&lt;/p&gt;

&lt;h3 id=&quot;debugging-profiling-and-observability&quot;&gt;Debugging, Profiling, and Observability&lt;/h3&gt;

&lt;p&gt;Stay tuned! Next week, we’ll be adding a detailed section on how to enable debugging and profiling flags in Bazel, as well as how to use ResLens’s flamegraph feature for observability and performance analysis. This will include practical steps, example commands, and tips for getting the most out of these powerful tools.&lt;/p&gt;

</description>
        <pubDate>Thu, 24 Jul 2025 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2025/07/24/Navigating-ResilientDB-Codebase.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2025/07/24/Navigating-ResilientDB-Codebase.html</guid>
      </item>
    
      <item>
        <title>Building Resilient Apps with ResilientDB &amp; ResVault</title>
        <description>&lt;p&gt;The ResilientDB Fullstack makes it easy to build and interact with blockchain-powered applications. At its core, it uses ResilientDB for high-speed transaction processing and ResVault as a wallet interface for seamless interactions. Web apps can connect effortlessly using the ResVault web SDK, while developers also get SDK support for Python, Rust, and TypeScript, making it simple to integrate ResilientDB into different applications. Whether you’re building for the web or other platforms, ResilientDB Fullstack provides the tools to get started quickly and efficiently.&lt;/p&gt;

&lt;h3 id=&quot;core-components-of-a-resilient-app&quot;&gt;Core Components of a Resilient App&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Your Decentralized App (dApp)&lt;/strong&gt; – Built on ResilientDB to enable trustless, high-throughput transactions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResVault&lt;/strong&gt; – A secure wallet interface that connects users to your dApp via the ResVault web SDK.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResilientDB GraphQL Server&lt;/strong&gt; – Provides an intuitive API layer for interacting with blockchain data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResilientDB KV/Smart Contract Service&lt;/strong&gt; – A robust key-value store and smart contract execution engine, combined with Crow HTTP Server and SDK support for Python, TypeScript, and Rust.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/FLhHPoJ.png&quot; alt=&quot;ResilientDB Fullstack&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Docker - &lt;a href=&quot;https://docs.docker.com/get-started/&quot;&gt;Setup Instructions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;setting-up-resilientdb-in-minutes&quot;&gt;Setting Up ResilientDB in Minutes&lt;/h2&gt;

&lt;p&gt;Getting started with ResilientDB is incredibly simple with ResilientDB-Ansible, which automates the setup of the Crow HTTP server and GraphQL API. A cross-platform GUI installer with Tauri is also in the works to make deployment even easier.&lt;/p&gt;

&lt;h4 id=&quot;quick-setup-instructions&quot;&gt;Quick Setup Instructions&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Clone the ResilientDB-Ansible repository:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/ResilientEcosystem/resilientdb-ansible
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resilientdb-ansible
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Build the Docker image:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker build &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; resilientdb-ansible &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Run the container with required privileges:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--privileged&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; /sys/fs/cgroup:/sys/fs/cgroup:ro &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 80:80 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 18000:18000 &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 8000:8000 resilientdb-ansible
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the container is running, you can access:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ResilientDB Crow HTTP Server at http://localhost/crow (Exposed port &lt;strong&gt;18000&lt;/strong&gt;)&lt;/li&gt;
  &lt;li&gt;ResilientDB GraphQL API at http://localhost/graphql (Exposed port &lt;strong&gt;8000&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This setup automatically configures ResilientDB with 4 replicas and 1 client, with Nginx handling routing inside the container.&lt;/p&gt;

&lt;h2 id=&quot;set-up-resvault-your-gateway-to-resilientdb&quot;&gt;Set Up ResVault: Your Gateway to ResilientDB&lt;/h2&gt;

&lt;p&gt;ResVault is a Chrome extension wallet for ResilientDB, allowing users to commit and retrieve data, manage accounts, and track transactions, all through the ResilientDB GraphQL server. Think of it as Metamask for ResilientDB, but tailored for high-throughput blockchain applications.&lt;/p&gt;

&lt;h2 id=&quot;features&quot;&gt;Features&lt;/h2&gt;

&lt;h3 id=&quot;core-wallet-functionality&quot;&gt;Core Wallet Functionality&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Create Account&lt;/strong&gt; - Generate new wallet accounts with secure key management&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Delete Account&lt;/strong&gt; - Remove accounts with proper cleanup&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Login/Logout&lt;/strong&gt; - Secure authentication system&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Submit Transactions&lt;/strong&gt; - Send transactions to ResilientDB network&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transaction Logging&lt;/strong&gt; - Complete transaction history and audit trail&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;User Profiles&lt;/strong&gt; - Manage multiple user identities&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Multi-account Support&lt;/strong&gt; - Handle multiple wallet accounts simultaneously&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;smart-contract-integration-v120&quot;&gt;Smart Contract Integration (v1.2.0)&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Contract Deployment&lt;/strong&gt; - Deploy Solidity smart contracts directly from the wallet&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Address Ownership&lt;/strong&gt; - Contracts are deployed using your wallet address for proper ownership&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GraphQL Integration&lt;/strong&gt; - Seamless communication with ResilientDB smart contract service&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Solidity Compilation&lt;/strong&gt; - Automatic compilation of Solidity contracts before deployment&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Enhanced Error Handling&lt;/strong&gt; - Improved debugging and error reporting for contract operations&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Network Flexibility&lt;/strong&gt; - Connect to mainnet or your local ResilientDB server&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;security--performance&quot;&gt;Security &amp;amp; Performance&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Secure Key Management&lt;/strong&gt; - Ed25519 key pairs with proper encryption&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transaction Validation&lt;/strong&gt; - Built-in validation for all operations&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Network Connectivity&lt;/strong&gt; - Support for custom ResilientDB network endpoints&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Real-time Updates&lt;/strong&gt; - Live transaction status and balance updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pending Features&lt;/strong&gt;:&lt;/p&gt;
&lt;ul class=&quot;task-list&quot;&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; /&gt;Password improvement&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; /&gt;Transaction details view&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; /&gt;View all transactions&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; /&gt;Contract execution and interaction&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; /&gt;Contract interaction history&lt;/li&gt;
  &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; /&gt;Gas estimation and optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;install-resvault&quot;&gt;Install ResVault&lt;/h3&gt;

&lt;h4 id=&quot;via-chrome-web-store-recommended&quot;&gt;Via Chrome Web Store (Recommended)&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;🎉 ResVault is now available on Chrome Web Store!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/resvault/ejlihnefafcgfajaomeeogdhdhhajamf&quot;&gt;&lt;img src=&quot;https://img.shields.io/badge/Chrome%20Web%20Store-Available-green&quot; alt=&quot;Chrome Web Store&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://chromewebstore.google.com/detail/resvault/ejlihnefafcgfajaomeeogdhdhhajamf&quot;&gt;Install ResVault from Chrome Web Store&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h4 id=&quot;build-resvault-from-source&quot;&gt;Build ResVault from Source&lt;/h4&gt;

&lt;h4 id=&quot;prerequisite&quot;&gt;Prerequisite&lt;/h4&gt;

&lt;p&gt;You need Node.js &lt;strong&gt;v16.20.2&lt;/strong&gt; for the build. The recommended way to manage multiple Node.js versions is using &lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;nvm&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;clone-the-resvault-repository&quot;&gt;Clone the ResVault Repository&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/apache/incubator-resilientdb-resvault
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;incubator-resilientdb-resvault
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;install-dependencies&quot;&gt;Install Dependencies&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;build-the-wallet&quot;&gt;Build the Wallet&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;verify-successful-build&quot;&gt;Verify Successful Build&lt;/h4&gt;
&lt;p&gt;If everything goes well, you’ll see this message:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The build folder is ready to be deployed.
You may serve it with a static server:

  serve &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; build

Find out more about deployment here:

  https://cra.link/deployment
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The wallet build will be available in the build directory inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;incubator-resilientdb-resvault&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, you’re all set to use ResVault as your secure wallet for ResilientDB transactions!&lt;/p&gt;

&lt;h3 id=&quot;add-build-to-chrome&quot;&gt;Add build to chrome&lt;/h3&gt;
&lt;p&gt;Once you have generated the build:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Open chrome and navigate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chrome://extensions/&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Make sure developer mode is enabled using the toggle button.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Finally, load the extension by clicking on load unpacked button and then select the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; directory that was created in the previous step.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now you can open the wallet from the extension button and start using it!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;integrating-resvault-sdk-with-your-resilient-app&quot;&gt;Integrating ResVault SDK with Your Resilient App&lt;/h2&gt;

&lt;p&gt;If you’re looking for the simplest way to build a ResilientDB-powered React or Vue application with &lt;a href=&quot;https://www.npmjs.com/package/resvault-sdk&quot;&gt;ResVault SDK&lt;/a&gt; integration, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create-resilient-app&lt;/code&gt; is the tool for you!&lt;/p&gt;

&lt;h3 id=&quot;why-use-create-resilient-app&quot;&gt;Why Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create-resilient-app&lt;/code&gt;?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Scaffold a new ResilientDB app with React or Vue in seconds.&lt;/li&gt;
  &lt;li&gt;Supports both JavaScript and TypeScript for flexibility.&lt;/li&gt;
  &lt;li&gt;Automatically integrates ResVault SDK, so you can start interacting with ResilientDB right away.&lt;/li&gt;
  &lt;li&gt;No manual setup, just run a single command!&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;installation--setup&quot;&gt;Installation &amp;amp; Setup&lt;/h4&gt;

&lt;p&gt;You don’t need to install anything globally. Just run:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx create-resilient-app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running the command without any flags will launch an interactive prompt.&lt;/p&gt;

&lt;p&gt;You’ll be asked:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Project Name&lt;/strong&gt; – Give your app a name.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Framework&lt;/strong&gt; – Choose between React or Vue.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Language&lt;/strong&gt; – Choose between JavaScript or TypeScript.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;one-command-setup&quot;&gt;One-Command Setup&lt;/h4&gt;

&lt;p&gt;Skip the prompts by specifying options directly:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx create-resilient-app &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; my-app &lt;span class=&quot;nt&quot;&gt;--framework&lt;/span&gt; react &lt;span class=&quot;nt&quot;&gt;--language&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;example-commands&quot;&gt;Example Commands&lt;/h4&gt;

&lt;p&gt;Create a React app with TypeScript:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx create-resilient-app &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; my-react-app &lt;span class=&quot;nt&quot;&gt;--framework&lt;/span&gt; react &lt;span class=&quot;nt&quot;&gt;--language&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a Vue app with JavaScript:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx create-resilient-app &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; my-vue-app &lt;span class=&quot;nt&quot;&gt;--framework&lt;/span&gt; vue &lt;span class=&quot;nt&quot;&gt;--language&lt;/span&gt; javascript
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;project-setup--running&quot;&gt;Project Setup &amp;amp; Running&lt;/h4&gt;

&lt;p&gt;After the project is generated, navigate to your project directory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;my-app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then install the required dependencies:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;start-your-project&quot;&gt;Start Your Project&lt;/h4&gt;

&lt;p&gt;For React:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For Vue:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, you can customize your app and start building powerful ResilientDB-powered decentralized applications.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/ALjmV6c.png&quot; alt=&quot;Resilient App&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;next-steps-connect-your-resilient-app-to-resvault&quot;&gt;Next Steps: Connect Your Resilient App to ResVault&lt;/h2&gt;

&lt;p&gt;Now that you’ve set up your first Resilient App, it’s time to connect it to ResVault and start interacting with ResilientDB.&lt;/p&gt;

&lt;h4 id=&quot;open-your-resilient-app&quot;&gt;Open Your Resilient App&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;Navigate to your Resilient App in your browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;open-resvault--create-an-account&quot;&gt;Open ResVault &amp;amp; Create an Account&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Open the ResVault extension in your browser.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you haven’t created an account yet, set a secure password and let ResVault generate your keys securely.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/9sldILH.png&quot; alt=&quot;ResVault SignUp&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;choose-a-network-in-resvault-and-connect&quot;&gt;Choose a Network in ResVault and Connect&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Once at the ResVault Dashboard, click the dropdown menu at the top.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;By default, it is set to ResilientDB Mainnet, which connects to ResilientDB Cloud (&lt;a href=&quot;https://cloud.resilientdb.com/graphql&quot;&gt;cloud.resilientdb.com/graphql&lt;/a&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you are running ResilientDB locally, select ResilientDB Localnet from the dropdown.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;On the right side of the dropdown, you’ll see a site icon, click on it once to connect ResVault to your Resilient App.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/IbUDe1G.png&quot; alt=&quot;ResVault connect&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;click-sign-in-via-resvault-in-your-resilient-app&quot;&gt;Click “Sign In Via ResVault” in Your Resilient App&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Inside your Resilient App, click Sign In Via ResVault.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;ResVault will prompt you to approve the transaction.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Once approved, ResVault will sign the transaction using your keys and send it to ResilientDB.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Your app will receive a callback confirming successful authentication and will be redirected to the authenticated page.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, you can send more transactions by submitting the form inside the authenticated page (with any JSON data as well).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/1NSUca0.png&quot; alt=&quot;ResVault authenticate&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;submit-transactions-from-the-authenticated-page&quot;&gt;Submit Transactions from the Authenticated Page&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Now that you’re authenticated, you can send more transactions using the form inside the authenticated page.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The form allows you to submit any JSON data, which will be securely signed and sent to ResilientDB.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/VIe0SVQ.png&quot; alt=&quot;ResVault authenticated page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You’re now fully connected to ResilientDB via ResVault! Whether on Mainnet (Cloud) or Localnet, you can authenticate, send transactions, and interact with decentralized applications seamlessly.&lt;/p&gt;

&lt;h2 id=&quot;smart-contract-usage&quot;&gt;Smart Contract Usage&lt;/h2&gt;

&lt;h3 id=&quot;deploying-contracts&quot;&gt;Deploying Contracts&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;Navigate to the &lt;strong&gt;Contract&lt;/strong&gt; tab in ResVault&lt;/li&gt;
  &lt;li&gt;Enter your ResilientDB server URL:
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Mainnet&lt;/strong&gt;: Use the production ResilientDB endpoint&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Local Development&lt;/strong&gt;: Use your local server (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:8400&lt;/code&gt;)&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Custom Server&lt;/strong&gt;: Use any ResilientDB instance (e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://your-server:8400&lt;/code&gt;)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Paste your Solidity contract code&lt;/li&gt;
  &lt;li&gt;Provide constructor arguments if needed&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Deploy&lt;/strong&gt; - the contract will be deployed using your wallet address&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;client-side-indexing-support-in-resilientdb-for-filtering-in-your-resilient-app&quot;&gt;Client-Side Indexing Support in ResilientDB for Filtering in Your Resilient App&lt;/h2&gt;

&lt;p&gt;When building ResilientDB-powered applications, efficient data retrieval is crucial. If your Resilient App needs a filtering functionality, you can index ResilientDB transaction data on the client side using MongoDB. This tutorial will guide you through setting up real-time synchronization with MongoDB using ResilientDB’s WebSocket and HTTP APIs for efficient querying.&lt;/p&gt;

&lt;h3 id=&quot;prerequisites-1&quot;&gt;Prerequisites&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;MongoDB - &lt;a href=&quot;https://www.mongodb.com/docs/manual/installation/&quot;&gt;Setup Instructions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;why-client-side-indexing&quot;&gt;Why Client-Side Indexing?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Efficient filtering of ResilientDB transactions for dApps.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Real-time sync using WebSocket and HTTP.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Query transactions based on public keys, timestamps, asset JSON, or metadata.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Automatic reconnection, batching, and concurrency handling.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;syncing-resilientdb-data-to-mongodb-for-efficient-filtering&quot;&gt;Syncing ResilientDB Data to MongoDB for Efficient Filtering&lt;/h3&gt;

&lt;h4 id=&quot;install-the-required-library&quot;&gt;Install the Required Library&lt;/h4&gt;

&lt;p&gt;For Node.js, install:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;resilient-node-cache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For Python, install:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;resilient-python-cache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;configure-mongodb-and-resilientdb&quot;&gt;Configure MongoDB and ResilientDB&lt;/h4&gt;

&lt;p&gt;Before syncing, ensure MongoDB is running and configure your connection settings:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Node.js Configuration (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sync.js&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;WebSocketMongoSync&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;resilient-node-cache&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mongoConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;mongodb://localhost:27017&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;dbName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;myDatabase&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;collectionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;myCollection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* resilientdb://localhost/crow to sync localnet */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resilientDBConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;resilientdb://crow.resilientdb.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;httpSecure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;wsSecure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;WebSocketMongoSync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mongoConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resilientDBConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;connected&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;WebSocket connected.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;newBlocks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Received new blocks:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newBlocks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Error:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;closed&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Connection closed.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Synchronization initialized.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Error during sync initialization:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Python Configuration (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sync.py&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;asyncio&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;resilient_python_cache&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResilientPythonCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResilientDBConfig&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mongo_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mongodb://localhost:27017&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;db_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myDatabase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;collection_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myCollection&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# resilientdb://localhost/crow to sync localnet
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;resilient_db_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResilientDBConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;base_url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;resilientdb://crow.resilientdb.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;http_secure&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ws_secure&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResilientPythonCache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mongo_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resilient_db_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;connected&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;WebSocket connected.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_blocks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Received new blocks:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_blocks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Error:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;closed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Connection closed.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Synchronization initialized.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Future&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Run indefinitely
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Error during sync initialization:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;asyncio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;fetch-transactions-by-public-key&quot;&gt;Fetch Transactions by Public Key&lt;/h4&gt;

&lt;p&gt;Once transactions are synced to MongoDB, you can query them efficiently using the public key of the owner.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Node.js Query (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetchTransactions.js&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MongoClient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;mongodb&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mongoConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;mongodb://localhost:27017&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;dbName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;myDatabase&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;collectionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;myCollection&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;targetPublicKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;8LUKr81SmkdDhuBNAHfH9C8G5m6Cye2mpUggVu61USbD&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;MongoClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mongoConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mongoConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dbName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mongoConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;collectionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Connected to MongoDB for fetching transactions.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Create an index for faster querying&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;indexName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;transactions.value.inputs.owners_before&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Index created: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pipeline&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;$unwind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;$transactions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;$unwind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;$transactions.value.inputs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;$match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;transactions.value.inputs.owners_before&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;targetPublicKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;$sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;transactions.value.asset.data.timestamp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;$project&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;$transactions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aggregate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Transactions:`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Error fetching transactions:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Python Query (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fetch_transactions.py&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pymongo&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoClient&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mongo_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;uri&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;mongodb://localhost:27017&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;db_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;myDatabase&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;collection_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;myCollection&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;target_public_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;8LUKr81SmkdDhuBNAHfH9C8G5m6Cye2mpUggVu61USbD&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MongoClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mongo_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;uri&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mongo_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;db_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mongo_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;collection_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Connected to MongoDB for fetching transactions.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Create an index for optimized querying
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;transactions.value.inputs.owners_before&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Index created: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Define aggregation pipeline to fetch transactions by public key
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$unwind&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$transactions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$unwind&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$transactions.value.inputs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$match&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;transactions.value.inputs.owners_before&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target_public_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$sort&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;transactions.value.asset.data.timestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$project&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;transaction&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;$transactions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aggregate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Transactions:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;No transactions found for publicKey: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target_public_key&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, your Resilient App can efficiently filter transactions based on user-specific data without slow queries to the blockchain.&lt;/p&gt;

&lt;h2 id=&quot;using-resilientdb-graphql-for-transactions-and-queries&quot;&gt;Using ResilientDB GraphQL for Transactions and Queries&lt;/h2&gt;

&lt;p&gt;ResilientDB provides a &lt;strong&gt;GraphQL API&lt;/strong&gt; for seamless interaction with the blockchain, allowing you to send transactions and fetch transaction details efficiently.&lt;/p&gt;

&lt;h3 id=&quot;accessing-resilientdb-graphql&quot;&gt;&lt;strong&gt;Accessing ResilientDB GraphQL&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;For Localnet:&lt;/strong&gt; ResilientDB GraphQL is available at:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://localhost/graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;For Mainnet (ResilientDB Cloud):&lt;/strong&gt;
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;https://cloud.resilientdb.com/graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ResVault&lt;/strong&gt; uses this GraphQL API internally to send transactions using stored keys. You can also use it directly in your application.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;sending-a-transaction-via-graphql&quot;&gt;&lt;strong&gt;Sending a Transaction via GraphQL&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;You can send a transaction to &lt;strong&gt;ResilientDB&lt;/strong&gt; using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postTransaction&lt;/code&gt; mutation.&lt;/p&gt;

&lt;h3 id=&quot;mutation-example&quot;&gt;&lt;strong&gt;Mutation Example&lt;/strong&gt;&lt;/h3&gt;
&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;mutation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;postTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;CREATE&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50632&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signerPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8fPAqJvAFAkqGs8GdmDDrkHyR7hHsscVjes39TVVfN54&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signerPrivateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;5R4ER6smR6c6fsWt3unPqP6Rhjepbn82Us7hoSj5ZYCc&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ECJksQuF9UWi3DPCYvQqJPjF6BqSbXrnDiXUjdiVvkyH&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1690881023169&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;explanation&quot;&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;operation:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;CREATE&quot;&lt;/code&gt; defines the type of transaction.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;amount:&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;50632&lt;/code&gt; specifies the transaction value.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;signerPublicKey &amp;amp; signerPrivateKey:&lt;/strong&gt; Used for transaction signing.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;recipientPublicKey:&lt;/strong&gt; Defines the recipient of the transaction.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;asset:&lt;/strong&gt; Stores additional transaction data (any JSON).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;🔹 Expected Response:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;postTransaction&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;f1df753f782dccd7e345175f67a3f8026113b1074724b202f24aa9073644ab47&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The response includes the &lt;strong&gt;transaction ID&lt;/strong&gt;, which can be used to fetch details later.&lt;/p&gt;

&lt;h2 id=&quot;fetching-a-transaction-by-id&quot;&gt;&lt;strong&gt;Fetching a Transaction by ID&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;You can retrieve transaction details using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getTransaction&lt;/code&gt; query.&lt;/p&gt;

&lt;h3 id=&quot;query-example&quot;&gt;&lt;strong&gt;Query Example&lt;/strong&gt;&lt;/h3&gt;
&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;f1df753f782dccd7e345175f67a3f8026113b1074724b202f24aa9073644ab47&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signerPublicKey&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;explanation-1&quot;&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;id:&lt;/strong&gt; Transaction ID (retrieved from the previous mutation).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Expected Response:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;getTransaction&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;f1df753f782dccd7e345175f67a3f8026113b1074724b202f24aa9073644ab47&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;amount&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50632&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;operation&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;CREATE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;asset&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1690881023169&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;publicKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ECJksQuF9UWi3DPCYvQqJPjF6BqSbXrnDiXUjdiVvkyH&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;uri&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ni:///sha-256;ORrcs4QnlphyiTL69-rcLNPNV_SfaCgmg7ywRhGgYBM?fpt=ed25519-sha-256&amp;amp;cost=131072&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ed25519-sha-256&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;signerPublicKey&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8fPAqJvAFAkqGs8GdmDDrkHyR7hHsscVjes39TVVfN54&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Two transactions will have identical IDs if all the fields in the postTransaction mutation are exactly the same. This is because ResilientDB deterministically generates transaction IDs based on the input fields, ensuring consistency across identical transactions.&lt;/p&gt;

&lt;h4 id=&quot;what-you-can-do-with-resilientdb-graphql&quot;&gt;&lt;strong&gt;What You Can Do with ResilientDB GraphQL&lt;/strong&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Send transactions&lt;/strong&gt; using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postTransaction&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Retrieve transactions&lt;/strong&gt; by ID using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getTransaction&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Use it in ResVault&lt;/strong&gt; for transaction signing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Directly interact with ResilientDB&lt;/strong&gt; via GraphQL instead of manually handling HTTP requests.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Congratulations! Your first Resilient App now has all the essential components set up! You’re now ready to build, authenticate, and interact seamlessly with ResilientDB. Happy coding!&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;demo-video&quot;&gt;Demo video&lt;/h4&gt;
&lt;p&gt;Coming soon!&lt;/p&gt;
</description>
        <pubDate>Thu, 13 Mar 2025 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2025/03/13/ResVault.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2025/03/13/ResVault.html</guid>
      </item>
    
      <item>
        <title>Getting Started with Smart Contract on ResilientDB</title>
        <description>&lt;p&gt;Here we illustrate how to run a smart contract on Nexres locally. We provide step-by-step tutorials to set up locally with 4 nodes and use the built-in smart contract service.&lt;/p&gt;

&lt;h1 id=&quot;install&quot;&gt;Install&lt;/h1&gt;
&lt;p&gt;Following the instruction &lt;a href=&quot;[https://blog.resilientdb.com/2022/09/28/GettingStartedNexRes.html](https://github.com/apache/incubator-resilientdb)&quot;&gt;install tutorial&lt;/a&gt; to initial the environment that runs a Key-Value Service locally.
If you are using our cloud, you can ignore the system install section.&lt;/p&gt;

&lt;h1 id=&quot;smart-contract-install&quot;&gt;Smart Contract Install&lt;/h1&gt;
&lt;p&gt;It contains three steps if you want to deploy your contract and execute its functions in ResilientDB: 
Create the contract account, deploy the contract, and execute the functions.&lt;/p&gt;

&lt;p&gt;The ‘contract_service_tools’ provides access to the system by providing a JSON file and the service config.&lt;/p&gt;

&lt;h2 id=&quot;contract_service_tools&quot;&gt;contract_service_tools&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/kv/api_tools/contract_service_tools -c ServiceConfig –config_file=JSON Path&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;parameters&quot;&gt;Parameters:&lt;/h3&gt;
&lt;blockquote&gt;
  &lt;p&gt;-c the client configuration path&lt;br /&gt;
–config_file the JSON file describing the actions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;create-a-owner-account&quot;&gt;Create a Owner Account&lt;/h2&gt;
&lt;p&gt;For creating an account, the &lt;a href=&quot;https://github.com/apache/incubator-resilientdb/blob/master/service/tools/kv/api_tools/create.js&quot;&gt;JSON file&lt;/a&gt; is simply to provide the action:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;command&quot;:&quot;create_account&quot;,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;command&quot;&gt;Command:&lt;/h3&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/kv/api_tools/contract_service_tools -c service/tools/config/interface/service.config –config_file=service/tools/kv/api_tools/create.js&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;response&quot;&gt;Response:&lt;/h3&gt;
&lt;p&gt;Then, you will see the result&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   create account: address: &quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;deploy-your-contract&quot;&gt;Deploy Your Contract&lt;/h2&gt;

&lt;h3 id=&quot;contract&quot;&gt;Contract&lt;/h3&gt;
&lt;p&gt;Nexres only handles the JSON description of the contract source code. We use solc, a tool from Solidity, to obtain the JSON file.
Currently, we only support solidity version is larger than 0.5.0 (solidity &amp;gt;= 0.5.0)&lt;/p&gt;

&lt;p&gt;We provide &lt;a href=&quot;[service/tools/kv/api_tools/example_contract/token.sol](https://github.com/apache/incubator-resilientdb/blob/master/service/tools/kv/api_tools/example_contract/token.sol)&quot;&gt;token.sol&lt;/a&gt; as an example below:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;solc –evm-version homestead –combined-json bin,hashes –pretty-json –optimize token.sol &amp;gt; token.json&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once get your &lt;a href=&quot;[service/tools/kv/api_tools/example_contract/token.json](https://github.com/apache/incubator-resilientdb/blob/master/service/tools/kv/api_tools/example_contract/token.json)&quot;&gt;json contract&lt;/a&gt;, you can find the contract name(“token.sol:Token”) and its function hashes under the contract name section in the file.&lt;/p&gt;

&lt;p&gt;token.sol：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pragma solidity &amp;gt;= 0.5.0;

// Transfer tokens from the contract owner
contract Token {
  mapping (address =&amp;gt; uint256) balances;

  event Transfer(address indexed _from, address indexed _to, uint256 _value);

  constructor(uint256 s) public {
    balances[msg.sender] = s;
  }

  // Get the account balance of another account with address _owner
  function balanceOf(address _owner) public view returns (uint256) {
    return balances[_owner];
  }

  // Send _value amount of tokens to address _to
  function transfer(address _to, uint256 _value) public returns (bool) {
    if (balances[msg.sender] &amp;gt;= _value) {
      balances[msg.sender] -= _value;
      balances[_to] += _value;
      emit Transfer(msg.sender, _to, _value);
      return true;
    }
    else
    {
      return false;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;token.json&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;contracts&quot;:
  {
    &quot;token.sol:Token&quot;:
    {
      &quot;bin&quot;: &quot;608060405234801561001057600080fd5b506040516101fe3803806101fe8339818101604052602081101561003357600080fd5b5051336000908152602081905260409020556101aa806100546000396000f3fe608060405234801561001057600080fd5b5060043610610052577c0100000000000000000000000000000000000000000000000000000000600035046370a082318114610057578063a9059cbb1461008f575b600080fd5b61007d6004803603602081101561006d57600080fd5b5035600160a060020a03166100cf565b60408051918252519081900360200190f35b6100bb600480360360408110156100a557600080fd5b50600160a060020a0381351690602001356100ea565b604080519115158252519081900360200190f35b600160a060020a031660009081526020819052604090205490565b33600090815260208190526040812054821161016b573360008181526020818152604080832080548790039055600160a060020a03871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a350600161016f565b5060005b9291505056fea265627a7a72315820600579dee5d66ea3489085c4cb41116045ba977cb4804caac8d5f24e248e337064736f6c63430005100032&quot;,
      &quot;hashes&quot;:
      {
        &quot;balanceOf(address)&quot;: &quot;70a08231&quot;,
        &quot;transfer(address,uint256)&quot;: &quot;a9059cbb&quot;
      }
    }
  },
  &quot;version&quot;: &quot;0.5.16+commit.9c3226ce.Linux.g++&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;deploy-json-file&quot;&gt;Deploy JSON file&lt;/h3&gt;
&lt;p&gt;Now we generate the &lt;a href=&quot;https://github.com/apache/incubator-resilientdb/blob/master/service/tools/kv/api_tools/deploy.js&quot;&gt;JSON&lt;/a&gt; for the deployment. The JSON file contains the command (“deploy”), the contract location, the contract section in the JSON file, the owner_address address who owns the contract (we have created in the previous step), and the initial parameters, which can be empty.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;command&quot;:&quot;deploy&quot;,
  &quot;contract_path&quot;: &quot;service/tools/kv/api_tools/example_contract/token.json&quot;,
  &quot;contract_name&quot;: &quot;token.sol:Token&quot;,
  &quot;init_params&quot;: &quot;1000&quot;,
  &quot;owner_address&quot;: &quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;command-1&quot;&gt;Command:&lt;/h3&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/kv/api_tools/contract_service_tools -c service/tools/config/interface/service.config –config_file=service/tools/kv/api_tools/deploy.js&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;response-1&quot;&gt;Response:&lt;/h3&gt;
&lt;p&gt;Then you will see the response:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;deploy contract:
owner_address: &quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;
contract_address: &quot;0xfc08e5bfebdcf7bb4cf5aafc29be03c1d53898f1&quot;
contract_name: &quot;token.sol:Token&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;execute-contract&quot;&gt;Execute Contract&lt;/h2&gt;
&lt;p&gt;Now we generate the JSON for the execution. The JSON file contains the command (“execute”), the contract address, the caller address who owns the contract, the function name, and the parameters to run the function.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;command&quot;:&quot;execute&quot;,
  &quot;contract_address&quot;: &quot;0xfc08e5bfebdcf7bb4cf5aafc29be03c1d53898f1&quot;,
  &quot;caller_address&quot;: &quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;,
  &quot;func_name&quot;:&quot;transfer(address,uint256)&quot;,
  &quot;params&quot;:&quot;0x1be8e78d765a2e63339fc99a66320db73158a35a,100&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;command-2&quot;&gt;Command:&lt;/h3&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/kv/api_tools/contract_service_tools -c service/tools/config/interface/service.config –config_file=service/tools/kv/api_tools/execute.js&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;response-2&quot;&gt;Response:&lt;/h3&gt;
&lt;p&gt;Once it is done, you will see the result:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;0x0000000000000000000000000000000000000000000000000000000000000001&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;using-key-value-interfaces&quot;&gt;Using Key-Value Interfaces&lt;/h1&gt;
&lt;p&gt;The Key-Value interfaces provide the API to access the accounts: get_balance and set_balance.&lt;/p&gt;

&lt;p&gt;The JSON files and corresponding commands are shown as below:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;command&quot;:&quot;get_balance&quot;,
  &quot;address&quot;:&quot;0x1be8e78d765a2e63339fc99a66320db73158a35a&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/kv/api_tools/contract_service_tools -c service/tools/config/interface/service.config –config_file=service/tools/kv/api_tools/get_balance.js&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;command&quot;:&quot;set_balance&quot;,
  &quot;address&quot;:&quot;0x1be8e78d765a2e63339fc99a66320db73158a35a&quot;,
  &quot;balance&quot;:&quot;2000&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/kv/api_tools/contract_service_tools -c service/tools/config/interface/service.config –config_file=service/tools/kv/api_tools/set_balance.js&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;notice&quot;&gt;Notice&lt;/h3&gt;
&lt;p&gt;The accounts do not need to be created using the &lt;a href=&quot;https://github.com/apache/incubator-resilientdb-blog/edit/main/_posts/2023-01-15-GettingStartedSmartContract.md#create-a-owner-account&quot;&gt;API&lt;/a&gt; before being used.
However, if the account is used to deploy the contract, it must first be created by the API to register in the contract database.&lt;/p&gt;

&lt;h1 id=&quot;future-work&quot;&gt;Future Work&lt;/h1&gt;
&lt;p&gt;Apply the authorization for the execution that verifies the owner to execute its contracts, like using the signatures.&lt;/p&gt;

</description>
        <pubDate>Fri, 14 Feb 2025 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2025/02/14/GettingStartedSmartContract.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2025/02/14/GettingStartedSmartContract.html</guid>
      </item>
    
      <item>
        <title>VoteChain 2.0 - Decentralizing Voting with Blockchain, One Vote at a Time</title>
        <description>&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;

&lt;p&gt;VoteChain 2.0 builds on the foundation of the original ResilientApp VoteChain, utilizing &lt;strong&gt;ResilientDB’s scalable blockchain infrastructure&lt;/strong&gt; to create a customizable and secure voting platform. The enhanced app includes customizable voting, voting history, and a results page and discussion panel for each poll. &lt;strong&gt;ResVault&lt;/strong&gt; now provides blockchain-based authentication and enables authorized voting and discussion access. ResilientDB’s blockchain guarantees data integrity, anonymity, and privacy, positioning VoteChain as a scalable solution for institutions seeking transparent yet customizable feedback mechanisms.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/votechain/home_screen.png&quot; alt=&quot;VoteChain Home Screen&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. VoteChain Home Screen
    &lt;/em&gt;
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;While the original ResilientApp VoteChain was designed for government-level elections, we recognized an opportunity to bring the benefits of secure, transparent voting to smaller communities. Research into voting fairness in the gaming community inspired the idea of decentralized, transparent voting to prevent fraud and build trust. To address these issues, we envisioned a solution that seamlessly blends security with user-friendly functionality that encourages collaboration and engagement. Leveraging ResilientDB’s robust blockchain capabilities, we developed VoteChain 2.0 — a secure, decentralized platform tailored for community use.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;key-features&quot;&gt;Key Features&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Secure and Transparent Elections&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Single Voting Instance&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Immutable Votes&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;User-Friendly Interface&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;NEW! User Authentication with ResVault&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;NEW! Customizable Voting&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;NEW! Participate in Discussion Panels&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;NEW! View Poll Results &amp;amp; Personal Vote History&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/votechain/features.png&quot; alt=&quot;VoteChain Features&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Key Features of VoteChain 2.0
    &lt;/em&gt;
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;system-architecture&quot;&gt;System Architecture&lt;/h2&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/votechain/architecture.png&quot; alt=&quot;System Architecture&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. System Architecture of VoteChain 2.0
    &lt;/em&gt;
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;tech-stack&quot;&gt;Tech Stack&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;ResilientDB&lt;/strong&gt; - Provides secure, transparent, and tamper-resistant data storage for voting.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;GraphQL&lt;/strong&gt; - Efficient data querying with APIs for transaction operations.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;React.js&lt;/strong&gt; - Builds interactive user interfaces.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Material UI&lt;/strong&gt; - Ensures responsive design across devices.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Node.js&lt;/strong&gt; - Handles server-side logic and API communication.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResVault&lt;/strong&gt; - Manages user authentication securely.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt; - Organizes poll-related data (topics, votes, messages).&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;screenshots&quot;&gt;Screenshots&lt;/h2&gt;

&lt;h3 id=&quot;home-screen&quot;&gt;Home Screen&lt;/h3&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/votechain/home_screen.png&quot; alt=&quot;Home Screen&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. Home Screen
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;login-page&quot;&gt;Login Page&lt;/h3&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/votechain/login_page.png&quot; alt=&quot;Login Page&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Login Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;create-polls-screen&quot;&gt;Create Polls Screen&lt;/h3&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/votechain/create_poll.png&quot; alt=&quot;Create Poll Screen&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 6. Create Poll Screen
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;results-screen&quot;&gt;Results Screen&lt;/h3&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/votechain/results_screen.png&quot; alt=&quot;Results Screen&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 7. Results Screen
    &lt;/em&gt;
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;h3 id=&quot;install-resvault-chrome-extension&quot;&gt;Install ResVault Chrome Extension&lt;/h3&gt;

&lt;p&gt;Google Chrome is available on macOS, Linux, and Windows platforms. Please refer to the official Google installation guide based on your platform.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Clone the ResVault repo to get started:&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; git clone https://github.com/ResilientApp/ResVault.git
 &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ResVault
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Create the build folder in the repository:&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; npm &lt;span class=&quot;nb&quot;&gt;install
 &lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Load the extension in Chrome:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Open &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;chrome://extensions/&lt;/code&gt; in Google Chrome and toggle &lt;strong&gt;Developer mode&lt;/strong&gt; on.&lt;/li&gt;
      &lt;li&gt;Click on &lt;strong&gt;Load unpacked&lt;/strong&gt;.&lt;/li&gt;
      &lt;li&gt;Select the build folder you just created.&lt;/li&gt;
      &lt;li&gt;You should see the ResVault extension in Chrome.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;steps-to-run-the-system&quot;&gt;Steps to Run the System&lt;/h2&gt;

&lt;h3 id=&quot;requirements&quot;&gt;Requirements&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Node.js&lt;/strong&gt;: Download and install Node.js from &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js Downloads&lt;/a&gt; based on your platform.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;npm (Node Package Manager)&lt;/strong&gt;: npm is included with Node.js. Verify installation:&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; node &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
 npm &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;running-votechain&quot;&gt;Running VoteChain&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Clone the VoteChain Git repository to your local machine:&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; git clone https://github.com/ItsBaiShiXi/VoteChain.git
 &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;VoteChain
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install required dependencies:&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Once the dependencies are installed successfully:
    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;Open a terminal and run the following command to start the backend:&lt;/p&gt;

        &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   npm run start-backend
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;Open another terminal and run the following command to start the frontend:&lt;/p&gt;

        &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;This will launch the application, and you can access it in your web browser.&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Connect the ResVault Chrome extension. You can now anonymously log in to VoteChain through ResVault.&lt;/li&gt;
&lt;/ol&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/votechain/resvault_connection.png&quot; alt=&quot;ResVault Connection&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Connecting ResVault to VoteChain
    &lt;/em&gt;
&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;contributors&quot;&gt;Contributors&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Shengzhe Zhang&lt;/li&gt;
  &lt;li&gt;Xin Tang&lt;/li&gt;
  &lt;li&gt;Madelyn Nguyen&lt;/li&gt;
  &lt;li&gt;Zixuan Weng&lt;/li&gt;
  &lt;li&gt;Xiuyuan Qi&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Mon, 09 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/09/VoteChain2.0.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/09/VoteChain2.0.html</guid>
      </item>
    
      <item>
        <title>PetChain</title>
        <description>&lt;p&gt;Built on the ResilientDB fabric, PetChain provides secure lost-and-found tracking, seamless health record management, streamlined ownership transfer, and automated pet insurance processing, ensuring reliability in pet care.&lt;/p&gt;

&lt;h2 id=&quot;project-overview&quot;&gt;Project Overview&lt;/h2&gt;
&lt;h3 id=&quot;motivation&quot;&gt;Motivation&lt;/h3&gt;

&lt;p&gt;The pet industry, valued at around $150 billion in the U.S. alone, faces critical challenges in pet identification, health record management, and delays in insurance processing. As a team of pet owners and technology enthusiasts, we’ve experienced various challenges in pet ownership—ranging from the frustration of delayed insurance disbursements during emergencies to difficulties accessing reliable information on pet ownership transfers. These shared experiences underscored the need for a unified, secure system that offers pet owners faster and better transparent solutions. This need drove us to develop PetChain, a blockchain-based platform designed to holistically address these issues and enhance the overall pet ownership experience.&lt;/p&gt;

&lt;h3 id=&quot;why-petchain&quot;&gt;Why PetChain?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Scalable and Reliable&lt;/strong&gt;: PetChain, powered by ResilientDB, delivers a robust platform designed to scale effortlessly with increasing data and users, maintaining high performance and fault tolerance.&lt;br /&gt;
&lt;strong&gt;Streamlined Lost-and-Found and Ownership Transfers&lt;/strong&gt;: Leveraging blockchain technology, PetChain enables swift and secure reunification of lost pets with their owners while simplifying the transfer of pet ownership.&lt;br /&gt;
&lt;strong&gt;Automated Insurance Processing&lt;/strong&gt;: PetChain uses smart contracts to automate insurance claims, ensuring faster, more efficient, and error-free processes.&lt;br /&gt;
&lt;strong&gt;Secure and Transparent&lt;/strong&gt;: Blockchain-based storage ensures pet identification and ownership data remain tamper-proof, fostering trust and transparency in pet care.&lt;/p&gt;

&lt;h2 id=&quot;feature-set&quot;&gt;Feature Set&lt;/h2&gt;
&lt;div style=&quot;display: flex; justify-content: center; gap: 10px;&quot;&gt;
    &lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/Landing-page.png&quot; alt=&quot;LandingPage&quot; width=&quot;500&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Landing Page&lt;/em&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/Signup.png&quot; alt=&quot;SignUp&quot; width=&quot;700&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;SignUp Page&lt;/em&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;h3 id=&quot;user-and-pet-registration&quot;&gt;User and Pet Registration&lt;/h3&gt;
&lt;p&gt;The registration and login workflow in PetChain uses JWT tokens for secure authentication and role-based access control. Passwords are hashed using bcrypt and stored securely in the database. A tamper-proof ownership hash, created using the owner’s custom ID and unique petId with SHA-256, is stored in ResDB for blockchain traceability, while pet details are saved in MongoDB for quick retrieval. Owners can retrieve pet details via the getPetDetails API, ensuring a secure and efficient process for pet registration and ownership validation.&lt;/p&gt;

&lt;p&gt;Pet registration event logged in ResDB:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(2024-12-09 11:05:19) [INFO    ] Request: 127.0.0.1:45068 0x7fccdc002870 HTTP/1.1 POST /v1/transactions/commit
I20241209 03:05:19.347833 652360 crow_service.cpp:158] body: {&quot;id&quot;:&quot;OWNER_1733742092244&quot;,&quot;value&quot;:{&quot;pet_id&quot;:&quot;PET_1733742319324&quot;,&quot;ownershipHash&quot;:&quot;a44f3f6cb0c0efc4671f254ffe1eeb28a09ae7dfc820f5be21e85c38c2eef74c&quot;,&quot;timeStamp&quot;:&quot;2024-12-09T11:05:19.326Z&quot;,&quot;status&quot;:&quot;active&quot;,&quot;event&quot;:&quot;register pet&quot;}}
I20241209 03:05:19.349356 652360 crow_service.cpp:180] Set OWNER_1733742092244 to {&quot;id&quot;:&quot;OWNER_1733742092244&quot;,&quot;value&quot;:{&quot;pet_id&quot;:&quot;PET_1733742319324&quot;,&quot;ownershipHash&quot;:&quot;a44f3f6cb0c0efc4671f254ffe1eeb28a09ae7dfc820f5be21e85c38c2eef74c&quot;,&quot;timeStamp&quot;:&quot;2024-12-09T11:05:19.326Z&quot;,&quot;status&quot;:&quot;active&quot;,&quot;event&quot;:&quot;register pet&quot;}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div style=&quot;display: flex; justify-content: center; gap: 10px;&quot;&gt;
    &lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/OwnerDashboard.png&quot; alt=&quot;User Landing Page&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;User DashBoard&lt;/em&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/RegisterPet.png&quot; alt=&quot;Register Pet&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Register Pet&lt;/em&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/ManagePet.png&quot; alt=&quot;Manage Pet&quot; /&gt;
        &lt;br /&gt;
&lt;/div&gt;
&lt;h3 id=&quot;lost-and-found&quot;&gt;Lost and Found&lt;/h3&gt;
&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/petchain/LostFoundSequence.png&quot; alt=&quot;Logo&quot; width=&quot;800&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 1. Sequence Diagram for Lost and Found Service
    &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;When a pet goes missing, the owner can report it by clicking the “Lost” button in the user interface, triggering a POST request to the petLostandFound() API. This API updates the pet’s status in MongoDB and generates a unique LostHash using the pet ID, owner ID, and event details, which is then securely stored in ResDB.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(2024-12-09 11:05:19) [INFO    ] Response: 0x7fccdc002870 /v1/transactions/commit 201 0
(2024-12-09 11:06:38) [INFO    ] Request: 127.0.0.1:39276 0x7fccdc000c20 HTTP/1.1 POST /v1/transactions/commit
I20241209 03:06:38.358037 652359 crow_service.cpp:158] body: {&quot;id&quot;:&quot;OWNER_1733742092244&quot;,&quot;value&quot;:{&quot;pet_id&quot;:&quot;PET_1733742319324&quot;,&quot;lostHash&quot;:&quot;0d753f137b9725f0bc7b8e29d376f4ff9ae67ff946a8fea7a301695dae293de9&quot;,&quot;timeStamp&quot;:&quot;2024-12-09T11:06:38.354Z&quot;,&quot;status&quot;:&quot;active&quot;,&quot;event&quot;:&quot;lost pet&quot;}}
I20241209 03:06:38.358719 652359 crow_service.cpp:180] Set OWNER_1733742092244 to {&quot;id&quot;:&quot;OWNER_1733742092244&quot;,&quot;value&quot;:{&quot;pet_id&quot;:&quot;PET_1733742319324&quot;,&quot;lostHash&quot;:&quot;0d753f137b9725f0bc7b8e29d376f4ff9ae67ff946a8fea7a301695dae293de9&quot;,&quot;timeStamp&quot;:&quot;2024-12-09T11:06:38.354Z&quot;,&quot;status&quot;:&quot;active&quot;,&quot;event&quot;:&quot;lost pet&quot;}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/MarkLost.png&quot; alt=&quot;MarkLost&quot; width=&quot;600&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Mark Pet as Lost&lt;/em&gt;
&lt;/div&gt;

&lt;p&gt;When the pet is found by someone, they can submit the pet’s details via the “Found” feature in the UI, prompting the searchLostPet() API to generate a FoundHash.  The system then retrieves the LostHash from ResDB, performs validation and updates the pet’s status to “found,” completing the process of reuniting the pets with its owner.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(2024-12-09 11:08:41) [INFO    ] Request: 127.0.0.1:35466 0x7fccdc002870 HTTP/1.1 POST /v1/transactions/commit
I20241209 03:08:41.755368 652360 crow_service.cpp:158] body: {&quot;id&quot;:&quot;OWNER_1733742092244&quot;,&quot;value&quot;:{&quot;pet_id&quot;:&quot;PET_1733742319324&quot;,&quot;foundHash&quot;:&quot;8c85e9e98417656cdbc5172bfac80aa7bde53deda0fd44f8d8d519646cfeb240&quot;,&quot;timeStamp&quot;:&quot;2024-12-09T11:08:41.752Z&quot;,&quot;status&quot;:&quot;active&quot;,&quot;event&quot;:&quot;found pet&quot;}}
I20241209 03:08:41.755961 652360 crow_service.cpp:180] Set OWNER_1733742092244 to {&quot;id&quot;:&quot;OWNER_1733742092244&quot;,&quot;value&quot;:{&quot;pet_id&quot;:&quot;PET_1733742319324&quot;,&quot;foundHash&quot;:&quot;8c85e9e98417656cdbc5172bfac80aa7bde53deda0fd44f8d8d519646cfeb240&quot;,&quot;timeStamp&quot;:&quot;2024-12-09T11:08:41.752Z&quot;,&quot;status&quot;:&quot;active&quot;,&quot;event&quot;:&quot;found pet&quot;}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div style=&quot;display: flex; justify-content: center; gap: 10px;&quot;&gt;
    &lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/Found.png&quot; alt=&quot;Found Pet&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Found Pet&lt;/em&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/NotifyOwner.png&quot; alt=&quot;Notify Owner&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Notify Owner&lt;/em&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;h3 id=&quot;pet-health-management&quot;&gt;Pet-Health Management&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Health Record Management&lt;/strong&gt;: Owners can record vaccination history, allergies, minor illnesses, and past treatments for their pets.&lt;/p&gt;
&lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/PetHealth.png&quot; alt=&quot;Pet Health&quot; /&gt;
        &lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
&lt;strong&gt;Veterinarian Access&lt;/strong&gt;: A dedicated Veterinarian Profile interface allows vets to view pet health records by entering the pet ID.&lt;/p&gt;
&lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/VetUpdate.png&quot; alt=&quot;Vet Portal&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Vet Portal&lt;/em&gt;
&lt;/div&gt;
&lt;h3 id=&quot;ownership-transfer&quot;&gt;Ownership Transfer&lt;/h3&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/petchain/OwnerTransferSequence.png&quot; alt=&quot;Logo&quot; width=&quot;800&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 2. Sequence Diagram for Ownership Transfer
    &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;The ownership transfer process in PetChain ensures a secure and seamless experience. When the “Transfer Ownership” button is clicked, a POST request initiates the transfer by generating an approval token, saving the transfer request in MongoDB, and sending an email notification to the new owner’s email using Nodemailer. The email contains an approval link that, when clicked, triggers a POST request to validate the transfer. This involves fetching pet details and ownership hashes from MongoDB and ResDB, validating the data, and generating a transfer hash upon success. The event is logged in ResDB, MongoDB is updated with the new owner’s details, and the new owner is redirected to the website with a success message. In case of validation failure, the transfer is rejected, and the owner is notified via a dialog box.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(2024-12-09 11:25:14) [INFO    ] Request: 127.0.0.1:38158 0x7fccdc002870 HTTP/1.1 POST /v1/transactions/commit
I20241209 03:25:14.258247 652360 crow_service.cpp:158] body: {&quot;id&quot;:&quot;OWNER_1733743246179&quot;,&quot;value&quot;:{&quot;pet_id&quot;:&quot;PET_1733742319324&quot;,&quot;ownershipTransfer&quot;:{&quot;oldOwnerId&quot;:&quot;OWNER_1733742092244&quot;,&quot;newOwnerId&quot;:&quot;OWNER_1733743246179&quot;},&quot;transferHash&quot;:&quot;0e3da49f70790cc3d2a761319c8e2432507d36c312f390ef0850f8803701ff99&quot;,&quot;timeStamp&quot;:&quot;2024-12-09T11:25:14.255Z&quot;,&quot;status&quot;:&quot;completed&quot;,&quot;event&quot;:&quot;ownership transfer&quot;}}
I20241209 03:25:14.258463 652360 crow_service.cpp:180] Set OWNER_1733743246179 to {&quot;id&quot;:&quot;OWNER_1733743246179&quot;,&quot;value&quot;:{&quot;pet_id&quot;:&quot;PET_1733742319324&quot;,&quot;ownershipTransfer&quot;:{&quot;oldOwnerId&quot;:&quot;OWNER_1733742092244&quot;,&quot;newOwnerId&quot;:&quot;OWNER_1733743246179&quot;},&quot;transferHash&quot;:&quot;0e3da49f70790cc3d2a761319c8e2432507d36c312f390ef0850f8803701ff99&quot;,&quot;timeStamp&quot;:&quot;2024-12-09T11:25:14.255Z&quot;,&quot;status&quot;:&quot;completed&quot;,&quot;event&quot;:&quot;ownership transfer&quot;}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div style=&quot;display: flex; justify-content: center; gap: 10px;&quot;&gt;
    &lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/InitTransfer.png&quot; alt=&quot;Initiate Request&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Initiate Request&lt;/em&gt;
    &lt;/div&gt;
    &lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/Notify.png&quot; alt=&quot;NotifyOldOwner&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Dialog pop up for owner&lt;/em&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;div style=&quot;display: flex; justify-content: center; gap: 10px;&quot;&gt;
&lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/ApproveRequest.png&quot; alt=&quot;EmailRequest&quot; width=&quot;800&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Approval Request to NewOwner&lt;/em&gt;
&lt;/div&gt;
&lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/TransferSuccess.png&quot; alt=&quot;OldOwnerView&quot; width=&quot;800&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Old Owner View&lt;/em&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;h3 id=&quot;smart-contract-based-insurance-processing&quot;&gt;Smart Contract Based Insurance Processing&lt;/h3&gt;
&lt;p&gt;The insurance service in PetChain provides two main functionalities: Add Insurance and Claim Insurance. In the Add Insurance process, a POST API maps a pet’s details (pet ID) to a policy’s information, including the policy number and coverage type. This information is securely stored in MongoDB, finalizing the policy addition. In the Claim Insurance process, a POST API integrates with a smart contract to handle claims in two stages: Pre-Approval, which verifies eligibility based on policy details, and Approval, which calculates the reimbursement amount by considering the coverage type and deductibles. This approach ensures a secure, efficient, and transparent insurance workflow.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/petchain/InsuranceSequence.png&quot; alt=&quot;Logo&quot; width=&quot;800&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 3. Sequence Diagram for Insurance Processing
    &lt;/em&gt;
&lt;/p&gt;
&lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/AddInsurance.png&quot; alt=&quot;AddInsurance&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Add Insurance&lt;/em&gt;
&lt;/div&gt;
&lt;div&gt;
        &lt;img src=&quot;/assets/images/petchain/ClaimInsurance.png&quot; alt=&quot;ClaimInsurance&quot; /&gt;
        &lt;br /&gt;
        &lt;em&gt;Claim Insurance&lt;/em&gt;
&lt;/div&gt;

&lt;h2 id=&quot;technical-specifications&quot;&gt;Technical Specifications&lt;/h2&gt;
&lt;h3 id=&quot;system-architecture&quot;&gt;System Architecture&lt;/h3&gt;
&lt;p&gt;This section outlines how the core components of the PetChain platform are integrated to deliver seamless functionality. The Node.js back-end is used to manage and mediate between the databases and contract services. MongoDB is used for quick retrieval of user, pet, health, and insurance data, while ResDB stores important hashes, IDs, and events for secure blockchain operations. Smart contracts ensure automated and transparent processes like insurance management, and the front-end provides an intuitive interface for interaction with all system features.&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/petchain/System-Architecture.jpg&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 4. Architecture Diagram
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;technology-stack&quot;&gt;Technology Stack&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: React, MaterialUI&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Node.js, Express.js, HardHat, ethers.js, Solidity, Nodemailer&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Databases&lt;/strong&gt;: ResilientDB, MongoDB&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;steps-to-run-the-system&quot;&gt;Steps to Run the System&lt;/h3&gt;
&lt;h4 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Download NodeJS from &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;here&lt;/a&gt; and ensure that it’s added to PATH.&lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;setup-resilientdb-and-start-kv-service&quot;&gt;Setup ResilientDB and start KV Service&lt;/h5&gt;
    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/apache/incubator-resilientdb.git resilientdb
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resilientdb
./INSTALL.sh
./service/tools/kv/server_tools/start_kv_service.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;h5 id=&quot;setup-crow-http-service&quot;&gt;Setup Crow HTTP Service&lt;/h5&gt;
    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/ResilientApp/ResilientDB-GraphQL.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ResilientDB-GraphQL
bazel build service/http_server/crow_service_main
bazel-bin/service/http_server/crow_service_main service/tools/config/interface/client.config service/http_server/server_config.config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;running-the-application&quot;&gt;Running the application&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Git clone the repositories linked below into individual folders. Navigate to project directories and run the following command in each.
    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Create a .env file in the backend folder and enter the following:
    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;EMAIL_USER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;email-address&amp;gt;
&lt;span class=&quot;nv&quot;&gt;EMAIL_PASS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;app-password-for-email-account&amp;gt;
&lt;span class=&quot;nv&quot;&gt;JWT_SECRET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;token&amp;gt;
&lt;span class=&quot;nv&quot;&gt;CONTRACT_ADDRESS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;contract-address&amp;gt;
&lt;span class=&quot;nv&quot;&gt;ACCOUNT_ADDRESS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;contract-account-address&amp;gt;
&lt;span class=&quot;nv&quot;&gt;DB_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;mongo-db-url&amp;gt;
&lt;span class=&quot;nv&quot;&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;private-key-for-contract-deployment&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Run the following command in each folder (frontend and backend) to get the application running.
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Navigate to http://localhost:3001/ to launch application in web browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;links&quot;&gt;Links&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Code repository:
&lt;a href=&quot;https://github.com/nehapradeep/PetChainPlus&quot;&gt;Frontend&lt;/a&gt;, 
&lt;a href=&quot;https://github.com/sakshisingh301/PetChainBackend/tree/master&quot;&gt;Backend&lt;/a&gt;
&lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://drive.google.com/drive/folders/1bGqkGbOBiAmOWikIJbD70ByvCTGR6PsK?usp=sharing&quot;&gt;Demo Video&lt;/a&gt;
&lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/190cyr4yLdWzSKJSrkdzT-m8rJX4C3bKX/edit?usp=sharing&amp;amp;ouid=116836227048374057417&amp;amp;rtpof=true&amp;amp;sd=true&quot;&gt;Presentation Slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;about-team&quot;&gt;About Team&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Sakshi Singh&lt;/li&gt;
  &lt;li&gt;Ansha Prashanth&lt;/li&gt;
  &lt;li&gt;Neha Pradeep&lt;/li&gt;
  &lt;li&gt;Sarika Dinesh&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sun, 08 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/08/PetChain.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/08/PetChain.html</guid>
      </item>
    
      <item>
        <title>Coinsensus</title>
        <description>
&lt;h2 id=&quot;coincensus-split-bills-and-track-balances-powered-by-resilientdb&quot;&gt;&lt;strong&gt;Coincensus: Split Bills and Track Balances&lt;/strong&gt;, Powered by ResilientDB&lt;/h2&gt;

&lt;p&gt;![Photo by &lt;a href=&quot;https://cdn-images-1.medium.com/max/14396/1*j7LPyKLoHwY-u9iHAuyhdA.png&quot;&gt;&lt;strong&gt;GoMoney](https://gomoney.global/blog/worry-less-about-the-bill-when-you-split-it-with-gomoney/)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Managing group expenses and financial transactions is often tedious, error-prone, and vulnerable to privacy breaches with traditional methods. Centralized platforms lack transparency, risk data breaches, and fail to provide secure, real-time updates. This creates a need for a decentralized, transparent, and user-friendly solution to ensure trust, automate calculations, and securely manage group expenses. Coinsensus addresses these challenges with blockchain technology and a seamless interface, redefining expense management.&lt;/p&gt;

&lt;h3 id=&quot;what-is-coincensus&quot;&gt;What is Coincensus?&lt;/h3&gt;

&lt;p&gt;Coinsensus, a blockchain-based bill management platform powered by ResilientDB, is designed to create a trustless and transparent system for expense tracking among friends and groups. By leveraging blockchain technology’s decentralized and tamper-resistant nature, the project ensures secure and reliable monitoring of debts and lending without relying on a central authority.&lt;/p&gt;

&lt;p&gt;Through integrating &lt;strong&gt;ResilientDB¹&lt;/strong&gt;, a high-performance blockchain framework that uses Practical Byzantine Fault Tolerant Consensus Protocol (PBFT)² internally, the system achieves fault tolerance, low latency, and scalability, guaranteeing data integrity even in environments prone to network failures or malicious attacks.&lt;/p&gt;

&lt;p&gt;![Photo by &lt;a href=&quot;https://github.com/apache/incubator-resilientdb-site&quot;&gt;&lt;strong&gt;Apache ResilientDB **&lt;/strong&gt;(Incubating)&lt;/a&gt;&lt;em&gt;*](https://cdn-images-1.medium.com/max/2000/1&lt;/em&gt;1yJUI8me1QqUwrQAIlpYrQ.png)&lt;/p&gt;

&lt;p&gt;Additionally, Coinsensus also automates balance calculations and updates while maintaining an immutable transaction history, addressing ineﬃciencies in manual record-keeping and vulnerabilities in centralized systems. This product aims to redefine financial technology by oﬀering a resilient, decentralized solution³ that prioritizes data privacy and transparency for the users.&lt;/p&gt;

&lt;h3 id=&quot;why-coinsensus&quot;&gt;Why Coinsensus?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Strengthens Transaction Management with ResilientDB:&lt;/strong&gt; Our integration with ResilientDB significantly enhances Coinsensus’ ability to manage financial transactions with unparalleled trust and transparency. Leveraging ResilientDB’s decentralized framework, the platform ensures fault tolerance and robust data integrity, even during network disruptions and malicious activities. This integration provides users with a secure, resilient, and high-performance system, redefining the reliability of payment management.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Streamlined Group Expense Tracking:&lt;/strong&gt; The core of our application is a robust system for automatic and transparent expense sharing among group members or individuals. Each transaction is securely recorded on the blockchain, creating an immutable and tamper-proof ledger while enabling real-time balance updates. This eliminates the need for manual record-keeping, enhancing eﬃciency, accuracy, and trust within the group and individuals.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;User-Friendly Interface:&lt;/strong&gt; Our frontend application, developed using ReactJS, delivers a seamless and engaging user experience. With an intuitive and user-friendly design, it empowers users to eﬃciently manage their transactions, whether it’s adding expenses, tracking real-time balances, or accessing a detailed transaction history. The application ensures smooth navigation and functionality, making group expense management eﬀortless and accessible for all users.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2128/1*y_39ECQ_ZT0zxwlhXEPz9Q.png&quot; alt=&quot;**Coincensus: Architecture Overview**&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;tools-and-development&quot;&gt;Tools and Development&lt;/h3&gt;

&lt;p&gt;Coinsensus combines modern front-end frameworks, efficient backend solutions, and powerful blockchain technology to deliver a seamless and secure expense management platform. Here’s an overview of the tools that brought this product to life.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;React with TypeScript&lt;/strong&gt;: Used to develop a highly interactive and scalable user interface, combining React’s flexibility with TypeScript’s type safety for robust front-end development.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Tailwind CSS&lt;/strong&gt;: Simplified the styling process with its utility-first approach, allowing for the creation of a sleek, responsive, and consistent UI design.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;FastAPI&lt;/strong&gt;: Powered the backend with a high-performance API framework, ensuring efficient data handling and secure communication between the client and server.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;ResilientDB&lt;/strong&gt;: Implemented as the blockchain framework, providing fault tolerance, scalability, and low-latency transaction management for secure and reliable expense tracking¹.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;SQLite&lt;/strong&gt;: A second database used to store the public keys of all the users, which will be eventually used to update the transaction (money sent and received) from both ends.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;GIT &amp;amp; GitHub&lt;/strong&gt;: Enabled version control and collaboration, ensuring smooth teamwork and reliable code management throughout the development process.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;JIRA&lt;/strong&gt;: Facilitated task tracking and project management, helping the team stay organized, manage sprints, and deliver features efficiently over six sprints of one week each.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;design-flow-of-coincensus&quot;&gt;Design Flow of Coincensus&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2560/1*pxPYzDZbXl0Fwc3wjW1mRQ.jpeg&quot; alt=&quot;**Coincensus: Design Flow**&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;coincensus-workflow&quot;&gt;Coincensus Workflow&lt;/h3&gt;

&lt;h3 id=&quot;1-user-registration-and-login&quot;&gt;1. User Registration and Login&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;New Users&lt;/strong&gt;: Register an account by providing personal details, then proceed to the landing page after successful registration.
&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/format:webp/1*Yk5TACIHGSSonrrnzOmK2w.png&quot; alt=&quot;Signup&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Existing Users&lt;/strong&gt;: Log in with credentials to directly access the home page.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/format:webp/1*PbktXcCIfWSMoqFfnjfOBA.png&quot; alt=&quot;Login&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;2-landing-home-page-and-navigation&quot;&gt;2. Landing/ Home Page and Navigation&lt;/h3&gt;

&lt;p&gt;After the authentication procedure, the application redirects to the landing page where we can see recent transactions, add expenses, check groups, and settle payments. Access the &lt;strong&gt;side menu&lt;/strong&gt;, which includes the following sections:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Activity&lt;/strong&gt;: View recent transactions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Friends&lt;/strong&gt;: Add new friends and view balances related to friends.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Account&lt;/strong&gt;: Customize user settings like theme preferences and currency.
&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/format:webp/1*c4QZ2J2kWervSXkrrOr45w.png&quot; alt=&quot;**Landing page**&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;3-activity-section&quot;&gt;3. Activity Section&lt;/h3&gt;

&lt;p&gt;View a summary of recent financial transactions for quick updates.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/format:webp/1*YzZ5ettDPiFnafQ55XbxpQ.png&quot; alt=&quot;**Activities**&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;4-friend-management&quot;&gt;4. Friend Management&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Add Friends&lt;/strong&gt;: Add friends to enable expense tracking and settlement.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;View Balance for Friends&lt;/strong&gt;: Monitor individual balances with friends&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Settle Up&lt;/strong&gt;: If a user decides to settle balances, process the payment directly. After payment, update the ledger.
&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/format:webp/1*TwKPh3eb2tKfd3dT9pUmoQ.png&quot; alt=&quot;**Friend Management**&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/format:webp/1*AB7iUp6fnjdXC1BNucynBQ.png&quot; alt=&quot;**Settle Balances**&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;5-adding-and-splitting-expenses&quot;&gt;5. Adding and Splitting Expenses&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Select Expense Type&lt;/strong&gt;: Choose a group for shared costs or choose specific friends for one-on-one expenses.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Enter Details&lt;/strong&gt;: Add expense specifics like amount and description.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Choose Split Type&lt;/strong&gt;: Distribute the amount evenly or allocate costs as per user input.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save the transaction, which updates the blockchain ledger in real time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/format:webp/1*-yi7cm55G-qu0xn8oJW5ww.png&quot; alt=&quot;**Add Expense**&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;6-account-settings&quot;&gt;6. Account Settings&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Edit Profile&lt;/strong&gt;: Update user information like name and avatar.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Light/Dark Theme&lt;/strong&gt;: Toggle between themes for a personalized interface.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Currency Settings&lt;/strong&gt;: Customize currency preferences based on user location.
&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/format:webp/1*AQO7pNzZvOOGMP5YuVwZGQ.png&quot; alt=&quot;**Account Settings**&quot; /&gt;
    &lt;h3 id=&quot;7-transaction-processing&quot;&gt;7. Transaction Processing&lt;/h3&gt;
  &lt;/li&gt;
  &lt;li&gt;Every action, such as adding an expense or settling balances, updates the tamper-proof blockchain ledger using ResilientDB. This ensures real-time synchronization and transparency. Each transaction is saved securely on the blockchain, ensuring an immutable and auditable history.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;8-caching&quot;&gt;8. Caching&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Using lightweight fast access SQLite DB to cache frequently queried data to decrease latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;9-error-handling-and-validation&quot;&gt;9. Error Handling and Validation&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Include mechanisms to validate user input and resolve errors (e.g., insufficient funds or incorrect splits).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;impact&quot;&gt;Impact&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;**Decentralized Trust and Data Security: **By using blockchain with ResilientDB, Coinsensus ensures secure, immutable transactions, reducing reliance on centralized platforms and minimizing the risk of data breaches, giving users more control over their financial data.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;**Efficient Financial Reconciliation: **Coinsensus automates balance and transaction calculations, eliminating manual reconciliation, reducing human error, and saving time for individuals and groups, leading to smoother financial settlements.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;**Encourages Financial Literacy: **By automating calculations and providing transparent transaction histories, Coinsensus promotes financial awareness and better decision-making, helping users improve their financial literacy.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;project-demo&quot;&gt;Project Demo&lt;/h3&gt;

&lt;p&gt;A short project video demo showcasing the implementation of &lt;strong&gt;Coinsensus&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Demo link: https://youtu.be/O51VAFmH8Vw&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;iframe src=&quot;[https://medium.com/media/6bdcdfdd687b804bc403f3b52a12294f](https://drive.google.com/file/d/1TXsNhkY_3_9bn-Zddv1HF1uEecSqdYJP/view?usp=sharing)&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Coinsensus demonstrates the power of blockchain technology in finance and expense management. By combining decentralization, automation, and an intuitive interface, the platform resolves inefficiencies and builds trust among users. This project sets the stage for more resilient, secure, and transparent financial management solutions, offering a significant step forward in financial technology.&lt;/p&gt;

&lt;h3 id=&quot;future-work&quot;&gt;&lt;strong&gt;Future Work&lt;/strong&gt;&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;**User Features: **Automate feature for real-time notifications for payment reminders and updates and facilitate connecting with friends in the application.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Integration and Interoperability:&lt;/strong&gt; Integrate Coincensus with third-party payment gateways for transaction settlements.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;User Experience Enhancements:&lt;/strong&gt; Integrate a chatbot feature powered by NLP (Natural Language Processing), to assist users with bill management queries.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Advanced Security:&lt;/strong&gt; Develop fraud detection and reporting algorithms to flag malicious or suspicious activities while recording payment transactions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Community Engagement:&lt;/strong&gt; Build and integrate features for group budgeting, enabling users to set financial goals and track progress collaboratively.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;p&gt;[1] &lt;strong&gt;Apache&lt;/strong&gt; &lt;strong&gt;ResilientDB&lt;/strong&gt;: Global-Scale Sustainable Blockchain Fabric &lt;a href=&quot;https://resilientdb.apache.org/&quot;&gt;https://resilientdb.apache.org/&lt;/a&gt;
[2] Gupta S, Hellings J , Sadoghi M. (2021). Fault-Tolerant Distributed Transactions on Blockchain, Synthesis Lectures on Data Management, February 2021, Vol. 16, No. 1 , Pages 1–268
[&lt;a href=&quot;https://doi.org/10.2200/S01068ED1V01Y202012DTM065&quot;&gt;https://doi.org/10.2200/S01068ED1V01Y202012DTM065&lt;/a&gt;]
[3] Nakamoto, S. (2008). “Bitcoin: A Peer-to-Peer Electronic Cash System”
[&lt;a href=&quot;https://bitcoin.org/bitcoin.pdf&quot;&gt;https://bitcoin.org/bitcoin.pdf&lt;/a&gt;]&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Thank you for exploring &lt;strong&gt;Coincensus&lt;/strong&gt; with us! We encourage you to experiment with ResilientDB’s features in your projects too!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;credits&quot;&gt;Credits&lt;/h3&gt;

&lt;p&gt;Designed and Developed by:
Sankalp Kashyap &lt;a href=&quot;mailto:sankashyap@ucdavis.edu&quot;&gt;sankashyap@ucdavis.edu&lt;/a&gt; |
Rajaram Manohar Joshi  &lt;a href=&quot;mailto:rmjoshi@ucdavis.edu&quot;&gt;rmjoshi@ucdavis.edu&lt;/a&gt; |
Vijeth Kumbarahally Lakshminarayana  &lt;a href=&quot;mailto:kumbara@ucdavis.edu&quot;&gt;kumbara@ucdavis.edu&lt;/a&gt; |
Sanchit Kaul  &lt;a href=&quot;mailto:skkaul@ucdavis.edu&quot;&gt;skkaul@ucdavis.edu&lt;/a&gt; |
Shaik Haseeb Ur Rahman  &lt;a href=&quot;mailto:hrahman@ucdavis.edu&quot;&gt;hrahman@ucdavis.edu&lt;/a&gt; |
&lt;strong&gt;&lt;em&gt;University of California, Davis | Fall ’24&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Go through the detailed code, &lt;a href=&quot;https://github.com/joshirajaram/coinsensus-frontend&quot;&gt;@coinsensus-frontend&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://github.com/joshirajaram/coinsensus-backend&quot;&gt;@coinsensus-backend&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Happy Blockchaining!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Click here to check out more blogs on &lt;strong&gt;ResilientDB&lt;/strong&gt;.
[&lt;strong&gt;@blog.resilientdb](https://blog.resilientdb.com/)&lt;/strong&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 08 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/08/Coinsensus.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/08/Coinsensus.html</guid>
      </item>
    
      <item>
        <title>ResMark - Revolutionizing Attendance and Quiz Tracking</title>
        <description>&lt;h1 id=&quot;what-is-resmark&quot;&gt;What is ResMark?&lt;/h1&gt;

&lt;p&gt;ResMark is system designed to streamline attendance and quiz monitoring in educational institutions by integrating geolocation technology with the robust security of blockchain. Built on ResilientDB and ResVault, this system offers a secure and tamper-proof solution to ensure fairness and accuracy in tracking students’ attendance and quiz submissions. Using HTML5 Geolocation and JavaScript, ResMark determines the coordinates of the classroom location and verifies whether a student’s request originates within a 50-meter proximity of the class. If the student is physically present within this geofenced area, they are granted access to mark their attendance and proceed to take the quiz. By combining geofencing and blockchain, ResMark eliminates fraudulent attempts at remote check-ins or quiz submissions, ensuring that attendance and quiz participation are strictly tied to physical presence.&lt;/p&gt;

&lt;h1 id=&quot;resmark---in-action&quot;&gt;ResMark - In Action!&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://youtu.be/FHxVrIj2h3U&quot;&gt;Youtube&lt;/a&gt;&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/FHxVrIj2h3U&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h1 id=&quot;architecture-diagram&quot;&gt;Architecture Diagram&lt;/h1&gt;
&lt;p&gt;Below is a diagram showing the architecture of ResMark and the high-level structure:&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resmark/architecture_diagram.png&quot; alt=&quot;Architecture Diagram&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Diagram displaying the architecture of ResMark and how data is passed between the different services.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;The diagram above shows the overall architecture of ResMark and the way various services interact with each other. The user can be either the Student or Professor. Users will login to the system using ResVault. ResVault is used to authenticate and let the user into the system. The request is then sent from the user’s browser to the GraphQL server which communicates with ResilientDB using the Resilient JS SDK. ResilientDB is used as the primary blockchain to store the public key and transaction details having attendance, quiz answers. MongoDB is used as a second database for custom indexing. The server interacts with MongoDB for data fetching and adding. To allow the sync between MondoDB and Resilient DB, the resilient-node-cache package is used.&lt;/p&gt;

&lt;h1 id=&quot;flowchart&quot;&gt;Flowchart&lt;/h1&gt;
&lt;p&gt;Below Flowchart shows overall flow of the application with both Admin (Professor) and User (Student) flow.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resmark/flowchart.png&quot; alt=&quot;Flowchart&quot; style=&quot;width: 60%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Diagram displaying the flowchart of ResMark showing how the user interacts with the system.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h1 id=&quot;technology-stack&quot;&gt;Technology stack&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;Web Application: ReactJS, HTML5/CSS3, JavaScript, TailwindCSS&lt;/li&gt;
  &lt;li&gt;Backend: NodeJS, ExpressJS, Python, GraphQL&lt;/li&gt;
  &lt;li&gt;Database: ResilientDB (blockchain), MongoDB, resilient-node-cache (package for syncing)&lt;/li&gt;
  &lt;li&gt;APIs: HTML5 Geolocation API&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;screenshots&quot;&gt;Screenshots&lt;/h1&gt;
&lt;h2 id=&quot;authentication-with-resvault&quot;&gt;Authentication with ResVault&lt;/h2&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/resmark/login_with_resvault.jpeg&quot; alt=&quot;Login&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. Displaying the screenshot of user logging in via ResVault.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;marking-attendance&quot;&gt;Marking Attendance&lt;/h2&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resmark/mark_attendance_location_permission.jpeg&quot; alt=&quot;Attendance&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. Displaying the screenshot of the mark attendance page where initially the system asks for location permission.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resmark/mark_attendance_correct_location.jpeg&quot; alt=&quot;Attendance&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Displaying the screenshot of the mark attendance page when student can mark attendance only if present within the class boundaries
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resmark/mark_attendance_wrong_location.jpeg&quot; alt=&quot;Attendance&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 6. Displaying the screenshot of the mark attendance page when student cannot mark attendance outside of the class boundaries
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;attempting-the-quiz&quot;&gt;Attempting the Quiz&lt;/h2&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resmark/quiz_wrong_location.jpeg&quot; alt=&quot;Quiz&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 7. Screenshot displaying the UI for attempting the quiz where student location is not within bounds.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resmark/quiz_attempting.jpeg&quot; alt=&quot;Quiz&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 8. Screenshot displaying the UI for attempting the quiz only displayed when the User location is within the classroom proximity.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;student-dashboard&quot;&gt;Student Dashboard&lt;/h2&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resmark/dashboard.jpeg&quot; alt=&quot;Dashboard&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 9. Screenshot displaying Student dashboard showing the overall status of all the quizzes taken by the student, courses registered and the attendance in classes along with the score.
    &lt;/em&gt;   
&lt;/p&gt;

&lt;h1 id=&quot;running-the-application&quot;&gt;Running the Application&lt;/h1&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Before running the ResMark application, you need to start KV service on the ResDB backend and the SDK and setup the ResVault.&lt;/p&gt;

&lt;h3 id=&quot;resilientdb&quot;&gt;ResilientDB&lt;/h3&gt;
&lt;p&gt;Clone the resilientDB repository and follow the instructions to set it up:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/apache/incubator-resilientdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Setup KV Service:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./service/tools/kv/server_tools/start_kv_service.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;sdk&quot;&gt;SDK&lt;/h3&gt;
&lt;p&gt;Clone the GraphQL Repository and follow the instructions on the ReadMe to set it up:&lt;/p&gt;

&lt;p&gt;Install GraphQL:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/ResilientApp/ResilientDB-GraphQL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Setup SDK:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build service/http_server:crow_service_main

bazel-bin/service/http_server/crow_service_main service/tools/config/interface/client.config service/http_server/server_config.config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;resvault&quot;&gt;ResVault&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/apache/incubator-resilientdb-resvault
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Steps -&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Generate the build file&lt;/li&gt;
  &lt;li&gt;Enable developr mode and unpack the build file in chrome extensions.&lt;/li&gt;
  &lt;li&gt;Register on ResVault&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;running-the-resmark-application&quot;&gt;Running the ResMark Application&lt;/h2&gt;

&lt;p&gt;Clone the repo and open it in a new folder.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/preyashyadav/resmark-v1/
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resmark-v1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For syncing between ResDB and mongoDB package called resilient-node-cache. 
To install this -&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm i resilient-node-cache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install other dependencies&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To run the code -&lt;/p&gt;
&lt;h4 id=&quot;resmark---client&quot;&gt;ResMark - Client&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;client
npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Application will be deployed on http://localhost:3000.&lt;/p&gt;

&lt;h4 id=&quot;resmark---server&quot;&gt;ResMark - Server&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;server
npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Server runs on http://localhost:5000 in development mode.&lt;/p&gt;

&lt;h1 id=&quot;future-work&quot;&gt;Future Work&lt;/h1&gt;

&lt;h4 id=&quot;1-integration-with-university-schedule-builder--&quot;&gt;1. Integration with University Schedule Builder -&lt;/h4&gt;
&lt;p&gt;ResMark can be integrated with the university’s Schedule Builder app to automatically retrieve class locations and course schedules of the student.&lt;/p&gt;
&lt;h4 id=&quot;2-canvas-integration--&quot;&gt;2. Canvas Integration -&lt;/h4&gt;
&lt;p&gt;ResMark can be further integrated with Canvas or similar LMS platforms to directly post quiz grades and attendance records, ensuring real-time updates and accessibility for both students and instructors.&lt;/p&gt;
&lt;h4 id=&quot;3-mobile-application-development--&quot;&gt;3. Mobile Application Development -&lt;/h4&gt;
&lt;p&gt;ResMark can be expanded to develop a mobile application for on-the-go access, allowing students and professors to interact seamlessly with the platform via their smartphones.&lt;/p&gt;

&lt;h2 id=&quot;source-code-repositories&quot;&gt;Source Code Repositories:&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/preyashyadav/resmark-v1/&quot;&gt;ResMark&lt;/a&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/apache/incubator-resilientdb&quot;&gt;ResilientDB&lt;/a&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/ResilientApp/ResilientDB-GraphQL&quot;&gt;GraphQL&lt;/a&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/apache/incubator-resilientdb-resvault&quot;&gt;ResVault&lt;/a&gt;
&lt;br /&gt;&lt;/p&gt;

&lt;h2 id=&quot;presentation-slides&quot;&gt;Presentation Slides:&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.canva.com/design/DAGYvtK214I/NMMlQWNQvJjlXZUjeiSLow/edit?utm_content=DAGYvtK214I&amp;amp;utm_campaign=designshare&amp;amp;utm_medium=link2&amp;amp;utm_source=sharebutton&quot;&gt;Slides&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;contributions&quot;&gt;Contributions:&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Fullstack Development - &lt;a href=&quot;https://www.linkedin.com/in/preyashyadav/&quot;&gt;Preyash Yadav&lt;/a&gt; (https://preyashyadav.com)&lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;Frontend development - &lt;a href=&quot;https://linkedin.com/in/sanjanamali/&quot;&gt;Sanjana Mali&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/hemang14/&quot;&gt;Hemang Singh&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;
  &lt;li&gt;Backend Development - &lt;a href=&quot;https://linkedin.com/in/akanksha-kulkarni-aa79591b3/&quot;&gt;Akanksha Kulkarni&lt;/a&gt;, &lt;a href=&quot;https://linkedin.com/in/varun-singh-7a6748113/&quot;&gt;Varun Singh&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;University of California, Davis &lt;br /&gt;
CA&lt;/p&gt;
</description>
        <pubDate>Sun, 08 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/08/ResMark.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/08/ResMark.html</guid>
      </item>
    
      <item>
        <title>ResIdentity Document Signer</title>
        <description>&lt;p&gt;&lt;strong&gt;Powered by the robust ResilientDB fabric, ResIdentity secures crucial documents with a tamper-proof signing process that ensures verifiable integrity and heightened protection.&lt;/strong&gt;&lt;!-- excerpt end --&gt;&lt;/p&gt;

&lt;h1 id=&quot;project-overview&quot;&gt;Project Overview&lt;/h1&gt;
&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What ResIdentity Does&lt;/strong&gt; &lt;br /&gt;
ResIdentity is a document signing application that allows users to securely authenticate and upload PDFs for signing. The digests of these signed PDFs are committed to the ResilientDB blockchain, which ensures that each document’s signature remains unaltered. Users can then download their signed PDFs as needed.&lt;/p&gt;

&lt;p&gt;Additionally, ResIdentity enables users to upload signed PDFs for verification. During this process, the application checks the ResilientDB blockchain for a matching digest of the signed document to verify its authenticity.&lt;/p&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Why We Built ResIdentity&lt;/strong&gt; &lt;br /&gt;
The need for secure and reliable document signing cannot be overstated. Traditional platforms, while prevalent, often fail to meet the necessary standards for handling sensitive documents like insurance contracts, loan paperwork, employment offers, etc. These platforms typically rely on centralized servers, which, if compromised, can expose personal information at the risk of theft or alteration. Such centralized systems are vulnerable to service disruptions owing to a single point of failure. This can impact the availability of critical services when they are most needed, causing operational delays, user frustration and reduced trust. Furthermore, privacy is another concern with conventional document signing solutions. Users must entrust their sensitive information to third-party providers, who manage and control all aspects of data security, leaving them withwith little control over their own data.&lt;/p&gt;

&lt;p&gt;ResIdentity was built to address these vulnerabilities by leveraging the power of blockchain technology.&lt;/p&gt;

&lt;h2 id=&quot;what-sets-us-apart&quot;&gt;What Sets Us Apart&lt;/h2&gt;
&lt;p&gt;By using the ResilientDB blockchain to store document digests, ResIdentity ensures that each document’s signature is immutable and verifiable. This decentralized approach eliminates single points of failure, enhances data security, and gives users full control over their documents. The blockchain’s inherent transparency also means that every transaction is auditable, providing a layer of accountability and trust that traditional platforms cannot match.&lt;/p&gt;

&lt;p&gt;Through ResIdentity, we aim to restore confidence in digital transactions and empower users with a tool that upholds the integrity and privacy of their documents, redefining the standards for document security in the digital world.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://residentity.resilientdb.com/&quot;&gt;ResIdentity Client Application&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://drive.google.com/drive/folders/1eYQ-X_1hTyO_Ni1gRFiTIvdXjPHuqLI7?usp=sharing&quot;&gt;Demo (accessible through UC Davis e-mail)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/orgs/ecs265-group/repositories&quot;&gt;Source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;feature-set&quot;&gt;Feature Set&lt;/h1&gt;
&lt;h2 id=&quot;registration&quot;&gt;Registration&lt;/h2&gt;
&lt;p&gt;A user’s interaction with ResIdentity begins at Registration, which features a straightforward interface that requires information such as an email address, a secure password, etc. for registration. A public-private keypair is generated after successful registration and is stored at the client’s machine; the public key is stored in MongoDB.&lt;/p&gt;

&lt;h2 id=&quot;login&quot;&gt;Login&lt;/h2&gt;
&lt;p&gt;Returning users can quickly enter their email address and password to continue their secure journey on our platform. Upon login, users are redirected to a dashboard which presents the options to upload a PDF, verify an already signed PDF and logout.&lt;/p&gt;

&lt;h2 id=&quot;upload-pdfs&quot;&gt;Upload PDFs&lt;/h2&gt;
&lt;p&gt;Our minimalist Upload PDF interface ensures a clear and direct user experience, allowing you to quickly upload your PDF for signing or verification with just a click.&lt;/p&gt;

&lt;h2 id=&quot;sign-pdfs&quot;&gt;Sign PDFs&lt;/h2&gt;
&lt;p&gt;ResIdentity’s PDF Signing UI displays the document uploaded in the previous step on the right for confirmation. On the left, it prompts the user to re-enter their password for additional security before affixing their signature to the document.&lt;/p&gt;

&lt;h2 id=&quot;download-pdfs&quot;&gt;Download PDFs&lt;/h2&gt;
&lt;p&gt;When the signed document is retrieved from ResIdentity’s backend service, this interface faciliates its saving on the user’s machine.&lt;/p&gt;

&lt;h2 id=&quot;verify-signed-pdfs&quot;&gt;Verify Signed PDFs&lt;/h2&gt;
&lt;p&gt;Users can quickly verify the authenticity of signed PDFs with by simply uploading their signed documents to ensure that they are genuine and unaltered.&lt;/p&gt;

&lt;h1 id=&quot;user-guide&quot;&gt;User Guide&lt;/h1&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Dependencies:&lt;/strong&gt;
&lt;a href=&quot;https://docs.docker.com/compose/install/&quot;&gt;Docker Compose&lt;/a&gt;, &lt;a href=&quot;https://resilientdb.incubator.apache.org/&quot;&gt;ResilientDB&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;To build and launch ResIdentity Server, run:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker-compose up -d --build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;If ResilientDB’s KVService doesn’t start by default, run:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker exec resid-core-backend bash -c &quot;cd /resdb &amp;amp;&amp;amp; chmod +x INSTALL.sh &amp;amp;&amp;amp; chmod +x service/tools/kv/server_tools/start_kv_service.sh &amp;amp;&amp;amp; ./INSTALL.sh &amp;amp;&amp;amp; service/tools/kv/server_tools/start_kv_service.sh&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;To verify the status of KV Service, run:&lt;/p&gt;
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl -X POST -d &apos;{&quot;id&quot;:&quot;key1&quot;,&quot;value&quot;:&quot;value1&quot;}&apos; 127.0.0.1:18000/v1/transactions/commit
curl 127.0.0.1:18000/v1/transactions/key1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;The server should be running on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:8000/&lt;/code&gt;.
Visit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://localhost:8000/api&lt;/code&gt; to verify its status.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;usage-screenshots&quot;&gt;Usage (Screenshots)&lt;/h2&gt;
&lt;h3 id=&quot;user-registration&quot;&gt;User Registration&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/residentity/ss_registration.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;upload-sign--download&quot;&gt;Upload, Sign &amp;amp; Download&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/residentity/ss_sign.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;viewing-the-signature&quot;&gt;Viewing the Signature&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/residentity/ss_viewsign.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;verifying-signature-authenticity&quot;&gt;Verifying Signature Authenticity&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/residentity/ss_verify.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;tech-specs&quot;&gt;Tech Specs&lt;/h1&gt;
&lt;h2 id=&quot;technology-stack&quot;&gt;Technology Stack&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Frontend Frameworks:&lt;/strong&gt;&lt;br /&gt;
Next.js, Tailwind CSS&lt;br /&gt;
&lt;strong&gt;Backend Frameworks:&lt;/strong&gt;&lt;br /&gt;
ResilientDB, Docker, Python FastAPI, MongoDB, AWS S3&lt;/p&gt;

&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/residentity/architecture.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;sequence-diagrams&quot;&gt;Sequence Diagrams&lt;/h2&gt;
&lt;h3 id=&quot;user-registration-1&quot;&gt;User Registration&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/residentity/Registration.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;pdf-upload-signing-and-download&quot;&gt;PDF Upload, Signing and Download&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/residentity/Upload-Sign-Download.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;signature-verification&quot;&gt;Signature Verification&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/residentity/Signature Verification.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;about-the-developers&quot;&gt;About The Developers&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Sachin Shankar Balasubramanyam:&lt;/strong&gt; A first-year MSCS student at UC Davis, Sachin earned his Computer Science degree from PES University, Bengaluru, in 2023. He was the lead engineer at a VC-funded AI startup, with expertise in software architecture, Python, and web development, essential for ResIdentity’s client application.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Ananya Pandey:&lt;/strong&gt; Ananya is an MSCS student at UC Davis. She earned her Bachelor’s in Computer Science from PES University, Bengaluru, in 2018. With over five years of software development experience at Zebra Technologies and Expedia Group, she specializes in Android/AOSP, 802.11 protocols, Node.js, Spring Boot, and AWS, focusing on backend services for ResIdentity.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Anish Kataria:&lt;/strong&gt; Anish is pursuing an MS in Computer Science at UC Davis, with a Bachelor’s in Computer Science from VIIT, Pune (2023). Formerly an Associate Software Engineer at LogicMonitor, he focused on backend development with Golang, Docker, Kubernetes, and scalable microservices. Anish is dedicated to the client application for ResIdentity.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Shyam Varahagiri:&lt;/strong&gt; Shyam is a first-year MSCS student at UC Davis and graduated from Manipal University Jaipur in 2024 with a BTech in Information Technology. He worked 11 months at Tata Elxsi as an MLOps Developer, using Docker, Kubernetes, and Python, and has frontend experience with React and Typescript. Shyam works on ResIdentity’s backend.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Kiransingh Pal:&lt;/strong&gt; Kiran, an MSCS student at UC Davis with a Bachelor’s in Electronics and Telecommunications from Pune Institute of Computer Technology, has two years at miniOrange, leading Cloud Access Security projects, building cross-browser extensions, and working with MERN, Golang, Docker, and Kubernetes. Skilled in blockchain and multi-wallet solutions, Kiran focuses on client app development for ResIdentity.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sun, 08 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/08/ResIdentityDocumentSigner.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/08/ResIdentityDocumentSigner.html</guid>
      </item>
    
      <item>
        <title>ResAuc, Engineering Transparency in Every Bid.</title>
        <description>&lt;p class=&quot;info&quot;&gt;ResAuc is a decentralized online auction platform built on blockchain technology (ResellientDB), ensuring transparent, secure, and anonymous bidding. Experience fair auctions with real-time updates and user-centric features.&lt;/p&gt;

&lt;p&gt;Contributors: Dhairye Gala, Himanshu Nimonkar, Sayali Lokhande, Shray Arora, Shreyas Shah&lt;/p&gt;

&lt;p&gt;Project Link: &lt;a href=&quot;https://resauc.resilientdb.com/&quot;&gt;ResAuc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Presentation Link: &lt;a href=&quot;https://drive.google.com/file/d/1VfXGwn7Dq13mVZODjLP-IpGbCD5UM2xD/view?usp=sharing&quot;&gt;PPT&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Since ancient times, auctions have been an important component of trade that facilitates the exchange of commodities and services. Conventional auction houses have long served as go-betweens for buyers and sellers, providing platforms for people to participate in auctions online, in-person, or hybrid formats. Sellers usually submit their items to auction houses for evaluation and appraisal; the auction company receives a commission for these services. These auction houses make transactions easier, but they limit the accessibility and fairness of the auction process by introducing problems with cost, inefficiencies, and potential bias. Furthermore, the dependence on actual locations and centralized systems may hinder the growth of traditional auctions, which causes challenges in adapting to modern demands.&lt;/p&gt;

&lt;h2 id=&quot;gap&quot;&gt;Gap&lt;/h2&gt;
&lt;p&gt;A decentralized auction system that provides a more fair, transparent, and economical setting is becoming increasingly necessary as our reliance on digital platforms grows. By eliminating intermediaries, a decentralized auction platform would provide buyers and sellers more freedom. These platforms are also in line with the principles of distributed ledger technologies (DLTs) and blockchain, which have gained popularity due to their capacity to provide transactions with immutability, security, and transparency [1]. In addition to lowering risks like fraud and manipulation, these technologies ensure that buyers and sellers can engage in transactions without the assistance of a reliable third party.&lt;/p&gt;

&lt;p&gt;Existing centralized auction platforms, such as eBay, often struggle with trust issues and high service fees. This further highlights the need for a decentralized solution [2]. Moreover, traditional auction systems often face problems related to bidding transparency and transaction recording. The development of decentralized platforms leverages the strengths of blockchain and DLTs to address these limitations. In particular, these platforms will provide transparency through an immutable ledger, thus allowing all transactions to be publicly recorded and available for verification.&lt;/p&gt;

&lt;h2 id=&quot;problem-statement&quot;&gt;Problem Statement&lt;/h2&gt;
&lt;p&gt;Our project, ResAuc is a decentralized auction platform that integrates ResilientDB [3] to transparently record all transactions, allowing for greater user control. Sellers can independently list their items, set minimum bids, and finalize sales with the highest bidder, while buyers participate in a secure, anonymous, and fair environment. Moreover, the platform is being developed with key features such as user profile management, real-time bid tracking, and a feature that enables sellers to close sales with the highest bidder. This report discusses the objectives and development of ResAuc, its integration with ResilientDB, its architecture and the working of ResAuc.&lt;/p&gt;

&lt;h1 id=&quot;objectives&quot;&gt;Objectives&lt;/h1&gt;
&lt;p&gt;ResAuc provides a decentralized, transparent, and secure platform for both buyers and sellers in an effort to improve the online auction process. Built on the foundation of ResilientDB, the platform prioritizes user control and efficiency by eliminating intermediaries and promoting direct communication to facilitate auctions. The primary objectives of ResAuc are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Transparency:&lt;/strong&gt; Makes use of ResilientDB’s blockchain-backed architecture, which offers an immutable ledger to record all events, which enables secure and transparent auction transactions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Decentralization:&lt;/strong&gt; By eliminating the need for third parties to participate in auctions, users can communicate with one another directly, which lowers overhead costs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;User Centric Experience:&lt;/strong&gt; Provides a user-friendly platform that enables users to manage transactions with real-time updates, and create detailed auction listings and place bids.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Live Bid Updates:&lt;/strong&gt; Incorporates live bid tracking to keep users informed of the current auction status.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Anonymity for Buyers:&lt;/strong&gt; Maintains the privacy of bidders and sellers to prevent bias and manipulation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Purchase &amp;amp; Sale History:&lt;/strong&gt; Provides a comprehensive history of the items and prices that users have bought and sold.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;market-opportunity&quot;&gt;Market Opportunity&lt;/h1&gt;
&lt;p&gt;The online auction industry has seen exponential growth in recent years, driven by the rise of E-commerce and the increasing comfort of users engaging in digital transactions. The global online auction market was valued at approximately 568.94 billion USD in 2023 and is projected to grow at a compound annual growth rate (CAGR) of 9.21%, reaching 934.25 billion USD by 2032 [4]. Global platforms like eBay and Christie’s online auctions have demonstrated the demand for such systems. However, these centralized platforms frequently face problems including high costs, trust issues, and limited flexibility for users. The market opportunity for a decentralized auction platform like ResAuc lies in addressing these shortcomings. Blockchain technology offers a transformative solution by decentralizing the auction process and eliminating the need for conventional intermediaries. A blockchain-based platform gives sellers access to a bidder pool. Transactions are recorded on a secure and distributed ledger, providing an immutable and transparent history of every auction event. In addition to improving trust and accountability, this decentralized approach significantly reduces operational costs, which can be as high as 10–20% in traditional auction systems.
Because all transactions can be audited on the public ledger, fraud [5], a persistent concern in traditional systems is mitigated. The transparency of blockchain ensures that every participant has equal access to the bidding process. Furthermore, blockchain allows for almost rapid settlement using cryptocurrencies, whereas traditional auction houses can take days or weeks to settle deals because of human processing and reliance on financial institutions.
With its ability to address these issues, a blockchain-based auction platform like ResAuc capitalizes on a significant market opportunity. In addition to eliminating the high costs and inefficiencies associated with traditional auction houses, it also introduces a transparent and user-friendly system made to meet the changing demands of buyers and sellers in a globalized economy. ResAuc provides an affordable alternative that appeals to both sellers seeking maximum value for their items and buyers looking for fair competition without concerns of fraud. Furthermore, leveraging blockchain technology through ResilientDB establishes ResAuc as an innovative platform that aligns with the increasing demand for secure and transparent digital marketplaces.&lt;/p&gt;

&lt;h1 id=&quot;architecture-overview&quot;&gt;Architecture Overview&lt;/h1&gt;
&lt;p&gt;Figure 1 shows the system architecture along with the technologies used for building ResAuc. The following subsections discuss each of them in detail.&lt;/p&gt;
&lt;h2 id=&quot;backend&quot;&gt;Backend&lt;/h2&gt;
&lt;p&gt;The backend of the system is built using Node.js and Express.js to provide a robust and scalable architecture that supports asynchronous handling of multiple user requests. The backend architecture uses Express.js as the API layer, acting as a bridge between the frontend, backend logic, and databases. Express.js ensures efficient communication by handling incoming HTTP requests, processing them through the middleware and routing layers, and sending appropriate responses. User registration and login functionalities are implemented using bcrypt for secure password hashing. The authorization mechanism ensures users can interact only with their own data when appropriate. Additionally, the backend also manages bid processing and auction listings. By entering information such as the item title, description, minimum bid amount, and image (Base64 encoded), users can create new listings. It also lets users place bids on items listed by others while imposing restrictions like minimum bid value and highest bid validation. The backend also offers user-specific features, such as retrieving listings created or purchased by a user and marking items as sold upon completion of transactions. The backend updates the database to reflect the sale status of the item after an auction is finalized. &lt;a href=&quot;https://github.com/himanshu-nimonkar/dds-backend-main&quot;&gt;This&lt;/a&gt; is the GitHub repository for the backend code.&lt;/p&gt;

&lt;p&gt;The frontend interacts with the backend through RESTful APIs, facilitating seamless communication and data exchange. This connection allows users to perform actions like posting bids, creating auction listings, and viewing purchased or listed items. The APIs ensure real-time updates and transaction processing, thus enhancing the user experience by providing immediate feedback on actions such as bid placement and transaction confirmation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/resauc/1.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 1: System Architecture&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The APIs are divided into four categories: User Management, Listing Management, Bidding, and Transaction Tracking.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;User Management&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;register&lt;/code&gt;: Manages user registration by checking whether the username already exists. If not, it generates a new user with the provided username and password and saves it to the database.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;login&lt;/code&gt;: Handles user login by verifying the entered username and password. It checks if the user exists in the database and compares the password with the stored hash.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Listing Management&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new-listing&lt;/code&gt;: Creates a new listing by validating fields such as title, description, minBidValue, username, and image. After that, it stores the modified user information and adds the new listing to the user’s profile.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;all-listings&lt;/code&gt;: Retrieves all listings from all users by first fetching all users from the database, then extracting and concatenating their listings into a single array.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my-listings&lt;/code&gt;: Retrieves the listings of a specific user based on the username provided.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delete-listing&lt;/code&gt;: Allows a user to delete a specific listing. It removes the listing from the user’s profile and updates the database.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sell-item&lt;/code&gt;: Allows a user to sell an item by selecting the highest bid. It first ensures that there are bids placed on the listing, then marks the item as sold, recording the final selling price and the buyer’s username in the soldTo field (not displayed on the ledger to maintain anonymity).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bidding&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post-bid&lt;/code&gt;: Allows a user to place a bid on a listing. It ensures that the user is not bidding on their own listing, that the first bid meets the minimum bid value, and that subsequent bids are higher than the current highest bid.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transaction Tracking&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bought-by-me&lt;/code&gt;: Retrieves all items purchased by a specific user by checking which listings have the soldTo field matching the provided username. It returns an array of items bought by the user from all sellers.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sold-by-me&lt;/code&gt;: Retrieves all items sold by a specific user. It checks if the user exists, filters through their listings to find the ones marked as sold, and returns the list of sold items.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Table 1 provides a list of the key APIs, grouped by their respective categories.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/resauc/1.1.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Table 1: List of APIs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All the information is stored on the MongoDB database while the ledger records information about new listings, bids and deleted listings.&lt;/p&gt;

&lt;h2 id=&quot;frontend&quot;&gt;Frontend&lt;/h2&gt;
&lt;p&gt;Frontend of the ResAuc platform is designed with a user-friendly interface leveraging React and Bootstrap for responsive layouts. It primarily serves the core functionalities for user login/registration, auction listings, and bid placements. While ExpoLab [6] provides skeletons in both Vue.js and React.js for integration with the ResVault [7] browser extension, React.js was chosen for its robust library ecosystem, flexibility, and component reusability. React’s component-based approach enables the efficient reuse of UI elements, which streamlines development and ensures consistency across the application. To further enhance functionality, the frontend integrates with the ResVault browser extension. This enables secure transaction handling and blockchain interactions.&lt;/p&gt;

&lt;p&gt;The frontend features secure login and registration forms that handle user authentication. Users can view, create, and participate in auctions through an interactive interface. A personalized dashboard allows users to view all listings, their active listings, bids, and auction history. It provides quick access to the user’s auction activities, including items they are selling, bidding on, or have won. Listings are displayed with details like title, description, minimum bid, and current bid status. &lt;a href=&quot;https://github.com/himanshu-nimonkar/dds-frontend&quot;&gt;This&lt;/a&gt; is the GitHub repository for the frontend code.&lt;/p&gt;

&lt;h2 id=&quot;database&quot;&gt;Database&lt;/h2&gt;
&lt;p&gt;The backend of the auction platform uses two databases, namely MongoDB and ResilientDB. MongoDB is used as the primary NoSQL database for real-time storage and retrieval of data such as creating new listings, deleting listings, placing bids, user profiles, and bid history. Its flexible schema allows for seamless handling of frequently updated records, which is crucial for an active auction environment where data such as bids and listings changes. ResilientDB is integrated into the system to address the need for transparency and accountability. It is used to maintain a ledger of completed auctions. When a listing is made, a bid is placed, or an item is sold, ResilientDB is leveraged to record these events in a tamper-proof manner, ensuring that users can trust the integrity of the auction result.&lt;/p&gt;

&lt;h2 id=&quot;resilientdb-and-its-integration-with-resauc&quot;&gt;ResilientDB and its integration with ResAuc&lt;/h2&gt;
&lt;p&gt;ResilientDB is a decentralized, fault-tolerant database designed to provide transparency and security for online transactions. It is particularly well-suited for applications like ResAuc, where trust and security are essential. ResilientDB plays a crucial role in the backend architecture of ResAuc by providing a decentralized and transparent method for recording transactions. The frontend integrates with ResilientDB via the ResVaultSDK. ResVaultSDK acts as an intermediary that enables the frontend to communicate with the ResVault browser extension. Through ResVaultSDK, the transaction data is securely sent from the frontend to the browser extension, which then posts the transaction to the ledger. The SDK enables secure communication with the decentralized database, allowing users to initiate transactions by sending messages such as bids or purchases. The integration ensures that transactions are processed securely and are immutable once committed. Once the transaction is processed, the user receives a response showing whether the transaction was successful or failed. This response is reflected in the frontend through a modal, thus ensuring that users are notified immediately of the transaction status.&lt;/p&gt;

&lt;h2 id=&quot;authentication-mechanism&quot;&gt;Authentication Mechanism&lt;/h2&gt;
&lt;p&gt;The authentication mechanism in ResAuc leverages ResVault, to ensure secure user access. This is shown in Figure 2. ResVault is a Chrome extension that serves as a wallet for ResilientDB.
&lt;img src=&quot;/assets/images/resauc/2.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 2: Authentication via ResVault&lt;/em&gt;
&lt;br /&gt;
The authentication process for the platform is divided into two parts:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;ResVault Extension Authentication&lt;/strong&gt;: This authentication leverages the preexisting authentication mechanism provided by the skeleton framework. It ensures that the ResVault extension is properly connected to the ResDB mainnet. This establishes a secure communication channel between the client and the blockchain network.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;User Authentication&lt;/strong&gt;: This part handles user-specific authentication for the app. It interacts with MongoDB to retrieve user data and bid information, verifying the user’s credentials and ensuring that the appropriate data is accessed for actions such as placing bids and managing listings.
&lt;img src=&quot;/assets/images/resauc/3.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 3: Transaction Form&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;working-of-resauc&quot;&gt;Working of ResAuc&lt;/h1&gt;
&lt;p&gt;In this section, we describe the different views of ResAuc and the detailed working of the application. The sketch of the top to down working is illustrated in Figure 4.
&lt;img src=&quot;/assets/images/resauc/4.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 4: High-level Working of ResAuc&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;User Registration &amp;amp; Login:&lt;/strong&gt; When users first visit ResAuc, they are given the option to either sign up for a new account or log in with existing credentials. New users can create an account by entering a username and password as shown in Figure 5a. Returning users can enter their credentials to access the platform on the login page as shown in Figure 5b.
&lt;img src=&quot;/assets/images/resauc/5.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 5: User Registration &amp;amp; Login&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dashboard:&lt;/strong&gt; After logging in, users are presented with the dashboard, as showcased in Figure 6. This view displays a list of ongoing auctions with details such as item description, minimum bid value, current bid amounts and item image. Users can browse through the auctions to view the items up for bidding and then place bids on them. A seller cannot place a bid on the item they have listed themselves. There is a common navbar for all pages from where a user can navigate to the dashboard, my listings, new listing, items sold, items bought and logout of the account.
&lt;img src=&quot;/assets/images/resauc/6.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 6: Dashboard&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Listing Items for Auction:&lt;/strong&gt; As shown in Figure 7, users can access the New Listing button where they can provide the details about the item such as item title, description, minimum bid value and also upload an image of the item. Upon submitting the form, the item details are securely stored on ResilientDB. The item is then visible to all users on the dashboard under all listings.
&lt;img src=&quot;/assets/images/resauc/7.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 7: Create New Listing&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;My Listings View:&lt;/strong&gt; Under My Listings, users can see a consolidated view of all the items they have listed for auction. Users can monitor the progress of their active auctions, delete a listing if needed and sell the item to the highest bidder if they feel they are getting a sufficient amount for their item. This section is shown in Figure 8a. However, users cannot delete a listing that has already been sold. Once an item has been sold, the ”Sell Item” button will be replaced with ”Sold” for that particular item. This is shown in Figure 8b.
&lt;img src=&quot;/assets/images/resauc/8.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 8: My Listings&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Items Sold View:&lt;/strong&gt; On this page, as depicted in Figure 9, sellers can view the items that have been successfully sold through ResAuc. It includes details such as the item information and the final selling price. This helps users keep a record of their transactions for reference.
&lt;img src=&quot;/assets/images/resauc/9.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 9: Items Sold&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Items Bought View:&lt;/strong&gt; Buyers can use this section to view the items they have purchased through the platform. It includes information about the item and the price that the item was bought for. This is shown in Figure 10.
&lt;img src=&quot;/assets/images/resauc/10.webp&quot; alt=&quot;defaultview&quot; /&gt;
&lt;em&gt;Figure 10: Items Bought&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;future-work&quot;&gt;Future Work&lt;/h1&gt;
&lt;p&gt;Future developments to ResAuc will focus on addressing current issues and improving the user experience even further. The following are important areas for improvement:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Identity Verification:&lt;/strong&gt; To lower the risk of fraudulent activities, implement mechanisms to verify the identity of both buyers and sellers to authenticate their legitimacy.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Seller Bidding Restrictions:&lt;/strong&gt; Put limitations to prevent sellers from using several accounts controlled by the same user to bid on their own listings. This could involve identity verification techniques or IP-based tracking.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Payment Gateway Integration:&lt;/strong&gt; To manage transactions between the buyers and sellers, integrate a secure payment gateway.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;In conclusion, ResAuc effectively uses ResilientDB’s features to meet the demand for a decentralized, transparent, and secure online auction platform. The platform enables users to conduct transactions directly by eliminating the need for intermediaries.&lt;/p&gt;

&lt;p&gt;The backend plays an essential role in managing transactions, keeping track of auction records, and ensuring secure communication between users and the blockchain database. The React.js based frontend, integrated with ResVault for authentication and transaction validation, ensures seamless user interactions and real-time updates. Users can easily create listings, place bids, and manage their auctions with the frontend and backend working together to provide an effective system.&lt;/p&gt;

&lt;p&gt;While ResAuc accomplishes its main objectives, it also identifies areas for improvement, such as improved fraud detection, identity verification, and additional user-focused features. ResAuc demonstrates how blockchain-based solutions may revolutionize conventional auction systems and open the door to innovative, transparent, and safe e-commerce ecosystems.&lt;/p&gt;

&lt;h1 id=&quot;contributions&quot;&gt;Contributions&lt;/h1&gt;
&lt;ul&gt;
  &lt;li&gt;Shreyas Shah (Frontend + Database Engineering): React.js Frontend Skeleton, Database Architecture, ResVault Integration with React.js, Integration of Web App&lt;/li&gt;
  &lt;li&gt;Dhairye Gala (Backend Engineering): Node.js with Express.js Backend, Integration of Web App&lt;/li&gt;
  &lt;li&gt;Shray Arora (FullStack Engineering): Node.js with Express.js Backend, Frontend Skeleton&lt;/li&gt;
  &lt;li&gt;Himanshu Nimonkar (Frontend Engineering): React.js Frontend Beautification, Feature Additions, Integration of Web App&lt;/li&gt;
  &lt;li&gt;Sayali Lokhande (FullStack Engineering): Database Architecture, Node.js Final Fixes, ResVault Integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;references&quot;&gt;References&lt;/h1&gt;
&lt;p&gt;[1] B. Liu, ”Overview of the Basic Principles of Blockchain,” 2021 International Conference on Intelligent Computing, Automation and Applications (ICAA), Nanjing, China, 2021, pp. 588–593, &lt;a href=&quot;https://doi.org/10.1109/10.1109/ICAA53760.2021.00108&quot;&gt;https://doi.org/10.1109/10.1109/ICAA53760.2021.00108&lt;/a&gt;
&lt;br /&gt;
[2] E. Chiquito, U. Bodin, O. Schel´en and a. Ahmed Afif Monrat, ”Digitalized and Decentralized Open-Cry Auctioning: Key Properties, Solution Design, and Implementation,” in IEEE Access, vol. 12, pp. 64686–64700, 2024, &lt;a href=&quot;https://doi.org/10.1109/ACCESS.2024.3395791&quot;&gt;https://doi.org/10.1109/ACCESS.2024.3395791&lt;/a&gt;
&lt;br /&gt;
[3] Suyash Gupta, Sajjad Rahnama, Jelle Hellings, and Mohammad Sadoghi. 2020. ResilientDB: Global Scale Resilient Blockchain Fabric. Proc. VLDB Endow. 13, 6 (feb 2020), 868–883, &lt;a href=&quot;https://doi.org/10.14778/3380750.3380757&quot;&gt;https://doi.org/10.14778/3380750.3380757&lt;/a&gt;
&lt;br /&gt;
[4] Market, “Online Auction Market Size, Share — Trends Analysis Latest,” Marketresearchfuture.com, 2023. &lt;a href=&quot;https://www.marketresearchfuture.com/reports/online-auction-market-22699&quot;&gt;https://www.marketresearchfuture.com/reports/online-auction-market-22699&lt;/a&gt;
&lt;br /&gt;
[5] Agarwal, Udit &amp;amp; Rishiwal, Vinay &amp;amp; Tanwar, Sudeep &amp;amp; Yadav, Mano. (2023). Blockchain and crypto forensics: Investigating crypto frauds. International Journal of Network Management. 34. 1–32. &lt;a href=&quot;https://doi.org/10.1002/nem.2255&quot;&gt;https://doi.org/10.1002/nem.2255&lt;/a&gt;
&lt;br /&gt;
[6] ”Mohammad Sadoghi — ExpoLab”, Expolab.org, 2023. &lt;a href=&quot;https://expolab.org/&quot;&gt;https://expolab.org/&lt;/a&gt;
&lt;br /&gt;
[7] E. S. Lab, “Getting started with ResVault — incubator-resilientdb-blog,” Resilientdb.com, Sep. 21, 2023. &lt;a href=&quot;https://blog.resilientdb.com/2023/09/21/ResVault.html&quot;&gt;https://blog.resilientdb.com/2023/09/21/ResVault.html&lt;/a&gt; (accessed Dec. 06, 2024).&lt;/p&gt;
</description>
        <pubDate>Sun, 08 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/08/ResAuc.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/08/ResAuc.html</guid>
      </item>
    
      <item>
        <title>ResArtifact - Resilient based Artifact Repository</title>
        <description>&lt;p&gt;ResVault is a novel decentralized tool that utilizes blockchain technology to track and store valuable artifact information securely. We have applied a blockchain-based distributed database, ResilientDB, for digital and physical artifact repositories for museums, auction houses,  institutions, and individuals. ResArtifact will be available for all users to review its transactions on a collection page displaying each artifact’s name, image, and description. Each artifact will contain a ledger of all transactions that provides its precedence of location, date moved, and changes in condition.  This information is available for the public to learn about an artifact or determine whether a claimed artifact is valid and make an update.&lt;/p&gt;

&lt;p&gt;Since each transaction is important in proving an artifact’s validity, we must ensure that only authenticated users can add artifacts. Institutions or individuals that own artifacts will have access to a secure account that allows them to add new artifacts, view their private collections, and transfer artifacts. They will also be able to view the history of their individual artifacts. Without needing a login, a user can view the collection of all artifacts from all users and search for artifacts as well. This accessibility to both the general public and authorized users allows everyone to use the ResArtifact.&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/resartifact_overview.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Image describing ResArtifact&lt;/em&gt;  
&lt;/p&gt;

&lt;h3 id=&quot;useful-links&quot;&gt;Useful Links&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Code Repository - &lt;a href=&quot;https://github.com/ResilientApp/ResArtifact&quot;&gt;https://github.com/ResilientApp/ResArtifact&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Presentation Slides - &lt;a href=&quot;https://docs.google.com/presentation/d/1SRIOvvB1Q6AJXESoSLsloJ1OOTNwrJiL6jXSrmAEMBg/edit?usp=sharing&quot;&gt;https://docs.google.com/presentation/d/1SRIOvvB1Q6AJXESoSLsloJ1OOTNwrJiL6jXSrmAEMBg/edit?usp=sharing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Demo Video: &lt;a href=&quot;https://drive.google.com/file/d/132lPbKemscHogvfnuNQIpsq9pLJg3BRZ/view?usp=sharing&quot;&gt;https://drive.google.com/file/d/132lPbKemscHogvfnuNQIpsq9pLJg3BRZ/view?usp=sharing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;problem-identified&quot;&gt;Problem Identified&lt;/h3&gt;
&lt;p&gt;Our market opportunity is to provide art museums and collectors with a way to verify and conduct transactions on valuable art pieces. We believe that there currently is no decentralized platform to host transactions for art pieces and that ResArtifact will provide both security to this market. Furthermore, there will be general interest from art enthusiasts who won’t have access to creating and logging transactions but will be able to search for artifacts and view them.&lt;/p&gt;

&lt;h3 id=&quot;solution&quot;&gt;Solution&lt;/h3&gt;
&lt;p&gt;To solve this problem we use blockchain technology, which has already been successfully applied in similar fields such as land registries. This improves the security of the database by preserving essential information about all known artifacts. A registrar for artifacts is extremely valuable as the documentation for an artifact’s history is directly tied to its value. All entries into the database must be authenticated and data will not be lost thanks to the redundancy of all distributed nodes owning the most current ledger. Institutions may purchase or trade artifacts without worry of fakes thanks to the ledger’s information on the validity of the piece as well as any changes in ownership. Art enthusiasts may also know whether the original artifact is available for public viewing.&lt;/p&gt;

&lt;h3 id=&quot;technology-stack&quot;&gt;Technology Stack&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;React.js&lt;/li&gt;
  &lt;li&gt;Backend: ResilientDb GraphQL server, MongoDB&lt;/li&gt;
  &lt;li&gt;Database: ResilientDB&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/technology_stack.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 2. Technology Stack of ResArtifact
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;architecture&quot;&gt;Architecture&lt;/h3&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/architecture_add.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 3. Sequence Diagram of Adding an Artifact
    &lt;/em&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/architecture_transfer.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 4. Sequence Diagram of Transferring an Artifact
    &lt;/em&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/high_level_design.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 5. High-Level Design of Artifact
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;features-and-user-guide&quot;&gt;Features and User Guide&lt;/h3&gt;

&lt;h3 id=&quot;home-page&quot;&gt;Home Page&lt;/h3&gt;
&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/home.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 6. Home Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/offerings.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 7. What we offer through ResArtifact
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Getting Started: To access the dashboard, users need to log in using Resvault. After a user is authenticated, they will be brought to the Dashboard page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/login.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 8. Login Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Straightforward actions: This Dashboard gives users to option to add a new artifact or view their personal collection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/dashboard.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 9. Dashboard
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;inventory&quot;&gt;Inventory&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Easy Addition Process: Allows users to easily add an artifact by inputting an artifact’s information: name, unique ID, place of origin, origin year, artifact description, condition, curator ID, museum ID, recipient’s public key, and an image URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;search&quot;&gt;Search&lt;/h3&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/add_artifact.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 10. Add Artifact Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;View Personal Inventory: Shows an exclusive inventory of artifacts that only the user has added. Users can transfer any artifact in their personal inventory to another user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/artifact_examples.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 11. View Artifact Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Seamless Transfer: In case a user wants to transfer an artifact to another user, they can update the artifact’s information and easily send it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/transfer_artifact.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 12. Transfer Artifact Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Inventory View: Shows a detailed display of updated inventory information on all artifacts that any user has added.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/collection.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 13. Artifact Collection Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Individual Artifact View: Shows all the information stored for an artifact.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/artifact_page.jpeg&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 14. Individual Artifact Information Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;History: Shows the history of an artifact with all past information about it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p align=&quot;center&quot;&gt;
    &lt;img src=&quot;/assets/images/resartifact/transaction_history.jpeg&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt; Figure 15. Artifact Transaction History
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;demo-video&quot;&gt;Demo Video&lt;/h3&gt;
&lt;p align=&quot;left&quot;&gt;
    &lt;a href=&quot;https://drive.google.com/file/d/132lPbKemscHogvfnuNQIpsq9pLJg3BRZ/view?usp=sharing&quot; target=&quot;_blank&quot;&gt;
        &lt;img src=&quot;/assets/images/resartifact/demo_ppt.png&quot; alt=&quot;Logo&quot; width=&quot;300&quot; /&gt;
    &lt;/a&gt;
    &lt;br /&gt;
&lt;/p&gt;

&lt;h3 id=&quot;steps-to-run-the-system&quot;&gt;Steps to run the system&lt;/h3&gt;

&lt;p&gt;Alright, folks, this is just the beginning — it’s like looking at a tall mountain, but trust us, we’re going to climb it together and reach the top. You’ve got this!&lt;/p&gt;

&lt;p&gt;Before we jump into setting up ResilientDB, let’s quickly check that we have all the prerequisites in place.&lt;/p&gt;

&lt;p&gt;Ensure you have the following installed and configured before proceeding:&lt;/p&gt;

&lt;p&gt;Node 20.17.0&lt;/p&gt;

&lt;p&gt;Bazel 6.0.0&lt;/p&gt;

&lt;p&gt;Python 3.10&lt;/p&gt;

&lt;p&gt;Ubuntu 22.04&lt;/p&gt;

&lt;p&gt;MongoDB 7.0.15&lt;/p&gt;

&lt;p&gt;With these prerequisites in place, we can move on to the setup.&lt;/p&gt;

&lt;h3 id=&quot;setup-crow-http-server-sdk-and-graphql-server&quot;&gt;Setup Crow HTTP server, SDK, and GraphQL server&lt;/h3&gt;
&lt;p&gt;Clone the ResilientDB repository:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/resilientdb/resilientdb.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Navigate into the ResilientDB directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd resilientdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install the required dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sh INSTALL.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start the ResilientDB KV Service (Take a short break, folks! The first time might take a few minutes!):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./service/tools/kv/server_tools/start_kv_service.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setup-crow-http-server-sdk-and-graphql-server-1&quot;&gt;Setup Crow HTTP server, SDK, and GraphQL server&lt;/h3&gt;
&lt;p&gt;Clone the ResilientDB GraphQL repository:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/ResilientDB-GraphQL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Navigate into the ResilientDB-GraphQL directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd ResilientDB-GraphQL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install the Crow dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo apt update
sudo apt install build-essential
sudo apt install python3.10-dev
sudo apt install apt-transport-https curl gnupg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Build the Crow HTTP server (this might take a few minutes the first time, so kick back, relax, and maybe stretch your legs while it does its thing!):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build service/http_server:crow_service_main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start the Crow HTTP server:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel-bin/service/http_server/crow_service_main service/tools/config/interface/service.config service/http_server/server_config.config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create virtual environment for the Python SDK:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3 -m venv venv –without-pip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Activate the virtual environment:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;source venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install pip in the virtual environment for the Python dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl https://bootstrap.pypa.io/get-pip.py | python
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install the Python dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start the GraphQL server:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3 app.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setup-wallet&quot;&gt;Setup Wallet&lt;/h3&gt;
&lt;p&gt;This is your key to ResArtifact&lt;/p&gt;

&lt;p&gt;Here is the link to setup &lt;a href=&quot;https://blog.resilientdb.com/2023/09/21/ResVault.html#prerequisites&quot;&gt;ResVault&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;setup-mongodb&quot;&gt;Setup MongoDB&lt;/h3&gt;
&lt;p&gt;All you need to do is set up MongoDB, and don’t worry about the rest — the resilient-node-cache will take care of everything else for you!&lt;/p&gt;

&lt;p&gt;Refer to this guide to install MongoDB in 7 simple &lt;a href=&quot;https://www.cherryservers.com/blog/install-mongodb-ubuntu-22-04&quot;&gt;steps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check if MongoDB is Running using :&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo systemctl status mongod
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;contributions&quot;&gt;Contributions:&lt;/h3&gt;

&lt;p&gt;The team members of this project are Alyssa Yee, Amy Vu, Alexander Gao, Zijin Cui, Guransh
Anand. Alyssa Yee is the leader of our project and has handled submitting all assignments and has supported backend transactions. Amy led the frontend development and connected the frontend application to the backend. Alexander supported the frontend development and strategic planning for features of the application. Guransh managed the backend development, which includes setting up transactions, making custom transactions required for this application, and testing the functionality on a sample frontend. Zijin Cui is gathering and organizing reference materials needed for this project.&lt;/p&gt;

</description>
        <pubDate>Sun, 08 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/08/ResArtifact.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/08/ResArtifact.html</guid>
      </item>
    
      <item>
        <title>Resilient Vote</title>
        <description>&lt;h1 id=&quot;resvote-a-scalable-and-secure-online-voting-system-built-on-resilientdb&quot;&gt;ResVote: A Scalable and Secure Online Voting System Built on ResilientDB&lt;/h1&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/aHThfkBDVPg?si=L9O4tg5dqE4qONS_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;our-motivation&quot;&gt;Our Motivation&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Traditional voting systems, such as in-person voting and mail-in ballots, are often slow, prone to errors, and vulnerable to fraud. These methods are labor-intensive and struggle to handle large-scale elections efficiently.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Resilient Vote leverages ResilientDB to create a secure, scalable online voting platform. The system guarantees confidentiality, integrity, and transparency, ensuring that elections are both reliable and tamper-proof.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;our-goals&quot;&gt;Our Goals&lt;/h2&gt;

&lt;h2 id=&quot;project-goals-and-objectives&quot;&gt;Project Goals and Objectives&lt;/h2&gt;

&lt;p&gt;The primary goal of &lt;strong&gt;Resilient Vote&lt;/strong&gt; is to develop a secure and scalable voting system that addresses the limitations of traditional voting methods. By using &lt;strong&gt;ResilientDB&lt;/strong&gt; as the underlying database, we aim to create a system that is not only reliable but also capable of handling large-scale elections efficiently.&lt;/p&gt;

&lt;p&gt;Key objectives of our project include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Build a platform that can handle a high volume of voters and election data without compromising performance.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Ensure the confidentiality and integrity of votes through cryptographic techniques and tamper-proof storage.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transparency&lt;/strong&gt;: Provide clear and accessible visualizations of election data to ensure transparency and accountability in the voting process.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Automation&lt;/strong&gt;: Eliminate the need for manual vote counting by automating the vote tallying process, reducing errors and human intervention.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;: Develop a user-friendly web interface that makes the voting process seamless for voters, administrators, and election officials.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;technical-approach&quot;&gt;Technical Approach&lt;/h2&gt;

&lt;p&gt;To build &lt;strong&gt;Resilient Vote&lt;/strong&gt;, we designed a secure, scalable, and user-friendly system by leveraging modern technologies and distributed database solutions. Our approach integrates a web-based front end, a robust back-end API, and a fault-tolerant database system powered by &lt;strong&gt;ResilientDB&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/ResVote.png&quot; alt=&quot;Resilient Vote&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;system-architecture&quot;&gt;System Architecture&lt;/h3&gt;

&lt;p&gt;The system is divided into three main components:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Front-End (React &amp;amp; XML-RPC)&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;The user interface is built using &lt;strong&gt;React&lt;/strong&gt;, ensuring a responsive and interactive experience for voters, administrators, and general users.&lt;/li&gt;
      &lt;li&gt;For communication between the front end and the back end, we use &lt;strong&gt;XML-RPC&lt;/strong&gt; (Extensible Markup Language Remote Procedure Call). XML-RPC allows the front-end React application to interact with the back-end services securely and efficiently. By using this protocol, the system can send method calls to the server and receive responses, ensuring smooth data exchange and integration between the user interface and the database.&lt;/li&gt;
      &lt;li&gt;This approach provides a lightweight solution for data transmission, making it easy to implement in a distributed environment while maintaining high security and reliability.
&lt;img src=&quot;https://yfhe.net/images/ResVote/ResVote_React.png&quot; alt=&quot;ResVote React Frontend&quot; /&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Back-End (ResilientDB Crow Service &amp;amp; ORM)&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;The back-end uses &lt;strong&gt;ResilientDB Crow Service&lt;/strong&gt; and &lt;strong&gt;ResilientDB ORM&lt;/strong&gt; to interact with the database. The &lt;strong&gt;Crow Service&lt;/strong&gt; ensures that the system is fault-tolerant and highly available, with data securely stored and accessible across distributed nodes.&lt;/li&gt;
      &lt;li&gt;The &lt;strong&gt;ResilientDB ORM&lt;/strong&gt; simplifies the database interactions by abstracting CRUD operations into Python-friendly methods, reducing boilerplate code and making it easier to manage votes and election data efficiently.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Database (ResilientDB &amp;amp; MongoDB)&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;ResilientDB&lt;/strong&gt; serves as the primary database, providing a distributed, fault-tolerant system to store and manage votes securely. Key features of ResilientDB, such as &lt;strong&gt;parallel processing&lt;/strong&gt;, &lt;strong&gt;system crash resilience&lt;/strong&gt;, and robust &lt;strong&gt;security&lt;/strong&gt;, ensure data integrity and high availability, making it the perfect solution for a scalable voting system.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt; is used as a caching layer for the transactions. It stores temporary data related to votes and election activities, helping to reduce latency and improve system performance by offloading frequent read and write operations from ResilientDB. MongoDB serves as a fast, scalable cache to ensure that the system can handle high volumes of requests during peak voting periods.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Randomized Vote Generator based-on Property-based Testing&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;To ensure the reliability and robustness of the voting system, we use the &lt;strong&gt;Hypothesis&lt;/strong&gt; library, a property-based testing tool for simulating election events. With &lt;strong&gt;Hypothesis&lt;/strong&gt;, we generate random election scenarios, including creating voters, elections, and votes. This enables us to test the system under various conditions and verify that it behaves as expected.&lt;/li&gt;
      &lt;li&gt;By stress-testing the system with large-scale, simulated data, &lt;strong&gt;Hypothesis&lt;/strong&gt; helps identify edge cases and potential issues, ensuring that &lt;strong&gt;Resilient Vote&lt;/strong&gt; performs accurately and securely under diverse scenarios.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;deployment-tutorial-from-scratch&quot;&gt;Deployment Tutorial From Scratch&lt;/h2&gt;

&lt;p&gt;In order to provide more complete examples for beginners who are interested in participating in distributed database projects, we have improved the project documentation to deliver a project guide from scratch.&lt;/p&gt;

&lt;h3 id=&quot;python&quot;&gt;Python&lt;/h3&gt;

&lt;p&gt;We recommend using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conda&lt;/code&gt; to manage python environment.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda create &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;resdb&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;python&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;3.10.0 ipython
conda activate resdb
pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;get-resilientdb-dependencies&quot;&gt;Get ResilientDB Dependencies&lt;/h3&gt;

&lt;p&gt;To save some time, we also provide a docker image that has all the dependencies installed.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker pull yfhecs/rsdb
docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 18000:18000 &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; resdb yfhecs/rsdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you choose to use docker, you can skip the following steps.
Please wait a few minutes for the docker container to start.
You can check if it is ready by the follow command:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;{&quot;id&quot;:&quot;key1&quot;,&quot;value&quot;:&quot;value1&quot;}&apos;&lt;/span&gt; localhost:18000/v1/transactions/commit
&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;: key1

❯ curl 127.0.0.1:18000/v1/transactions/key1
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;id&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;key1&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;value1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can also find the related dockerfile in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./docker&lt;/code&gt; directory.&lt;/p&gt;

&lt;h4 id=&quot;resilientdb&quot;&gt;ResilientDB&lt;/h4&gt;

&lt;p&gt;The following commands will clone and build ResilientDB,
and then starts 4 replicas and 1 client. Each replica instantiates a key-value store.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/apache/incubator-resilientdb.git resilientdb
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resilientdb
./INSTALL.sh
./service/tools/kv/server_tools/start_kv_service.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;graph-ql&quot;&gt;Graph QL&lt;/h4&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/apache/incubator-resilientdb-graphql.git resilientdb-graphql
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resilientdb-graphql
sh ./INSTALL.sh
pip &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;running-crow-service-http-endpoints&quot;&gt;Running Crow service (HTTP endpoints)&lt;/h5&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build service/http_server/crow_service_main
bazel-bin/service/http_server/crow_service_main service/tools/config/interface/client.config service/http_server/server_config.config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;resvote-server&quot;&gt;ResVote Server&lt;/h3&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; ./env.sh
python app/serve.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;resvote-tui-client&quot;&gt;ResVote TUI Client&lt;/h3&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; ./env.sh
python app/tui.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;results--achievements&quot;&gt;Results &amp;amp; Achievements&lt;/h2&gt;

&lt;p&gt;The development of &lt;strong&gt;Resilient Vote&lt;/strong&gt; has yielded significant progress in both the &lt;strong&gt;Virtual Vote Generator&lt;/strong&gt; and &lt;strong&gt;Data Visualizations&lt;/strong&gt;, two core features of the system.&lt;/p&gt;

&lt;h3 id=&quot;virtual-vote-generator&quot;&gt;Virtual Vote Generator&lt;/h3&gt;

&lt;p&gt;One of the key innovations of our project is the &lt;strong&gt;Virtual Vote Generator&lt;/strong&gt;, developed using the &lt;strong&gt;Hypothesis&lt;/strong&gt; library. This tool simulates large-scale election events by automatically generating random voting data. It creates virtual voters, assigns them different identity attributes (such as age, gender, region, race, education level, timestamp etc.), and simulates voting in various election scenarios.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Virtual Vote Generator&lt;/strong&gt; serves three main purposes:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Stress Testing&lt;/strong&gt;: It helps simulate high volumes of votes to ensure the system can handle large-scale elections without performance degradation.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;System Validation&lt;/strong&gt;: The generator validates that the system handles diverse voting scenarios correctly, ensuring data consistency across distributed nodes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Demographic Analysis&lt;/strong&gt;: By generating voters with varied attributes, the system can examine how different demographics might influence election outcomes, thus guiding more informed decision-making.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This feature is essential for testing the resilience and scalability of the system before it’s deployed in real-world elections.&lt;/p&gt;

&lt;h3 id=&quot;data-visualizations&quot;&gt;Data Visualizations&lt;/h3&gt;

&lt;p&gt;The system includes a powerful &lt;strong&gt;data visualization&lt;/strong&gt; component that provides a clear and interactive view of the election results. The visualizations include a variety of charts and graphs that are automatically updated as votes are cast. Key features of the data visualization component include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Real-Time Election Results&lt;/strong&gt;: As votes are cast, the system displays real-time updates in the form of bar charts, pie charts, and line graphs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Voter Demographics&lt;/strong&gt;: The system visualizes the distribution of votes across different voter demographics, such as age groups, gender, regions, race, education level and other attributes. For each attribute, we make overall visualization based on total voters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;https://yfhe.net/images/ResVote/ResVote_React.png&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/candidate_distribution.png&quot; alt=&quot;Candidate Distribution&quot; style=&quot;width:150px; height:150px;&quot; /&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/age_attribute_distribution.png&quot; alt=&quot;Age Distribution&quot; style=&quot;width:150px; height:auto;&quot; /&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/gender_attribute_distribution.png&quot; alt=&quot;Gender Distribution&quot; style=&quot;width:150px; height:auto;&quot; /&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Candidate Distribution&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Age Distribution&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Gender Distribution&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/region_attribute_distribution.png&quot; alt=&quot;Region Distribution&quot; style=&quot;width:150px; height:auto;&quot; /&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/race_attribute_distribution.png&quot; alt=&quot;Race Distribution&quot; style=&quot;width:150px; height:auto;&quot; /&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/education_attribute_distribution.png&quot; alt=&quot;Education Distribution&quot; style=&quot;width:150px; height:auto;&quot; /&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Region Distribution&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Race Distribution&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Education Distribution&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;And we also make grouped analysis of different candidates for better comparison.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/age_grouped_bar_chart.png&quot; alt=&quot;Age Grouped Bar Chart&quot; style=&quot;width:150px; height:auto;&quot; /&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/gender_grouped_bar_chart.png&quot; alt=&quot;Gender Grouped Bar Chart&quot; style=&quot;width:150px; height:auto;&quot; /&gt;&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;https://yfhe.net/images/ResVote/region_grouped_bar_chart.png&quot; alt=&quot;Region Grouped Bar Chart&quot; style=&quot;width:150px; height:auto;&quot; /&gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Age Grouped Bar Chart&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Gender Grouped Bar Chart&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Region Grouped Bar Chart&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div style=&quot;display: flex; justify-content: center;&quot;&gt;

| &lt;img src=&quot;https://yfhe.net/images/ResVote/race_grouped_bar_chart.png&quot; alt=&quot;Race Grouped Bar Chart&quot; style=&quot;width:150px; height:auto;&quot; /&gt; | &lt;img src=&quot;https://yfhe.net/images/ResVote/education_grouped_bar_chart.png&quot; alt=&quot;Education Grouped Bar Chart&quot; style=&quot;width:150px; height:auto;&quot; /&gt; |
|:-------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------:|
| Race Grouped Bar Chart                                                                                         | Education Grouped Bar Chart                                                                                       |

&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Trend Analysis&lt;/strong&gt;: The visualizations show trends in voting over time, helping administrators understand voter participation patterns.
&lt;img src=&quot;https://yfhe.net/images/ResVote/time_series.png&quot; alt=&quot;Time Series Analysis&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These visualizations not only enhance the transparency of the voting process but also make it easier to interpret the results and track the progress of elections.&lt;/p&gt;

&lt;p&gt;By combining these two powerful features—automated voting simulations and real-time, interactive data visualizations—&lt;strong&gt;Resilient Vote&lt;/strong&gt; provides a robust platform for conducting scalable, transparent, and efficient elections.&lt;/p&gt;

&lt;h3 id=&quot;feasibility-analysis&quot;&gt;Feasibility Analysis&lt;/h3&gt;

&lt;p&gt;While the Virtual Vote Generator was initially designed to produce synthetic data for stress-testing and validation, its underlying structure closely mirrors that of real-world voting data. By leveraging randomized yet controlled attribute assignments—gender, region, age, race, education level—the generator ensures broad coverage of realistic scenarios. This design principle allows the transition from testing scenarios to actual election data to be seamless.&lt;/p&gt;

&lt;p&gt;In practice, once real votes start coming in, the same code paths and visualization routines used for generated data can be directly applied to genuine voting records. Since the generator’s outputs and real votes share the same data schema, all existing analytic and graphical methods remain valid. The rich set of demographic and temporal charts that clarify patterns in synthetic elections will likewise provide meaningful insights when applied to real voter populations. In other words, the visualizations that help us pinpoint unexpected trends or correlations in randomized testing scenarios are just as effective in highlighting authentic voter behaviors, preferences, and participation patterns.&lt;/p&gt;

&lt;p&gt;By maintaining this consistent data format and analysis approach, &lt;strong&gt;Resilient Vote&lt;/strong&gt; ensures that lessons learned from simulation inform actual voting events. As a result, insights gained during development translate into actionable understanding and enhanced transparency once real ballots are being cast.&lt;/p&gt;

&lt;h2 id=&quot;future-plans&quot;&gt;Future Plans&lt;/h2&gt;

&lt;p&gt;As we continue to develop &lt;strong&gt;Resilient Vote&lt;/strong&gt;, there are several key areas we plan to improve and enhance:&lt;/p&gt;

&lt;h3 id=&quot;1-ui-enhancement-and-front-end--back-end-integration-upgrade&quot;&gt;1. UI Enhancement and Front-End &amp;amp; Back-End Integration Upgrade&lt;/h3&gt;

&lt;p&gt;Our primary focus for future development is to &lt;strong&gt;enhance the user interface&lt;/strong&gt; with more user-friendly operating logic and &lt;strong&gt;strengthen the integration between the front-end and back-end&lt;/strong&gt;. While the current system is functional, we aim to improve the overall user experience by ensuring a seamless flow of data between the front-end and back-end, making the platform more responsive and efficient.&lt;/p&gt;

&lt;h3 id=&quot;2-real-time-visualization-of-vote-trends&quot;&gt;2. Real-Time Visualization of Vote Trends&lt;/h3&gt;

&lt;p&gt;We will take the &lt;strong&gt;data visualization&lt;/strong&gt; features a step further by incorporating &lt;strong&gt;real-time vote trends&lt;/strong&gt; during elections. This will allow voters and administrators to track the election results dynamically, providing insights into voter participation and trends as the voting progresses.&lt;/p&gt;

&lt;h3 id=&quot;3-enhanced-user-registration-security&quot;&gt;3. Enhanced User Registration Security&lt;/h3&gt;

&lt;p&gt;We will implement more robust security measures like Multi-factor authentication (MFA) to protect user identities and prevent unauthorized access. In addition, we plan to achieve advanced encryption methods to protect personal information and prevent data breaches.&lt;/p&gt;

&lt;h2 id=&quot;about-team&quot;&gt;About Team&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ECS 265 Distributed Database Systems Fall 2024&lt;/strong&gt;&lt;br /&gt;
Professor &lt;a href=&quot;https://expolab.org/&quot;&gt;Mohammad Sadoghi&lt;/a&gt;
TA &lt;a href=&quot;https://dakaikang.github.io/&quot;&gt;Daikai Kang&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;team-members&quot;&gt;Team Members:&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Tyler Culp&lt;/li&gt;
  &lt;li&gt;Jason Eissayou&lt;/li&gt;
  &lt;li&gt;Simon Draeger&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://yfhe.net/about/&quot;&gt;Yifeng He&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.linkedin.com/in/jicheng-jeremy-wang-0a07b833b/&quot;&gt;Jicheng Wang&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Boqi Zhao&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;University of California, Davis&lt;br /&gt;
Davis, CA&lt;/p&gt;
</description>
        <pubDate>Sun, 08 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//science/2024/12/08/ECS265-ResVoteTUI.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//science/2024/12/08/ECS265-ResVoteTUI.html</guid>
      </item>
    
      <item>
        <title>MemLens - Continuous Profiling tool for ResilientDB</title>
        <description>&lt;h1 id=&quot;what-is-memlens&quot;&gt;What is MemLens?&lt;/h1&gt;

&lt;p&gt;MemLens is a comprehensive CPU and memory profiler designed for ResilientDB, offering granular, real-time performance insights through continuous profiling. By integrating advanced profiling tools and aggregating data from various system and process specific sources, MemLens provides a robust platform for database-specific metrics.&lt;/p&gt;

&lt;p&gt;Our platform delivers detailed insights into the inner workings of the database, empowering users to optimize system performance effectively. Key metrics include cache hit ratios, storage and disk performance, CPU usage, call stack visualizations, dependency graphs, and more. The integration of continuous profiling ensures that performance trends and anomalies can be identified over time, enabling proactive optimization and system tuning.&lt;/p&gt;

&lt;p&gt;MemLens represents an ambitious and evolving vision to bridge the gap between high-level performance monitoring and low-level system insights. We are proud to share a packaged version that highlights the potential of this innovative tool and are committed to ongoing improvements to push the boundaries of database profiling.&lt;/p&gt;

&lt;h2 id=&quot;key-highlights&quot;&gt;Key Highlights&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Integrated Terminal Playground&lt;/strong&gt;:
Provides a seamless terminal-like interface for retrieving (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt;) and storing (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SET&lt;/code&gt;) values directly within ResilientDB, enhancing ease of use for developers and operators.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Real-Time Flame Graphs&lt;/strong&gt;:
Automatically generates detailed flame graphs for memory and CPU profiling, paired with in-depth call stack analysis for processes to identify bottlenecks and optimize performance.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Custom LevelDB Metrics&lt;/strong&gt;:
Incorporates Custom C++ hooks to expose critical LevelDB metrics not available by default, such as:
    &lt;ul&gt;
      &lt;li&gt;Cache hit ratios.&lt;/li&gt;
      &lt;li&gt;Storage engine metrics, including the number of SST tables and file counts at each level.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Interactive Web-Based Frontend&lt;/strong&gt;:
Features a user-friendly, web-based interface for exploring performance insights interactively, making profiling data accessible and actionable.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Unified Profiling Dashboard&lt;/strong&gt;:
Aggregates data from multiple profiling tools into a cohesive dashboard, offering a single, unified view of system performance.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Optimized for Linux&lt;/strong&gt;:
Designed to be lightweight and highly efficient, ensuring minimal overhead and smooth operation on Linux-based systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;

&lt;p&gt;Below is a architecture diagram of MemLens:&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/memlens/architecture.jpeg&quot; alt=&quot;Architecture Diagram&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Diagram displaying the architecture of MemLens and how profiling metrics are collected.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;The diagram can be broken down as follows. A client request for a particular metric is made by the client to the middleware. This layer acts as a data aggregation platform which collects metrics from the ResDB environment. The various data sources include time series data from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_exporter&lt;/code&gt;, call stack data from &lt;a href=&quot;https://pyroscope.io/&quot;&gt;pyroscope&lt;/a&gt;, storage engine metrics from hooks integrated into ResDB’s CPP source code. ResDB Graphql service is also running to interface GET and SET API calls via HTTP requests.&lt;/p&gt;

&lt;hr /&gt;
&lt;h2 id=&quot;metrics&quot;&gt;Metrics&lt;/h2&gt;

&lt;h3 id=&quot;call-stack-visualization&quot;&gt;Call Stack Visualization&lt;/h3&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/memlens/flamegraph_get_method.png&quot; alt=&quot;Flamegraph Get Method&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Flamegraph showing Call Stack when a transaction is retrieved
    &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;Flamegraph showing the call stack when a Get method is called on ResilientDB’s key value store. This graph shows the function caller which is invoked by the ResilientDB-GraphQL service and is serviced at the end by the storage engine which is LevelDB. The storage engine calls the in-memory LRU cache to check for cache hits and when not found calls its internal functions to retrieve the key value pair.&lt;/p&gt;

&lt;h3 id=&quot;cpu-usage&quot;&gt;CPU Usage&lt;/h3&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/memlens/cpu_usage.png&quot; alt=&quot;CPU Usage Graph&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. Line Graph showing showing CPU usage of ResDB KV Service over a period of 6 hours
    &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;Linegraph showing the CPU usage of ResDB’s KV Service over a period of 6 hours. This data is collected from &lt;a href=&quot;https://github.com/ncabatoff/process-exporter&quot;&gt;process-exporter&lt;/a&gt; which is used to profile individual processes and export metrics through prometheus. We run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;process-exporter&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd&lt;/code&gt; process to ensure persistent monitoring.&lt;/p&gt;

&lt;h3 id=&quot;storage-engine-metrics&quot;&gt;Storage Engine Metrics&lt;/h3&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/memlens/storage_engine_metrics.png&quot; alt=&quot;Storage Engine Metrics&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. Dashboard showing storage engine metrics.
    &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;Dashboard showing storage engine metrics, like cache hit ratio, approximate database size of leveldb, snapshot of process metrics like RSS, number of block reads and number of block writes. Each metric has a information tooltip which can be used to display more information about the metrics.&lt;/p&gt;

&lt;h3 id=&quot;disk-metrics&quot;&gt;Disk Metrics&lt;/h3&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/memlens/disk_metrics.png&quot; alt=&quot;Disk Metrics&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. Dashboard showing Disk metrics.
    &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;Dashboard showing disk metrics like time spent during IO, disk read and write data, disk IOPS (Input and Output operations per second) and disk average wait time. These metrics are exposed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_exporter&lt;/code&gt; and are exporter through prometheus. We run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_exporter&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;systemd&lt;/code&gt; process to ensure persistent monitoring.&lt;/p&gt;

&lt;h3 id=&quot;dependency-analyzer&quot;&gt;Dependency Analyzer&lt;/h3&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/memlens/dependency_graph.png&quot; alt=&quot;Dependency Graph&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Dependency Graph for ResDB&apos;s KV Service.
    &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;Dependency Graph for ResDB’s KV Service obtained by running the command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bazel query --notool_deps --noimplicit_deps &quot;deps(//service/kv:kv_service, $(depth))&quot;&lt;/code&gt;. The value of depth can be selected among 2,3 and 4. This generated a deeper dependency graph with links to libraries and other dependent services.&lt;/p&gt;

&lt;h2 id=&quot;data-collection&quot;&gt;Data Collection&lt;/h2&gt;

&lt;p&gt;MemLens uses a data aggregation layer, a thin HTTP service which sits between the Visualizer and the ResDB environment. As the name suggests this aggregation layer collects data from various profiling tools and exposes a single platform for the frontend to request data. We chose this architecture as it would allows us to scale this system by introducing a time series databases in the future and collect data over a period of time and analyze trends and gauge behaviour.&lt;/p&gt;

&lt;h2 id=&quot;data-sources&quot;&gt;Data Sources&lt;/h2&gt;

&lt;p&gt;MemLens leverages a wide range of tools and integrations to provide detailed, real-time performance insights for ResilientDB. By utilizing data from various industry-standard sources, MemLens offers a holistic view of system performance. Below is an overview of the key data sources:&lt;/p&gt;

&lt;h3 id=&quot;1-leveldb-cpp-hooks&quot;&gt;1. &lt;strong&gt;LevelDB CPP Hooks&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Provides access to internal statistics and performance metrics of LevelDB.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Custom hooks enable MemLens to monitor and profile critical metrics such as:
    &lt;ul&gt;
      &lt;li&gt;Cache hit/miss ratios.&lt;/li&gt;
      &lt;li&gt;Read/write latencies.&lt;/li&gt;
      &lt;li&gt;Compaction stats and storage utilization.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Benefits&lt;/strong&gt;: Delivers database-specific insights that help optimize LevelDB’s storage layer performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-node-exporter&quot;&gt;2. &lt;strong&gt;Node Exporter&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Collects hardware and operating system metrics.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Node Exporter gathers low-level system data such as:
    &lt;ul&gt;
      &lt;li&gt;CPU utilization and system load.&lt;/li&gt;
      &lt;li&gt;Memory usage (heap, stack, swap).&lt;/li&gt;
      &lt;li&gt;Disk I/O and network throughput.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Benefits&lt;/strong&gt;: Provides a baseline for understanding system resource utilization alongside database performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;3-process-exporter&quot;&gt;3. &lt;strong&gt;Process Exporter&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Monitors resource usage at the process level.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Tracks resource usage specific to ResilientDB processes, including:
    &lt;ul&gt;
      &lt;li&gt;Per-process CPU and memory consumption.&lt;/li&gt;
      &lt;li&gt;Process life cycles and thread usage.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Benefits&lt;/strong&gt;: Enables granular profiling of ResilientDB, isolating bottlenecks at the process level.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;4-pyroscope&quot;&gt;4. &lt;strong&gt;Pyroscope&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Enables continuous profiling for CPU and memory usage.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Captures detailed call stacks and resource usage trends over time, including:
    &lt;ul&gt;
      &lt;li&gt;Hot path identification for CPU-intensive operations.&lt;/li&gt;
      &lt;li&gt;Memory allocation and garbage collection patterns.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Benefits&lt;/strong&gt;: Provides a time-series view of performance, enabling developers to pinpoint and resolve inefficiencies effectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;5-prometheus&quot;&gt;5. &lt;strong&gt;Prometheus&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Collects and queries time-series data.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Custom Prometheus hooks gather both standard and database-specific metrics such as:
    &lt;ul&gt;
      &lt;li&gt;Query execution latencies.&lt;/li&gt;
      &lt;li&gt;Disk write/read performance.&lt;/li&gt;
      &lt;li&gt;Custom database events for fine-grained profiling.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Benefits&lt;/strong&gt;: Delivers a unified and extensible monitoring solution, enabling seamless visualization through dashboards like Grafana.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;demo-video&quot;&gt;Demo Video&lt;/h2&gt;

&lt;!-- &lt;iframe width=&quot;100%&quot; height=&quot;500px&quot; src=&quot;https://youtu.be/LJbUECTEd6k&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt; --&gt;
&lt;div class=&quot;extensions extensions--video&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/LJbUECTEd6k?rel=0&amp;amp;showinfo=0&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h1 id=&quot;usage&quot;&gt;Usage&lt;/h1&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Before running the MemLens application, you need to start kv service on the ResDB backend and the sdk.&lt;/p&gt;

&lt;h3 id=&quot;resilientdb&quot;&gt;ResilientDB&lt;/h3&gt;
&lt;p&gt;Git clone the MemLens backend repository, a fork of ResilientDB and follow the instructions to set it up:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/harish876/incubator-resilientdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Setup KV Service:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./service/tools/kv/server_tools/start_kv_service_monitoring.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;sdk&quot;&gt;SDK&lt;/h3&gt;
&lt;p&gt;Git clone the GraphQL Repository and follow the instructions on the README to set it up:&lt;/p&gt;

&lt;p&gt;Install GraphQL:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/ResilientApp/ResilientDB-GraphQL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Setup SDK:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build service/http_server:crow_service_main

bazel-bin/service/http_server/crow_service_main service/tools/config/interface/client.config service/http_server/server_config.config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;middleware&quot;&gt;Middleware&lt;/h3&gt;
&lt;p&gt;Git clone the MemLens Middleware Repository:&lt;/p&gt;

&lt;p&gt;Install MemLens Middleware:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/harish876/MemLens-middleware
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Setup MemLens Middleware:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install
&lt;/span&gt;npm run start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;monitoring-tools&quot;&gt;Monitoring tools&lt;/h3&gt;
&lt;p&gt;Follow this &lt;a href=&quot;https://github.com/Bismanpal-Singh/MemLens/blob/main/INSTALLATION.md&quot;&gt;link&lt;/a&gt; to setup prometheus, grafana and a few other monitoring tools used in this application.&lt;/p&gt;

&lt;p&gt;With these 3 services running, the MemLens front end can now send aggregate metrics from the middleware.&lt;/p&gt;

&lt;h2 id=&quot;running-the-memlens-application&quot;&gt;Running the MemLens Application&lt;/h2&gt;

&lt;p&gt;Clone the repo and open in a new folder.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/Bismanpal-Singh/MemLens
npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run the below code to start the app and load the script.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;using-the-memlens-application&quot;&gt;Using the MemLens Application&lt;/h2&gt;

&lt;p&gt;Once MemLens has been started, go to http://localhost:5173&lt;/p&gt;

&lt;p&gt;You will see a landing page with a brief description of the project and on scrolling down will see a brief of the PBFT protocol, and a explorer card to access the dashboard.&lt;/p&gt;

&lt;p&gt;Once the dashboard page has loaded, it will make an API call to the middleware running on http://localhost:3002 to check if the middleware is active and running. If the middleware is running and all profiling tools are installed then , the dashboard switches to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Live&lt;/code&gt; mode which fetches live data from the middleare. If no accompanying backend services are running, then the app switches to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Offline&lt;/code&gt; mode which loads snapshots of data collected by the team. This mode could be used for exploration and familiarising with the interface.&lt;/p&gt;

&lt;p&gt;The dashboard has 3 tabs, Memory Tracker, CPU and Bazel Build. The memory tracker loads a playground which is a terminal emulator to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SET&lt;/code&gt; values into the KV store. A dashboard card dedicated to storage engine metrics and disk metrics. Each graphical card can be be refreshed which will refresh the data. The CPU tab displays a CPU Line graph which displays a graphical view of CPU usage over a period of time, and a accompanying flamegraph to display the call stack. The line graph can be highlighted into in order to magnify the CPU usage over that specific time window and the flamegraph automatically updates according to the time frame chosen.  The bazel build tab displays a dependency graph showcasing the dependencies for the KV service and a select menu to dynamically change the depth of the graph output and the command run to generate the visualized build data.&lt;/p&gt;

&lt;h1 id=&quot;future-work&quot;&gt;Future Work&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;Package, installation and setup of monitoring tools into a bash script or ansible playbook.&lt;/li&gt;
  &lt;li&gt;Remote setup of MemLens middleware and migrating the current setup to an AWS EC2 instance or Linode.&lt;/li&gt;
  &lt;li&gt;Set up profiling tools on a Raspberry Pi and collect metrics.&lt;/li&gt;
  &lt;li&gt;Development of eBPF profiler from scratch and integrating it into code, instead of using a sandboxed profiling environment.&lt;/li&gt;
  &lt;li&gt;Stabilising metric collection and develop a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;remote&lt;/code&gt; mode to push data into InfluxDB or equivalent time series database to analyze trends.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;source-code-repositories&quot;&gt;Source Code Repositories&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Bismanpal-Singh/MemLens&quot;&gt;MemLens Frontend&lt;/a&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/harish876/MemLens-middleware&quot;&gt;MemLens Middleware&lt;/a&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/apache/incubator-resilientdb&quot;&gt;MemLens Backend / ResDB Fork&lt;/a&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/ResilientApp/ResilientDB-GraphQL&quot;&gt;ResDB GraphQL&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;slides&quot;&gt;Slides&lt;/h3&gt;
&lt;p&gt;Link to - &lt;a href=&quot;https://docs.google.com/presentation/d/1dU_16nNGHC5o-ntX5aj_SWO-JTJ4MP1zW-lacOqLzhk/edit?usp=sharing&quot;&gt;Presentation Slides&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;contributions&quot;&gt;Contributions&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/harish-gokul01/&quot;&gt;Harish&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Designed the project architecture and proposed innovative feature ideas.&lt;/li&gt;
  &lt;li&gt;Integrated profiling tools and developed C++ hooks to export LevelDB statistics, memory metrics, and explored alternatives like integrating an LMDB storage layer.&lt;/li&gt;
  &lt;li&gt;Developed a middleware layer to ensure seamless end-to-end connectivity between the monitoring environment and the frontend.&lt;/li&gt;
  &lt;li&gt;Implemented frontend features including Flamegraph visualization, the ability to toggle between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Live&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Offline&lt;/code&gt; modes, and a terminal emulator.&lt;/li&gt;
  &lt;li&gt;Created scripts to bootstrap monitoring tools and set up the profiling environment efficiently.&lt;/li&gt;
  &lt;li&gt;Authored comprehensive project documentation, estimated timelines, conducted research on existing tools, tested feasibility, and explored ideas that were ultimately not included in the final implementation.
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/bismanpal-singh/&quot;&gt;Bisman&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Collaborated on designing and conceptualizing the frontend’s look and feel, exploring component libraries and frameworks, and testing feature feasibility.&lt;/li&gt;
  &lt;li&gt;Designed the UI/UX architecture, including the skeleton, contexts, and pages. Developed the primary PBFT diagram, set up graph component skeletons, and styled the application for cohesive functionality and aesthetics.&lt;/li&gt;
  &lt;li&gt;Created and integrated key frontend components such as the Navbar, links, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INFO&lt;/code&gt; tags on graphs, and refresh button functionality. Incorporated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Live&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Offline&lt;/code&gt; modes seamlessly into the frontend.&lt;/li&gt;
  &lt;li&gt;Led the full-stack integration of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Disk Metric&lt;/code&gt; cards, including middleware API development and frontend implementation. Developed reusable components for graph display and utilities for efficient data fetching.&lt;/li&gt;
  &lt;li&gt;Architected and managed frontend features, ensuring project milestones were met consistently while maintaining high standards of quality and usability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/georgy-zaets/&quot;&gt;George&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Contributed to project ideation, exploring profiling tools and assessing the feasibility of various features.&lt;/li&gt;
  &lt;li&gt;Led efforts to expand the project scope, introducing support for additional facets such as running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResilientDB&lt;/code&gt; on Raspberry Pi.&lt;/li&gt;
  &lt;li&gt;Addressed and resolved challenges in setting up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResilientDB&lt;/code&gt; on Raspberry Pi, including testing multiple Pi versions and stabilizing overheating issues.&lt;/li&gt;
  &lt;li&gt;Maintained a project tracker to monitor progress, manage tasks, and ensure timely delivery of milestones.&lt;/li&gt;
  &lt;li&gt;Set up comprehensive documentation for GitHub repositories, enabling clear guidance for contributors and maintaining project standards.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/krishna-karthik-97b74b222/&quot;&gt;Krishna&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Polished the visual design and functionality of the application, including creating a sliding button link for a smoother user experience. Assisted team during the presentation by ensuring the frontend was presentation-ready.&lt;/li&gt;
  &lt;li&gt;Supported the development of frontend components, enhancing usability and visual appeal while ensuring seamless integration with the backend.&lt;/li&gt;
  &lt;li&gt;Played a key role in developing features like Bazel build visualization to enhance project debugging and performance monitoring capabilities.
&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;notable-contributions&quot;&gt;Notable Contributions&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/shreya-chadha-37249423a/&quot;&gt;Shreya&lt;/a&gt; - For designing the MemLens logo, bringing creativity and a design to the project.&lt;/p&gt;
</description>
        <pubDate>Sat, 07 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/07/MemLens.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/07/MemLens.html</guid>
      </item>
    
      <item>
        <title>ResCash</title>
        <description>&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;

&lt;h2 id=&quot;rescash-a-secure-and-user-friendly-financial-accounting-solution&quot;&gt;ResCash: A Secure and User-Friendly Financial Accounting Solution&lt;/h2&gt;

&lt;p&gt;In our increasingly digital world, managing finances effectively is critical for both individuals and businesses. &lt;strong&gt;ResCash&lt;/strong&gt; addresses this challenge with a cutting-edge accounting application that is &lt;strong&gt;secure&lt;/strong&gt;, &lt;strong&gt;efficient&lt;/strong&gt;, and &lt;strong&gt;intuitive&lt;/strong&gt;. Designed with individual users and freelancers in mind, ResCash leverages advanced technology to streamline transaction handling, budgeting, and financial reporting. It redefines the way financial management is approached by combining &lt;strong&gt;distributed accounting&lt;/strong&gt; principles, &lt;strong&gt;ResilientDB integration&lt;/strong&gt;, and &lt;strong&gt;secure transaction management&lt;/strong&gt; for a seamless user experience.&lt;/p&gt;

&lt;h2 id=&quot;technologies-that-power-rescash&quot;&gt;Technologies That Power ResCash&lt;/h2&gt;

&lt;p&gt;ResCash is built on a &lt;strong&gt;modern and robust tech stack&lt;/strong&gt;, ensuring scalability, reliability, and ease of use:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Frontend with React&lt;/strong&gt;: A responsive and seamless user interface, delivering smooth interactions and intuitive navigation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Backend with Node.js&lt;/strong&gt;: A high-performance environment for efficient API handling and business logic implementation.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Database Integration&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;ResilientDB&lt;/strong&gt;: A distributed database that provides top-notch security and reliability for critical financial data.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;: A secondary database optimized for advanced features like sorting, filtering, and quick data indexing.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Authentication via ResVault&lt;/strong&gt;: Ensures secure and controlled access to sensitive data, enhancing user trust.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Data Visualization&lt;/strong&gt;: Interactive charts and dashboards make complex financial metrics, such as cash flow and net worth trends, easy to understand and actionable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/ResCash/ResCash-Architecture.jpeg&quot; alt=&quot;ResCash Architecture&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-innovation&quot;&gt;The Innovation&lt;/h2&gt;

&lt;p&gt;ResCash stands out by integrating distributed database technology with an intuitive user experience. It combines the reliability of &lt;strong&gt;ResilientDB&lt;/strong&gt; with the flexibility of &lt;strong&gt;MongoDB&lt;/strong&gt;, offering a platform that prioritizes data security, high availability, and advanced functionality. Detailed financial &lt;strong&gt;visualization tools&lt;/strong&gt; and &lt;strong&gt;secure transaction management&lt;/strong&gt; ensure ResCash meets the dynamic needs of modern users.&lt;/p&gt;

&lt;h2 id=&quot;why-rescash&quot;&gt;Why ResCash?&lt;/h2&gt;

&lt;p&gt;ResCash goes beyond traditional accounting tools by emphasizing &lt;strong&gt;security&lt;/strong&gt;, &lt;strong&gt;transparency&lt;/strong&gt;, and &lt;strong&gt;flexibility&lt;/strong&gt;. Its advanced &lt;strong&gt;CRUD functionality&lt;/strong&gt;, customizable reports, and real-time budgeting tools adapt to the diverse needs of individual users and freelancers. With ResCash, managing your finances isn’t just easier—it’s smarter, empowering users to take control with confidence and clarity.&lt;/p&gt;

&lt;h2 id=&quot;elevator-pitch&quot;&gt;Elevator Pitch&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ResCash&lt;/strong&gt; is the next generation of financial accounting tools, offering a secure, distributed, and user-centric platform. By integrating state-of-the-art technologies like &lt;strong&gt;ResilientDB&lt;/strong&gt; and &lt;strong&gt;ResVault&lt;/strong&gt;, ResCash ensures that your data is protected, accessible, and actionable. Whether you’re a individual user or a freelancer, ResCash simplifies complex financial tasks, giving you the insights and tools you need to succeed.&lt;/p&gt;

&lt;h1 id=&quot;the-problem&quot;&gt;The Problem&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;The Commercial Opportunity&lt;/strong&gt;:
In an era where data security and transparency have become necessities for both bussiness man and college students, the ResCash accounting application sets out to redefine how individuals and small enterprises manage their financial records. Rather than relying on outdated methods prone to human error and data breaches, ResCash introduces cutting-edge blockchain-inspired solutions and distributed databases to ensure that every recorded transaction is secure and easy to use. While many competing appllications promise efficiency, few can match the level of data integrity and trust that come from a design philosophy centered on transparency and resilience. This quality positions ResCash as a credible choice for those who value long-term stability and security over quick, superficial fixes. There are too many college students and people who just starting working on their own small bussiness lacking of safety awareness in this society, becuase they still do not have much social experience. In that situation, ResCash provided a reliable way for them to manage their financial information in the absence of doubt. In our future plan, we can also cooperate with universities to build their own database, which increase the secuirty and customizability of ResCash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pain Points in Traditional Systems&lt;/strong&gt;:
Traditional accounting systems often leave users feeling uncertain about the sercurity and reliability of their financial data. Concerns over potential information theft and unauthorized access are widespread. With ResCash, these issues are addressed head-on. By employing a distributed database platform ResilientDB and MongoDB in this project, the application safeguards each transaction entry from spiteful interference. In doing so, it instills a sense of security and trust—key factors that appeal to college student and small bussiness man who want to maintain control over their financial information. ResCash’s capacity to preserve data integrity in any situation is one of its primary advantages. This distributed architecture is only little impacted by system failures and cyberattacks that would destroy a conventional, centralized database. Errors and interruptions barely affect the system’s overall performance because the data is duplicated and checked across several nodes. Knowing that their records are reliable and available whenever they’re needed allows users to log in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Highlights of the ResCash&lt;/strong&gt;:
A distributed and secure strategy guarantees that the system remains operational and accessible even in the event of a single node failure or server interruption. Because of its resilience, data integrity is maintained and catastrophic outages that may ruin profits, undermine confidence, and damage a company’s brand are avoided. Additionally, teams can focus on strategic growth, innovative problem-solving, and strengthening client connections when they are freed from time-consuming troubleshooting by well-designed and effective solutions. Efficiency directly results in savings and a stronger competitive advantage; it is not a luxury.Investing in safe, distributed, and efficient solutions is ultimately a strategic decision that affects long-term trends and aids in businesses’ or college students quick adaptation, since the market is changing at a fast pace. Those that are prepared to reconsider their data management and security strategies and adopt methods that prioritize security and smooth efficiency will be rewarded in the future.&lt;/p&gt;

&lt;h1 id=&quot;our-solution&quot;&gt;Our Solution&lt;/h1&gt;

&lt;p&gt;ResCash leverages cutting-edge technologies to provide a reliable, secure, and scalable cash flow management platform.&lt;/p&gt;

&lt;h2 id=&quot;foundational-technology&quot;&gt;Foundational Technology&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Distributed Database Architecture&lt;/strong&gt;:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Powered by &lt;strong&gt;ResilientDB&lt;/strong&gt;, a state-of-the-art distributed database, ResCash ensures high availability, fault tolerance, and efficient transaction processing.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Cryptographic Key Integration&lt;/strong&gt;:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Cryptographic keys are utilized for secure user authentication and transaction management.&lt;/li&gt;
      &lt;li&gt;Ensures immutable transaction records while protecting user data from unauthorized access.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;distributed-system-security&quot;&gt;Distributed System Security&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Consensus-Based Validation&lt;/strong&gt;:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;ResCash employs ResilientDB’s consensus protocols to validate transactions across distributed nodes, ensuring consistency and preventing fraudulent modifications.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;End-to-End Encryption&lt;/strong&gt;:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Data transmitted between the client and the server is encrypted using industry-standard algorithms, protecting sensitive financial information from interception.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Access Control and Authentication&lt;/strong&gt;:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Secure authentication mechanisms, including the use of cryptographic keys and tokens, ensure that only authorized users can access or modify transaction records.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Fault Tolerance and Data Integrity&lt;/strong&gt;:&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;ResilientDB’s distributed replication ensures that transaction data is stored across multiple nodes. In the event of a node failure, data remains accessible and unaltered.&lt;/li&gt;
      &lt;li&gt;Transaction logs are immutable, ensuring tamper-proof audit trails for regulatory compliance.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Periodic Security Audits&lt;/strong&gt;:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Regular audits and vulnerability assessments ensure that ResCash remains secure against evolving threats.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By integrating these distributed system security measures, ResCash provides a platform that not only ensures high performance but also guarantees data privacy, integrity, and availability, making it a reliable solution for financial management.&lt;/p&gt;

&lt;h1 id=&quot;core-features&quot;&gt;Core Features&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Create Transactions&lt;/strong&gt;:
ResCash allows users to create detailed financial transactions with fields such as amount, category, transaction type, merchant, and payment method. Transactions are stored securely in ResilientDB for data integrity and MongoDB for efficient indexing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Read Transactions&lt;/strong&gt;:
Users can view all transactions with advanced filtering options. The “Read” feature provides a structured display of transaction data, ensuring easy navigation and understanding. It supports personalized views based on user-specific data retrieved securely through token-based authentication.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Update Transactions&lt;/strong&gt;:
The update functionality allows users to modify existing transaction details, including amounts, categories, transaction type, merchant, and payment method, ensuring data consistency and accuracy.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Delete Transactions&lt;/strong&gt;:
ResCash implements a “soft delete” mechanism, marking transactions as inactive without permanently removing them in ResilientDB. This ensures data traceability while maintaining clean records for users.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Cash Flow Chart&lt;/strong&gt;:
The cash flow chart is a dynamic visualization tool that tracks the movement of funds over time. This feature provides a clear and comprehensive view of income, expenses, and net cash flow. Users can identify patterns, such as periods of liquidity surplus or deficit, enabling better financial planning. Income and expenses are categorized, helping users understand the sources of inflows and outflows. By monitoring cash flow, users can make informed decisions about spending, saving, or investing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Net Worth Chart&lt;/strong&gt;:
The net worth chart provides a real-time snapshot of a user’s financial position by calculating the accumulation between income and expense. This feature is crucial for individuals and businesses to measure financial progress over time. Users can view how their net worth has evolved, with historical data displayed through an easy-to-read line chart.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;usage&quot;&gt;Usage&lt;/h1&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Install ResVault Chrome Extension&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Follow the instructions &lt;a href=&quot;https://blog.resilientdb.com/2023/09/21/ResVault.html&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;Ensure that the ResVault extension is connected to:
        &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;76.158.247.201:8070
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
        &lt;p&gt;&lt;em&gt;(You may substitute this URI with your own GraphQL server URI if needed.)&lt;/em&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Install Node.js and npm&lt;/strong&gt;&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Refer to the &lt;a href=&quot;https://docs.npmjs.com/downloading-and-installing-node-js-and-npm&quot;&gt;official guide&lt;/a&gt;.&lt;/li&gt;
      &lt;li&gt;Confirm installation by running:
        &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;setting-up-rescash&quot;&gt;Setting Up ResCash&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Clone the ResCash Repository&lt;/strong&gt;&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/quiet98k/resCash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Navigate to the Root Directory&lt;/strong&gt;&lt;/p&gt;

    &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resCash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Set Up the Frontend&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Navigate to the frontend directory (same name as the root directory):
        &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resCash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;Install dependencies:
        &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;Start the frontend server:
        &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Set Up the Backend&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Open a new terminal and return to the root directory:
        &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resCash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;Navigate to the backend directory:
        &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;backend
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; file with the following configuration:
        &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MONGODB_URI=****
MONGODB_DB_NAME=****
GRAPHQL_URI=****
CROW_SERVER_URI=****
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
        &lt;ul&gt;
          &lt;li&gt;&lt;strong&gt;MONGODB_URI&lt;/strong&gt;: MongoDB connection URI (customizable).&lt;/li&gt;
          &lt;li&gt;&lt;strong&gt;MONGODB_DB_NAME&lt;/strong&gt;: Database name.&lt;/li&gt;
          &lt;li&gt;&lt;strong&gt;GRAPHQL_URI&lt;/strong&gt;: GraphQL server URI (include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/graphql&lt;/code&gt; suffix).&lt;/li&gt;
          &lt;li&gt;&lt;strong&gt;CROW_SERVER_URI&lt;/strong&gt;: Crow server URI (must match the GraphQL URI).&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Install backend dependencies:
        &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;Start the backend server:
        &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Access the Application:&lt;/strong&gt;
Open your browser and navigate to:&lt;/p&gt;
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://localhost:3000/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;notes&quot;&gt;Notes&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Ensure all URIs are consistent between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.env&lt;/code&gt; files and the ResVault extension.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;future-developments&quot;&gt;Future Developments&lt;/h1&gt;

&lt;h2 id=&quot;1-enhanced-uiux-design&quot;&gt;1. Enhanced UI/UX Design&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Objective:&lt;/strong&gt; Improve the user interface and experience to make ResCash more intuitive, accessible, and visually appealing for all users.&lt;/p&gt;

&lt;h3 id=&quot;implementation-path&quot;&gt;Implementation Path:&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;User Research:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Conduct user interviews and surveys to gather feedback on pain points and usability issues in the current design.&lt;/li&gt;
      &lt;li&gt;Perform usability testing to identify areas for improvement.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;UI Redesign:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Revamp the interface with a clean, modern design using frameworks like &lt;strong&gt;Material UI&lt;/strong&gt;.&lt;/li&gt;
      &lt;li&gt;Prioritize ease of navigation with clear menu options and a step-by-step onboarding process for new users.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;UX Enhancements:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Simplify complex blockchain-related actions with user-friendly workflows.&lt;/li&gt;
      &lt;li&gt;Add tooltips, animations, and explanations for blockchain concepts to educate users.&lt;/li&gt;
      &lt;li&gt;Implement a dark mode for user customization.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Performance Optimization:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Optimize the UI for speed by minimizing assets and using asynchronous data fetching to ensure smooth performance.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Testing and Iteration:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Use A/B testing to experiment with different layouts and features.&lt;/li&gt;
      &lt;li&gt;Continuously collect user feedback post-launch and iterate on the design.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;2-multi-currency-support&quot;&gt;2. Multi-Currency Support&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Objective:&lt;/strong&gt; Enable ResCash to handle transactions in multiple currencies.&lt;/p&gt;

&lt;h3 id=&quot;implementation-path-1&quot;&gt;Implementation Path:&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Database Update:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Extend the MongoDB schema to include currency fields for transactions.&lt;/li&gt;
      &lt;li&gt;Store exchange rates in a separate collection for real-time updates.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Blockchain Integration:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Enhance the smart contracts or backend logic to handle currency conversions when needed.&lt;/li&gt;
      &lt;li&gt;Support multiple token standards (e.g., ERC-20 for Ethereum-based cryptocurrencies).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Frontend Changes:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Add a dropdown menu for users to select their preferred currency.&lt;/li&gt;
      &lt;li&gt;Display balances and transaction amounts in the selected currency.&lt;/li&gt;
      &lt;li&gt;Implement a real-time currency converter using exchange rate APIs (e.g., CoinGecko).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ResVault Update:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Modify the wallet extension to support multiple currency wallets.&lt;/li&gt;
      &lt;li&gt;Allow users to switch between wallets and manage private keys for each currency.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Testing and Deployment:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Conduct thorough testing to ensure accurate currency conversions and compatibility with blockchain protocols.&lt;/li&gt;
      &lt;li&gt;Deploy the updates incrementally to avoid disruptions.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;3-smart-budgeting-and-analytics&quot;&gt;3. Smart Budgeting and Analytics&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Objective:&lt;/strong&gt; Introduce more budgeting tools and analytics to help users track and plan their spending more effectively.&lt;/p&gt;

&lt;h3 id=&quot;implementation-path-2&quot;&gt;Implementation Path:&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Budgeting Feature:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Allow users to set monthly or weekly spending limits in specific categories.&lt;/li&gt;
      &lt;li&gt;Store user-defined budgets in MongoDB.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transaction Categorization:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Implement machine learning (ML) models to automatically categorize transactions based on descriptions or merchants.&lt;/li&gt;
      &lt;li&gt;Use a library like TensorFlow.js for lightweight ML in the backend or frontend.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Analytics Dashboard:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Create an interactive dashboard to display spending trends, savings, and projections.&lt;/li&gt;
      &lt;li&gt;Include features like:
        &lt;ul&gt;
          &lt;li&gt;Monthly spending breakdown.&lt;/li&gt;
          &lt;li&gt;Alerts for overspending in certain categories.&lt;/li&gt;
          &lt;li&gt;Forecasting future expenses.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Notifications:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Integrate email or push notifications to alert users about budget thresholds.&lt;/li&gt;
      &lt;li&gt;Use Node.js libraries like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Nodemailer&lt;/code&gt; or Firebase for notification delivery.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;User Testing and Feedback:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Deploy the feature to a small group of users for feedback.&lt;/li&gt;
      &lt;li&gt;Iterate based on user input to refine the budgeting and analytics tools.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;4-mobile-application-development&quot;&gt;4. Mobile Application Development&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Objective:&lt;/strong&gt; Expand the reach of ResCash by creating a mobile application for Android and iOS.&lt;/p&gt;

&lt;h3 id=&quot;implementation-path-3&quot;&gt;Implementation Path:&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Frontend Development:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Use a cross-platform framework like &lt;strong&gt;React Native&lt;/strong&gt; to build the app.&lt;/li&gt;
      &lt;li&gt;Design a responsive and user-friendly interface optimized for smaller screens.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Backend API Optimization:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Ensure the backend APIs are mobile-friendly by optimizing response times and minimizing data payloads.&lt;/li&gt;
      &lt;li&gt;Use tools like GraphQL subscriptions for real-time updates on mobile devices.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Integration with ResVault:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Develop a mobile version of ResVault.&lt;/li&gt;
      &lt;li&gt;Ensure seamless interaction between the app and the wallet for signing transactions.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Testing and Deployment:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Test the app on emulators and physical devices for compatibility.&lt;/li&gt;
      &lt;li&gt;Publish the app on Google Play Store and Apple App Store, adhering to their guidelines for blockchain apps.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Push Notifications:&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Add push notifications for transaction confirmations, balance updates, and other alerts using Firebase Cloud Messaging.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;the-team&quot;&gt;The Team&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Yiming Feng&lt;/strong&gt; &lt;a href=&quot;ymfeng@ucdavis.edu&quot;&gt;[ymfeng@ucdavis.edu]&lt;/a&gt;
    &lt;ul class=&quot;task-list&quot;&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement Create Feature&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement Report Feature&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Application Testing and feature improvement&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Project management, coordinating between team members&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Qingyue Yang&lt;/strong&gt; &lt;a href=&quot;yqmyang@ucdavis.edu&quot;&gt;[yqmyang@ucdavis.edu]&lt;/a&gt;
    &lt;ul class=&quot;task-list&quot;&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;The overall coding of the ResCash user interface frame&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement Home Page features&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement the Edit Feature&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Project management, creating project roadmap, and formatting reports&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Alex Chen&lt;/strong&gt; &lt;a href=&quot;yscchen@ucdavis.edu&quot;&gt;[yscchen@ucdavis.edu]&lt;/a&gt;
    &lt;ul class=&quot;task-list&quot;&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement Delete Feature&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Develop Net Worth function and chart&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Mark Le&lt;/strong&gt; &lt;a href=&quot;ltble@ucdavis.edu&quot;&gt;[ltble@ucdavis.edu]&lt;/a&gt;
    &lt;ul class=&quot;task-list&quot;&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement Update Feature&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Develop Net Worth function and chart&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Jennifer Liu&lt;/strong&gt; &lt;a href=&quot;zijliu@ucdavis.edu&quot;&gt;[zijliu@ucdavis.edu]&lt;/a&gt;
    &lt;ul class=&quot;task-list&quot;&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement user authentication&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement the backend of the Read Feature&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Jiawen Zhang&lt;/strong&gt; &lt;a href=&quot;nkzhang@ucdavis.edu&quot;&gt;[nkzhang@ucdavis.edu]&lt;/a&gt;
    &lt;ul class=&quot;task-list&quot;&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement the frontend of the Read Feature&lt;/li&gt;
      &lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;task-list-item-checkbox&quot; disabled=&quot;disabled&quot; checked=&quot;checked&quot; /&gt;Implement the frontend of the CashFlow Feature&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 03 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/12/03/ResCash.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/12/03/ResCash.html</guid>
      </item>
    
      <item>
        <title>Dive into Smart Contracts with GraphQL API 🌐</title>
        <description>&lt;p&gt;Unlock the power of smart contracts with our GraphQL API. This guide will walk you through setting up and using the API to interact with smart contracts seamlessly.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ResilientEcosystem/smart-contracts-graphql&quot;&gt;Smart Contracts GraphQL API&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Welcome to the world of smart contracts on ResilientDB! Our GraphQL API provides a streamlined way to interact with smart contracts, making it easier than ever to create, deploy, and execute contracts. Whether you’re a seasoned developer or just getting started, this guide will help you navigate the setup and usage of the Smart Contracts GraphQL API.&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Before diving in, ensure you have the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;ResilientDB&lt;/strong&gt;: A running instance of ResilientDB with the smart contracts service running. More information and setup instructions can be found here: &lt;a href=&quot;https://github.com/apache/incubator-resilientdb&quot;&gt;ResilientDB&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;ResContract CLI&lt;/strong&gt;: Install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rescontract-cli&lt;/code&gt; tool globally. Follow the instructions in the &lt;a href=&quot;https://github.com/apache/incubator-resilientdb-ResContract&quot;&gt;ResContract CLI Repository&lt;/a&gt; to install and configure it.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; rescontract-cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Node.js (version &amp;gt;= 15.6.0)&lt;/strong&gt;: Download and install Node.js version 15.6.0 or higher, as the application uses crypto.randomUUID() which was introduced in Node.js v15.6.0.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# You can check your Node.js version with:&lt;/span&gt;
node &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The prerequisites listed above can be installed using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSTALL.sh&lt;/code&gt; script:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x INSTALL.sh
   ./INSTALL.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check out this blog post to find out more about Smart Contracts on ResilientDB - &lt;a href=&quot;https://blog.resilientdb.com/2023/01/15/GettingStartedSmartContract.html&quot;&gt;Getting Started with Smart Contract on Nexres&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;setting-up-the-graphql-api&quot;&gt;Setting Up the GraphQL API&lt;/h2&gt;

&lt;h3 id=&quot;step-1-clone-the-repository&quot;&gt;Step 1: Clone the Repository&lt;/h3&gt;

&lt;p&gt;Start by cloning the repository to your local machine:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/yourusername/smart-contracts-graphql.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;smart-contracts-graphql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-2-install-dependencies&quot;&gt;Step 2: Install Dependencies&lt;/h3&gt;

&lt;p&gt;Install the necessary dependencies using npm:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Step 3: Start the Server&lt;/p&gt;

&lt;p&gt;Launch the GraphQL API server:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;node server.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Your server will be up and running on port 8400. Access the GraphQL API at http://localhost:8400/graphql.&lt;/p&gt;

&lt;h2 id=&quot;exploring-the-graphql-api&quot;&gt;Exploring the GraphQL API&lt;/h2&gt;
&lt;p&gt;Our API supports several operations to manage and interact with smart contracts. Here’s a look at what you can do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create Account&lt;/strong&gt;
Generate a new account using a configuration file.&lt;/p&gt;

&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createAccount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/config/file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Add Address&lt;/strong&gt;
Add an existing address to the configuration.&lt;/p&gt;

&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/config/file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0xAddressToAdd&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Compile Contract&lt;/strong&gt;
Compile a smart contract from a source file and save the output.&lt;/p&gt;

&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compileContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/source/file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Deploy Contract&lt;/strong&gt;
Deploy a compiled smart contract with specified parameters.&lt;/p&gt;

&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deployContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/config/file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/contract/file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contractName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;constructorArguments&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ownerAddress&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Execute Contract&lt;/strong&gt;
Execute a function of a deployed smart contract.&lt;/p&gt;

&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executeContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/config/file&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;senderAddress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contractAddress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;functionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;functionName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;functionArguments&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;sample-queries&quot;&gt;Sample Queries&lt;/h2&gt;
&lt;p&gt;Here are some practical examples to get you started:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create Account:
    &lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createAccount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;incubator-resilientdb/service/tools/config/interface/service.config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Add Address:
    &lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addAddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;incubator-resilientdb/service/tools/config/interface/service.config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Compile Contract:
    &lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compileContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;token.sol&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Deploy Contract:
    &lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deployContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;incubator-resilientdb/service/tools/config/interface/service.config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;compiled_contracts/MyContract.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;token.sol:Token&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Execute Contract:
    &lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executeContract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;incubator-resilientdb/service/tools/config/interface/service.config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0xfc08e5bfebdcf7bb4cf5aafc29be03c1d53898f1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;functionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;transfer(address,uint256)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x1be8e78d765a2e63339fc99a66320db73158a35a,100&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;advanced-usage-with-type-parameter&quot;&gt;Advanced Usage with Type Parameter&lt;/h2&gt;

&lt;p&gt;The API supports both “path” and “data” types for all mutations. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; parameter defaults to “path” and doesn’t have to be explicitly set.&lt;/p&gt;

&lt;h3 id=&quot;using-type-path-default&quot;&gt;Using type “path” (Default)&lt;/h3&gt;
&lt;p&gt;When using file paths, you don’t need to specify the type parameter:&lt;/p&gt;

&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;mutation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createAccount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;../incubator-resilientdb/service/tools/config/interface/service.config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;using-type-data&quot;&gt;Using type “data”&lt;/h3&gt;
&lt;p&gt;When passing configuration data directly, specify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type: &quot;data&quot;&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-graphql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;mutation&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;createAccount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;5 127.0.0.1 10005&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The response formats differ between “path” and “data” types:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;“path” type&lt;/strong&gt;: Returns structured JSON objects&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;“data” type&lt;/strong&gt;: Returns string responses with newlines&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sample-responses&quot;&gt;Sample Responses&lt;/h2&gt;

&lt;p&gt;Here are the expected responses for each mutation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Create Account Response:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;createAccount&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Add Address Response:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;addAddress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Address added successfully&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Compile Contract Response:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compileContract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Compiled successfully to /users/yourusername/smart-contracts-graphql/compiled_contracts/MyContract.json&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Deploy Contract Response:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;deployContract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ownerAddress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0x67c6697351ff4aec29cdbaabf2fbe3467cc254f8&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contractAddress&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0xfc08e5bfebdcf7bb4cf5aafc29be03c1d53898f1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;contractName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;token.sol:Token&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Execute Contract Response:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;executeContract&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Execution successful&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The Smart Contracts GraphQL API simplifies the process of interacting with smart contracts on ResilientDB. By following this guide, you can set up the API and start making API calls to manage and execute your smart contracts efficiently. If you have any questions or run into any issues, don’t hesitate to reach out for support.&lt;/p&gt;

&lt;p&gt;Happy coding! 🚀&lt;/p&gt;
</description>
        <pubDate>Fri, 13 Sep 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/09/13/SmartContractsGraphQL.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/09/13/SmartContractsGraphQL.html</guid>
      </item>
    
      <item>
        <title>Simplifying Database Interactions with ResDB ORM</title>
        <description>&lt;p&gt;&lt;strong&gt;ResDB ORM is a Python module designed to streamline interactions with ResilientDB’s key-value store database. It provides basic CRUD operations, making it easier for developers to integrate ResilientDB into their applications.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ResilientEcosystem/ResDB-ORM&quot;&gt;https://github.com/ResilientEcosystem/ResDB-ORM&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;-why-use-resdb-orm&quot;&gt;🌐 Why Use ResDB ORM?&lt;/h2&gt;

&lt;p&gt;Interacting with databases can often involve writing repetitive and complex code, especially when it comes to handling basic operations such as creating, reading, updating, and deleting data. The &lt;strong&gt;ResDB ORM&lt;/strong&gt; library aims to abstract these operations, allowing developers to focus on the business logic of their applications rather than the intricacies of database management.&lt;/p&gt;

&lt;p&gt;Here are some key advantages of using ResDB ORM:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Ease of Use&lt;/strong&gt;: ResDB ORM abstracts complex database interactions into simple Python methods.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Reduced Boilerplate Code&lt;/strong&gt;: Developers can perform CRUD operations without writing repetitive SQL queries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;-features-of-resdb-orm&quot;&gt;🔍 Features of ResDB ORM&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;CRUD Operations&lt;/strong&gt;: ResDB ORM provides methods for creating, reading, updating, and deleting records.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pythonic API&lt;/strong&gt;: The library offers a Python-friendly interface that seamlessly integrates with other Python-based projects.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Includes built-in error handling mechanisms to manage exceptions during database operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;-getting-started-with-resdb-orm&quot;&gt;👨🏻‍💻 Getting Started with ResDB ORM&lt;/h2&gt;

&lt;h3 id=&quot;step-1-installation&quot;&gt;&lt;strong&gt;Step 1: Installation&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;To start using ResDB ORM, follow the instructions available on the resdb-orm repository:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;https://github.com/ResilientEcosystem/ResDB-ORM/blob/main/README.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-2-setting-up-your-project&quot;&gt;&lt;strong&gt;Step 2: Setting Up Your Project&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Once ResDB ORM is installed, you can start using it in your Python project. Here’s a quick guide to get you started.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Importing ResDB ORM:
 Begin by importing the ResDB ORM module into your Python script:
    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;resdb_orm&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResDBORM&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Establishing a Connection:
 You need to establish a connection to your ResilientDB instance, update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.yaml&lt;/code&gt; file with the crow server details:
    &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ResDBORM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Performing CRUD Operations:
 With the connection established, you can now perform CRUD operations.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;Create&lt;/strong&gt;:
 To create a new record in the database, use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create&lt;/code&gt; method:
        &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;abc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;n&quot;&gt;create_response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Read&lt;/strong&gt;:
 To read data from the database, use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read&lt;/code&gt; method:
        &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;read_response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Update&lt;/strong&gt;:
 Updating an existing record is done using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt; method:
        &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;update_response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;def&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;456&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Delete&lt;/strong&gt;:
 To delete a record, use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delete&lt;/code&gt; method:
        &lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;delete_response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;-conclusion&quot;&gt;🎉 Conclusion&lt;/h2&gt;
&lt;p&gt;ResDB ORM simplifies database interactions for developers working with ResilientDB. By abstracting the complexities of database operations, it allows developers to focus on building robust and scalable applications. Whether you’re managing simple CRUD operations or complex version-based data, ResDB ORM provides a reliable and Pythonic solution.&lt;/p&gt;

</description>
        <pubDate>Sat, 24 Aug 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/08/24/ResDBORM.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/08/24/ResDBORM.html</guid>
      </item>
    
      <item>
        <title>Getting Started with ResContract CLI 🚀</title>
        <description>&lt;p&gt;&lt;strong&gt;This guide provides a comprehensive walkthrough of the ResContract CLI for managing smart contracts on ResilientDB. It covers installation, configuration, and usage of various commands to create accounts, compile contracts, deploy contracts, and execute contract functions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ResilientEcosystem/ResContract&quot;&gt;ResContract CLI GitHub Repository&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;-smart-contracts-on-resilientdb-today&quot;&gt;🌐 Smart Contracts on ResilientDB Today&lt;/h2&gt;

&lt;p&gt;ResilientDB now supports smart contracts, allowing developers to deploy and interact with decentralized applications seamlessly. Here’s an overview of the current state:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Simplified Workflow&lt;/strong&gt;: The ResContract CLI provides an intuitive interface for managing smart contracts.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Comprehensive Commands&lt;/strong&gt;: It includes commands for account creation, contract compilation, deployment, and execution.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Enhanced Logging&lt;/strong&gt;: Improved logging for better debugging and auditing.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;-getting-started-with-rescontract-cli&quot;&gt;📈 Getting Started with ResContract CLI&lt;/h2&gt;

&lt;h3 id=&quot;prerequisites&quot;&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Before you begin, ensure you have the following installed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Node.js (version &amp;gt;= 14)&lt;/strong&gt;: &lt;a href=&quot;https://nodejs.org/en/download/&quot;&gt;Download and install Node.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;npm&lt;/strong&gt;: Comes with Node.js. Ensure it’s up-to-date.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Solidity Compiler (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;solc&lt;/code&gt;)&lt;/strong&gt;: Required to compile smart contracts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;installing-solc&quot;&gt;Installing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;solc&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Linux (Ubuntu/Debian):&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;add-apt-repository ppa:ethereum/ethereum
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; solc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;macOS:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew update
brew upgrade
brew tap ethereum/ethereum
brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;solidity
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;ResilientDB&lt;/strong&gt;: A running instance with the smart contracts service enabled.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;installing-rescontract-cli&quot;&gt;Installing ResContract CLI&lt;/h2&gt;
&lt;h3 id=&quot;install-the-rescontract-cli-globally-using-npm&quot;&gt;Install the ResContract CLI globally using npm:&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; rescontract-cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;configuration&quot;&gt;Configuration&lt;/h2&gt;

&lt;p&gt;Before using the ResContract CLI, you &lt;strong&gt;must&lt;/strong&gt; set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResDB_Home&lt;/code&gt; environment variable or provide the path to your ResilientDB installation in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.yaml&lt;/code&gt; file. The CLI will &lt;strong&gt;not&lt;/strong&gt; prompt you for this path and will exit with an error if it’s not set.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Set ResDB_Home Environment Variable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResDB_Home&lt;/code&gt; environment variable to point to the directory where ResilientDB is installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linux/macOS:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ResDB_Home&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/incubator-resilientdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add the above line to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bashrc&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.zshrc&lt;/code&gt; file to make it persistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 2: Use a config.yaml File&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.yaml&lt;/code&gt; file in the same directory where you run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rescontract&lt;/code&gt; command or in your home directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.yaml&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;ResDB_Home&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/path/to/incubator-resilientdb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ensure the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResDB_Home&lt;/code&gt; path is correct.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The CLI checks for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.yaml&lt;/code&gt; in the current directory first, then in your home directory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;-using-the-rescontract-cli&quot;&gt;👨🏻‍💻 Using the ResContract CLI&lt;/h2&gt;

&lt;h3 id=&quot;command-overview&quot;&gt;Command Overview&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;create&lt;/code&gt;: Create a new account.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile&lt;/code&gt;: Compile a Solidity contract.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deploy&lt;/code&gt;: Deploy a smart contract.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execute&lt;/code&gt;: Execute a function within a deployed smart contract.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add_address&lt;/code&gt;: Add external addresses to the system.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list-deployments&lt;/code&gt;: List all deployed contracts.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clear-registry&lt;/code&gt;: Clear the deployment registry.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;creating-a-new-account&quot;&gt;Creating a New Account&lt;/h4&gt;

&lt;p&gt;Command:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract create &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; &amp;lt;path_to_config&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract create &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; ../incubator-resilientdb/service/tools/config/interface/service.config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sample Output:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0x3b706424119e09dcaad4acf21b10af3b33cde350
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;compiling-a-smart-contract&quot;&gt;Compiling a Smart Contract&lt;/h4&gt;

&lt;p&gt;Command:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract compile &lt;span class=&quot;nt&quot;&gt;--sol&lt;/span&gt; &amp;lt;inputFile.sol&amp;gt; &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; &amp;lt;outputFile.json&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract compile &lt;span class=&quot;nt&quot;&gt;--sol&lt;/span&gt; /users/gopuman/ResContract/token.sol &lt;span class=&quot;nt&quot;&gt;--output&lt;/span&gt; output.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sample Output:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;Compiled&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;successfully&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;output.json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;deploying-a-smart-contract&quot;&gt;Deploying a Smart Contract&lt;/h4&gt;

&lt;p&gt;Command:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract deploy &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; &amp;lt;configPath&amp;gt; &lt;span class=&quot;nt&quot;&gt;--contract&lt;/span&gt; &amp;lt;contract.json&amp;gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &amp;lt;contractName&amp;gt; &lt;span class=&quot;nt&quot;&gt;--arguments&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;parameters&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--owner&lt;/span&gt; &amp;lt;ownerAddress&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract deploy &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; ../incubator-resilientdb/service/tools/config/interface/service.config &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--contract&lt;/span&gt; output.json &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/users/gopuman/ResContract/token.sol:Token&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--arguments&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1000&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--owner&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0x3b706424119e09dcaad4acf21b10af3b33cde350&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sample Output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-vbnet&quot;&gt;owner_address: &quot;0x3b706424119e09dcaad4acf21b10af3b33cde350&quot;
contract_address: &quot;0xc975ab41e0c2042a0229925a2f4f544747fd66cd&quot;
contract_name: &quot;/users/gopuman/ResContract/token.sol:Token&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&quot;executing-a-smart-contract-function&quot;&gt;Executing a Smart Contract Function&lt;/h4&gt;

&lt;p&gt;Command:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract execute &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; &amp;lt;configPath&amp;gt; &lt;span class=&quot;nt&quot;&gt;--sender&lt;/span&gt; &amp;lt;senderAddress&amp;gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--contract&lt;/span&gt; &amp;lt;contractAddress&amp;gt; &lt;span class=&quot;nt&quot;&gt;--function-name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;functionSignature&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--arguments&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;parameters&amp;gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract execute &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; ../incubator-resilientdb/service/tools/config/interface/service.config &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--sender&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0x3b706424119e09dcaad4acf21b10af3b33cde350&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--contract&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0xc975ab41e0c2042a0229925a2f4f544747fd66cd&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--function-name&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;transfer(address,uint256)&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--arguments&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0x4847155cbb6f2219ba9b7df50be11a1c7f23f829,100&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sample Output:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;executed&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;successfully.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;adding-external-addresses&quot;&gt;Adding External Addresses&lt;/h4&gt;

&lt;p&gt;Command:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract add_address &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; &amp;lt;path&amp;gt; &lt;span class=&quot;nt&quot;&gt;--external-address&lt;/span&gt; &amp;lt;address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract add_address &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; ../incubator-resilientdb/service/tools/config/interface/service.config &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;--external-address&lt;/span&gt; 0xExternalAddress
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;listing-deployed-contracts&quot;&gt;Listing Deployed Contracts&lt;/h4&gt;

&lt;p&gt;Command:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract list-deployments
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract list-deployments
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command displays all deployed contracts with their owner addresses, contract names, and contract addresses.&lt;/p&gt;

&lt;h4 id=&quot;clearing-the-registry&quot;&gt;Clearing the Registry&lt;/h4&gt;

&lt;p&gt;Command:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract clear-registry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Example:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rescontract clear-registry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; This command permanently removes all deployment tracking information.&lt;/p&gt;

&lt;h2 id=&quot;-deployment-registry&quot;&gt;📋 Deployment Registry&lt;/h2&gt;

&lt;p&gt;The ResContract CLI automatically tracks all deployed contracts in a registry file located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.rescontract_deployed_contracts.json&lt;/code&gt;. This registry provides several benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Duplicate Prevention&lt;/strong&gt;: Prevents deploying the same contract with the same owner and name&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Contract Tracking&lt;/strong&gt;: Maintains a record of all deployed contracts with their addresses&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Easy Management&lt;/strong&gt;: Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list-deployments&lt;/code&gt; to view all contracts and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clear-registry&lt;/code&gt; to reset&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The registry stores the following information for each deployment:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Owner address&lt;/li&gt;
  &lt;li&gt;Contract name&lt;/li&gt;
  &lt;li&gt;Contract address&lt;/li&gt;
  &lt;li&gt;Deployment timestamp&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;-advanced-usage-and-tips&quot;&gt;📝 Advanced Usage and Tips&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Logging&lt;/strong&gt;: The ResContract CLI logs important events and errors to ~/.rescontract-logs/cli.log.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: If you encounter errors, check the logs for detailed information.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Permissions&lt;/strong&gt;: Ensure you have the necessary permissions to execute commands and access files.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Registry Management&lt;/strong&gt;: Use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;list-deployments&lt;/code&gt; to track your deployed contracts and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clear-registry&lt;/code&gt; to reset when needed.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Duplicate Prevention&lt;/strong&gt;: The registry automatically prevents deploying the same contract with the same owner and name.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Updating ResContract CLI&lt;/strong&gt;: Keep your CLI up-to-date by running:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm update &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; rescontract-cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;-contributing&quot;&gt;🤝 Contributing&lt;/h2&gt;

&lt;p&gt;We welcome contributions! Please read our Contributing Guidelines to get started.&lt;/p&gt;

&lt;h2 id=&quot;-license&quot;&gt;📄 License&lt;/h2&gt;

&lt;p&gt;This project is licensed under the Apache License&lt;/p&gt;

&lt;h2 id=&quot;-additional-resources&quot;&gt;📚 Additional Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;ResilientDB Documentation: &lt;a href=&quot;https://github.com/apache/incubator-resilientdb&quot;&gt;ResilientDB GitHub Repository&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Solidity Documentation: &lt;a href=&quot;https://docs.soliditylang.org/en/v0.8.27/&quot;&gt;Solidity Official Site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Tue, 16 Jul 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/07/16/SmartContractsCLI.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/07/16/SmartContractsCLI.html</guid>
      </item>
    
      <item>
        <title>ResChat</title>
        <description>&lt;h2 id=&quot;1-project-description&quot;&gt;1. Project Description&lt;/h2&gt;
&lt;h3 id=&quot;11-overview&quot;&gt;1.1 Overview&lt;/h3&gt;
&lt;p&gt;In today’s life, when we try to send a message on most chat software, the message will first be sent to the central server,
and then forwarded to the target user by the central server.
The disadvantage of this is that all data will be captured and stored by the central server,
which greatly increases the risk of data leakage and leakage of private information.
Now, we will create a decentralized chat system based on the ResilientDB blockchain.
This decentralized chat system does not store any personal information,
and only the sender and recipient can encrypt and decrypt the message during the transmission of the message.&lt;/p&gt;

&lt;h3 id=&quot;12-key-features&quot;&gt;1.2 Key Features&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;Decentralized Architecture: Our system avoids the need for a central server. All messages are transmitted through ResilientDB blockchain.&lt;/li&gt;
  &lt;li&gt;Security: By using the combined encryption algorithm(RSA + AES), we can ensure that information cannot be easily cracked during blockchain transmission. Only the sender and recipient of the message can use their keys to encrypt and decrypt&lt;/li&gt;
  &lt;li&gt;Privacy-first Approach: User data is never stored on any central server. No chat history will be stored.&lt;/li&gt;
  &lt;li&gt;Open-source: To ensure utmost transparency and security, our system is fully open-source, allowing community participation and review.&lt;/li&gt;
  &lt;li&gt;Flexibility: Users can create their own ResilientDB blockchain and use ResChat as an intranet chatting software, or users can connect to the main blockchain and use ResChat as an internet chatting software.&lt;/li&gt;
  &lt;li&gt;Extremely low disk space usage: Users only need to store their private key locally, and everything else is stored in the blockchain.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;2-overall-idea&quot;&gt;2. Overall Idea&lt;/h2&gt;
&lt;h3 id=&quot;21-message-and-page&quot;&gt;2.1 Message and Page&lt;/h3&gt;
&lt;p&gt;The key of messages is a custom class called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Page&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Page&lt;/code&gt; serves as a container to store and transfer messages.
Each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Page&lt;/code&gt; has 20 messages and each message has 7 different fields. When a page is full, a new page will be created.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Receiver’s public key: Who will receive this message, base on this we can identify who is the sender and receiver of this message.&lt;/li&gt;
  &lt;li&gt;Message type: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEXT&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FILE&lt;/code&gt; to identify how to process this message.&lt;/li&gt;
  &lt;li&gt;Time stamp: When this message been sent.&lt;/li&gt;
  &lt;li&gt;Message type extension: Only in use when message type is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FILE&lt;/code&gt; to store file name and extension such like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testFile.pdf&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Encrypted message: If message type is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TEXT&lt;/code&gt;, this field will store the encrypted text string.
If message type is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FILE&lt;/code&gt;, this field will store a key(A ResilientDB key) and the corresponding value is IPFS filesystem’s hashes and their metadata that.
In this way, it will not give a high pressure to the internet, and computing power. Users can choose to download the file or not.&lt;/li&gt;
  &lt;li&gt;Encrypted AES key with sender’s RSA public key: Use sender’s RSA public key to encrypt randomly generated AES key.
So, sender can decrypt AES key with his/her RSA private key.&lt;/li&gt;
  &lt;li&gt;Encrypted AES key with receiver’s RSA public key: Use receiver’s RSA public key to encrypt the AES key. Only receiver can decrypt this message.
In this approach, sender and receiver can both encrypt and decrypt certain message with their own RSA private keys without expose the keys to each other.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both sender and receiver will obtain some shared pages. This project is using kv service of the ResilientDB,
and the command line instructions are set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; and get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt;.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; part constructed with two fields &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page name&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page number&lt;/code&gt;.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page name&lt;/code&gt; is constructed by sender and receiver’s username(sorted in ASCII order) to ensure that both receiver and sender will have the same page name.
Page name will never change throughout the chatting. On the other hand, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;page number&lt;/code&gt; starts at 1,
and it will increase by 1 everytime the page is full.
ResChat will load most recent two pages everytime user start up the client(current page and current page -1) In this way,
all chat history are stored on the chain(ResilientDB) and user can load as many as previous chatting history as he/she wants.&lt;/p&gt;

&lt;h3 id=&quot;22-encryptiondecryption&quot;&gt;2.2 Encryption/Decryption&lt;/h3&gt;
&lt;p&gt;This project uses RSA + AES as the encryption algorithm. The message will be first encrypted by a randomly generated 16 bytes(128 bits) AES key.
Then, this AES key will be encrypted by 2048 bits RSA public key(AES key will be encrypted twice, one with sender’s public key, another with receiver’s public key).
In this approach, ResChat can achieve not only secure text messages transfer but also secure file transfer(RSA can not encrypt a string that is too long).
&lt;img src=&quot;/assets/images/reschat/encryption.svg&quot; alt=&quot;encryption diagram&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;3-how-to-run&quot;&gt;3. How to run&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.anaconda.com/download#downloads&quot;&gt;Install Anaconda&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install Bazel 5.0.0 on &lt;a href=&quot;https://bazel.build/install/ubuntu&quot;&gt;Ubuntu&lt;/a&gt; or &lt;a href=&quot;https://bazel.build/install/os-x&quot;&gt;Mac&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Setup Anaconda Environment
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;conda create --name YOUR_ENV_NAME python=3.8
conda activate YOUR_ENV_NAME
cd ResChat
pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Build Bazel(Make sure run bazel build command with the Anaconda environment just crated )
    &lt;pre&gt;&lt;code class=&quot;language-angular2html&quot;&gt;cd ResChat
bazel build :pybind_kv_so
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;Run Front-end Service
    &lt;pre&gt;&lt;code class=&quot;language-angular2html&quot;&gt;cd frontend
npm run install
npm run start
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
  &lt;li&gt;Run Back-end Service
    &lt;pre&gt;&lt;code class=&quot;language-angular2html&quot;&gt;python3 http_request.py
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;4-some-screenshot&quot;&gt;4. Some screenshot&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;Login page
&lt;img src=&quot;/assets/images/reschat/login_page.png&quot; alt=&quot;Login Page&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;Chatting page
&lt;img src=&quot;/assets/images/reschat/chatting_page.png&quot; alt=&quot;Login Page&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
        <pubDate>Fri, 31 May 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/05/31/ResChat.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/05/31/ResChat.html</guid>
      </item>
    
      <item>
        <title>ResLenses</title>
        <description>&lt;h2 id=&quot;project-overview&quot;&gt;Project Overview:&lt;/h2&gt;
&lt;p&gt;The Res-Lenses page is an in browser UTXO heatmap visualization of the ResilientDB network and the Ethereum network. 
It utilizes the three.js 3D graphics library for the browser to visualize transaction activity across all possible pairs of addresses collected, allowing for the viewing of transaction activity in various configurations to best find patterns in UTXO movement.&lt;/p&gt;

&lt;h5 id=&quot;browsers-this-is-known-to-work-in-others-may-have-difficulty-microsoft-edge-and-google-chrome&quot;&gt;Browsers this is known to work in (others may have difficulty): Microsoft Edge and Google Chrome&lt;/h5&gt;

&lt;p&gt;You may access the ResLenses app &lt;a href=&quot;https://res-lenses.resilientdb.com&quot;&gt;here&lt;/a&gt; and view the demo &lt;a href=&quot;https://www.youtube.com/watch?v=IzGxG4_WkDQ&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;front-end-overview&quot;&gt;Front End Overview&lt;/h2&gt;

&lt;h3 id=&quot;getting-started-on-page-launch&quot;&gt;Getting Started on Page Launch&lt;/h3&gt;
&lt;p&gt;Opening the page up, you will initially view the top left corner of a very large grid representing transactions on the ResilientDB network. As you mouse around, you will notice green and blue lines pinpointing the block you are hovering. That block represents the transaction activity between two address as shown on the top left tab. As you will also notice, addresses implicity line the X and Y axis of the grid, and each block represents activity of the intersecting addresses. If the activity between two addresses is non-grey, then there is some activity, and double clicking on that block will pull up a tab on the left. In that tab, you can see all UTXO sent from one address to the other in a &lt;em&gt;From&lt;/em&gt; and &lt;em&gt;To&lt;/em&gt; relationship.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/res-lenses/reslenses default getting started.png&quot; alt=&quot;defaultview&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;scene-controls&quot;&gt;Scene Controls&lt;/h3&gt;

&lt;p&gt;The basis of the visualization is with the Three.js library, which allows for the creation and viewing of 3D scenes in the browser. The camera is fixed to face down on the grid and can be navigated using purely mouse controls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Movement:&lt;/strong&gt;
Hold click and drag aronud to move through the 2D Grid. Clicking the &lt;em&gt;Return to Origin&lt;/em&gt; button in the bottom left will return you to the top left corner of the grid.
Chunks of blocks will load and unload as you move around, you may even see some chunks load in if moving quickly enough. Mouse dragging does not work when the mouse is hovering over UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Selection:&lt;/strong&gt;
Blocks that are moused over will display their From and To addresses in the top left tab with a summation of the transactions between the two addresses.
Double clicking a block will focus and highlight it and open a tab to the left that displays all the transactions that occurred. Regular clicking anywhere will de-focus the block.&lt;/p&gt;

&lt;h3 id=&quot;bottom-bar-buttons&quot;&gt;Bottom Bar Buttons&lt;/h3&gt;

&lt;p&gt;At the bottom of the page is a bar with five buttons. These allow for various configurations for visualizing the same data. Though the data can also be swapped between ResilientDB and the Ethereum Mainnet. Aside from the data selection button, all configurations are computer client side.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/res-lenses/reslenses_bottom_bar.png&quot; alt=&quot;bottombar&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Return to Origin:&lt;/strong&gt;
Reset the position of the camera to the top left corner. If view mode is in &lt;em&gt;bar&lt;/em&gt; mode, this simply moves the camera back to the far left.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data:&lt;/strong&gt; 
Selects the source of the data to view. Default is &lt;em&gt;ResDB&lt;/em&gt;.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResDB&lt;/code&gt;: ResilientDB data. All transactions that have occurred on the ResilientDB network with amounts involved.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ethereum&lt;/code&gt;: Sampled data collected on the ethereum network. A sample of 48,000 transactions from the last 24 hours and all the addresses involved. Typically will have more addresses than transactions. Note that this will take a second to load.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: With Ethereum, there are typically more addresses than transactions, resulting in very sparse looking data. It is recommnded that this data is viewed with the &lt;em&gt;Largest Transaction&lt;/em&gt; sorting scheme and or with the &lt;em&gt;Symmetry&lt;/em&gt; setting set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; to bring forth more activity to the top left.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sort:&lt;/strong&gt; 
Selects the sorting method for the order in which the adddresses appear from left/top to right/bottom. Default is &lt;em&gt;Transactions Total&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Transactions Total&lt;/code&gt;: Addresses are sorted by the sum total of UTXO sent out.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Number of Transaction&lt;/code&gt;: Addresses are sorted by the total number of transactions they’ve sent out.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Largest Transaction&lt;/code&gt;: The address-to-address activity blocks are sorted first, then the addresses belonging to the largest activity are added first. This typically results in a diagonal pattern of blocks that slowly shrink from top left to bottom right.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Ethererum, data would typically look like this with default settings:
&lt;img src=&quot;/assets/images/res-lenses/reslenses_eth.png&quot; alt=&quot;ethdata&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There is basically nothing for a far range. You would need to search extensively to find the activity. But with &lt;em&gt;Sort by Largest Transaction&lt;/em&gt;, you will get something like this:
&lt;img src=&quot;/assets/images/res-lenses/reslenses_eth_sort_by_largest.png&quot; alt=&quot;ethdata_sorted&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View:&lt;/strong&gt; 
Selects the viewing method of transaction activity. Default is &lt;em&gt;Grid&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Grid&lt;/code&gt;: This is the primary way to view transactions. Displays all pairwise activity between addresses as a 2D grid, forming a physical adjacency matrix of addresses to addresses with blocks as the activity between them.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bar&lt;/code&gt;: This flattens all the transactions into a single block along the y axis, changing the view into a bar graph along a single axis. This gives the total activity of each address, with details on all transactions still available on the focus tab to the left when bars are selected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the sparse Ethereum data with bar view. We can more aptly view the activity of the addresses.
&lt;img src=&quot;/assets/images/res-lenses/reslenses_bar_view.png&quot; alt=&quot;barview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Symmetry:&lt;/strong&gt;
Toggle for whether or not to combine transactions sent out and transactions recieved when computing blocks. Default it &lt;em&gt;False&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt;: Transactions as asymmetrical, the transactions sent from and to and address are distinct.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;: Transactions are symmetrical, as in there is no distinction between transactions sent from or to an address, they are the same and just considered transactions between addresses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is how the ResilientDB data looks with &lt;em&gt;Sort by Largest Transaction&lt;/em&gt; with &lt;em&gt;Symmetry&lt;/em&gt; set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt;
&lt;img src=&quot;/assets/images/res-lenses/reslenses_asymmetric.png&quot; alt=&quot;asym&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here is the same configuration except with &lt;em&gt;Symmetry&lt;/em&gt; set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt;. Notice how seemingly more activity shows up as transactions sent to and transactions recieved from addresses are compounded together to form the blocks. This is an alternative way to reduce visual sparsity in the data as it increases the value of many blocks while also giving new blocks to addresses that only receive transactions.
&lt;img src=&quot;/assets/images/res-lenses/reslenses_symmetric.png&quot; alt=&quot;sym&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;back-end-overview&quot;&gt;Back End Overview&lt;/h2&gt;

&lt;h3 id=&quot;server&quot;&gt;Server&lt;/h3&gt;
&lt;p&gt;The backend is a Node.js Express app that runs on the ResilientDB cloud. It procures data from the ResilientDB and Ethereum Mainnet networks at regular intervals, processes and stores the data on the server, and provides endpoints for Res-Leneses to access that processed data.&lt;/p&gt;

&lt;h3 id=&quot;data-collection&quot;&gt;Data collection&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ResilientDB:&lt;/strong&gt;
Data is collected at a one hour interval from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://crow.resilientdb.com/v1/transactions&lt;/code&gt; endpoint. This contains all transactions that have ever occurred on the ResilientDB network and is then processed for only From/To transactions with UTXO amounts. Processing cleans out the data of invalid JSON and bad transactions down to a set of addresses and transactions. A single file holds the processed ResilientDB data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ethereum Mainnet:&lt;/strong&gt;
Data is collected at a 30 minute inverval using the &lt;a href=&quot;https://bitquery.io&quot;&gt;Bit Query API&lt;/a&gt;. Using this, the server collects 1000 transactions at a time per interval containing only transactions from that interval. Each interval correlates to a file holding transactions for that interval. Transactions 24 hours old are discarded every interval. This leaves the newest 48,000 transactions available at all times. Due to API limitations, this is the most data that can be collected per day. Processing is very simple with some naming tweaks as the API already provides relatively clean data.&lt;/p&gt;

&lt;h3 id=&quot;endpoints&quot;&gt;Endpoints&lt;/h3&gt;
&lt;p&gt;There are two endpoints provided by the backend which the Res-Lenese front end utilizes, each to supply data for the ResilientDB network and the Ethereum Mainnet. The format of the data is listed as a list of all addresses involved and then all transactions. All configuration and reorganization of data is done client side on the front end.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://res-lenses-backend.resilientdb.com/getData_RESDB&lt;/code&gt;: This provides the processed ResilientDB file containing all transactions with transactions times set as DateTime numbers.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://res-lenses-backend.resilientdb.com/getData_ETH&lt;/code&gt;: This compiles all the data from all the Ethereum data files and send them. Transaction times are set as DateTime strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Transaction data is relatively simple, they contain the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;From&lt;/code&gt;: Address UTXO is sent from&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;To&lt;/code&gt;: Address UTXO is sent to&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Amount&lt;/code&gt;: Amount  of UTXO sent&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Timestamp&lt;/code&gt;: Time of transaction (Number for RESDB and String for ETH)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what you should see if you try to directly access &lt;a href=&quot;https://res-lenses-backend.resilientdb.com/getData_RESDB&quot;&gt;https://res-lenses-backend.resilientdb.com/getData_RESDB&lt;/a&gt;.
&lt;img src=&quot;/assets/images/res-lenses/reslenses_backend.png&quot; alt=&quot;backend&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 21 May 2024 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2024/05/21/ResLenses.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2024/05/21/ResLenses.html</guid>
      </item>
    
      <item>
        <title>Using the ResilientDB Desktop Wallet</title>
        <description>&lt;p&gt;&lt;strong&gt;This is a blog to help get started with the Desktop Wallet for Tx/Rx built on the Resilient DB network&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#connecting-to-resilientdb&quot;&gt;&lt;strong&gt;Connecting to Resilient DB&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#building-the-frontend&quot;&gt;&lt;strong&gt;Building the Frontend&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#securing-user-accounts&quot;&gt;&lt;strong&gt;Securing User Accounts&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#familiarizing-yourself-with-your-wallet&quot;&gt;&lt;strong&gt;Familiarizing Yourself with Your Wallet&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#familiarizing-yourself-with-your-wallet&quot;&gt;&lt;strong&gt;Future Plans for ResilientDB Desktop Wallet&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;connecting-to-resilient-db&quot;&gt;Connecting to Resilient DB&lt;/h2&gt;

&lt;p&gt;There are a host of ways we can connect to the Resilient DB decentralized system:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Crow HTTP server&lt;/li&gt;
  &lt;li&gt;Python SDK&lt;/li&gt;
  &lt;li&gt;GraphQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We chose the last option, GraphQL, as it it offers a high level and easy to implement API for a fast development cycle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mini SDK and Third Party Libraries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s hard to use raw HTTP requests for accessing GraphQL. It’s difficult to read and complicated to understand GraphQL documents.&lt;/p&gt;

&lt;p&gt;To facilitate our development, we built a mini sdk using typescript and the open source library &lt;a href=&quot;https://www.npmjs.com/package/graphql-request&quot;&gt;graphql-request&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mutations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The primary mutation we implemented is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postTransaction&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;postTransation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;appName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;appVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gql&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`
        mutation { postTransaction(data: {
            operation: &quot;CREATE&quot;
            amount: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
            signerPublicKey: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;
            signerPrivateKey: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;
            recipientPublicKey: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;
            asset: &quot;&quot;&quot;{
                        &quot;data&quot;:  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,
                    }&quot;&quot;&quot;
            }) 
            {
                id
            }
        }
    `&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;postTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PostTransactionResult&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;postTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postTransaction&lt;/code&gt; is responsible for sending RoKs between user accounts.&lt;/p&gt;

&lt;p&gt;Here we allow for the developer to pass in arguments related relevant for sending tokens.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amount&lt;/code&gt; – the total number to tokens to send&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recipientPublicKey&lt;/code&gt; – the public key of the recipient&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata&lt;/code&gt; – optional metadata to pass in the transaction&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; – other data to pass into the asset field&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Queries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While we did implement quries such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getTransaction&lt;/code&gt;, the primary method we use to retrieve transactions data is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getFilteredTransactions&lt;/code&gt; query.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;getFilteredTransactions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;ownerPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;FilteredTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gql&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`
        query {getFilteredTransactions(filter: {
            ownerPublicKey: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ownerPublicKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;,
            recipientPublicKey: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;recipientPublicKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;
        }) {
            id
            version
            amount
            metadata
            operation
            asset
            publicKey
            uri
            type
        }}
    `&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetFilteredTransactionsResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 
        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFilteredTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getFilteredTransactions&lt;/code&gt; allow us to retrieve the list of transactions either sent or received by our user.&lt;/p&gt;

&lt;p&gt;We retrieve sent transactions by passing in the user’s public key as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ownerPublicKey&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Alternatively we retrieve transactions the user received by passing in their public key as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recipientPublicKey&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Processing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The GraphQL queries and transactions do not directly allow us to view the user’s wallet contents.&lt;/p&gt;

&lt;p&gt;To do so we need additional processing.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;getPastTransactions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;WalletGetTransactionsResult&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactionsSent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;graphqlClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFilteredTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactionsReceived&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;graphqlClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFilteredTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;transactionsSent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;transactionsReceived&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This utility function allows us to retrieve all of the users transactions.&lt;/p&gt;

&lt;p&gt;We pass in the user’s public key as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ownerPublicKey&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recipientPublicKey&lt;/code&gt; separately to receive both transactions sent and received.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;getWalletContent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactionsSent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactionsReceived&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getPastTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;transactionsReceived&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;transactionsSent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To actually calculate the amount of RoKs in the user’s wallet:&lt;/p&gt;

&lt;p&gt;We first add up the amount of RoKs received in all transactions, then subtract the amount of RoKs sent from the wallet to calculate the final amount.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We choose to use the GraphQL API in connecting to the Resilient DB instance due to it’s simplicity and use of use.&lt;/p&gt;

&lt;p&gt;We created a Mini-SDK implementing functions for querying and mutating transactions.&lt;/p&gt;

&lt;p&gt;We established a method for calculating the total amount of RoKs in the user’s wallet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://blog.resilientdb.com/2023/09/21/ResVault.html&quot;&gt;ResDB API&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://cloud.resilientdb.com/graphql&quot;&gt;Playground&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;building-the-frontend&quot;&gt;Building the Frontend&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Technologies Used&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;React.js&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Electron.js&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;GraphQL&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Mantine&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Theme Forest Template (Hexadash)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why React.js?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Given the time constraint that we had, we had to make sure that we chose frameworks that all of our members were comfortable with! 
As all of us had experience with React before, we decided to go ahead with React, as opposed to other JavaScript frameworks like Angular or Vue.&lt;/p&gt;

&lt;p&gt;We were also debating as to whether we should use React.js or React Native. 
However, once we eventually settled on the fact that we were going to make a Desktop app, and not a mobile app, React.js was an easy choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Electron.js&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React.js is normally used for locally hosting a website that follows HTTP/HTTPS standards. 
However, we were aiming for a Desktop app, to make it easier to use for users. 
Similar to how Discord uses Electron to convert their web app into a desktop app, we used Electron.js on top of our React.js code to develop a desktop app instead of a web app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Communicating between the frontend and backend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Given that we wanted to make our app functional, it was vital that there was a clear path for the frontend to talk to the backend. 
We did this using GraphQL. We called the GraphQL from the frontend, which then executed our queries on the backend, and efficiently returned the data back to the frontend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample backend call for sending a transaction&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;postTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;metaData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;metaData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;CSS templates/components&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once again, given the time constraint, we wanted to focus on the functionality of our app more than the design.
As a result, we went on &lt;a href=&quot;https://themeforest.net/&quot;&gt;Theme Forest&lt;/a&gt;, and searched for potential templates we could use. 
We were looking for templates that had built-in designs for a dashboard and a sign in page, as that was the main part of our app.&lt;/p&gt;

&lt;p&gt;We also used &lt;a href=&quot;https://mantine.dev/&quot;&gt;React components&lt;/a&gt; to make it easier to write CSS. 
Mantine has built in components for common things used in websites such as cards, checkboxes, or confirmation modals.&lt;/p&gt;

&lt;p&gt;Overall, using these external libraries had both positives and negatives. 
As the theme forest library we chose had a huge number of files, it was hard to simply integrate their code into our repository. 
The library had a lot of dependencies and functions in other files that they relied on.
As a result, we ended up only using the Theme Forest library for our sign in page, and wrote the CSS for the dashboard ourselves, with help from Mantine as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example of a Mantine &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TextInput&lt;/code&gt; component&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TextInput&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;placeholder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Enter amount&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;onChange&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;setAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;currentTarget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;rightSectionPointerEvents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;rightSection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;CloseButton&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aria&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Clear input&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onClick&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;withErrorStyles&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;required&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;amountError&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Please fill out this field&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;securing-user-accounts&quot;&gt;Securing User Accounts&lt;/h2&gt;

&lt;p&gt;If you’re wondering how we made our passwords secured, you’ve come to the right place! Our code was written in Nodejs.&lt;/p&gt;

&lt;p&gt;You can access the 4 open source libraries that we implemented by importing the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nacl&lt;/code&gt;: Able to generate a new pair of public and private keys:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nacl&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;tweetnacl&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base58&lt;/code&gt;: Encodes or Decodes our password and returns a string&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import base58 from &quot;bs58&quot;;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crypto&lt;/code&gt;: Used to implement SHA512 and AES-256-CBC to hash and cipher/decipher passwords&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import crypto from &quot;crypto&quot;;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keytar&lt;/code&gt;: Acts like a keychain where we can store passwords and access them safe and easily&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import keytar from &quot;keytar&quot;;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve imported all the necessary libraries, let’s dive into the functions that we’ve created to understand how we did it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generating Keys&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Recalling from before, we were able to create a key pair with the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nacl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With the help of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nacl&lt;/code&gt;, we will have two outputs with our variable pair, one being a public key and the other being a secret key.&lt;/p&gt;

&lt;p&gt;Accessing them through the pair will get us our public and private keys.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createKeyValPair&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nacl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keyPair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// keypair&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base58&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//public key&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base58&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;secretKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// private key&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Hashing Password&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the help of the crypto library, we are able to use SHA512 to create a hash object and update the password and lastly putting it into hexadecimal format.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hashPassword&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;crypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createHash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;sha512&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;digest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// hashes the password&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cipher and Decipher Password&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similarly like SHA512, we used the crypto library to use AES-256-CBC.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;We first converted the password to a buffer out of ASCII.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We make sure that the password is exactly 32 bytes so it doesn’t throw any errors.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We create the cipher object using AES-256-CBC along with our paddedkeybytes and cipherIV.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Lastly, we update the cipher with the private key in UTF-8 encoding and produce the encrypted private key in hexadecimal format.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;encryptPrivateKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;keybytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ascii&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keybytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;keybytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Password must be between 1 and 32 bytes long&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;paddedKeyBytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keybytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cipher&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;crypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createCipheriv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;aes-256-cbc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;paddedKeyBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;cipherIV&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;encryptedPrivateKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;cipher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cipher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The Decipher functions reverses the ciphering process:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;decryptPrivateKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;keybytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ascii&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;paddedKeyBytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keybytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;decipher&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;crypto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createDecipheriv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;aes-256-cbc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;paddedKeyBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;cipherIV&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;decipher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;encryptedPrivateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;decipher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Keytar&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After the user creates the account, the keys get saved into the keychain using keytar&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;writeUserAccountToFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;keytar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setPassword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;appName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;passwordHash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;passwordHash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;encryptedPrivateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;encryptedPrivateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;familiarizing-yourself-with-your-wallet&quot;&gt;Familiarizing Yourself with Your Wallet&lt;/h2&gt;

&lt;p&gt;When you first launch our desktop wallet, things might look a little bit confusing.
But don’t worry! We’ve made our wallet simple to understand and navigate. However, if you’re still lost, you’ve come to the right place to learn more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sign in / Register&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When launched, the application will display the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://drive.google.com/file/d/1WgptYKE2sdNOLPpamPdG8dq7JfeMuXqM/view?usp=sharing&quot; alt=&quot;Login/Signup Page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see, you have the option to register a new account with us, or log-in to an existing account in our database.&lt;/p&gt;

&lt;p&gt;We’ll assume that you are a new user that has just registered an account. Once your account is created, you’ll be directed to your Dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your dashboard is the main hub of your wallet. It’s where all of the wallet’s functionality can be accessed.&lt;/p&gt;

&lt;p&gt;Here’s what the dashboard of a newly registered user looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://drive.google.com/file/d/1RfeU4Ozq3sFGNzNeFvRjh0J6UrMddRFw/view?usp=sharing&quot; alt=&quot;Initial Dashboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There are 3 important sections of your dashboard (circled in red above)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Your Past Transactions&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Send a Transaction&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;View Keys&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Your Past Transactions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This section of the application displays all previous transactions that your account has made. 
Naturally, for a new account, this section would be empty. However, as you accumulate transactions, they will start to display here, and you can scroll through all of them horizontally.&lt;/p&gt;

&lt;p&gt;For example, this is what the dashboard for a highly-active account may look like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://drive.google.com/file/d/1DU0CugQzmPNNmaLJuK4rLPBFdiFcDAsU/view?usp=sharing&quot; alt=&quot;Older Dashboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Send a Transaction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are 2 things you must have for a successful transaction:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Your recipient’s public key&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The amount that you want to transfer&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a third (optional) spot, reserved for metadata. This could include a brief description of the transaction, ex. Groceries or Pizza.&lt;/p&gt;

&lt;p&gt;To send a transaction, you’ll have to ask your recipient for their public key first. Once you have that, do the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Paste the recipients public key&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Enter the transfer amount&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add a description if you’d like&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then hit ‘Send’ and you’ll see a pop-up indicating a successful transfer.&lt;/p&gt;

&lt;p&gt;To view the details of the transaction, just refresh the page, and it will pop up under ‘Your Past Transactions’.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View Your Account’s Keys&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ‘View Keys’ section displays some important information about your account. It holds sensitive information such as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Account Balance&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Public Key&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Private Key&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The account balance shows the money your account holds. It updates every time you make a transaction.&lt;/p&gt;

&lt;p&gt;Your public key is what you give to others so they can pay you. Only give someone your public key if you know them and if they want to initiate a transfer to your account.&lt;/p&gt;

&lt;p&gt;Your private key is sensitive information that is unique to your account and your account only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NEVER&lt;/strong&gt; give someone your private key. To ensure that your private key isn’t easily viewable, we’ve added a button that, when clicked, either shows or hides the private key for extra security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logging Out&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To log out, simply click the button at the top right. This will securely save your information in our database which can easily be re-accessed by logging in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrapping Up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once again, thanks for choosing to use our Desktop Wallet for your financial needs. We hope this post gave you a better understanding of the features of your wallet to help you use it to its maximum potential.&lt;/p&gt;

&lt;p&gt;If you have any further questions, don’t hesitate to contact us!&lt;/p&gt;

&lt;h2 id=&quot;future-plans-for-resilientdb-desktop-wallet&quot;&gt;Future Plans for ResilientDB Desktop Wallet&lt;/h2&gt;

&lt;p&gt;In the dynamic world of digital currencies, 
the ResilientDB Desktop Wallet stands as a beacon of innovation. 
As we envision the future, our mission is to enhance accessibility, security, and user experience. 
Let’s delve into the exciting potential plans that await our desktop application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App Store Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gone are the days of complex installations! Soon, users will find our desktop wallet on the app store, simplifying access for everyone. 
No more command lines or dependencies—just a seamless experience for all. We hope to soon have our application displayed right on the front page of the App Store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Going Mobile&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine the freedom to manage your digital assets anytime, anywhere. 
Introducing the mobile version of our ResilientDB Desktop Wallet—a sleek and intuitive design tailored for on-the-go users.
The mobile app mirrors the desktop features with enhanced mobile-friendly interfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Currency Exchange at Your Fingertips&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We’re breaking barriers by introducing a currency exchange option directly on the dashboard. 
Users can effortlessly convert or trade their funds, opening the door to financial flexibility. 
Registering your bank account seamlessly links your financial world with our wallet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fortifying Security&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Protecting your assets is paramount. 
Our enhanced security features include a authentication via email or phone, ensuring each login is secure. 
Additionally, receive instant transaction alerts via email, offering real-time updates on your wallet activity.&lt;/p&gt;

&lt;p&gt;As we embark on this journey, the ResilientDB Desktop Wallet is poised to revolutionize the digital currency landscape.
Join us in this exciting chapter—try our wallet, share your thoughts, and be a part of the future we’re crafting together. 
The possibilities are endless, and the future is now.&lt;/p&gt;
</description>
        <pubDate>Wed, 20 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/12/20/DesktopWallet.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/12/20/DesktopWallet.html</guid>
      </item>
    
      <item>
        <title>Using the ResilientDB TypeScript SDK</title>
        <description>&lt;p&gt;Introduction to ResilientDB TypeScript SDK: Building Robust Applications&lt;/p&gt;

&lt;p&gt;The digital era demands robust solutions that can handle data with precision, security, and flexibility. Blockchain technology is championing this revolution, and at the heart of many innovative applications is ResilientDB, a versatile distributed ledger that offers both trust and transparency.&lt;/p&gt;

&lt;p&gt;In this in-depth look, we will explore the ResilientDB TypeScript SDK, an essential toolkit for developers seeking to leverage the ResilientDB platform in their JavaScript and TypeScript applications. Through the integration of GraphQL, the SDK simplifies interactions with the ResilientDB server, enabling easy queries and mutations to manage transactions effectively.&lt;/p&gt;

&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#what-is-resilientdb&quot;&gt;&lt;strong&gt;What Is ResilientDB?&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#prerequisites&quot;&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#installation&quot;&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#introducing-the-sdk&quot;&gt;&lt;strong&gt;SDK&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#clients&quot;&gt;&lt;strong&gt;Clients&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#resilientdb-client-methods&quot;&gt;&lt;strong&gt;ResilientDB Client Methods&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#types&quot;&gt;&lt;strong&gt;Types&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#sdk-demo-application&quot;&gt;&lt;strong&gt;SDK Demo Application&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#use-the-sdk-in-6-easy-steps&quot;&gt;&lt;strong&gt;Use the SDK in 6 easy steps&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#real-world-value-and-implications&quot;&gt;&lt;strong&gt;Real-World Value and Implications&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;what-is-resilientdb&quot;&gt;What Is ResilientDB?&lt;/h2&gt;

&lt;p&gt;ResilientDB is a distributed ledger infrastructure that emphasizes resilience, scalability, and decentralized control. It allows applications to perform transactions in a distributed environment with trust and transparency being paramount.&lt;/p&gt;

&lt;h2 id=&quot;npm-package-resilientdb-javascript-sdk&quot;&gt;NPM Package: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resilientdb-javascript-sdk&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Before diving deep into the codebase, let’s address how to get the SDK into your project. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resilientdb-javascript-sdk&lt;/code&gt; is readily available on the NPM registry and can be included in your project with ease.&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;h3 id=&quot;setup-node-v18&quot;&gt;Setup Node v18&lt;/h3&gt;
&lt;p&gt;Ensure you have Node v18 installed&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; node &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
v18.17.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setup-resilientdb-graphql-run-locally&quot;&gt;Setup ResilientDB-GraphQL (Run Locally)&lt;/h3&gt;
&lt;p&gt;If you would like to use your own ResilientDB replica set, you must run the ResilientDB stack along with ResilientDB-GraphQL.
Instructions can be found &lt;a href=&quot;https://blog.resilientdb.com/2023/09/21/ResVault.html&quot;&gt;here&lt;/a&gt;
Otherwise, point the client to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://cloud.resilientdb.com&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;p&gt;To install the SDK, run the following command in your project directory:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;resilientdb-javascript-sdk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;introducing-the-sdk&quot;&gt;Introducing the SDK&lt;/h2&gt;

&lt;p&gt;The SDK comes with three main modules that form its core functionality. Each plays a significant role in ensuring a streamlined interface for communicating with the ResilientDB server.&lt;/p&gt;

&lt;h3 id=&quot;clients&quot;&gt;Clients&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FetchClient&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AxiosClient&lt;/code&gt; are two interchangeable network clients that ResilientDB utilizes to make HTTP requests to the ResilientDB server.&lt;/p&gt;

&lt;h4 id=&quot;fetchclient-fetchclientts&quot;&gt;FetchClient (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FetchClient.ts&lt;/code&gt;)&lt;/h4&gt;

&lt;p&gt;A lightweight client using the Fetch API. It’s optimal for environments where size and simplicity are key.&lt;/p&gt;

&lt;p&gt;Example of initializing a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FetchClient&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ResilientDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FetchClient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;resilientdb-javascript-sdk&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetchClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FetchClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;axiosclient-axiosclientts&quot;&gt;AxiosClient (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AxiosClient.ts&lt;/code&gt;)&lt;/h4&gt;

&lt;p&gt;A feature-rich client based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;axios&lt;/code&gt;. This client is suited for those who may need interceptors, progress indicators, or other advanced features provided by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;axios&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example of initializing an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AxiosClient&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ResilientDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AxiosClient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;resilientdb-javascript-sdk&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axiosClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AxiosClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;resilientdb-client-resilientdbts&quot;&gt;ResilientDB Client (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResilientDB.ts&lt;/code&gt;)&lt;/h3&gt;

&lt;p&gt;The SDK’s main class provides a user-friendly interface to the ResilientDB server’s GraphQL API. It includes methods for retrieving, filtering, and posting transactions, as well as generating cryptographic key pairs.&lt;/p&gt;

&lt;h3 id=&quot;core-types-typests&quot;&gt;Core Types (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;types.ts&lt;/code&gt;)&lt;/h3&gt;

&lt;p&gt;Defines the interfaces and types used throughout the SDK, ensuring type safety and developer experience.&lt;/p&gt;

&lt;h2 id=&quot;resilientdb-client-methods&quot;&gt;ResilientDB Client Methods&lt;/h2&gt;

&lt;p&gt;Here’s a detailed look at each method provided by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResilientDB&lt;/code&gt; client.&lt;/p&gt;

&lt;h3 id=&quot;transaction-retrieval-methods&quot;&gt;Transaction Retrieval Methods&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Method&lt;/th&gt;
      &lt;th&gt;Input Parameters&lt;/th&gt;
      &lt;th&gt;Output&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getTransaction&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requestId: string&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise&amp;lt;RetrieveTransaction&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Retrieves a single transaction by its unique ID.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getAllTransactions&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;-&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise&amp;lt;RetrieveTransaction[]&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Fetches all transactions.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getFilteredTransactions&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter?: FilterKeys&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise&amp;lt;RetrieveTransaction[]&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Retrieves transactions that match the given filtering criteria.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#filterkeys&quot;&gt;&lt;strong&gt;FilterKeys&lt;/strong&gt;&lt;/a&gt;: A type that includes optional fields for filtering transactions by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ownerPublicKey&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recipientPublicKey&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;transaction-mutation-methods&quot;&gt;Transaction Mutation Methods&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Method&lt;/th&gt;
      &lt;th&gt;Input Parameters&lt;/th&gt;
      &lt;th&gt;Output&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;postTransaction&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transaction: PrepareAsset&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise&amp;lt;CommitTransaction&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Posts a new transaction to the ledger.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updateTransaction&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transaction: UpdateAsset&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise&amp;lt;RetrieveTransaction&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Updates an existing transaction.&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;updateMultipleTransaction&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transactions: UpdateAsset[]&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise&amp;lt;RetrieveTransaction[]&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Updates multiple transactions at once.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#prepareasset&quot;&gt;&lt;strong&gt;PrepareAsset&lt;/strong&gt;&lt;/a&gt;: A type representing the necessary information to prepare a transaction for posting.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#updateasset&quot;&gt;&lt;strong&gt;UpdateAsset&lt;/strong&gt;&lt;/a&gt;: A type used for detailing the specifications required to update a transaction.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#committransaction&quot;&gt;&lt;strong&gt;CommitTransaction&lt;/strong&gt;&lt;/a&gt;: Represents the output of posting a new transaction, which includes, at minimum, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; of the committed transaction.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;key-generation-method&quot;&gt;Key Generation Method&lt;/h3&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Method&lt;/th&gt;
      &lt;th&gt;Input Parameters&lt;/th&gt;
      &lt;th&gt;Output&lt;/th&gt;
      &lt;th&gt;Description&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;static generateKeys()&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;-&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ publicKey: string; privateKey: string}&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Generates a pair of public and private keys for signing transactions.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;types&quot;&gt;Types&lt;/h2&gt;

&lt;h3 id=&quot;networkclient&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NetworkClient&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NetworkClient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TReturn&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TReturn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;retrievetransaction&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RetrieveTransaction&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RetrieveTransaction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// integer&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;committransaction&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CommitTransaction&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CommitTransaction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;prepareasset&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PrepareAsset&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PrepareAsset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;CREATE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;signerPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;signerPrivateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;updateasset&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UpdateAsset&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;UpdateAsset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// int&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;signerPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;signerPrivateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;filterkeys&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FilterKeys&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FilterKeys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;ownerPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;keys&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Keys&lt;/code&gt;&lt;/h3&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;privateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;sdk-demo-application&quot;&gt;SDK Demo Application&lt;/h2&gt;

&lt;p&gt;Included within the SDK repository is a demo React application that showcases the SDK’s capabilities. The app allows users to filter transactions, post new transactions, and explore the core features of the ResilientDB TypeScript SDK.&lt;/p&gt;

&lt;h2 id=&quot;use-the-sdk-in-6-easy-steps&quot;&gt;Use the SDK in 6 easy steps&lt;/h2&gt;

&lt;h3 id=&quot;step-1-project-setup-and-sdk-installation&quot;&gt;Step 1: Project Setup and SDK Installation&lt;/h3&gt;

&lt;p&gt;Set up a new TypeScript project and install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resilientdb-javascript-sdk&lt;/code&gt; package as well as TypeScript and the necessary types for Node.js.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;resilientdb-ts-example
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;resilientdb-ts-example
npm init &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;
npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;resilientdb-javascript-sdk
npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;typescript ts-node @types/node &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tsconfig.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;compilerOptions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;es2018&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;commonjs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;strict&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;esModuleInterop&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-2-generating-keys&quot;&gt;Step 2: Generating Keys&lt;/h3&gt;

&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.ts&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ResilientDB&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;resilientdb-javascript-sdk&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Generate public and private keys&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ResilientDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;generateKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Public Key: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Private Key: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-3-initializing-the-client&quot;&gt;Step 3: Initializing the Client&lt;/h3&gt;

&lt;p&gt;Continue editing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.ts&lt;/code&gt; to initialize the client:&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ResilientDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FetchClient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;resilientdb-javascript-sdk&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Initialize the client&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resilientDBClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ResilientDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://cloud.resilientdb.com&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FetchClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-4-fetching-and-filtering-transactions&quot;&gt;Step 4: Fetching and Filtering Transactions&lt;/h3&gt;

&lt;p&gt;Add functions to fetch all transactions and filter based on certain criteria.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Fetch all transactions&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getAllTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resilientDBClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getAllTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;All Transactions:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Fetch transactions with filters&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getFilteredTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ownerPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// recipientPublicKey can also be specified here.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resilientDBClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getFilteredTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Filtered Transactions:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;getAllTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;getFilteredTransactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-5-posting-and-updating-transactions&quot;&gt;Step 5: Posting and Updating Transactions&lt;/h3&gt;

&lt;p&gt;Add functions to post a new transaction and then update it.&lt;/p&gt;

&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Post a new transaction&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactionData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;CREATE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;signerPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;signerPrivateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// For the sake of example, sending to self&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Initial transaction&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transaction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resilientDBClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;postTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;transactionData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Transaction posted:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// We&apos;ll need the transaction ID to update it next&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Update the created transaction&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updateTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;transactionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updateData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Updated amount&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;signerPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;signerPrivateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;privateKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;recipientPublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;publicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Still sending to self&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Updated transaction data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updatedTransaction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resilientDBClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;updateTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;updateData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Transaction updated:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updatedTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;runDemo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;transactionId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updateTransaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;transactionId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;runDemo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-6-running-the-project&quot;&gt;Step 6: Running the Project&lt;/h3&gt;

&lt;p&gt;You can now run the project from the terminal:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx ts-node index.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;real-world-value-and-implications&quot;&gt;Real-World Value and Implications&lt;/h2&gt;

&lt;p&gt;By simplifying the integration and interaction with the ResilientDB server, the SDK opens the door to a plethora of applications. Whether you’re developing a finance app that requires ledger capabilities or seeking the immutability of blockchain for asset tracking, the ResilientDB TypeScript SDK is a capable starting point.&lt;/p&gt;

&lt;p&gt;The versatility in choosing between the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FetchClient&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AxiosClient&lt;/code&gt; ensures developers have the liberty to pick a client that best suits their specific needs, whether they prioritize speed and minimalism or extensive features.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The ResilientDB TypeScript SDK stands as a testament to the possibilities when modern web technologies meet blockchain principles. Through its approachable interface and adaptable architecture, the SDK demonstrates how applications can be built with resilience at their core, ready to scale and secure transactions across a distributed network.&lt;/p&gt;

&lt;p&gt;Whether you’re an experienced blockchain developer or a newcomer to distributed ledger technology, the SDK provides the necessary tools to interface with the ResilientDB platform with confidence and ease.&lt;/p&gt;
</description>
        <pubDate>Sun, 17 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/12/17/TypeScriptSDK.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/12/17/TypeScriptSDK.html</guid>
      </item>
    
      <item>
        <title>The Emergence of Echo in the Gig Economy</title>
        <description>&lt;p&gt;The gig economy, with giants like Uber, Lyft, and Doordash, has transformed the employment landscape, offering flexibility and convenience. But with these benefits come challenges, especially in identity verification. The authenticity of contractors is crucial in maintaining operational integrity and user trust. Echo arises as a solution to streamline identity verification, enhancing trust and efficiency in the gig economy.&lt;/p&gt;

&lt;h3 id=&quot;challenges-of-current-verification-systems&quot;&gt;Challenges of Current Verification Systems&lt;/h3&gt;

&lt;p&gt;Present systems face issues like inconsistent processes, technological limitations, and privacy concerns. Scaling these systems is often inefficient, leading to bottlenecks. Echo addresses these problems by offering a universal, technologically advanced, and secure solution.&lt;/p&gt;

&lt;h3 id=&quot;echos-solution-facial-recognition-and-blockchain-integration&quot;&gt;Echo’s Solution: Facial Recognition and Blockchain Integration&lt;/h3&gt;

&lt;p&gt;Echo integrates advanced facial recognition and ResilientDB blockchain technology, providing a robust framework for identity verification. Our system leverages the MXFace API for accurate facial recognition and mints NFTs on the blockchain for secure and transparent contractor history.&lt;/p&gt;

&lt;h4 id=&quot;mxface-api-call-to-compare-2-faces&quot;&gt;MXFace API call to compare 2 faces:&lt;/h4&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;optionsFaceCompare&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_apiUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;verify&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;subscriptionkey&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_subscriptionKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;encoded_image1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base64SingleFace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;encoded_image2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;base64MultipleFace&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;rejectUnauthorized&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

  

&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;optionsFaceCompare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Response /verify&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;
    &lt;img src=&quot;/assets/images/echo/verification.png&quot; alt=&quot;Echo Verification Process&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;User submits an image to be verified and minted
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;system-design-simplicity-and-security&quot;&gt;System Design: Simplicity and Security&lt;/h3&gt;

&lt;p&gt;The user interface of Echo focuses on ease of use, featuring a straightforward landing and login page. The system ensures privacy by keeping personal data like photos and personal information off the blockchain, only using them for identity comparison. Additionally, the use of Google Authentication allows for a streamlined and accessible way to view and verify and induvidudal.&lt;/p&gt;

&lt;h3 id=&quot;technical-implementation-mongodb-resilientdb-and-react&quot;&gt;Technical Implementation: MongoDB, ResilientDB, and React&lt;/h3&gt;

&lt;p&gt;Echo employs MongoDB for secure data storage, ResilientDB blockchain for verification tokens, and a React-based ledger page for user interaction. This blend of technologies ensures security, transparency, and ease of use.&lt;/p&gt;

&lt;h4 id=&quot;mongodb-api-call-for-creating-an-account-using-google-authentication&quot;&gt;MongoDB API call for creating an account using Google Authentication:&lt;/h4&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createPerson&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;convos&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emptyFields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;emptyFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;emptyFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emptyFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Please fill in all fields&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emptyFields&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newPerson&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;convos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;user_id&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;newPerson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This code allows us to store user information, in order to keep track of wallets using private and public keys, and to mint and access the NFTs later.&lt;/p&gt;

&lt;h4 id=&quot;python-sdk-calls-to-interact-with-resilientdb-flask&quot;&gt;Python SDK calls to interact with ResilientDB (Flask):&lt;/h4&gt;

&lt;h5 id=&quot;creating-a-new-key&quot;&gt;Creating a New Key&lt;/h5&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/create_key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;  
    &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;generate_keypair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;key_dict&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;private&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;public&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;key_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dumps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key_json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This route is responsible for generating a new key pair.&lt;/p&gt;

&lt;p&gt;It uses the generate_keypair function to create a new private and public key.&lt;/p&gt;

&lt;p&gt;The keys are then formatted into a JSON response, providing the user with their unique keys.&lt;/p&gt;

&lt;h5 id=&quot;minting-an-nft&quot;&gt;Minting an NFT&lt;/h5&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/create_token&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signer_public_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signer_private_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_public_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;service&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adminkeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adminkeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;user_public_key&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;utc_time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;utcnow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;utc_time_str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utc_time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;isoformat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Resdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db_root_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;token_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;start_time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;utc_time_str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&quot;service&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;prepared_token_tx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prepare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CREATE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;signers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signer_public_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;recipients&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_public_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)],&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fulfilled_token_tx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fulfill&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prepared_token_tx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;private_keys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signer_private_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send_commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fulfilled_token_tx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;response_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;transaction_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fulfilled_token_tx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Token created successfully&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jsonify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This POST route is crucial for creating a token that represents a particular service.&lt;/p&gt;

&lt;p&gt;It extracts necessary data like the service name, public and private keys of the platform(Uber, Doordash, etc …) and user (contractor/driver) from the incoming JSON request.&lt;/p&gt;

&lt;p&gt;A timestamp is added to the token data, ensuring each token is unique and time-bound (so we can determine when an induvidual is verified).&lt;/p&gt;

&lt;p&gt;The token is then prepared and fulfilled using ResilientDB’s transaction functionalities (contacting the Crow server that ResDB is running on), securely associating the token with the user’s public key.&lt;/p&gt;

&lt;p&gt;Upon successful creation, it returns a JSON response with the transaction ID and a success message.&lt;/p&gt;

&lt;h5 id=&quot;retrieving-minted-nfts&quot;&gt;Retrieving Minted NFTs&lt;/h5&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/retrieve&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_nft&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;nft_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;retrieve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;txid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nft_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jsonify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nft_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jsonify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;NFT not found&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;404&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This POST route is designed for retrieving Non-Fungible Token (NFT) data.&lt;/p&gt;

&lt;p&gt;It accepts a transaction ID (from the user’s wallet) and uses it to query the ResilientDB (again, the Crow server that ResDB is running on) for the corresponding NFT.&lt;/p&gt;

&lt;p&gt;If the NFT is found, the data is returned in JSON format; otherwise, an error message is sent.&lt;/p&gt;

&lt;p&gt;Once the entire process of minting and retrieving has been completed, the wallet is visible on the ledger page.&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;
    &lt;img src=&quot;/assets/images/echo/ledger.png&quot; alt=&quot;Echo Verification Process&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Echo Ledger Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;why-choose-echo&quot;&gt;Why Choose Echo?&lt;/h3&gt;

&lt;p&gt;The choice of technologies like ResilientDB and MongoDB is rooted in their ability to offer transparency, security, and scalability. These attributes align with the dynamic needs of the gig economy, ensuring a robust and reliable verification process.&lt;/p&gt;

&lt;h3 id=&quot;evaluation-methodology&quot;&gt;Evaluation Methodology&lt;/h3&gt;

&lt;p&gt;Echo integrates the Mxface facial recognition model, accessed via API, for identity verification. This process is central to our solution’s effectiveness in the gig economy.&lt;/p&gt;

&lt;h3 id=&quot;the-future-of-echo&quot;&gt;The Future of Echo&lt;/h3&gt;

&lt;p&gt;Looking ahead, Echo aims to partner with leading gig delivery companies, enhancing the ledger with proprietary data. Our vision includes incorporating biometric data into the verification process for heightened security and accuracy.&lt;/p&gt;

&lt;h3 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h3&gt;

&lt;p&gt;Echo stands as a comprehensive solution to the challenges in the gig economy, offering a transparent, secure, and efficient system for identity verification. By leveraging blockchain technology and advanced facial recognition, Echo redefines trust and safety standards in this dynamic sector.&lt;/p&gt;

&lt;h3 id=&quot;next-steps-expanding-and-refining-echo&quot;&gt;Next Steps: Expanding and Refining Echo&lt;/h3&gt;

&lt;p&gt;Our journey includes evolving the verification process and forging partnerships to broaden Echo’s impact in the gig economy. Staying at the forefront of technological innovation, we aim to refine and advance our system to meet and anticipate the evolving industry needs.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Further Resources and Demonstrations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For a deeper dive into Echo’s technical aspects, visit our &lt;a href=&quot;https://github.com/ashw24/echoresDB&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;View a &lt;a href=&quot;https://www.youtube.com/watch?v=8_GzAwVrBy8&quot;&gt;demo&lt;/a&gt; of Echo’s functionality and user interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;
</description>
        <pubDate>Sun, 17 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/12/17/The_Emergence_of_Echo_in_the_Gig_Economy.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/12/17/The_Emergence_of_Echo_in_the_Gig_Economy.html</guid>
      </item>
    
      <item>
        <title>CrypGo, Accessibility on the Go!</title>
        <description>&lt;p&gt;CrypGo serves as a wallet for the Global-Scale Sustainable Blockchain Fabric ResilientDB. With CrypGo you can easily access your ResilientDB account, and submit and view transactions on the Go!&lt;/p&gt;

&lt;h1 id=&quot;crypgo-features-and-screens&quot;&gt;CrypGo Features and Screens:&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Page 1: Login Page&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Login Page is a pivotal feature of CrypGo, designed to enhance user experience and security. Users can enter their login information, ensuring their public key remains constant with each login. We think this is a significant improvement over the existing Res-wallet system as it creates a key each time a user creates an ID. This static key approach simplifies the user experience by eliminating the need to track changing keys, thus reducing potential confusion and enhancing security. Our focus here is on creating an intuitive and secure login process that aligns with the best practices of user interface and experience design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page 2: Registration Page&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Registration Page marks the beginning of a user’s journey with CrypGo. It’s here where users set up their accounts by choosing a username and password. A unique public key is generated during registration, linked to the user’s login information. This key is crucial for user identification and transaction validation within the ResilientDB blockchain. We aim to make this process as streamlined and user-friendly as possible, ensuring that even those new to blockchain technology can easily navigate through the setup. This page is designed to be straightforward yet secure, prioritizing ease of use while maintaining rigorous data security standards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page 3: Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Dashboard serves as the central hub of the CrypGo app, listing all features and functionalities. It includes user-centric buttons like “Get All Transactions” and “Set Transactions,” which lead to detailed transaction pages. The design of the Home Page emphasizes ease of navigation, allowing users to access various functionalities of the app effortlessly. The integration of these features is aimed at providing a comprehensive overview of the app’s capabilities, enhancing the user experience. Our goal is to ensure that this page is not only aesthetically pleasing but also intuitive, enabling users to utilize the app’s full potential with minimal effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page 4: Get All Transactions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ‘Get All Transactions’ page is a critical component of CrypGo, offering users a detailed view of their transaction history. This includes information on the amount, date, and time of each transaction. Users can interact with this page by selecting specific transactions for more detailed views or updating them as required. This feature is designed to provide a transparent and comprehensive record of users’ blockchain activities, enhancing their understanding and control over their digital assets. The interface is planned to be user-friendly, ensuring that even those unfamiliar with blockchain technology can easily navigate and understand their transaction history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page 5: Set Transactions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ‘Set Transactions’ page allows users to initiate new transactions within the ResilientDB blockchain network. Here, users can input the transaction amount and submit it for processing. This feature is integral to the app, empowering users to engage with the blockchain actively. Our focus is on ensuring this process is intuitive, fast, and secure, catering to the needs of both seasoned blockchain users and newcomers. The page will be designed to provide clear instructions and feedback, ensuring a smooth transaction process. This includes error handling and confirmations to enhance user confidence and satisfaction with every transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page 6: Update Transactions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On the ‘Update Transactions’ page, users can modify existing transactions, a feature that adds flexibility and control over their digital assets. This process generates a new public key for the updated transaction, ensuring security and traceability. The design of this page is centered around user convenience and clarity, providing an easy-to-navigate interface for updating transaction details. It’s a testament to our commitment to offering a dynamic and adaptable platform that responds to the evolving needs of our users. By allowing transaction updates, we ensure that CrypGo remains a versatile and user-centric tool in the rapidly changing landscape of digital transactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Page 7: Get Transactions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ‘Get Transactions’ page is dedicated to providing detailed information on individual transactions. Users can view key details such as Transaction ID, Amount, and Time created. This functionality is crucial for users who need to closely monitor and analyze specific transactions for various purposes, including auditing, reporting, or simply keeping track of their digital asset movements. The design of this page focuses on clarity and ease of access, presenting information in a user-friendly format. By offering a granular view of transactions, CrypGo empowers users with the information they need to make informed decisions regarding their digital assets.&lt;/p&gt;

&lt;h1 id=&quot;results&quot;&gt;Results:&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://github.com/resilientdb/blog/assets/91711219/55935afa-f172-4e99-9703-6e3fa13cc968&quot; alt=&quot;Untitled design (2)&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;how-does-crypgo-work&quot;&gt;How does CrypGo work?&lt;/h1&gt;

&lt;p&gt;CrypGo is directly connected to the Python SDK which is connected to the Crow HTTPS server which communicates with ResilientDB. Our Application runs similar to how ResVault works.&lt;/p&gt;

&lt;h1 id=&quot;running-the-application&quot;&gt;Running the Application&lt;/h1&gt;

&lt;h2 id=&quot;installing-and-setting-up-the-expo-go-app&quot;&gt;Installing and Setting Up the Expo Go App&lt;/h2&gt;

&lt;p&gt;Install the Expo Go App from the App Store.
Expo Go is an application for iOS and Android that allows developers to quickly preview and test React Native apps on mobile devices during development. It connects with the Expo CLI to load up projects instantly, streamlining the development process by enabling live coding and debugging directly on a smartphone or tablet.&lt;/p&gt;

&lt;h2 id=&quot;running-the-app---crypgo&quot;&gt;Running the App - CrypGo&lt;/h2&gt;
&lt;h3 id=&quot;installing-and-setting-up-xcode&quot;&gt;Installing and Setting Up Xcode&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;Navigate and Download Xcode on the App Store on your iOS laptop devices.&lt;/li&gt;
  &lt;li&gt;Download the required packages for your designated mobile and laptop.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;creating-a-new-reactnative-project&quot;&gt;Creating a New ReactNative Project&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;Fork from our repository and then run the following command on an IDE:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;The command used in the Node.js environment to install packages from the Node Package Manager (npm) registry. It reads the package.json file in the current directory to automatically install all the dependencies listed there, allowing developers to easily manage and share packages across different projects.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Navigate to the Frontend file using this command:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd Frontend/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;running-the-expo-simulator-app&quot;&gt;Running the Expo Simulator App&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;Simply type this command:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx expo start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Since we are an iOS app, select “i”:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;i
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;You are now all set to use the CrypGo App. With the CrypGo App now installed, you’re ready to embark on a seamless cryptocurrency tracking experience.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;In conclusion, CrypGo presents a user-friendly gateway to ResilientDB, revolutionizing the management of user transactions at the tip of their fingers. With seamless account creation and secure login procedures, CrypGo empowers users to engage effortlessly with ResilientDB. Detailed transaction logging keeps everything transparent, helping users easily monitor their accounts. This mobile app marks a significant step towards accessibility, security, and convenience addition to the ResilientDB network. Looking forward, CrypGo aims to further enhance user experience, through the addition of a settings screen, and metadata to the SDK.&lt;/p&gt;

&lt;h1 id=&quot;future-work&quot;&gt;Future Work&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Add more functions to check balance and view received transactions.&lt;/li&gt;
  &lt;li&gt;Adding metadata to each transaction such as time, date and name of transactions.&lt;/li&gt;
  &lt;li&gt;Adding user customisation to the mobile app such as the Settings page, and theme changes and making it more user-friendly&lt;/li&gt;
  &lt;li&gt;Improving the design implementations of the mobile application&lt;/li&gt;
  &lt;li&gt;Making a web application for CrypGo !!&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sun, 17 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/12/17/CrypoGo.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/12/17/CrypoGo.html</guid>
      </item>
    
      <item>
        <title>Arrayán - A Resilient Blockchain-based Food Supply Chain</title>
        <description>&lt;p&gt;Arrayán is a revolutionary web application seamlessly integrated with the ResilientDB blockchain fabric, empowering industries to achieve end-to-end transparency in tracking products, by-products, and their historical journey across the supply chain. Tailored especially for the food sector, Arrayán offers an intuitive platform to visualize the lifecycle of goods from farm to retail, fostering accountability and trust at every stage.&lt;/p&gt;

&lt;p&gt;Beyond traditional tracking, Arrayán redefines traceability as a driver of sustainability. The platform introduces a forward-thinking mechanism to reclaim and repurpose food by-products—such as stems, peels, and seeds—by securely documenting their origin, usage intent, and transfer timelines on the blockchain. This verifiable, tamper-proof data unlocks opportunities to scale the reuse of by-products as raw materials in sectors like cosmetics and clean energy production.&lt;/p&gt;

&lt;p&gt;With seamless blockchain-backed agreements and instant access to tracking data through lightweight tools, Arrayán ensures a frictionless experience for producers, buyers, and consumers alike. It transforms traceability into a dynamic ecosystem for innovation, collaboration, and resource optimization—all while championing a more transparent and circular economy.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/logo.png&quot; alt=&quot;Logo&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Picture describing Arrayán
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;useful-links&quot;&gt;Useful Links&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;Website is live at &lt;a href=&quot;https://arrayan.resilientdb.com/&quot;&gt;https://arrayan.resilientdb.com/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Code Repository - &lt;a href=&quot;https://github.com/ResilientApp/Arrayan&quot;&gt;https://github.com/ResilientApp/Arrayan&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Presentation Slides - &lt;a href=&quot;https://github.com/apache/incubator-resilientdb-blog/blob/main/presentations/Arrayan.pdf&quot;&gt;https://github.com/apache/incubator-resilientdb-blog/blob/main/presentations/Arrayan.pdf&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;We have modified the existing ResilientDB-GraphQL APIs catering to the needs of a blockchain-based food supply chain and added a new API to fetch the products in the forked &lt;a href=&quot;https://github.com/Amoolya-Reddy/ResilientDB-GraphQL&quot;&gt;repo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;problem-identified&quot;&gt;Problem Identified&lt;/h2&gt;

&lt;p&gt;Scientific evidence supports the potential of food by-products as valuable sources of molecules for the cosmetic industry. However, their utilization has been limited as the chemical composition and yield variability are influenced by factors such as variety, environmental conditions, and the methods of cultivation and processing. Currently, there is a lack of comprehensive traceability for most by-products, hindering the recording of crucial data. This absence of information results in a lack of standardization, contributing to uncertain yields and increased costs associated with the extraction and purification processes. A parallel challenge is observed in the use of by-products for hydrogen production and other upcycling applications.&lt;/p&gt;

&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;

&lt;p&gt;This web application plays a pivotal role in meticulously tracing the generation of by-products at each stage. This granular information is instrumental in standardizing by-products, facilitating their upcycling on a larger scale, and pinpointing key areas where substantial amounts of by-products are produced. Our traceability-for-sustainability model not only offers a blueprint for companies to embrace circular economy models but also ensures compliance with regulations such as the Food Safety Modernization Act.
The primary objective of the Food Safety Modernization Act is to enhance food safety. In the event of a foodborne incident, rapid tracking within 24 hours is mandated. The regulation emphasizes the necessity for companies to share information seamlessly across their supply chain, and blockchain emerges as a powerful tool to streamline this process.
Arrayán stands as more than just a tracing tool; it is a catalyst for the food industry to not only meet regulatory requirements but also to potentially increase profitability from their by-products and reduce its environmental footprint.
&lt;strong&gt;During the development of the application, we established a partnership with the teaching and research winery of UC Davis. To kick-start our journey, we are delivering a Proof of Concept utilizing the data generously provided by our collaborators.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Arrayán also aligns with Senate Bill 1883, offering a pathway to compliance with this additional regulation.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;technology-stack&quot;&gt;Technology Stack&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Web Application: Built using React JS, &lt;a href=&quot;https://github.com/facebook/create-react-app&quot;&gt;Create React App&lt;/a&gt;, &lt;a href=&quot;https://react.dev/&quot;&gt;React Official Website&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Backend: ResilientDb GraphQL server, Python&lt;/li&gt;
  &lt;li&gt;Database: Powered by &lt;a href=&quot;https://resilientdb.com/&quot;&gt;ResilientDB&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Theme: BLK Design System React, &lt;a href=&quot;https://demos.creative-tim.com/blk-design-system-pro-react/?_ga=2.58939236.839164262.1702005007-948628969.1702005007#/presentation&quot;&gt;BLK Design System Pro React&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;

&lt;p&gt;The sequence diagrams of the inventory manager, product tracker, smart Contract and chrome extension below give an overview of the function triggers and the process of upload/claim.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inventory Manager&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/seq_diagram_inventory.jpg&quot; alt=&quot;Home Page&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Sequence Diagram of Inventory Manager
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Product Tracker&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/seq_diagram_tracker.jpg&quot; alt=&quot;Home Page&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. Sequence Diagram of Product Tracker and Claim Workflow
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Smart Contract&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/seq_diagram_smartContract.png&quot; alt=&quot;Home Page&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. Sequence Diagram of Smart Contract
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tracker Chrome Extension&lt;/strong&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/seq_diagram_chromeExtension.png&quot; alt=&quot;Home Page&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Sequence Diagram of Tracker Chrome Extension 
    &lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;Upon breaking the overall architecture, the user is authenticated and will be provided with a dashboard, current inventory, and product tracker.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Dashboard fetches data from the Google Firestore and displays the real-time data in sync with the ResilientDb.&lt;/li&gt;
  &lt;li&gt;After uploading the inventory from an Excel file or providing the manual input, transactions are constructed to the Schema required for the GraphQL server of ResilientDb, and POST_TRANSACTION mutation is used to save the data to the ResilientDb. Upon a successful response, transaction IDs are stored in the Google Firestore. Only transaction IDs and metadata are saved outside the ResilientDb, ensuring data transparency on the global-scale blockchain fabric — ResilientDb.&lt;/li&gt;
  &lt;li&gt;When a user searches for a product, the relevant transaction IDs are retrieved from Google Firestore, and point queries are made to ResilientDb. The complete food supply chain is displayed, detailing each stage. The system also allows users to claim byproducts generated during the process. Claimed byproducts are recorded as transactions on ResilientDb, with their transaction IDs securely stored in Google Firestore.&lt;/li&gt;
&lt;/ol&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/hld.jpg&quot; alt=&quot;Home Page&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 6. High level design of Arrayan
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;features-and-user-guide&quot;&gt;Features and User Guide&lt;/h2&gt;

&lt;h3 id=&quot;home-page&quot;&gt;Home Page&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Provides a general overview of the solution offered through the website.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/homepage.png&quot; alt=&quot;Home Page&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 7. Home Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Getting Started&lt;/strong&gt;: To access the portal’s features, users first need to register and log in. Once logged in, they can unlock functionalities such as inventory management and search capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/register.png&quot; alt=&quot;Login&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 8. Login Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Live Inventory Visualization&lt;/strong&gt;: The dashboard provides an instant, real-time representation of the current status of the inventory, ensuring up-to-the-moment insights.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/dashboard.png&quot; alt=&quot;Dashboard&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 9. Dashboard
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;inventory&quot;&gt;Inventory&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Seamless Upload Process&lt;/strong&gt;: Allows consumers to easily upload Excel files containing inventory data. Multiple Excel files can be uploaded and loaded consecutively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/uploadpage.png&quot; alt=&quot;Upload&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 10. Upload Page
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Inventory View&lt;/strong&gt;: Shows a clear and accessible display of updated inventory information visible to consumers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/inventory.png&quot; alt=&quot;Inventory&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 11. Inventory
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;search&quot;&gt;Search&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Search Option&lt;/strong&gt;: Enables users to search and track any final product through the food supply chain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/track.jpg&quot; alt=&quot;Track&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 12. Track your products and by-products
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Visualizes Supply Chain&lt;/strong&gt;: Provides a comprehensive supply chain mapping of each product’s entire supply chain and process details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/traces.png&quot; alt=&quot;Traces&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 13. Visualize your product through the supply chain
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Claiming By-Products&lt;/strong&gt;: Consumers can easily claim by-products in the process, fostering a circular economy. This feature empowers consumers to actively participate in sustainable practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/claim.png&quot; alt=&quot;Claim&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 14. Claim by-products
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;smart-contract&quot;&gt;Smart Contract&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Smart Contract Page&lt;/strong&gt;: Allows users to create a contract for a time period to automatically claim the byproduct of  a particular product from a particular source. This avoids redundant visits to the website and makes the process automatic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/smartcontract.png&quot; alt=&quot;Claim&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 15. Smart Contract Page for Arrayán
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;View My Contracts&lt;/strong&gt;: Allows the user to track their existing contracts which are valid.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/currentcontract.png&quot; alt=&quot;Claim&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 16. View current contracts
    &lt;/em&gt;
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Auto-Claim&lt;/strong&gt;: On the search page, the user can easily view the available by-products to claim and also see if any by-product  is already auto-claimed under the contract.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/autoclaim.png&quot; alt=&quot;Claim&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 17. Auto-claimed by-products based on signed Contracts
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;tracker-chrome-extension&quot;&gt;Tracker Chrome Extension&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Chrome Extension&lt;/strong&gt;: Allows users to check the transparency of the system by getting the information from the blockchain based database, ResilientDB transaction id.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/chrome.png&quot; alt=&quot;Claim&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 18. Popup UI of Arrayan chrome Extension
    &lt;/em&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align:center;&quot;&gt;
    &lt;img src=&quot;/assets/images/arrayan/viewchrome.png&quot; alt=&quot;Claim&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 19. View of Report card based on Transaction ID provided
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;demo-videodiv-classextensions-extensions--video&quot;&gt;Demo Video&amp;lt;div class=&quot;extensions extensions--video&quot;&amp;gt;&lt;/h3&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/2iAvVZ5YgMQ?rel=0&amp;amp;showinfo=0&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;h2 id=&quot;steps-to-run-the-system&quot;&gt;Steps to run the system&lt;/h2&gt;

&lt;p&gt;Download NodeJS from &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;here&lt;/a&gt; and ensure that it’s added to PATH.&lt;/p&gt;

&lt;p&gt;Clone the repo of arrayan to get started:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/ResilientApp/Arrayan.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then navigate inside the ResVault directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd arrayan
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install the dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start the project:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Build the project:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above code uses online instance of Resilient DB and the application is ready to be launched. For further exploration, below steps can be followed to setup and play around with local instance.&lt;/p&gt;

&lt;h3 id=&quot;setup-python310&quot;&gt;Setup Python3.10&lt;/h3&gt;
&lt;p&gt;Ensure you have Python3.10, otherwise download it and set it up as default.&lt;/p&gt;

&lt;h3 id=&quot;setup-resilientdb&quot;&gt;Setup ResilientDB&lt;/h3&gt;
&lt;p&gt;You will need to clone the ResilientDB repo to get started:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/resilientdb/resilientdb.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then navigate inside the ResilientDB directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd resilientdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sh INSTALL.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run ResilientDB KV Service (this may take a few minutes for the first time):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./service/tools/kv/server_tools/start_kv_service.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setup-crow-http-server-sdk-and-graphql-server&quot;&gt;Setup Crow HTTP server, SDK, and GraphQL server&lt;/h3&gt;
&lt;p&gt;You will need to clone the ResilientDB GraphQL repo to get started:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/Amoolya-Reddy/ResilientDB-GraphQL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then navigate inside the ResilientDBGraphQL directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd ResilientDB-GraphQL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install the Crow dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo apt update sudo apt install build-essential sudo apt install python3.10-dev sudo apt install apt-transport-https curl gnupg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Build Crow HTTP server (this may take a few minutes for the first time):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build service/http_server:crow_service_main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start the Crow HTTP server:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel-bin/service/http_server/crow_service_main service/tools/config/interface/service.config service/http_server/server_config.config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create virtual environment for the Python SDK:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3 -m venv venv –without-pip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Activate the virtual environment:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;source venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install pip in the virtual environment for the Python dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl https://bootstrap.pypa.io/get-pip.py | python
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install the Python dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Start the GraphQL server:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3 app.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Setup cited from &lt;a href=&quot;https://blog.resilientdb.com/2023/09/21/ResVault.html#prerequisites&quot;&gt;ResVault&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;contributions&quot;&gt;Contributions:&lt;/h3&gt;
&lt;p&gt;Amoolya Gali: Designed the overall architecture of the application, translating requirements into technical functionalities. Led the development of the frontend, including UI/UX design and animations, and implemented the Ag-GraphQL wrapper to interface with the existing ResilientDB-GraphQL server, setting up all necessary APIs. Built the real-time dashboard, implemented Excel file parsing for constructing transactions, and managed interactions with Google Firestore by developing all Firestore APIs. Delivered an intuitive food supply chain tracking system and completed the end-to-end claim workflow.
&lt;br /&gt;
Mariana Larrañaga: Defined the project scope and high-level requirements as the founder of Arrayan. Conducted market research, pitched the product, and maintained active interactions with wineries and farmers, incorporating their input into the product. Served as the product manager, ensuring user needs were integrated into the development process and shaping the overall vision of Arrayan.
&lt;br /&gt;
Other Contributors: Shravani Shete, Manali Modi, Tarun Tiwari, Srishti Singh&lt;/p&gt;
</description>
        <pubDate>Wed, 13 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/12/13/Arrayan.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/12/13/Arrayan.html</guid>
      </item>
    
      <item>
        <title>ResilientDB Blockchain Analyzer</title>
        <description>&lt;h1 id=&quot;what-is-the-resilientdb-blockchain-analyzer&quot;&gt;What is the ResilientDB Blockchain Analyzer?&lt;/h1&gt;

&lt;p&gt;The ResilientDB Blockchain Analyzer offers a comprehensive visualization tool for transactions on the ResilientDB blockchain, similarly to Etherscan’s role for Ethereum. The two main features that the program offers are displaying all wallets connected to the ResilientDB blockchain, along with their respective transaction histories and offering a chronological visual representation of transactions, enabling easy tracking of transaction volume over time. It can also be used to help track the movement of illegally obtained funds or just to help see what transactions have been made on the blockchain. Currently the analyzer is already running live on the main instance of ResilientDB and can be viewed &lt;a href=&quot;http://34.31.61.19:8000/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;interfacing-with-resilientdb&quot;&gt;Interfacing with ResilientDB&lt;/h2&gt;

&lt;p&gt;When the website is first accessed it will read the response from &lt;a href=&quot;https://crow.resilientdb.com/v1/transactions&quot;&gt;https://crow.resilientdb.com/v1/transactions&lt;/a&gt; and then save all of the transactions made on the blockchain as a single json file. The ResilientDB blockchain visualizer then displays transactions in the form of a tree. At the top of the tree will be a single node containing the original wallet ID and then below that will be nodes displaying all of the transactions made by that specific wallet ID. If you click on any of those transactions you can see all the subsequent transactions made by the recipient of the selected transaction. If no subsequent transaction had been made then the transaction will not show up as being clicked.&lt;/p&gt;

&lt;h2 id=&quot;data-collection&quot;&gt;Data Collection&lt;/h2&gt;
&lt;h3 id=&quot;data-collection-for-homepage&quot;&gt;Data collection for homepage&lt;/h3&gt;
&lt;p&gt;If you run the python backend for the blockchain, then each time the webpage is accessed the flask script will download the blockchain’s json data and will store it under&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./Finecharts/js/settings/transactions.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This python backend and json file is necessary to make the graph on the homepage of the website display up to date data.&lt;/p&gt;
&lt;h3 id=&quot;data-collection-for-treehtml&quot;&gt;Data collection for tree.html&lt;/h3&gt;
&lt;p&gt;For tree.html the data is collected when the javascript code (tree.js) runs. This means that the data will be updated every time the page refreshed.&lt;/p&gt;

&lt;h2 id=&quot;viewing-the-data&quot;&gt;Viewing the Data&lt;/h2&gt;

&lt;h4 id=&quot;there-are-two-graphs-to-display-the-data-from-the-json-file&quot;&gt;There are two graphs to display the data from the json file:&lt;/h4&gt;
&lt;p&gt;First we have a simple line griph that displays the transactions made within the last year with the month on the x-axis and the amount of transactions on the y-axis.&lt;/p&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/resdb-visualizer/Year-Graph.png&quot; alt=&quot;Year Graph photo&quot; style=&quot;width: 75%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Image of the Transactions Graph.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;The second way is the tree that was described above. You can track the transaction history coming from a single user’s wallet ID and follow the subsequent transactions.&lt;/p&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/resdb-visualizer/Tree-Graph.png&quot; alt=&quot;Tree Graph photo&quot; style=&quot;width: 75%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Image of the Tree of Transactions.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;demo-video&quot;&gt;Demo Video&lt;/h2&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/u7TX2o8UjcA?si=0F8q2pSspPf3uxkF&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h1 id=&quot;running-the-application&quot;&gt;Running the Application&lt;/h1&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Before running the ResilientDB Blockchain Analyzer website, you need to start kv service on the ResDB backend and the sdk. We chose to run this on Google Cloud but any cloud service will work. You also must ensure that the way your data is stored in the json follows this format:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;id&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Transaction id&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;version&quot;&lt;/span&gt;: version,
    &lt;span class=&quot;s2&quot;&gt;&quot;inputs&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
        0: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;owners_before&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                0: &lt;span class=&quot;s2&quot;&gt;&quot;ID of Sender Wallet&quot;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;outputs&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
        0: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;public_keys&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                0: &lt;span class=&quot;s2&quot;&gt;&quot;ID of Reciever Waller&quot;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;amount&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Transaction Amount&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;operation&quot;&lt;/span&gt;: operation,
    &lt;span class=&quot;s2&quot;&gt;&quot;asset&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;data&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Timestamp in epoch time&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If your json structure does not follow this format go to &lt;a href=&quot;#changing-the-default-json-formatting&quot;&gt;Setting up the website frontend&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;setting-up-the-python-backend&quot;&gt;Setting up the python backend&lt;/h2&gt;
&lt;p&gt;First you need to install apache2 using:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;apache2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You will also need to install gunicorn using:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pip &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;gunicorn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then navigate to where your index.html folder is located, for google cloud it is under:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/var/www/http/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And delete index.html if present (we will replace this with the new home page). &lt;br /&gt;
Git Clone the ResDB-Chain-Analyzer Repository into this folder:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;git clone https://github.com/Richard-Voragen/ResDB-Chain-Analyzer/tree/main/ResDB-Chain-Analyzer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;next-we-need-to-ensure-that-the-proper-urls-are-set-to-retrieve-the-json-data-from&quot;&gt;Next we need to ensure that the proper url’s are set to retrieve the json data from:&lt;/h4&gt;
&lt;p&gt;Inside of the App.py file modify the fields.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;IP_ADDRESS_TO_TRANSACTIONS &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;URL that contains json of transactions&apos;&lt;/span&gt;
IP_ADDRESS_TO_HOSTING_SITE &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;URL/Domain Name of hosting site&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;finally-we-need-to-run-the-flask-script-that-will-update-transactionsjson-when-a-user-visits-the-website&quot;&gt;Finally we need to run the flask script that will update transactions.json when a user visits the website:&lt;/h4&gt;
&lt;p&gt;Run this command from /var/www/http/ResDB-Chain-Analyzer:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;gunicorn &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; 4 &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; 0.0.0.0 app:app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If any changes need to be made by the user to the app.py file then you must first end the gunicorn task with:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pkill gunicorn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setting-up-the-website-frontend&quot;&gt;Setting up the website frontend&lt;/h2&gt;

&lt;p&gt;Within the directory /var/www/http/ResDB-Chain-Analyzer/js/tree.js change to field at the top from:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://crow.resilientdb.com/v1/transactions&quot;&lt;/span&gt; to the URL that contains json of transactions
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;changing-the-default-json-formatting&quot;&gt;Changing the default json formatting&lt;/h3&gt;
&lt;p&gt;First open the Javascript file located at:
Install GraphQL:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/js/jsonFormat.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then modify the field to return their desired outputs:
Install GraphQL:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;get_id&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;jsonObj&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; : &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;the &lt;span class=&quot;nb&quot;&gt;id &lt;/span&gt;of the transaction
get_sender&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;jsonObj&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; : &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;the sender of the transaction
get_recipient&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;jsonObj&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; : &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;the recipient of the transaction
get_amount&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;jsonObj&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; : &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;the quantity of the transaction
get_time&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;jsonObj&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; : &lt;span class=&quot;k&quot;&gt;return &lt;/span&gt;the &lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;of the transaction
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;source-code-repositories&quot;&gt;Source Code Repositories:&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Richard-Voragen/ResDB-Chain-Analyzer&quot;&gt;https://github.com/Richard-Voragen/ResDB-Chain-Analyzer&lt;/a&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/Richard-Voragen/ResDB-Chain-Analyzer&quot;&gt;https://github.com/ResilientApp/ResilientDB-GraphQL&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;contributions&quot;&gt;Contributions:&lt;/h3&gt;
&lt;p&gt;Voragen: Designed chronological tree visualization of tree data and javascript background. Created main code for parsing and handling of the chain transaction history on the JSON file.
&lt;br /&gt;
Fennen: Designed front end of webpage, created monthly graph on front page of website, and handled JSON parsing for data displayed on the monthly graph.
&lt;br /&gt;
Allyn: Set up backend infrastructure and handled initial chain interactions.&lt;/p&gt;
</description>
        <pubDate>Tue, 12 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/12/12/BlockchainAnalyzer.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/12/12/BlockchainAnalyzer.html</guid>
      </item>
    
      <item>
        <title>Getting Started with Rust SDK</title>
        <description>&lt;p&gt;We provide a Rust SDK for committing transactions to create and transfer assets. Despite NexRes being written in C++, users can interface with ResilientDB through Rust. This article assumes you have setup a ResilientDB instance that is accessible through HTTP requests and are familiar with Rust, we will walk you through basics of using ResilientDB in your first Rust project.&lt;/p&gt;

&lt;h1 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h1&gt;
&lt;h3 id=&quot;install-rust-and-cargo&quot;&gt;Install Rust and Cargo&lt;/h3&gt;
&lt;p&gt;The easiest way to get Cargo is to install the current stable release of Rust by using rustup. Installing Rust using rustup will also install cargo.
On Linux and macOS systems, this is done as follows:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl https://sh.rustup.rs -sSf | sh&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It will download a script, and start the installation. If everything goes well, you’ll see this appear:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rust is installed now. Great!&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On Windows, download and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustup-init.exe&lt;/code&gt;. It will start the installation in a console and present the above message on success.&lt;/p&gt;

&lt;p&gt;After this, you can use the rustup command to also install beta or nightly channels for Rust and Cargo.&lt;/p&gt;

&lt;p&gt;You can find more informatin on rust on &lt;a href=&quot;https://doc.rust-lang.org/cargo/getting-started/installation.html&quot;&gt;The Cargo Book&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;starting-a-new-rust-project-and-installing-the-sdk&quot;&gt;Starting a new Rust Project and installing the SDK&lt;/h3&gt;
&lt;p&gt;You can start a new rust project through cargo with the following command:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo new resilientDB_test&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should now see a new folder generated named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resilientDB_test&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd resilientDB_test
$ tree .
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can get started with the Rust SDK in one of two ways:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;You can simply run the following command:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cargo add resilientdb_rust_sdk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;You can also add the following line to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cargo.toml&lt;/code&gt;
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;resilientdb_rust_sdk = &quot;0.1.1&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It’s that easy! You are now good to go with our SDK. Make sure you have a ResilientDB instance setup, for more info on that follow this &lt;a href=&quot;https://blog.resilientdb.com/2023/11/22/Deploying-ResilientDB.html&quot;&gt;blog&lt;/a&gt;. This tutorial also makes a graphql query to resdb, if you don’t have graphql setup take a look at this other &lt;a href=&quot;&quot;&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h3&gt;

&lt;p&gt;You may need to install the following dependencies as our library has &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;future&lt;/code&gt; return types, meaning some returns from our APIs would need to be unwrapped within an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;This is by design as we encourage users to handle errors on their end as many of the calls are made asynchrounously. Following good error handling practices would be beneficial to developing a secure application with ResilientDB. You can run obtain the dependencies through:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Running the following command
    &lt;blockquote&gt;
      &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo add tokio serde serde_json reqwest&lt;/code&gt;&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Adding this to your Cargo.toml file:
    &lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;tokio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;full&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;n&quot;&gt;serde&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;derive&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;n&quot;&gt;serde_json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.0&quot;&lt;/span&gt;
 &lt;span class=&quot;n&quot;&gt;reqwest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0.11.22&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;blocking&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;developement&quot;&gt;Developement&lt;/h1&gt;
&lt;h3 id=&quot;import-the-sdk&quot;&gt;Import the SDK&lt;/h3&gt;

&lt;p&gt;Let’s build a sample program that makes a transactions and then fetches transactions to and from your ResilientDB instance. In your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.rs&lt;/code&gt; file import the SDK like so:&lt;/p&gt;
&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;resilientdb_rust_sdk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;initializing-a-resdb-object&quot;&gt;Initializing a ResDB object&lt;/h3&gt;

&lt;p&gt;Our first step to using the functions within the SDK is to create a ResDB object in main like so:&lt;/p&gt;
&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ResDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;creating-keypairs&quot;&gt;Creating Keypairs&lt;/h3&gt;

&lt;p&gt;Generating public/private keypairs is as easy as calling the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;generate_kepair()&lt;/code&gt; function provided in the crypto module of our sdk. The Key pair generation is done using the Ed25519 algorithm. Here’s how you would use this API:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keypair&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.generate_keypair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Public Key: {:?}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keypair&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Private Key: {:?}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keypair&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;transaction-api---committing&quot;&gt;Transaction API - Committing&lt;/h3&gt;

&lt;p&gt;Currently the SDK support transaction commits through the graphql format. In our case, we will use the public and private key pairs that we generated using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;generate_keypair()&lt;/code&gt; function above. In the future we plan to add support for Struct and Hash map based transaction commits. Here’s how you would commit a transaction.&lt;/p&gt;
&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&quot;r#&quot;&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;&quot;query&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;mutation { postTransaction(data: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;signerPrivateKey: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;recipientPublicKey: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ECJksQuF9UWi3DPCYvQqJPjF6BqSbXrnDiXUjdiVvkyH&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;asset: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;          }}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;\&quot;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;      }}) &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keypair&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keypair&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endpoint&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;http://YouResDBInstance.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.post_transaction_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;endpoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Error: {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;transaction-api---fetching&quot;&gt;Transaction API - Fetching&lt;/h3&gt;

&lt;p&gt;We can fetch the transaction we just posted either using a struct to guide are JSON schema or a untyped Hash map. You would need to define a struct like so to pass into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_all_transactions()&lt;/code&gt; functions:&lt;/p&gt;
&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;serde&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Deserialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cd&quot;&gt;/** User Defined Struct for transaction endpoints **/&lt;/span&gt; 

&lt;span class=&quot;nd&quot;&gt;#[derive(Debug,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;serde::Deserialize)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Transaction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;serde_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Transaction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Transaction&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;operation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;#[derive(Debug,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;serde::Deserialize)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;owners_before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fulfills&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;serde_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fulfillment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;owners_before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;fulfills&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;fulfillment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;#[derive(Debug,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;serde::Deserialize)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;public_keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;public_keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Condition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;#[derive(Debug,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;serde::Deserialize)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Condition&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConditionDetails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Condition&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Condition&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ConditionDetails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;#[derive(Debug,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;serde::Deserialize)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConditionDetails&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;#[serde(rename&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;condition_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;public_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConditionDetails&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ConditionDetails&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;condition_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;public_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;#[derive(Debug,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;serde::Deserialize)]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Asset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;serde_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Default&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Asset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Asset&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;serde_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now that we have defined the JSON through structs, we can pass them to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get_all_transactions()&lt;/code&gt; function, along with that it will take our endpoint URL - this will be the local or remote URL to your ResilientDB instance.&lt;/p&gt;
&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch_transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;.get_all_transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Transaction&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://YouResDBInstance.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transaction&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transactions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Access and process each transaction&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transaction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Handle the error&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Error fetching transactions: {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The struct defined may seem verbose, this is by design as we want to ensure that users are building type safe and fault tolerant applications using ResilientDB. While the struct defines the JSON schema it also comes with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;impl&lt;/code&gt; that constructors for the stucts. For those who want to interface with ResilientDB in an unstructured manner we also provide the Hash map varient of the same function.&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ResDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.get_all_transactions_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;http://YouResDBInstance.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;data_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Access fields of the transaction (replace with the desired field)&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nf&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Handle the error&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Error: {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All the retrival functions provided by the SDK come in both Struct and Hash Map varients to provide the you with the choice between safety, type strictness and flexibility.&lt;/p&gt;

&lt;h3 id=&quot;blocks-api&quot;&gt;Blocks API&lt;/h3&gt;

&lt;p&gt;Similarly, the SDK offers APIs for interacting with blocks. You can fetch blocks by range, group them, or retrieve all blocks from a specified API endpoint. Below is an example of fetching all blocks:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ResDB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Call the asynchronous function to get blocks&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;.get_all_blocks_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://YouResDBInstance.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;.await&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blocks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;blocks&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// Access fields of the first transaction (replace with the desired field)&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{:?}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;No transactions available&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Handle the error&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;eprintln!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Error: {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;crypto-operations&quot;&gt;Crypto operations&lt;/h3&gt;

&lt;p&gt;Our Crypto API also provides a convinient function to hash strings. Here is how you would use the function:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, ResilientDB!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hashed_data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res_db&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.hash_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hashed Data: {}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hashed_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;This guide provides a glimpse into the powerful features our ResilientDB Rust SDK offers for seamless integration into your Rust projects. Explore the full potential of ResilientDB, experiment with different APIs, and leverage the SDK’s capabilities to build robust and secure applications.&lt;/p&gt;

&lt;p&gt;For more in-depth information and advanced features, refer to the official &lt;a href=&quot;https://docs.rs/resilientdb_rust_sdk/0.1.2/resilientdb_rust_sdk/&quot;&gt;ResilientDB Rust SDK documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy coding with ResilientDB and Rust!&lt;/p&gt;
</description>
        <pubDate>Sun, 10 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/12/10/Getting-Started-with-Rust-SDK.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/12/10/Getting-Started-with-Rust-SDK.html</guid>
      </item>
    
      <item>
        <title>ResView- Visualizing Resilient DB</title>
        <description>&lt;h1 id=&quot;what-is-resview&quot;&gt;What is ResView?&lt;/h1&gt;

&lt;p&gt;ResView is a tool for visualizing the PBFT process in Resilient DB. ResView is built on top of  Resilient DB and gathers statistics from transactions to display in graphical form. ResView works on all transactions performed with local instances of Resilient DB, whether sent from ResView, another application, or in the ResilientDB terminal. Our goal for ResView is to enable greater understanding of the ResilientDB backend by people who want to learn more about how the PBFT consensus protocol works and the general flow of blockchain consensus, as well as developers who want to observe the status of ResilientDB and test their own applications/changes on the ResilientDB framework.&lt;/p&gt;

&lt;p&gt;Below is a diagram showing the workflow of ResView and the high-level structure:&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resview/resview_structure.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Diagram displaying the structure of ResView and how data is passed between the different services.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;The diagram can be broken down as follows. An application sends a transaction to the GraphQL server, which parses the request and transforms it into a usable Request for ResilientDB. The GraphQL server then forwards this request to the ResilientDB instance, which performs the consensus protocol on the request then executes the request contents. During the process of inter-replica communication, data about the consensus protocol is collected. Once the transaction is completed, the ResilientDB service sends the consensus data along a websocket connected to ResView, which then collects and stores this data. Once ResView acquires the consensus data, ResView transforms and leverages it to create various diagrams which show what happened in the consensus process to the user.&lt;/p&gt;

&lt;h2 id=&quot;interfacing-with-resilientdb&quot;&gt;Interfacing with ResilientDB&lt;/h2&gt;

&lt;p&gt;ResView offers both ways to interact with the ResilientDB architecture, as well as ways to visualize what is occurring in ResilientDB. Users are able to interact with ResilientDB through the application using the transaction forms and “make a replica faulty” buttons. Within the transaction forms, users input the data fields for the transaction they wish to send and press either set or get. Once this transaction is confirmed, it is sent via Axios to the sdk, which verifies the transaction and forwards it to the ReslientDB backend, where it is then processed and executed.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resview/txn_form.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 50%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Image of the Transaction Form.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;For the faulty buttons, when these are pressed, they send a signal to the corresponding the replica informing it to reject any transactions it receives, simulating a replica unable to receive messages. Before this addition, there was no method of forcing a replica to be faulty, making this a valuable addition for testing various cases and potential situations ResilientDB could face.&lt;/p&gt;

&lt;h2 id=&quot;data-collection&quot;&gt;Data Collection&lt;/h2&gt;

&lt;p&gt;ResView collects the data for visualization directly from the ResilientDB application, as while transactions are being ran, a statistics data structure collects the contents of the transaction, timestamps of when each state was reached, and timestamps of when messages were received. These statistics are then grouped as a JSON, which is then sent out to the front end application. The reason the data is collected this way is to enable ResView to produce visualizations even without access to log files, as well as gather information regardless of who initiated the transaction.&lt;/p&gt;

&lt;h2 id=&quot;viewing-the-data&quot;&gt;Viewing the Data&lt;/h2&gt;

&lt;p&gt;On the application, users are able to select which transaction’s data they want to see diagrams of, as all data is stored as a history while the application is running. Once a transaction is selected, there are 3 viewable graphs: PBFT diagram, prepare messages vs time, and commit messages vs time. In order to select a transaction, it can be chosen from the list of performed transactions in the transaction table.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resview/txn_table.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. Transaction Table.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;The PBFT diagram is dynamically constructed using the data collected from the replicas. The main data points utilized are the primary id, which signifies in the diagram where the client should send its request to, the timestamps of each state, as they identify that the replica reached that state and how long it took, and the existence of each replica’s data, as faulty replicas do not send their data to the front end. This allows the PBFT diagram to work with real time data and accurately convey the state of ResilientDB to the user, as well as the flow of the consensus protocol.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resview/pbft_graph.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. PBFT Diagram.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;Both the prepare message vs time and commit message vs time graphs use a line graph containing a line of each replica’s message collection. The timestamps start from when a replica is first able to start sending messages, which the message collection times are relative to. The purpose of displaying lines from each replica is to easily compare the rates at which replicas collected messages to understand the relationship between them, as well as identify any potential issues with message collection. In order to focus on specific replicas, the user is also able to toggle the lines of any replica which reduces the amount of data of the graph being displayed.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resview/mvt_graph.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Commit Message Graph.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;The status of each of the replicas is also visible on the side of the application, showing which replicas are non-faulty and which are either faulty or unavailable. Previously, in order to tell which replicas were down, users had to go into the log file and see which replicas were not being updated actively or processing requests, but now users can easily see which replicas are available while sending transactions.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/resview/replica_status.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 30%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 6. Replica Availability Status.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h2 id=&quot;demo-video&quot;&gt;Demo Video&lt;/h2&gt;

&lt;!-- &lt;iframe width=&quot;100%&quot; height=&quot;500px&quot; src=&quot;http://www.youtube.com/embed/9aStTvGUekI&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt; --&gt;
&lt;div class=&quot;extensions extensions--video&quot;&gt;
  &lt;iframe src=&quot;https://www.youtube.com/embed/9aStTvGUekI?rel=0&amp;amp;showinfo=0&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h1 id=&quot;running-the-application&quot;&gt;Running the Application&lt;/h1&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Before running the ResView application, you need to start kv service on the ResDB backend and the sdk.&lt;/p&gt;

&lt;h3 id=&quot;resilientdb&quot;&gt;resilientdb&lt;/h3&gt;
&lt;p&gt;Git clone the ResView backend repository and follow the instructions to set it up:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/apache/incubator-resilientdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Setup KV Service:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./service/tools/kv/server_tools/start_kv_service.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;sdk&quot;&gt;sdk&lt;/h3&gt;
&lt;p&gt;Git clone the GraphQL Repository and follow the instructions on the ReadMe to set it up:&lt;/p&gt;

&lt;p&gt;Install GraphQL:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/ResilientApp/ResilientDB-GraphQL
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Setup SDK:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bazel build service/http_server:crow_service_main

bazel-bin/service/http_server/crow_service_main service/tools/config/interface/client.config service/http_server/server_config.config
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With these 2 services running, the ResView front end can now send transactions to the ResDB framework&lt;/p&gt;

&lt;h2 id=&quot;running-the-resview-application&quot;&gt;Running the ResView Application&lt;/h2&gt;

&lt;p&gt;Clone the repo and open in a new folder.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Run the below code to start the app and load the script.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;using-the-resview-application&quot;&gt;Using the ResView Application&lt;/h2&gt;

&lt;p&gt;Once ResView has been started, go to http://localhost:3000/pages/visualizer or https://resview.resilientdb.com/&lt;/p&gt;

&lt;p&gt;Load KV_Service on resilient db once on the visualizer page, the web sockets should connect and log the 
“OPEN” message into the console 4 times.&lt;/p&gt;

&lt;p&gt;Once on the visualizer page, send a transaction using the transaction form. Once the transaction’s data has been sent back, click on the various graphs to view the transaction data in a more comprehensive way. In order to select previous transactions, go to the transaction table and choose the specific transaction. In order to test different edge cases, set various replicas to faulty or not faulty and observe how the messages are now sent between replicas.&lt;/p&gt;

&lt;h1 id=&quot;future-work&quot;&gt;Future Work&lt;/h1&gt;

&lt;p&gt;Set up ResView on Cloud Instance to retrieve far more transaction data&lt;/p&gt;

&lt;h3 id=&quot;source-code-repositories&quot;&gt;Source Code Repositories:&lt;/h3&gt;
&lt;p&gt;https://github.com/ResilientApp/ResView
&lt;br /&gt;
https://github.com/apache/incubator-resilientdb
&lt;br /&gt;
https://github.com/ResilientApp/ResilientDB-GraphQL&lt;/p&gt;

&lt;h3 id=&quot;slides&quot;&gt;Slides:&lt;/h3&gt;
&lt;p&gt;https://www.canva.com/design/DAGSGOyLh8g/pEC_FJgR6B_7RldsQBMrKQ/edit?utm_content=DAGSGOyLh8g&amp;amp;utm_campaign=designshare&amp;amp;utm_medium=link2&amp;amp;utm_source=sharebutton&lt;/p&gt;

&lt;h3 id=&quot;contributions&quot;&gt;Contributions:&lt;/h3&gt;
&lt;p&gt;Saipranav: Designed project architecture and workflow, feature ideas, coded the backend data collection, faulty replica toggles, configured all websockets, wrote JSON data parsing code, created Message vs Time graphs and line toggles, created sample transactions, setup all APIs, and added transaction sending and sdk incorporation.
&lt;br /&gt;
Aunsh: Designed the front end UI/UX and architecture, skeleton, contexts, and pages, developed main PBFT diagram, setup graph component skeletons and general styling, look and functionality of the entire application. Also worked on adding tables, the home page, and seamless transition to viewing earlier transactions.
&lt;br /&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 06 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/12/06/ResView.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/12/06/ResView.html</guid>
      </item>
    
      <item>
        <title>Deploying ResilientDB</title>
        <description>&lt;p&gt;This tutorial assumes that you have setup ResilientDB by following this &lt;a href=&quot;https://blog.resilientdb.com/2023/09/21/ResVault.html&quot;&gt;blog&lt;/a&gt;. In order to get started with deploying ResilientDB and the extended applications on cloud you will need to follow the steps below.&lt;/p&gt;

&lt;h1 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h1&gt;
&lt;h3 id=&quot;create-a-cloud-instance&quot;&gt;Create a Cloud instance&lt;/h3&gt;
&lt;p&gt;You can create a cloud instance on either AWS &lt;a href=&quot;https://console.aws.amazon.com/ec2/&quot;&gt;(EC2)&lt;/a&gt;, GCP &lt;a href=&quot;https://console.cloud.google.com/compute/instances?_ga=2.30596543.1077298781.1700583534-792349637.1700583534&quot;&gt;(Compute Engine)&lt;/a&gt;, or choose any other Virtual Private Server &lt;a href=&quot;https://en.wikipedia.org/wiki/Virtual_private_server&quot;&gt;(VPS)&lt;/a&gt;. Ensure that you select the image as Ubuntu 22.04.&lt;/p&gt;

&lt;h3 id=&quot;setup-resilientdb-and-other-repositories&quot;&gt;Setup ResilientDB and other repositories&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Clone and Install the dependencies for ResilientDB, CROW HTTP Server, and GraphQL by following this [blog]((https://blog.resilientdb.com/2023/09/21/ResVault.html).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;purchase-a-domain-and-setup-cloudflare-dns&quot;&gt;Purchase a domain and setup Cloudflare DNS&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Go to &lt;a href=&quot;https://www.namecheap.com/&quot;&gt;Namecheap&lt;/a&gt; and purchase a domain. Then, once you have registered a domain click on Manage option and under DNS select custom DNS.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Then go to &lt;a href=&quot;https://www.cloudflare.com/en-in/&quot;&gt;Cloudflare&lt;/a&gt; and create an account. Then, proceed to add the domain that you just registered. Add the two nameservers given by Cloudflare in the Namecheap Custom DNS. (This change might take a while to reflect)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, navigate to the DNS management page on the Cloudflare Dashboard and create the following five subdomain records:&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;An A record with name &lt;strong&gt;crow&lt;/strong&gt; and IPv4 address as the external IP of your cloud instance.&lt;/li&gt;
      &lt;li&gt;An A record with name &lt;strong&gt;cloud&lt;/strong&gt; and IPv4 address as the external IP of your cloud instance.&lt;/li&gt;
      &lt;li&gt;An A record with name &lt;strong&gt;explorer&lt;/strong&gt; and IPv4 address as the external IP of your cloud instance.&lt;/li&gt;
      &lt;li&gt;An A record with name &lt;strong&gt;prometheus&lt;/strong&gt; and IPv4 address as the external IP of your cloud instance.&lt;/li&gt;
      &lt;li&gt;An A record with name &lt;strong&gt;monitoring&lt;/strong&gt; and IPv4 address as the external IP of your cloud instance.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;setup-nginx&quot;&gt;Setup Nginx&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;SSH into your cloud instance and install Nginx with the following command:
    &lt;blockquote&gt;
      &lt;p&gt;sudo apt update&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;blockquote&gt;
      &lt;p&gt;sudo apt upgrade&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;blockquote&gt;
      &lt;p&gt;sudo apt install nginx&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Then, start and enable Nginx as a service:
    &lt;blockquote&gt;
      &lt;p&gt;sudo systemctl start nginx&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;blockquote&gt;
      &lt;p&gt;sudo systemctl enable nginx&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The next step is to create a configuration file, we are going to name it &lt;strong&gt;conf&lt;/strong&gt; but you can name it whatever you want:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;sudo nano /etc/nginx/sites-available/conf&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Then, copy and paste the following configuration inside the file, make sure to edit &lt;em&gt;yourdomain.com&lt;/em&gt; with your domain:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;For the Flask app
server {
   listen 80;
   server_name cloud.yourdomain.com;

   location / {
       proxy_pass http://127.0.0.1:8000;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
   }
}

# For the Vite app
server {
   listen 80;
   server_name explorer.yourdomain.com;

   location / {
       proxy_pass http://127.0.0.1:8080;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection &quot;upgrade&quot;;
   }

   location /block {
       proxy_pass http://127.0.0.1:8080/;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection &quot;upgrade&quot;;
   }

   location /transactions {
       proxy_pass http://127.0.0.1:8080/;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection &quot;upgrade&quot;;
   }

   location /api/ {
       proxy_pass http://localhost:18000/;
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection &apos;upgrade&apos;;
       proxy_set_header Host $host;
       proxy_cache_bypass $http_upgrade;
       proxy_redirect off;
   }
}

# For the CROW HTTP server
server {
    listen 80;
    server_name crow.yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:18000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # CORS headers
        add_header &apos;Access-Control-Allow-Origin&apos; &apos;*&apos; always;
        add_header &apos;Access-Control-Allow-Methods&apos; &apos;GET, POST, OPTIONS&apos; always;
        add_header &apos;Access-Control-Allow-Headers&apos; &apos;Origin, X-Requested-With, Content-Type, Accept&apos; always;
    }
   location /blockupdatelistener {
        # Set up the proxy pass to your WebSocket server
        proxy_pass http://127.0.0.1:18000;

        # Upgrade headers for WebSocket
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection &quot;upgrade&quot;;

        # Set WebSocket specific headers
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # CORS headers
        add_header &apos;Access-Control-Allow-Origin&apos; &apos;*&apos; always;
        add_header &apos;Access-Control-Allow-Methods&apos; &apos;GET, POST, OPTIONS&apos; always;
        add_header &apos;Access-Control-Allow-Headers&apos; &apos;Origin, X-Requested-With, Content-Type, Accept&apos; always;

        # Handle WebSocket specific &quot;OPTIONS&quot; request
        if ($request_method = &apos;OPTIONS&apos;) {
            add_header &apos;Access-Control-Allow-Origin&apos; &apos;*&apos;;
            add_header &apos;Access-Control-Allow-Methods&apos; &apos;GET, POST, OPTIONS&apos;;
            add_header &apos;Access-Control-Allow-Headers&apos; &apos;Origin, X-Requested-With, Content-Type, Accept&apos;;
            add_header &apos;Access-Control-Max-Age&apos; 1728000;
            add_header &apos;Content-Type&apos; &apos;text/plain charset=UTF-8&apos;;
            add_header &apos;Content-Length&apos; 0;
            return 204;
        }
    }
}

# For Prometheus
server {
   listen 80;
   server_name prometheus.yourdomain.com;

   location / {
       proxy_pass http://127.0.0.1:9090;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
   }

   access_log /var/log/nginx/prometheus.access.log;
   error_log /var/log/nginx/prometheus.error.log;
}

# For Grafana
# this is required to proxy Grafana Live WebSocket connections.
map $http_upgrade $connection_upgrade {
 default upgrade;
 &apos;&apos; close;
}

upstream grafana {
 server localhost:3000;
}

server {
  listen 80;
  server_name monitoring.yourdomain.com;

  location / {
    proxy_set_header Host $http_host;
    proxy_pass http://grafana;
  }

# Proxy Grafana Live WebSocket connections.
  location /api/live/ {
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header Host $http_host;
    proxy_pass http://grafana;
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Save the configuration file by pressing ctrl+o and then exit the editor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Enable the site configuration by running the following command:
    &lt;blockquote&gt;
      &lt;p&gt;sudo ln -s /etc/nginx/sites-available/conf /etc/nginx/sites-enabled/&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Check for syntax errors using the command below:
    &lt;blockquote&gt;
      &lt;p&gt;sudo nginx -t&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;If everything is fine then restart Nginx to view the changes:
    &lt;blockquote&gt;
      &lt;p&gt;sudo systemctl restart nginx&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, you can navigate to the different subdomains via your web browser and view the different services.&lt;/p&gt;

&lt;h3 id=&quot;using-docker-compose-for-resilientdb-and-python-sdk&quot;&gt;Using Docker Compose for ResilientDB and Python SDK&lt;/h3&gt;

&lt;p&gt;Utilize Docker images from the Docker Hub registry to effortlessly create instances of ResDB and the Python SDK.&lt;/p&gt;

&lt;p&gt;Below is the docker-compose.yaml file. Switch &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amd64&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arm64&lt;/code&gt; if you are on an Mac Silicon system.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3&quot;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;resilientdb&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;expolab/resdb:amd64&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;10005:10005&quot;&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;sdk&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;expolab/sdk:amd64&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;resilientdb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Execute the following command to launch ResilientDB and the SDK:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; docker-compose up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once the command completes, access the SDK container and modify the URL within the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test_driver.py&lt;/code&gt; file to connect to the created ResDB server.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Accessing the SDK container:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use the following commands to identify the container ID and access the SDK container:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; docker ps -a

CONTAINER ID   IMAGE                 COMMAND             CREATED      STATUS                             PORTS                      NAMES
2a9251b89b6c   expolab/sdk:arm64     &quot;./entrypoint.sh&quot;   7 days ago   Up 23 seconds (health: starting)   18000/tcp                  sdk-sdk-1
e6ffad8d591c   expolab/resdb:arm64   &quot;./entrypoint.sh&quot;   8 days ago   Up 23 seconds                      0.0.0.0:10005-&amp;gt;10005/tcp   sdk-resilientdb-1

&amp;gt; docker exec -it 2a9251b89b6c bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Edit test_driver.py and replace db_root_url from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1:18000&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://resilientdb:10005&lt;/code&gt;:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; sed -i &apos;s/db_root_url = &quot;http:\/\/127.0.0.1:18000&quot;/db_root_url = &quot;http:\/\/resilientdb:10005&quot;/&apos; test_driver.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures that the SDK communicates correctly with the ResilientDB server.&lt;/p&gt;
</description>
        <pubDate>Wed, 22 Nov 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/11/22/Deploying-ResilientDB.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/11/22/Deploying-ResilientDB.html</guid>
      </item>
    
      <item>
        <title>Logging in ResilientDB</title>
        <description>&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/nexres/logging.png&quot; alt=&quot;logging overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Logging is used to help ResilientDB to recover its local state after restarting. The state can be the one before it is shut down or the state from other replicas.
When ResilientDB receives a request related to the consensus logic, it will be written to a log file by appending to the tail to guarantee written order.
Requests in the log file will be the same as the requests received from the network.
If the system uses multi-threads to process the requests, the written order is random but it guarantees that requests will be persistent to the disk before
processing.
Thus, if a system restarts and redo all the requests from the log file, it will produce the same state.&lt;/p&gt;

&lt;h2 id=&quot;storage-restriction&quot;&gt;Storage Restriction&lt;/h2&gt;
&lt;p&gt;Since ResilientDB will redo the requests from the log, the storage needs to handle repeated requests. 
At least, it can go to the same state if producing the same operations from some points. 
For example, for the raw key-value service which provides only Get and Set interfaces. 
No matter from which point to redo the requests, as long as it is the logging point before its last update, it will reach the same state
since all the Set requests will overwrite the previous records and only the last set will be kept.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/nexres/logging%20files.png&quot; alt=&quot;logging overview&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;checkpoint-files&quot;&gt;Checkpoint Files&lt;/h2&gt;
&lt;p&gt;To reduce the size of the log file, it will be split into some small files.
In most of the consensus protocols that support checkpoints, they will generate some stable checkpoints which indicates that the system can remove the logs before these checkpoints.
In ResilientDB, a stable checkpoint is a sequence number that all the requests earlier than that number have been committed.
Thus, the redo process can start from a stable checkpoint.&lt;/p&gt;

&lt;p&gt;As the requests are out of order in the log files, each file will save the request information including the stable checkpoint,
the minimum and the maximum sequence numbers of the requests in the files in their file names except the latest active one.&lt;/p&gt;

&lt;p&gt;When loading the requests starting from a stable checkpoint S, start from the earliest file whose maximum sequence of the requests is less than S.&lt;/p&gt;

&lt;h2 id=&quot;consistency-to-storage&quot;&gt;Consistency to Storage&lt;/h2&gt;
&lt;p&gt;Starting from a middle stable checkpoint could not guarantee the storage has executed all the requests before the checkpoint as the stable 
checkpoint generation and the storage execution are isolated.&lt;/p&gt;

&lt;p&gt;To solve this problem, we switch to a new file only if the storage has executed all the requests whose sequences are less than the smallest stable checkpoint in the file.
That means that, in one log file, there will be many stable checkpoints. We only consider the smallest one.
In other words, we guarantee that when we finish log file A whose minimum stable checkpoint is X, all the requests with sequence numbers less than X have been committed.&lt;/p&gt;

&lt;p&gt;So it is safe to redo the requests starting from A. However, because some requests will fall into the files before A, we need to find the starting log file using the maximum 
sequence number discussed above.&lt;/p&gt;

</description>
        <pubDate>Sat, 18 Nov 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/11/18/LoggingInResDB.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/11/18/LoggingInResDB.html</guid>
      </item>
    
      <item>
        <title>Recovery and Checkpoint Protocols in NexRes</title>
        <description>&lt;p&gt;The view-change protocol and checkpoint algorithm provide PBFT with liveness by allowing the system to make progress when the primary fails. In this blog, we introduce how we implement the PBFT view-change protocol and checkpoint algorithm in NexRes, list what Byzantine failures our current version is resilient to, and illustrate how our view-change protocol and checkpoint algorithm provide liveness in the presence of the failures.&lt;/p&gt;

&lt;p&gt;We use the same model in the PBFT paper. There are $n = 3f+1$ replicas, at most $f$ of while can be Byzantine, where a Byzantine replica can have arbitrary malicious behavior.&lt;/p&gt;

&lt;h2 id=&quot;view-change-protocol&quot;&gt;view-change protocol&lt;/h2&gt;

&lt;h3 id=&quot;failure-detection&quot;&gt;FAILURE DETECTION&lt;/h3&gt;

&lt;p&gt;In this section, we describe how PBFT in NexRes detects the failure of the primary $P$.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Client $C$ sends a request $T$ to the primary and sets a timer $t_c$.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;replica_communicator_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetPrimary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;AddWaitingResponseRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;If $C$ receives $f+1$ valid responses for $T$ before $t_c$ expires, then $C$ considers $T$ as stable in the ledger.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;CollectorResultCode&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AddResponseMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                       &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TransactionCollector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CollectorDataType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                     &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_unique&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                     &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                   &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CollectorResultCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STATE_CHANGED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;RemoveWaitingResponseRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;If not, $C$ broadcasts $T$ to all replicas.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CheckTimeOut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetTimeOutRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;replica_communicator_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BroadCast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;When receiving $T$, if a replica $R$ is not the current primary, then it forwards to the current primary $P$ and sets a timer $t_r$.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetCurrentPrimary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;replica_communicator_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;message_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetCurrentPrimary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;request_complained_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;When $t_r$ expires, $R$ checks if it has committed any request form $C$ since it starts $t_r$.&lt;/li&gt;
  &lt;li&gt;If not, $R$ requests a &lt;em&gt;view-change&lt;/em&gt;.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ViewChangeTimerType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_COMPLAINT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ViewChangeStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NONE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;viewchange_timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system_info_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetCurrentView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start_time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetLastCommittedTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proxy_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;checkpoint_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TimeoutHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;requesting-a-view-change&quot;&gt;REQUESTING A VIEW-CHANGE&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Detecting the failure of the primary is not the only reason to request a view-change. Besides, if a replica $R$ receives f+1 VIEW-CHANGE messages of the current view from other replicas and $R$ has not requested a view-change in the current view, then $R$ requests a view-change as well.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetMaxMaliciousReplicaNum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;checkpoint_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TimeoutHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Once a view-change is requested, replicas process no more consensus messages and then proceed to construct the &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; message and broadcast it to all the replicas at periodic intervals.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;checkpoint_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetTimeoutHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ViewChangeStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NONE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;view_change_counter_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ViewChangeStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READY_NEW_VIEW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;view_change_counter_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ChangeStatue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ViewChangeStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READY_VIEW_CHANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SendViewChangeMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;The &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; message contains a set $S$ of requests that $R$ has prepared, which means that for each request $T\in S$, $R$ has received $2f+1$ &lt;strong&gt;PREPARE&lt;/strong&gt; messages in support of $T$.&lt;/li&gt;
  &lt;li&gt;For each $T\in S$, the &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; message includes a corresponding &lt;em&gt;Prepare-Proof&lt;/em&gt; that contains the $2f+1$ digitally-signed &lt;strong&gt;PREPARE&lt;/strong&gt; messages.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetTransactionState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TransactionStatue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READY_COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RequestInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proof_info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetPreparedProof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view_change_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_prepared_msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;txn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proof_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proof&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_proof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proof&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mutable_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;proof&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mutable_signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;$R$ moves to the next view, broadcasts the &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; message, and sets a timer $t_v$. If $R$ fails to receive $2f+1$ &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; messages, then $R$ broadcasts the &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; message for the current view again.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ViewChangeTimerType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_VIEWCHANGE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ViewChangeStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READY_VIEW_CHANGE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;viewchange_timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system_info_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetCurrentView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()){&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LOG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;It is time to rebroadcast viewchange messages&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ChangeStatue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ViewChangeStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VIEW_CHANGE_FAIL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;checkpoint_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TimeoutHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;proposing-new-view&quot;&gt;PROPOSING NEW-VIEW&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;If the replica $R$ receives $2f+1$ &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; messages for the current view, $R$ sets a timer $t_n$.&lt;/li&gt;
  &lt;li&gt;If $R$ is the new primary $P’$, then $P’$ constructs and broadcasts a &lt;strong&gt;NEW-VIEW&lt;/strong&gt; message.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AddRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetMinDataReceiveNum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsNextPrimary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SendNewViewMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;StartNewViewTimer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ChangeStatue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ViewChangeStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READY_NEW_VIEW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;The &lt;strong&gt;NEW-VIEW&lt;/strong&gt; message contains the $2f+1$ digitally-signed &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; messages.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;viewchange_request_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;NewViewMessage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_view_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;new_view_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_view_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_view_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// &amp;lt;sequence, digest&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ViewChangeMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_view_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_view_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_viewchange_messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;starting-a-new-view&quot;&gt;STARTING A NEW VIEW&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;If $R$ fails to receive a valid &lt;strong&gt;NEW-VIEW&lt;/strong&gt; message before $t_n$ expires, then $R$ requests one more view-change, enters the next view, and broadcasts &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; message.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewchange_timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ViewChangeTimerType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_NEWVIEW&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ViewChangeStatus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READY_NEW_VIEW&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;viewchange_timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system_info_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetCurrentView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()){&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;checkpoint_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TimeoutHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;If a valid &lt;strong&gt;NEW-VIEW&lt;/strong&gt; message with the highest sequence number (round number) $max_s$ is received, then, for each sequence number $r &amp;lt; max_s$ with a valid &lt;em&gt;Prepare-Proof&lt;/em&gt;, $R$ broadcasts the corresponding &lt;strong&gt;COMMIT&lt;/strong&gt; message for round $r$, while for each sequence number $r’ &amp;lt; max_s$ without a valid &lt;em&gt;Prepare-Proof&lt;/em&gt;, $R$ broadcasts &lt;strong&gt;PREPARE&lt;/strong&gt; message of &lt;em&gt;null&lt;/em&gt; value for round $r’$.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_view_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_PRE_PREPARE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;new_view_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;replica_communicator_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_view_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                                       &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;replica_communicator_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BroadCast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_view_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;checkpoint-algorithm&quot;&gt;CHECKPOINT ALGORITHM&lt;/h2&gt;

&lt;p&gt;We have introduced the view-change protocol above. However, view-change protocol cannot prevent malicious replicas from keeping up to $f$ non-faulty replicas in the dark. Malicious replicas do so by not sending any consensus messages replicas to the $f$ replicas. Thus, the $f$ non-faulty replicas cannot commit any new requests while other non-faulty replicas can.&lt;/p&gt;

&lt;p&gt;To solve this problem, we need to implement the checkpoint algorithm.&lt;/p&gt;

&lt;h3 id=&quot;sending-checkpoint&quot;&gt;SENDING CHECKPOINT&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;When initiating the system, we set a checkpoint watermark size value, such as 5. Then, every 5 consecutive rounds, a replica $R$ broadcasts a &lt;strong&gt;CHECKPOINT&lt;/strong&gt; message with sequence number $r$, where $r$ is the highest sequence number of the 5 rounds, informing other replicas that it has committed and executed the requests in the last 5 rounds.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_ckpt_seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;water_mark&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;last_ckpt_seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;BroadcastCheckPoint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_ckpt_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stable_hashs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stable_seqs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;fetching-unknown-requests&quot;&gt;FETCHING UNKNOWN REQUESTS&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;If a replica $R$ receives $f+1$ valid &lt;strong&gt;CHECKPOINT&lt;/strong&gt; messages of the same sequence number $r$ and the highest sequence number that $R$ has executed is $r’, r’&amp;lt;r$, then, $R$ needs to fetch the unknown requests behind round $r’$.&lt;/li&gt;
  &lt;li&gt;$R$ calls an interface to fetch the requests, asking the senders of the $f+1$ &lt;strong&gt;CHECKPOINT&lt;/strong&gt; messages one by one until it fetches valid requests.&lt;/li&gt;
  &lt;li&gt;To check the validity of the fetched requests, $R$ verifies the hash and signatures.&lt;/li&gt;
  &lt;li&gt;If the fetched requests are valid, then $R$ commits and executes them.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replicas_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetReplicaInfos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replica_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replicas_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;txn_accessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetRequestFromReplica&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_seq_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;committable_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replica_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PassAllChecks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;executor_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;executor_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Commit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_unique&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;stable-checkpoint&quot;&gt;STABLE CHECKPOINT&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;If a replica $R$ receives $2f+1$ valid &lt;strong&gt;CHECKPOINT&lt;/strong&gt; messages of the same sequence number $r$. It means that at least $f+1$
non-faulty replicas have executed requests with sequence number $r$. And we consider $r$ as a &lt;em&gt;stable checkpoint&lt;/em&gt;.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetMinDataReceiveNum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stable_seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stable_hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      
  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SignatureInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;votes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_stable_seq_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stable_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;votes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sign_ckpt_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stable_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stable_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)];&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stable_ckpt_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stable_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stable_ckpt_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stable_hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stable_ckpt_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mutable_signatures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vote&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;votes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stable_ckpt_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_signatures&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;current_stable_seq_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stable_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;A &lt;em&gt;Stable-Checkpoint-Proof&lt;/em&gt; with sequence number $r$ can be considered as &lt;em&gt;Prepare-Proof&lt;/em&gt; for all rounds before $r$ because a request &lt;em&gt;committed&lt;/em&gt; by a non-faulty replica must have been &lt;em&gt;prepared&lt;/em&gt; by at least $f+1$ non-faulty replicas. A &lt;em&gt;Prepare-Proof&lt;/em&gt; for the request will definitely appear in at least one of the $2f+1$ &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; messages in the &lt;strong&gt;NEW-VIEW&lt;/strong&gt; message.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;optimizing-view-change-with-checkpoint&quot;&gt;OPTIMIZING VIEW-CHANGE WITH CHECKPOINT&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;With the checkpoint algorithm, we can reduce the overhead of the view-change protocol. Instead of all &lt;em&gt;Prepare-Proofs&lt;/em&gt; from the first round, a &lt;strong&gt;VIEW-CHANGE&lt;/strong&gt; message contains a &lt;em&gt;Stable-Checkpoint-Proof&lt;/em&gt; with the highest sequence number $r$ and all &lt;em&gt;Prepare-Proofs&lt;/em&gt; with a higher sequence number $r’, r’&amp;gt;r$.
    &lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_change_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mutable_stable_ckpt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;checkpoint_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetStableCheckpointWithVotes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;view_change_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stable_ckpt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetTransactionState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TransactionStatue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READY_COMMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RequestInfo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proof_info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;message_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetPreparedProof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;resilience-to-byzantine-behaviors&quot;&gt;RESILIENCE TO BYZANTINE BEHAVIORS&lt;/h2&gt;

&lt;p&gt;In this section, we list the Byzantine behaviors that our implementation is resilient to and illustrate how our implementation is equipped with resilience.&lt;/p&gt;

&lt;h3 id=&quot;non-responsive-primary&quot;&gt;NON-RESPONSIVE PRIMARY&lt;/h3&gt;

&lt;p&gt;We consider a primary as &lt;em&gt;non-responsive&lt;/em&gt; if it crashes or deliberately stops broadcasting new &lt;strong&gt;PRE-PREPARE&lt;/strong&gt; messages. If the primary becomes &lt;em&gt;non-responsive&lt;/em&gt;, then the client cannot receive responses and will complain. Thus, replicas will forward the complained requests to the primary and start a timer. If the primary keeps being &lt;em&gt;non-responsive&lt;/em&gt;, then at least $2f+1$ non-faulty replicas will request a &lt;em&gt;view-change&lt;/em&gt; and eventually enter a new view.&lt;/p&gt;

&lt;h3 id=&quot;keeping-replicas-in-the-dark&quot;&gt;KEEPING REPLICAS IN THE DARK&lt;/h3&gt;

&lt;p&gt;Obviously, non-faulty replicas in the dark can catch up with other replicas via the checkpoint algorithm.&lt;/p&gt;

&lt;h3 id=&quot;equivocation&quot;&gt;EQUIVOCATION&lt;/h3&gt;

&lt;p&gt;There are two cases when the primary equivocates in round $r$, which means that the primary sends different &lt;strong&gt;PRE-PREPARE&lt;/strong&gt; messages to different replicas. In the first case, no request gets enough votes to be &lt;em&gt;committed&lt;/em&gt; by a non-faulty replica, which is the same as the case when the primary becomes &lt;em&gt;non-responsive&lt;/em&gt;. In the second case, there is one request that gets &lt;em&gt;committed&lt;/em&gt; by some of the non-faulty replicas, which is the same as the case when the primary attempts to keep some replicas in the dark. From what we have illustrated for the two malicious behaviors above, we know that we are able to recover from both of the cases when the primary equivocates.&lt;/p&gt;

&lt;h3 id=&quot;consecutive-faulty-primaries&quot;&gt;CONSECUTIVE FAULTY PRIMARIES&lt;/h3&gt;

&lt;p&gt;There can be consecutive Byzantine primaries in consecutive views. Thus, it is possible that the new primary is &lt;em&gt;non-responsive&lt;/em&gt; as well and does not broadcast &lt;strong&gt;NEW-VIEW&lt;/strong&gt; messages. To provide liveness in such a case, as mentioned before, non-faulty replicas will request a new &lt;em&gt;view-change&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;duplication&quot;&gt;DUPLICATION&lt;/h3&gt;

&lt;p&gt;A byzantine primary or primaries in different views may broadcast &lt;strong&gt;PRE-PREPARE&lt;/strong&gt; the same request twice, which we call &lt;em&gt;duplication&lt;/em&gt;. To eliminate &lt;em&gt;duplication&lt;/em&gt;, when proposing a new &lt;strong&gt;PRE-PREPARE&lt;/strong&gt; message, non-faulty primaries check if the request is already proposed. And non-faulty replicas check if the request is already proposed when receiving a &lt;strong&gt;PRE-PREPARE&lt;/strong&gt; message.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Commitment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessNewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;duplicate_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CheckAndAddProposed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;                                  
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Commitment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessProposeMsg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;duplicate_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CheckAndAddProposed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())){&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;LOG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;The request is already proposed, reject&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Tue, 22 Aug 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/08/22/ViewChangeInNexRes.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/08/22/ViewChangeInNexRes.html</guid>
      </item>
    
      <item>
        <title>Using the NexRes Explorer</title>
        <description>&lt;p&gt;Our Explorer page is a tool for visualizing the NexRes blockchain. The Explorer displays specific blocks on the blockchain, transactions within the blocks, ledger configuration data, and a chart exposing transaction history.&lt;/p&gt;

&lt;h1 id=&quot;install&quot;&gt;Install&lt;/h1&gt;
&lt;p&gt;Go to our &lt;a href=&quot;https://blog.resilientdb.com/2022/09/28/GettingStartedNexRes.html&quot;&gt;install tutorial&lt;/a&gt; for instructions on how to install NexRes.&lt;/p&gt;

&lt;h1 id=&quot;set-up&quot;&gt;Set Up&lt;/h1&gt;

&lt;p&gt;You will need to clone three repos to get started: &lt;a href=&quot;https://github.com/resilientdb/resilientdb&quot;&gt;resilientdb&lt;/a&gt; for the ResilientDB servers, &lt;a href=&quot;https://github.com/resilientdb/sdk&quot;&gt;sdk&lt;/a&gt; for the HTTP endpoints and websocket, and &lt;a href=&quot;https://github.com/resilientdb/resilientdb.github.io&quot;&gt;resilientdb.github.io&lt;/a&gt; for the webpage.&lt;/p&gt;

&lt;h3 id=&quot;resilientdb&quot;&gt;resilientdb&lt;/h3&gt;
&lt;p&gt;Install dependencies.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;./INSTALL.sh&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Start the KV servers with the example script. This script uses the example/kv_config.config file.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;./service/tools/kv_service/service_tools/start_kv_service.sh&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will observe that four kv_server replicas have locally launched.&lt;/p&gt;

&lt;h3 id=&quot;sdk&quot;&gt;sdk&lt;/h3&gt;
&lt;p&gt;We use &lt;a href=&quot;https://github.com/CrowCpp/Crow&quot;&gt;Crow&lt;/a&gt;, a C++ framework for creating HTTP or Websocket web services to connect NexRes to the Explorer.&lt;/p&gt;

&lt;p&gt;In another terminal shell after starting KV Server, build the crow service from the sdk repo:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel build service/http_server/crow_service_main&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run the binary to start the service:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/http_server/crow_service_main service/tools/config/interface/client.config service/http_server/server_config.config&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will see this if successful:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  (2022-12-19 06:12:02) [INFO    ] Crow/master server is running at http://0.0.0.0:18000 using 16 threads
  (2022-12-19 06:12:02) [INFO    ] Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;resilientdbgithubio&quot;&gt;resilientdb.github.io&lt;/h3&gt;
&lt;p&gt;In another terminal open the resilientdb.github.io repo and follow the steps below.&lt;/p&gt;

&lt;p&gt;Switch to explorer branch&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;git fetch&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;git checkout explorer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Project Setup&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;npm install&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Compile and Hot-Reload for Development&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;npm run dev&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will now be able to access a development server for &lt;a href=&quot;https://resilientdb.com&quot;&gt;resilientdb.com&lt;/a&gt; running at http://localhost:3000. Click on the explorer icon in the top right corner to migrate to http://localhost:3000/explorer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE: You must disable cross-origin restrictions in the browser where you open the development server.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;populating-the-blockchain&quot;&gt;Populating the Blockchain&lt;/h2&gt;
&lt;p&gt;At this point you will be able to see the ledger configuration data, but the transaction history chart and block table will be empty. The next step is populating the NexRes blockchain to view blocks and transactions using the Explorer.&lt;/p&gt;

&lt;p&gt;You can use an API tester tool such as &lt;a href=&quot;https://chrome.google.com/webstore/detail/talend-api-tester-free-ed/aejoelaoggembcahagimdiliamlcdmfm/reviews&quot;&gt;Talend API Tester&lt;/a&gt; for committing and getting transactions using the routes defined by our &lt;a href=&quot;https://github.com/resilientdb/sdk/blob/main/service/http_server/crow_service.cpp&quot;&gt;crow service&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also use curl commands to transfer data to and from the server. Here are some examples of the routes available.&lt;/p&gt;

&lt;p&gt;For committing a transaction:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;curl -X POST  -d ‘{“id”:”samplekey”,”value”:”samplevalue”}’ localhost:18000/v1/transactions/commit&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For getting the transaction:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;curl localhost:18000/v1/transactions/samplekey&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For getting &lt;strong&gt;all&lt;/strong&gt; transactions:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;curl localhost:18000/v1/transactions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have set and get some transactions you will be able to see the blocks and the transactions within them in the table and chart.&lt;/p&gt;

&lt;p&gt;There are currently two options for how the blocks table refreshes. The method that is used on the nexres branch
uses a websocket and fetches the updated list of blocks whenever a new transaction is committed through the HTTP
endpoints. The second option, which is available on the &lt;a href=&quot;https://github.com/resilientdb/resilientdb.github.io/tree/explorer-alternate-refresh&quot;&gt;explorer-alternate-refresh branch&lt;/a&gt;, polls an updated list of blocks every five seconds. You may use whichever one suits your needs better.&lt;/p&gt;

&lt;h2 id=&quot;video-demo&quot;&gt;Video Demo&lt;/h2&gt;

&lt;p&gt;Here is a video demo showing how to run and use the Explorer. The video assumes
that all the dependencies have already been installed.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/QbzbFF2v51I&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
</description>
        <pubDate>Sat, 06 May 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/05/06/NexResExplorer.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/05/06/NexResExplorer.html</guid>
      </item>
    
      <item>
        <title>GeoBFT in NexRes</title>
        <description>&lt;p&gt;In this article, we present a comprehensive introduction to the &lt;strong&gt;Geo-Scale Byzantine Fault-Tolerant consensus protocol (GeoBFT)&lt;/strong&gt; through the lens of the NexRes codebase. We will illustrate the algorithm of inter-cluster sharing and remote view-change of the protocol, and how to implement it on NexRes. We will also show the performance experiment results we got for GeoBFT on NexRes.&lt;/p&gt;

&lt;h3 id=&quot;the-challenges-in-geo-scale-blockchains&quot;&gt;The challenges in Geo-scale blockchains&lt;/h3&gt;

&lt;p&gt;The traditional blockchain protocols like PBFT&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, rely on a single primary replica to coordinate all consensus decisions, and require a vast amount of global communication between all pairs of replicas, hence, they often attain low throughput, especially when the replicas are spread across a wide-area network or geographically large distances.&lt;/p&gt;

&lt;p&gt;As the following figure shows, the global message latencies are at least 33-270 times higher than local latencies, while the maximum throughput is 10-151 times lower, both implying that the communication between regions is much more costly than communications within regions.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/Real-World Communication.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Real-world inter- and intra-cluster communication costs in terms of the ping round-trip times (which determines latency) and bandwidth (which determines throughput). These measurements are taken in Google Cloud using clusters of n1 machines (replicas) that are deployed in six different regions.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;geo-scale-byzantine-fault-tolerant-consensus-protocol-geobft&quot;&gt;Geo-Scale Byzantine Fault-Tolerant consensus protocol (GeoBFT)&lt;/h3&gt;

&lt;p&gt;Here we present GeoBFT that uses topological information to group all replicas in a single region into a single cluster&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. GeoBFT assigns each client to a single cluster, and it operates in rounds, in each round, every cluster will be able to propose a single client request for execution. Each round consists of the three steps sketched in Figure 2: local replication, global sharing, and ordering and execution, which we further detail next.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/Steps_in_GeoBFT.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/GeoBFT Working Overview.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. Steps in a round of the GeoBFT protocol.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h4 id=&quot;local-replication&quot;&gt;Local Replication&lt;/h4&gt;

&lt;p&gt;In the first step of GeoBFT, each round starts with each cluster replicating a client request &lt;em&gt;T&lt;/em&gt;, to do so, GeoBFT relies on PBFT. In addition, when each non-faulty replica commits the proposed request, it will also construct a &lt;em&gt;commit certificate&lt;/em&gt; $\langle T\rangle_{C}$ consisting of the client request and &lt;strong&gt;n-f &amp;gt; 2f&lt;/strong&gt; identical COMMIT messages for $\langle T\rangle_{P_{C}}$ signed by distinct replicas. The following graph shows the normal-case workflow of round $\rho$ of PBFT within a cluster $C$: a client $c$ requests transaction $T$, the primary $P_{C}$ proposes this request to all local replicas, which prepare and commit this proposal, and, finally, all replicas can construct a commit certificate.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/normal-case of PBFT.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. The normal-case working of round ρ of PBFT within a cluster C
    &lt;/em&gt;
&lt;/p&gt;

&lt;h4 id=&quot;global-sharing&quot;&gt;Global Sharing&lt;/h4&gt;

&lt;p&gt;Once a cluster has completed local replication of a client request, it proceeds with the second step: sharing the client request with all other clusters. After $C$ reaches local consensus on client request $\langle T\rangle_{P_{C}}$ in round $\rho$—enabling the construction of the commit certificate $[\langle T \rangle_{P_{C}}, \rho]$ that proves local consensus— $C$ needs to exchange this client request and the accompanying proof with all other clusters. The following graphs show the global sharing protocol used by $C_{1}$ to send $m := (\langle T \rangle_{P_{c}}, [ \langle T \rangle_{P_{c}}, \rho ])$ to $C_{2}$ and the pseudo-code of this protocol, which we will illustrate next.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/Global Sharing.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. The normal-case working of the global sharing protocol.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/Global Sharing Pseudo Code.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Pseudo Code of the normal-case global sharing protocol.
    &lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;Let $m := (\langle T \rangle_{P_{c}}, [ \langle T \rangle_{P_{c}}, \rho ])$ be the message that some replica in cluster $C_{1}$ needs to send to some replicas $C_{2}$.&lt;/p&gt;

&lt;p&gt;In the global phase, the primary $P_{C_{1}}$ sends $m$ to $f+1$ replicas in $C_{2}$. In the local phase, each non-faulty replica in $C_2$ that receives a well-formed m forwards m to all replicas in its cluster $C_{2}$.&lt;/p&gt;

&lt;p&gt;There are two cases in which replicas in $C_{2}$ do not receive $m$ from $C_{1}$: either $P_{C_{1}}$ is faulty and did not send $m$ to $f+1$ replicas in $P_{C_{2}}$, or communication is unreliable, and messages are delayed or lost. In both cases, non-faulty replicas in $C_{2}$ initiate &lt;em&gt;remote view-change&lt;/em&gt; to force primary replacement in $C_{1}$.&lt;/p&gt;

&lt;h4 id=&quot;remote-view-change&quot;&gt;Remote View-Change&lt;/h4&gt;

&lt;p&gt;To recover from any failures, we provide a remote view-change protocol. To simplify the presentation, we focus on the case in which the primary of cluster $C_{1}$ fails to send $m := (\langle T \rangle_{P_{c}}, [ \langle T \rangle_{P_{c}}, \rho ])$ to replicas of $P_{C_{2}}$. As the following graph describes, our remote view-change protocol consists of four phases, which we detail next. This protocol is triggered when a cluster $C_{2}$ ∈ S expects a message from $C_{1}$ ∈ S, but does not receive this message in time.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;First, non-faulty replicas in cluster $C_{2}$ detect the failure of the current primary $P_{C_{1}}$ of ${C_{1}}$ to send m. Note that although the replicas in $C_{2}$ have no information about the contents of message m, they are awaiting the arrival of a well-formed message m from $C_{1}$ in round $\rho$.&lt;/li&gt;
  &lt;li&gt;Second, the non-faulty replicas in $C_{2}$ initiate agreement on failure detection.&lt;/li&gt;
  &lt;li&gt;Third, after reaching an agreement, the replicas in $C_{2}$ send their request for a remote view-change to the replicas in $C_{1}$ in a reliable manner.&lt;/li&gt;
  &lt;li&gt;In the fourth and last phase, the non-faulty replicas in $C_{1}$ trigger a local view-change, replace $P_{C_{1}}$ , and instruct the new primary to resume global sharing with $C_{2}$.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/Remote View Change.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 6. The remote view-change protocol of GeoBFT. 
    &lt;/em&gt;
&lt;/p&gt;

&lt;h4 id=&quot;ordering-and-execution&quot;&gt;Ordering and Execution&lt;/h4&gt;

&lt;p&gt;Once replicas of a cluster have chosen a client request for execution and have received all client requests chosen by other clusters, the final step is ordering and executing these client requests. In specific, in round $\rho$, any non-faulty replica that has valid requests from all clusters can move ahead and execute these requests. To put these client requests in a unique order, execute them, and inform the clients of the outcome, GeoBFT simply uses a pre-defined ordering on the clusters. For example, each replica executes the transactions in the order $[T_{1}, . . . , T_{z}]$. Once the execution is complete, each replica $R \in C_{i}, 1 \leq i \leq z$, informs the client $c_{i}$ of any outcome.&lt;/p&gt;

&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;

&lt;p&gt;Now we will give a brief overview of the implementation of the GeoBFT protocol in NexRes. To implement GeoBFT on NexRes, we will need to add a few modules: &lt;em&gt;Local Executor, Global Executor, GeoBFT Consensus Service&lt;/em&gt;, and also adjust the &lt;em&gt;Configuration&lt;/em&gt;, which we will introduce next. Below is the normal-case working graph of GeoBFT on NexRes.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/GeoBFT_1.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 100%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 7. The normal-case working of GeoBFT on NexRes 
    &lt;/em&gt;
&lt;/p&gt;

&lt;h4 id=&quot;configuration&quot;&gt;Configuration&lt;/h4&gt;

&lt;p&gt;To implement GeoBFT on NexRes, we need to first add a few fields in the configuration file, which specify the timeout for remote view-change, and the flag that indicates whether the local view-change is enabled.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  region: [
    {
      replicaInfo: {
        id:
        ip:
        port:
      },
      regionId: 1
    }
  ],
  selfRegionId: 1,
  rvc_timeout_ms: 60000,	 # Timeout for Remote View-Change
  enable_viewchange: true	 # View-Change Flag
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;local-executor&quot;&gt;Local Executor&lt;/h4&gt;

&lt;p&gt;After committing a local client request at the end of PBFT, the local executor will construct the &lt;em&gt;commit certificate&lt;/em&gt; which is of &lt;em&gt;TYPE_GEO_REQUEST&lt;/em&gt;, here we call it &lt;em&gt;geo_request&lt;/em&gt;. The primary replica will be responsible for sending out the &lt;em&gt;geo_request&lt;/em&gt; to every other cluster in the system. Specifically, for each round, the same &lt;em&gt;geo_request&lt;/em&gt; will only need to be sent to &lt;em&gt;f+1&lt;/em&gt; replicas in each cluster.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoTransactionExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SendBatchGeoMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batch_geo_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Construct geo_request&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;geo_request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resdb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_GEO_REQUEST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self_region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// set sequence number, proxy id, hash value, data in geo_request&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;// Only for primary node, send out geo_request to other regions.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;system_info_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetPrimaryId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;	
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self_region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;	&lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_faulty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replica_info_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// maximum number of faulty replicas in this region&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_request_sent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replica&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replica_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_request_sent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_faulty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;LOG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;send batch_geo_request to node &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replica&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replica_client_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SendBatchMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batch_geo_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replica&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// send to f + 1 replicas in the region&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;num_request_sent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;global-executor&quot;&gt;Global Executor&lt;/h4&gt;

&lt;p&gt;After receiving a &lt;em&gt;geo_request&lt;/em&gt; from another region, push it into &lt;em&gt;order_queue_&lt;/em&gt;, which is storing the transactions that are not yet ordered. The global executor will constantly pop out &lt;em&gt;geo_request&lt;/em&gt; from &lt;em&gt;order_queue_&lt;/em&gt;, and add it to &lt;em&gt;execute_map_&lt;/em&gt;, which is storing the transactions that are waiting to be executed by order. Then, the global executor will find the next transaction to execute in the &lt;em&gt;execute_map_&lt;/em&gt; according to the current round $\rho$. We use a thread to keep this ordering and execution process going.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execute_map_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;thread&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_thread_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeoGlobalExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderRound&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoGlobalExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderGeoRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;order_queue_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoGlobalExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_queue_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Pop geo_request from order_queue_&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seq_num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execute_map_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// add geo_request to execute_map_&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoGlobalExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderRound&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    	&lt;span class=&quot;n&quot;&gt;AddData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Pop geo_request from order_queue_, add it to execute_map_&lt;/span&gt;
    	&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsStop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seq_map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetNextMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Get next geo_request to execute in the execute_map_&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq_map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq_map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Execute the geo_request and reset the timer for remote view change.&lt;/span&gt;
    	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The global executor also has $\mathcal{n-1}$ timers to trigger remote view-change in $\mathcal{n-1}$ other regions. Let $\mathcal{R} \in \mathcal{C_{1}}$ be the replica we are looking at. Upon receiving a geo_request from another region, the global executor will need to reset the timer for that region. When the timeout function is triggered, $\mathcal{R}$ will broadcast a &lt;em&gt;drvc_request&lt;/em&gt; locally. After receiving $\mathcal{f+1}$ distinct &lt;em&gt;drvc_request&lt;/em&gt; from other replicas in local cluster, $\mathcal{R}$ will also start to broadcast a &lt;em&gt;drvc_request&lt;/em&gt; locally. After receiving $\mathcal{n-f}$ distinct &lt;em&gt;drvc_request&lt;/em&gt; from other replicas in the local cluster, $\mathcal{R}$ will start to send a new type of request-&lt;em&gt;rvc_request&lt;/em&gt; to $\mathcal{Q} \in \mathcal{C_{2}}$ with $id(\mathcal{Q})=id(\mathcal{R})$, with $C_{2}$ being the target cluster of this remote view-change.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoGlobalExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// reset the timer for the region which the request came from.&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next_region_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;TryResetTimer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next_seq_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;	
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;TryResetTimer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next_seq_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// detect failure of region rvc_target_region in round ρ, trigger RVC&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoGlobalExecutor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TriggerRVCLocalBroadcast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// broadcast drvc_request locally&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;drvc_request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resdb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_DRVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self_region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;drvc_request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_current_executed_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;drvc_request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;replica_client_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BroadCast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drvc_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;geobft-consensus-service&quot;&gt;GeoBFT Consensus Service&lt;/h4&gt;

&lt;p&gt;To process those types of messages we mentioned (&lt;em&gt;geo_request, drvc_request, rvc_request&lt;/em&gt;) we need to implement the &lt;em&gt;GeoBFT Consensus Service&lt;/em&gt; as the entry for the process of those requests.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConsensusServiceGeoPBFT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConsensusCommit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                             &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_GEO_REQUEST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commitment_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeoProcessCcm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;		&lt;span class=&quot;c1&quot;&gt;// Process geo_request&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_DRVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commitment_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessDRVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;			&lt;span class=&quot;c1&quot;&gt;// Process drvc_request&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_RVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commitment_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessRVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;			&lt;span class=&quot;c1&quot;&gt;// Process rvc_request&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ConsensusServicePBFT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ConsensusCommit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// Norcal-case PBFT processing&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoPBFTCommitment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeoProcessCcm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// filter of duplicate message&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// if the request comes from another region, do local broadcast&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_region_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self_region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;broadcast_geo_req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;resdb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_GEO_REQUEST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender_region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;replica_client_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BroadCast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;broadcast_geo_req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// push the request into order_queue_&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;global_executor_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderGeoRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoPBFTCommitment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessDRVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                   &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_executed_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rvc_target_region&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;drvc_sender_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// filter of duplicate messages&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// when receives f+1 DRVC request: detect failure of region C in round&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ρ broadcast DRvc(C, ρ) to all replicas in local region.&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_replicas&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetReplicaNum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_faulty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;num_replicas&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drvc_map_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_faulty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;global_executor_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TriggerRVCLocalBroadcast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// when receives DRvc(C1, ρ) from n − f replicas, send Rvc(C1, ρ)_R to Q ∈ C1, id(R) = id(Q).&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drvc_map_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make_pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_replicas&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_faulty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rvc_request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resdb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_RVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self_region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rvc_request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_current_executed_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rvc_request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_target_region&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// find target_replica Q&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;replica_client_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target_replica&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GeoPBFTCommitment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProcessRVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                  &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;uint64_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_executed_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_faulty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetReplicaNum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;	&lt;span class=&quot;c1&quot;&gt;// filter of duplicate messages&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// If received f+1 idendical rvc from distinct replicas in C2, trigger local view change.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_map_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_faulty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;viewchange_manager_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RunTimeoutFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Broadcast rvc locally.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self_region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rvc_request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resdb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TYPE_RVC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self_region_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rvc_request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_current_executed_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;missing_seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;replica_client_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BroadCast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rvc_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;preliminary-experiments-and-results&quot;&gt;Preliminary Experiments and Results&lt;/h3&gt;

&lt;h4 id=&quot;experiment-setup&quot;&gt;Experiment Setup&lt;/h4&gt;

&lt;p&gt;We ran all the experiments on AWS using:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;t3.2xlarge&lt;/li&gt;
  &lt;li&gt;8 vCPU&lt;/li&gt;
  &lt;li&gt;64GB of RAM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nexres ran on Ubuntu, 20.04 LTS, amd64 focal image build on 2022-09-14.&lt;/p&gt;

&lt;h4 id=&quot;throughput-and-latency-performance&quot;&gt;Throughput and Latency Performance&lt;/h4&gt;

&lt;p&gt;The first experiment is designed to test the maximum throughput and latency of GeoBFT and compare the result with PBFT performance under the same configuration. The throughput and latency of PBFT and GeoBFT with 4 clusters with different numbers of replicas are recorded. The replica number is set to 16, 32, 64, and 128.&lt;/p&gt;

&lt;p&gt;From the figure below, we can see that as the system scales, the throughput decreases and the latency increases for both PBFT and GeoBFT. With respect to throughput, GeoBFT outperforms PBFT at all replica settings. In general, the average latency of GeoBFT is smaller than PBFT at all replica settings except for the 16-replica setting, and it is almost half of PBFT latency at the 128-replica setting.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/Throughput Performance.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 80%&quot; /&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/Latency Performance.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 80%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 8. Throughput and latency as a function of the number of replicas.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h4 id=&quot;impact-of-primary-failure&quot;&gt;Impact of Primary Failure&lt;/h4&gt;

&lt;p&gt;In the second experiment, we measure the performance of GeoBFT when a single primary fails (in one of the two regions). The system configuration is 2 clusters with 16 replicas in each cluster, 32 replicas in total.&lt;/p&gt;

&lt;p&gt;Figure 9 shows the throughput attained by GeoBFT when the primary of one cluster fails, and the replicas run the remote view change protocol to replace the faulty primary. The primary of one of the clusters fails at 45s, and the system’s average throughput starts decreasing; Later, GeoBFT again observes an increase in throughput at 60s.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/GeoBFT/Impact of Primary Failure in One Cluster.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 80%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 9. GeoBFT&apos;s throughput under the primary failure of one cluster out of two.
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;strong&gt;Castro, Miguel, and Barbara Liskov. “&lt;em&gt;Practical byzantine fault tolerance.&lt;/em&gt;” OsDI. Vol. 99. No. 1999. 1999.&lt;/strong&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;strong&gt;Suyash Gupta, Sajjad Rahnama, Jelle Hellings, and Mohammad Sadoghi. “&lt;em&gt;ResilientDB: Global Scale Resilient Blockchain Fabric&lt;/em&gt;” URL: https://arxiv.org/abs/2002.00160&lt;/strong&gt; &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Tue, 07 Mar 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/03/07/GeoBFT.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/03/07/GeoBFT.html</guid>
      </item>
    
      <item>
        <title>NexRes Durability Layer</title>
        <description>&lt;p&gt;We provide two databases to choose from to use for durable storage: LevelDB and RocksDB. Both are key-value stores based on log-structured merge (LSM) trees. LSM trees are optimized for write-heavy workloads, and consist of multiple levels, with the keys sorted at each level. The top level is called the memtable, where the most recently inserted data is kept in-memory. The two databases are similar, as RocksDB was initially built on top of LevelDB.&lt;/p&gt;

&lt;h1 id=&quot;install&quot;&gt;Install&lt;/h1&gt;
&lt;p&gt;If you don’t have NexRes installed already please check the &lt;a href=&quot;https://blog.resilientdb.com/2022/09/28/GettingStartedNexRes.html&quot;&gt;install tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;leveldb-vs-rocksdb&quot;&gt;LevelDB vs RocksDB&lt;/h1&gt;

&lt;p&gt;Through testing we have found that NexRes works up to ~35-40% faster with LevelDB enabled than with RocksDB. When batched writes are enabled in the durable layer, performance increases by up to 3x with with LevelDB and up to around 2x with RocksDB. RocksDB also provides multiple features not in LevelDB, including allowing the user to set the number of worker threads used.&lt;/p&gt;

&lt;h1 id=&quot;configuration&quot;&gt;Configuration&lt;/h1&gt;

&lt;p&gt;We use Google’s Protobuf to specify the configurations for NexRes. You can configure following settings for the durable layer in a config file such as the one provided below:&lt;/p&gt;

&lt;p&gt;LevelDB and RocksDB&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;enable_leveldb/enable_rocksdb
    &lt;ul&gt;
      &lt;li&gt;Make sure to only set one of these to true at the same time&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;write_buffer_size_mb&lt;/li&gt;
  &lt;li&gt;write_batch_size
    &lt;ul&gt;
      &lt;li&gt;Keep at 1 to use only individual writes. For batched writes, sizes of 100+ bring higher performance numbers&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;path&lt;/li&gt;
  &lt;li&gt;generate_unique_pathnames&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RocksDB only&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;num_threads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;example/kv_config.config&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  region : {
    ...
  },
  ...
  rocksdb_info : {
    enable_rocksdb:false,
    num_threads:1,
    write_buffer_size_mb:32,
    write_batch_size:1,
    generate_unique_pathnames:true,
  },
  leveldb_info : {
    enable_leveldb:false,
    write_buffer_size_mb:128,
    write_batch_size:1,
    generate_unique_pathnames:true,
  },
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;warning&quot;&gt;Warning&lt;/h1&gt;
&lt;p&gt;Currently, reads are guaranteed to be correct when batched writes are enabled in the durable layer. This is because a read may access the old value of a key whose value is updated in a write that is in a batch that has not been committed yet.&lt;/p&gt;

&lt;p&gt;If “path” is not set in the durability settings for RocksDB or LevelDB then default paths will be generated in the /tmp/ folder, which is cleared whenever the machine is shut down.&lt;/p&gt;

&lt;p&gt;If you are testing NexRes on your local machine using localhost ip, then make sure to set generate_unique_pathnames to true, since multiple processes are not allowed to open up the same RocksDB/LevelDB directory at the same time. When generate_unique_pathnames is set to true, the durable layer uses the cert file names to generate separate directories for each port of the localhost ip.&lt;/p&gt;

&lt;p&gt;For example, the process hosting a server with cert_1.cert will append “1” to its directory path. If the cert file name does not contain a number and generate_unique_pathnames is set, “0” will be appended to the path.&lt;/p&gt;
</description>
        <pubDate>Wed, 15 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/02/15/NexResDurabilityLayer.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/02/15/NexResDurabilityLayer.html</guid>
      </item>
    
      <item>
        <title>UTXO On NexRes</title>
        <description>&lt;p&gt;An unspent transaction output (&lt;a href=&quot;https://en.wikipedia.org/wiki/Unspent_transaction_output&quot;&gt;UTXO&lt;/a&gt;) model helps us to make crypto transactions more efficient and it is a crucial core part in Bitcoin.
In this document, we introduce the UTXO implementation on NexRes.&lt;/p&gt;

&lt;h2 id=&quot;crypto-key&quot;&gt;Crypto key&lt;/h2&gt;
&lt;p&gt;A Crypt key is a private-public key pair to provide the security of the transaction. 
We use ECDSA as the encoding algorithm and sign each message.&lt;/p&gt;

&lt;h2 id=&quot;wallet&quot;&gt;Wallet&lt;/h2&gt;
&lt;p&gt;Wallet manages the coins of each user. The address of each user is created by its public key,
using &lt;a href=&quot;https://github.com/fiatjaf/bech32&quot;&gt;bech32&lt;/a&gt; as encoding as what Bitcoin does, also wrapped by ripemd160 and sha256.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;address = bech32Encode(ripemd160(sha256(public key)))&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;utxo&quot;&gt;UTXO&lt;/h2&gt;
&lt;p&gt;UTXO is a data structure representing a transaction of a wallet user, including some inputs and outputs. 
Each input is a transaction that transfers coins from other users. 
In the UTXO on NexRes, the input contains the input transaction ids and the output index of the output transaction that delivers coins to the user.
All these input transactions are the available input of the current transaction,
and the outputs indicate how to deliver these coins from these transactions. It contains the addresses of the delivered users, how many coins are to be delivered, and their public keys.
The sum of the inputs should be larger than the sum of the outputs. The delta can be used as the gas fee.&lt;/p&gt;

&lt;div style=&quot;text-align: center&quot;&gt;
&lt;img src=&quot;/assets/images/nexres/utxo.jpg&quot; style=&quot;zoom: 60%;&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;security&quot;&gt;Security&lt;/h2&gt;
&lt;p&gt;Each transaction will be signed by the address of the owner and the signatures can be verified by the public key inside its input transactions. Plus, the addresses of the input transactions should be the same as the address of the issue transaction.
Therefore, it should guarantee that each transaction can only be spent once.&lt;/p&gt;

&lt;h2 id=&quot;system-architecture&quot;&gt;System Architecture&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/assets/images/nexres/utxo_nexres.jpg&quot; alt=&quot;utxo_nexres&quot; /&gt;
UTXO is running on NexRes and managed by its local UTXO Manager. Transactions will be included into a transaction block (tx block) and go through the consensus protocol 
by NexRes, then are saved locally into a transaction queue.&lt;/p&gt;

&lt;p&gt;UTXO Manager iteratively fetches the transactions and executes the UTXO data in each transaction.
All the valid UTXO data will be calculated as coins and saved into the user wallets so that they can view their accounts.
What’s more, the transactions will be handled by a transaction pool so that not only the UTXO manager can keep checking 
whether the transaction has been spent or users can be able to trace the transaction history.&lt;/p&gt;
</description>
        <pubDate>Sun, 12 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/02/12/UtxoOnNexres.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/02/12/UtxoOnNexres.html</guid>
      </item>
    
      <item>
        <title>Getting Started On UTXO</title>
        <description>&lt;p&gt;Here we illustrate how to run the UTXO service on NexRes. We provide steps by steps tutorial to set up the UTXO service locally with 4 nodes and 1 client. We also provide tools to access the UTXO transactions and the user wallets.&lt;/p&gt;

&lt;h2 id=&quot;create-a-wallet&quot;&gt;Create a Wallet&lt;/h2&gt;

&lt;p&gt;Beginning using UTXO transactions on NexRes, we need to create a wallet by generating a private key, a public key, 
and an address corresponding to your wallet.
Wallet addresses are encoded by bech32 which is also used for Bitcoin.&lt;/p&gt;

&lt;p&gt;These are some steps to build your private-public keys and your address:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Go to the source folder which contains the WORKSPACE file.&lt;/p&gt;

    &lt;p&gt;Make sure  bech32 has been installed which is used for the address encoding.&lt;/p&gt;
    &lt;blockquote&gt;
      &lt;p&gt;pip install bech32&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Create your own private key. It will return a private key and a public key, encoded by ECDSA.
 In the example here, we will create two key pairs and two addresses.
    &lt;blockquote&gt;
      &lt;p&gt;bazel run //service/tools/utxo/wallet_tool/py:keys&lt;/p&gt;
      &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  private key:303E020100301006072A8648CE3D020106052B8104000A0427302502010104202CB99BBB2AFEB7F48A574064091B34F24781C93AD8181A511C8DCFB2A111AD82
  public key:3056301006072A8648CE3D020106052B8104000A034200049C8FBD86EA4E38FD607CD3AC49FEB75E364B0C694EFB2E6DDD33ABED0BB1017575A79CC53EC6A052F839B4876E96FF9E4B08ECF23EC9CD495B82ECF9D95303BD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;      &lt;/div&gt;
      &lt;p&gt;bazel run //service/tools/utxo/wallet_tool/py:keys&lt;/p&gt;
      &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  private key:303E020100301006072A8648CE3D020106052B8104000A0427302502010104202BDCC4974026EC852F95D481AE8FEC3AC31E130AB6C78A32EB8410CCDCA4B337
  public key:3056301006072A8648CE3D020106052B8104000A03420004F838F3253A5224411D8951AA6EF2BB474EDD283EC088CD13D5404956C0A88079ECF539D9669A3D639A35BF9FD0F67ECBB3D332733C59B0272EB844405B6568D3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;      &lt;/div&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;Create your wallet address based on the public key.
  This will return an bech32 address encoded from ripemd160(sha256(public_key))
    &lt;blockquote&gt;
      &lt;p&gt;bazel run //service/tools/utxo/wallet_tool/py:addr -- 3056301006072A8648CE3D020106052B8104000A034200049C8FBD86EA4E38FD607CD3AC49FEB75E364B0C694EFB2E6DDD33ABED0BB1017575A79CC53EC6A052F839B4876E96FF9E4B08ECF23EC9CD495B82ECF9D95303BD&lt;/p&gt;
      &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  address: bc1q09tk54hqfz5muzn9rgalfkdjfey8qpuhmzs5zn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;      &lt;/div&gt;
      &lt;p&gt;bazel run //service/tools/utxo/wallet_tool/py:addr -- 3056301006072A8648CE3D020106052B8104000A03420004F838F3253A5224411D8951AA6EF2BB474EDD283EC088CD13D5404956C0A88079ECF539D9669A3D639A35BF9FD0F67ECBB3D332733C59B0272EB844405B6568D3&lt;/p&gt;
      &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  address: bc1qd5ftrxa3vlsff5dl04nxg06ku6p4w6enk0cna9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;      &lt;/div&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;start-utxo-service&quot;&gt;Start UTXO Service&lt;/h2&gt;

&lt;p&gt;Before starting the service, you need to assign a genesis coin to some addresses.&lt;/p&gt;

&lt;p&gt;Modify the UTXO config to add coins.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;service/tools/config/server/utxo_config.config&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;the field ‘out’ indicates the output of a UTXO.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  genesis_transactions: {
    transactions: {
        out:  {
            address : &quot;bc1q09tk54hqfz5muzn9rgalfkdjfey8qpuhmzs5zn&quot;,
            value : 1000
            pub_key: &quot;3056301006072A8648CE3D020106052B8104000A034200049C8FBD86EA4E38FD607CD3AC49FEB75E364B0C694EFB2E6DDD33ABED    0BB1017575A79CC53EC6A052F839B4876E96FF9E4B08ECF23EC9CD495B82ECF9D95303BD&quot;
        }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once you added the genesis coins, start the UTXO service.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;./service/tools/utxo/service_tools/start_utxo_service.sh&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;transfer-your-coins&quot;&gt;Transfer your coins&lt;/h2&gt;

&lt;p&gt;First, we need to build the tools&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;bazel build service/tools/utxo/wallet_tool/cpp:utxo_client_tools&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then, run the tools to transfer the coins&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/utxo/wallet_tool/cpp/utxo_client_tools -c service/tools/utxo/wallet_tool/cpp/client_config.config -m transfer -t bc1qd5ftrxa3vlsff5dl04nxg06ku6p4w6enk0cna9 -d bc1q09tk54hqfz5muzn9rgalfkdjfey8qpuhmzs5zn -x 0 -v 100 -p 303E020100301006072A8648CE3D020106052B8104000A0427302502010104202CB99BBB2AFEB7F48A574064091B34F24781C93AD8181A511C8DCFB2A111AD82 -b 3056301006072A8648CE3D020106052B8104000A03420004F838F3253A5224411D8951AA6EF2BB474EDD283EC088CD13D5404956C0A88079ECF539D9669A3D639A35BF9FD0F67ECBB3D332733C59B0272EB844405B6568D3&lt;/p&gt;
&lt;/blockquote&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;-c&lt;/td&gt;
      &lt;td&gt;server config points to the client node&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-m&lt;/td&gt;
      &lt;td&gt;function&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-d&lt;/td&gt;
      &lt;td&gt;owner address&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-t&lt;/td&gt;
      &lt;td&gt;address list to transfer (using “,” to split)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-x&lt;/td&gt;
      &lt;td&gt;input transaction id&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-v&lt;/td&gt;
      &lt;td&gt;transfered value list of coins (using “,” to split)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-p&lt;/td&gt;
      &lt;td&gt;private key of the owner&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-b&lt;/td&gt;
      &lt;td&gt;public key list of the delivered address (using “,” to split)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;If it runs successfully, it returns the transaction id.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  E20230214 17:55:23.280972 39813 utxo_client_tools.cpp:61] execute result:
  1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;transfer-your-coins-with-multi-addresses&quot;&gt;Transfer your coins with multi addresses&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/utxo/wallet_tool/cpp/utxo_client_tools -c service/tools/utxo/wallet_tool/cpp/client_config.config -m transfer -t bc1qd5ftrxa3vlsff5dl04nxg06ku6p4w6enk0cna9,bc1q09tk54hqfz5muzn9rgalfkdjfey8qpuhmzs5zn -d bc1q09tk54hqfz5muzn9rgalfkdjfey8qpuhmzs5zn -x 0 -v 100,800 -p 303E020100301006072A8648CE3D020106052B8104000A0427302502010104202CB99BBB2AFEB7F48A574064091B34F24781C93AD8181A511C8DCFB2A111AD82 -b 3056301006072A8648CE3D020106052B8104000A03420004F838F3253A5224411D8951AA6EF2BB474EDD283EC088CD13D5404956C0A88079ECF539D9669A3D639A35BF9FD0F67ECBB3D332733C59B0272EB844405B6568D3,3056301006072A8648CE3D020106052B8104000A034200049C8FBD86EA4E38FD607CD3AC49FEB75E364B0C694EFB2E6DDD33ABED0BB1017575A79CC53EC6A052F839B4876E96FF9E4B08ECF23EC9CD495B82ECF9D95303BD&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;get-the-transaction-list&quot;&gt;Get the transaction list&lt;/h2&gt;

&lt;p&gt;Obtain the transaction list from one of the replica nodes. The server config is different from the one used in the transfer, which uses the client one.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/utxo/wallet_tool/cpp/utxo_client_tools -c service/tools/utxo/wallet_tool/cpp/server_config0.config -m list -e -1 -n 5&lt;/p&gt;
&lt;/blockquote&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;-c&lt;/td&gt;
      &lt;td&gt;server config points to the server node&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-m&lt;/td&gt;
      &lt;td&gt;function&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-e&lt;/td&gt;
      &lt;td&gt;last transaction id, or -1 points to the last one&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-n&lt;/td&gt;
      &lt;td&gt;the number of utxos needed to be returned&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  {&quot;in&quot;:[{}],&quot;out&quot;:[{&quot;address&quot;:&quot;bc1qd5ftrxa3vlsff5dl04nxg06ku6p4w6enk0cna9&quot;,&quot;value&quot;:&quot;100&quot;}],&quot;address&quot;:&quot;bc1q09tk54hqfz5muzn9rgalfkdjfey8qpuhmzs5zn&quot;,&quot;transactionId&quot;:&quot;1&quot;}
  {&quot;out&quot;:[{&quot;address&quot;:&quot;bc1q09tk54hqfz5muzn9rgalfkdjfey8qpuhmzs5zn&quot;,&quot;value&quot;:&quot;1000&quot;,&quot;spent&quot;:true}]}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;get-the-wallet-value&quot;&gt;Get the wallet value&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/tools/utxo/wallet_tool/cpp/utxo_client_tools -c service/tools/utxo/wallet_tool/cpp/server_config0.config -m wallet -t bc1qd5ftrxa3vlsff5dl04nxg06ku6p4w6enk0cna9&lt;/p&gt;
&lt;/blockquote&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;-c&lt;/td&gt;
      &lt;td&gt;server config points to the server node&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-m&lt;/td&gt;
      &lt;td&gt;function&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;-t&lt;/td&gt;
      &lt;td&gt;wallet address to be fetched&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  E20230214 18:02:26.936648 41575 utxo_client_tools.cpp:76] address:bc1qd5ftrxa3vlsff5dl04nxg06ku6p4w6enk0cna9 get wallet value:100
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sun, 12 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/02/12/GettingStartedOnUtxo.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/02/12/GettingStartedOnUtxo.html</guid>
      </item>
    
      <item>
        <title>Using the NexRes Python SDK</title>
        <description>&lt;p&gt;We provide a Python SDK for committing transactions to create and transfer assets. Despite NexRes being written in C++, the code for validating transactions is written in Python so that we can use the cryptoconditions library, which provides functionalities not available in any widely distributed C++ libraries currently.&lt;/p&gt;

&lt;h1 id=&quot;install-nexres-and-python39&quot;&gt;Install NexRes and Python3.9+&lt;/h1&gt;
&lt;p&gt;Please check the &lt;a href=&quot;https://blog.resilientdb.com/2022/09/28/GettingStartedNexRes.html&quot;&gt;install tutorial&lt;/a&gt; to install &lt;a href=&quot;https://github.com/resilientdb/resilientdb&quot;&gt;NexRes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After this you will need some additional steps for &lt;a href=&quot;https://github.com/pybind/pybind11&quot;&gt;pybind11&lt;/a&gt; to work, as we are embedding the Python interpreter in the C++ code.&lt;/p&gt;

&lt;p&gt;Make sure your Python version is 3.9+. Check the version with&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;python3 --version&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the .bazelrc file in your nexres directory, have the PYTHON_BIN_PATH reference the location of your python executable. For example, if you have Python installed at /home/ubuntu/.linuxbrew/bin/python3, then it will look like&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;build –action_env=PYTHON_BIN_PATH=”/home/ubuntu/.linuxbrew/bin/python3”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then install the Python dev library for your corresponding Python version. These are used when the C++ binary is run.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;sudo apt-get install python3.10-dev&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If apt cannot find the dev library, you might not have deadsnakes added as a source. You can use the following commands to check your sources and add if needed:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;ls /etc/apt/sources.list.d&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;sudo add-apt-repository ppa:deadsnakes/ppa&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;setting-up-virtual-environment&quot;&gt;Setting Up Virtual Environment&lt;/h1&gt;
&lt;p&gt;It is heavily advised to set up a virtual Python environment so you do not disturb your system’s Python settings.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;sudo apt-get install python3.10-venv&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;python3 -m venv venv&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;source venv/bin/activate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then install the Python dependencies&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;pip install -r requirements.txt&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you wish to deactivate the virtual environment you can enter&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;deactivate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;running-nexres-kv-service&quot;&gt;Running NexRes KV Service&lt;/h1&gt;
&lt;p&gt;NexRes needs to be running first for the SDK endpoints to connect to. Go to the &lt;strong&gt;resilientdb&lt;/strong&gt; folder you have downloaded from the &lt;a href=&quot;https://github.com/resilientdb/resilientdb&quot;&gt;resilientdb&lt;/a&gt; repository.&lt;/p&gt;

&lt;p&gt;Start the KV Service with the example script.&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;./service/tools/kv/server_tools/start_kv_service.sh&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;running-crow-service&quot;&gt;Running Crow Service&lt;/h1&gt;
&lt;p&gt;We use &lt;a href=&quot;https://github.com/CrowCpp/Crow&quot;&gt;Crow&lt;/a&gt;, a C++ framework for creating HTTP or Websocket web services to connect our SDK to NexRes.&lt;/p&gt;

&lt;p&gt;In another terminal shell after starting KV Server, go to the &lt;strong&gt;ResilientDB-GraphQL&lt;/strong&gt; folder that you have downloaded from the &lt;a href=&quot;https://github.com/ResilientApp/ResilientDB-GraphQL&quot;&gt;ResilientDB-GraphQL&lt;/a&gt; repository, build the crow service:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;bazel build service/http_server:crow_service_main&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run the binary to start the service:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;bazel-bin/service/http_server/crow_service_main service/tools/config/interface/client.config service/http_server/server_config.config&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will see this if successful:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  (2022-12-19 06:12:02) [INFO    ] Crow/master server is running at http://0.0.0.0:18000 using 16 threads
  (2022-12-19 06:12:02) [INFO    ] Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;running-the-sdk&quot;&gt;Running the SDK&lt;/h1&gt;

&lt;h2 id=&quot;check-your-python-is-up-to-date-39&quot;&gt;Check your Python is up-to-date (3.9+)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;python3 --version&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your Python version number is too low you may encounter type hinting issues when attempting to run the code&lt;/p&gt;

&lt;h2 id=&quot;activating-virtual-environment&quot;&gt;Activating virtual environment&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;source venv/bin/activate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;running-the-driver&quot;&gt;Running the Driver&lt;/h2&gt;

&lt;p&gt;Examples of using the driver can be seen in &lt;em&gt;test_sdk.py&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;python3 test_sdk.py&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will see the output &lt;em&gt;‘The retrieved txn is successfully validated’&lt;/em&gt; if successful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Now you are set with the Python SDK&lt;/em&gt;&lt;/strong&gt;. 
Below are the design details of the Python SDK.&lt;/p&gt;

&lt;h1 id=&quot;validation&quot;&gt;Validation&lt;/h1&gt;

&lt;h2 id=&quot;entrypoint&quot;&gt;Entrypoint&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;validator.py&lt;/code&gt;
    call the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;is_valid_tx(tx_dict)&lt;/code&gt; function with the transaction json (tx_dict) as the argument.&lt;/p&gt;

&lt;h2 id=&quot;transaction-validation-rules&quot;&gt;Transaction Validation Rules&lt;/h2&gt;
&lt;p&gt;A transaction is said to be valid if it satisfies certain conditions or rules.&lt;/p&gt;

&lt;p&gt;We employ a simpler version of the transaction spec and validation rules specified by &lt;a href=&quot;https://github.com/bigchaindb/BEPs/tree/master/13#transaction-validation&quot;&gt;BigchainDB&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;json-schema-validation&quot;&gt;JSON Schema Validation&lt;/h4&gt;
&lt;p&gt;The json structure of a transaction should be the transaction spec v2 of BigchainDB&lt;/p&gt;

&lt;h4 id=&quot;the-outputamount-rule&quot;&gt;The output.amount Rule&lt;/h4&gt;
&lt;p&gt;For all output.amount must be an integer between 1 and 9×10^18, inclusive. The reason for the upper bound is to keep amount within what a server can comfortably represent using a 64-bit signed integer, i.e. 9×10^18 is less than 2^63.&lt;/p&gt;

&lt;h4 id=&quot;the-duplicate-transaction-rule&quot;&gt;The Duplicate Transaction Rule&lt;/h4&gt;
&lt;p&gt;If a transaction is a duplicate of a previous transaction, then it’s invalid. A quick way to check that is by checking to see if a transaction with the same transaction ID is already stored.
A transaction ID is the hash of the transaction.&lt;/p&gt;

&lt;h4 id=&quot;the-transfer-transaction-rules&quot;&gt;The TRANSFER Transaction Rules&lt;/h4&gt;
&lt;p&gt;if a transaction is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TRANSFER&lt;/code&gt; transaction:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;TODO: If an input attempts to fulfill an output that has already been fulfilled (i.e. spent or transferred) by a previous valid transaction, then the transaction is invalid. (You don’t have to check if the fulfillment string is valid.)&lt;/li&gt;
  &lt;li&gt;If two or more inputs (in the transaction being validated) attempt to fulfill the same output, then the transaction is invalid. (You don’t have to check any fulfillment strings.)&lt;/li&gt;
  &lt;li&gt;The sum of the amounts on the inputs must equal the sum of the amounts on the outputs. In other words, a TRANSFER transaction can’t create or destroy asset shares.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For all inputs, if input.fulfills points to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;a transaction that doesn’t exist, then it’s invalid.&lt;/li&gt;
  &lt;li&gt;a transaction that’s invalid, then it’s invalid. (This check may be skipped if invalid transactions are never kept.)&lt;/li&gt;
  &lt;li&gt;a transaction output that doesn’t exist, then it’s invalid.&lt;/li&gt;
  &lt;li&gt;a transaction with an asset ID that’s different from this transaction’s asset ID, then this transaction is invalid. (The asset ID of a CREATE transaction is the same as the transaction ID. The asset ID of a TRANSFER transaction is asset.id.)
Note: The first two rules prevent double spending.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;the-inputfulfillment-rule&quot;&gt;The input.fulfillment Rule&lt;/h4&gt;
&lt;p&gt;Regardless of whether the transaction is a CREATE or TRANSFER transaction: For all inputs, input.fulfillment must be valid.&lt;/p&gt;

&lt;h1 id=&quot;transactions&quot;&gt;Transactions&lt;/h1&gt;

&lt;p&gt;Transaction structure:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;id&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;version&quot;&lt;/span&gt;: version,
    &lt;span class=&quot;s2&quot;&gt;&quot;inputs&quot;&lt;/span&gt;: inputs,
    &lt;span class=&quot;s2&quot;&gt;&quot;outputs&quot;&lt;/span&gt;: outputs,
    &lt;span class=&quot;s2&quot;&gt;&quot;operation&quot;&lt;/span&gt;: operation,
    &lt;span class=&quot;s2&quot;&gt;&quot;asset&quot;&lt;/span&gt;: asset,
    &lt;span class=&quot;s2&quot;&gt;&quot;metadata&quot;&lt;/span&gt;: metadata
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Tx ID: The ID of a transaction is the SHA3-256 hash of the transaction, loosely speaking. It’s a string. An example is:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;0e7a9a9047fdf39eb5ead7170ec412c6bffdbe8d7888966584b4014863e03518&quot;&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Version: 2.0 (TODO: remove)&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Inputs&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;List&lt;/em&gt; of tx inputs&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;Each tx input spends a previous tx output&lt;/li&gt;
      &lt;li&gt;a CREATE tx must have exactly one input&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;a TRANSFER tx should have at least one input&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;Transaction inputs and outputs are the mechanism by which control or ownership of an asset&lt;/li&gt;
      &lt;li&gt;Amounts of an asset are encoded in the outputs of a transaction, and each output may be spent separately&lt;/li&gt;
      &lt;li&gt;To spend an output, the output’s condition must be met by an input that provides a corresponding fulfillment&lt;/li&gt;
      &lt;li&gt;Each output may be spent at most once, by a single input&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;Example of a structure of an element in the input list&lt;/p&gt;
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;fulfills&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;transaction_id&quot;&lt;/span&gt;: transaction_id,
          &lt;span class=&quot;s2&quot;&gt;&quot;output_index&quot;&lt;/span&gt;: output_index
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;owners_before&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;public_key_1, public_key_2, etc.],
      &lt;span class=&quot;s2&quot;&gt;&quot;fulfillment&quot;&lt;/span&gt;: fulfillment
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;blockquote&gt;
      &lt;p&gt;For create tx, the value for fulfills is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt;&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;ul&gt;
      &lt;li&gt;Owners_before: public keys&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;fulfillment: a str as per crypto conditions spec&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;The basic steps to compute a fulfillment string are:&lt;/p&gt;

        &lt;ol&gt;
          &lt;li&gt;Construct the fulfillment as per the crypto-conditions spec.&lt;/li&gt;
          &lt;li&gt;Encode the fulfillment to bytes using the &lt;a href=&quot;http://www.itu.int/ITU-T/recommendations/rec.aspx?rec=12483&amp;amp;lang=en&quot;&gt;ASN.1 Distinguished Encoding Rules (DER)&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;Encode the resulting bytes using “base64url” (&lt;em&gt;not&lt;/em&gt; typical base64) as per &lt;a href=&quot;https://tools.ietf.org/html/rfc4648#section-5&quot;&gt;RFC 4648, Section 5&lt;/a&gt;&lt;/li&gt;
        &lt;/ol&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Outputs&lt;/p&gt;

    &lt;p&gt;list of Tx outputs&lt;/p&gt;

    &lt;p&gt;Each output indicates the crypto-conditions which must be satisfied by anyone wishing to spend/transfer that output. It also indicates the number of shares of the asset tied to that output.&lt;/p&gt;

    &lt;p&gt;output eg:&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;condition&quot;&lt;/span&gt;: condition,
      &lt;span class=&quot;s2&quot;&gt;&quot;public_keys&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;public_key_1, public_key_2, etc.],
      &lt;span class=&quot;s2&quot;&gt;&quot;amount&quot;&lt;/span&gt;: amount
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;Condition:  its a list or array&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;details&quot;&lt;/span&gt;: subcondition,
      &lt;span class=&quot;s2&quot;&gt;&quot;uri&quot;&lt;/span&gt;: uri
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;subconditions:&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;ED25519-SHA-256 (We only care about this for NFTs!)&lt;/li&gt;
      &lt;li&gt;THRESHOLD-SHA-256&lt;/li&gt;
    &lt;/ol&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ed25519-sha-256&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;public_key&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;HFp773FH21sPFrn4y8wX3Ddrkzhqy4La4cQLfePT2vz7&quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;uri: &lt;a href=&quot;https://datatracker.ietf.org/doc/html/draft-thomas-crypto-conditions-03#section-7.2.2&quot;&gt;cost&lt;/a&gt;&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;uri&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ni:///sha-256;at0MY6Ye8yvidsgL9FrnKmsVzX0XrNNXFmuAPF4bQeU?fpt=ed25519-sha-256&amp;amp;cost=131072&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;Code to compute the uri&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  import base58
  from cryptoconditions import Ed25519Sha256
    
  pubkey &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;HFp773FH21sPFrn4y8wX3Ddrkzhqy4La4cQLfePT2vz7&apos;&lt;/span&gt;
    
  &lt;span class=&quot;c&quot;&gt;# Convert pubkey to a bytes representation (a Python 3 bytes object)&lt;/span&gt;
  pubkey_bytes &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; base58.b58decode&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;pubkey&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    
  &lt;span class=&quot;c&quot;&gt;# Construct the condition object&lt;/span&gt;
  ed25519 &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; Ed25519Sha256&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;public_key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;pubkey_bytes&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    
  &lt;span class=&quot;c&quot;&gt;# Compute the condition uri (string)&lt;/span&gt;
  uri &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; ed25519.condition_uri
  &lt;span class=&quot;c&quot;&gt;# uri should be:&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# &apos;ni:///sha-256;at0MY6Ye8yvidsgL9FrnKmsVzX0XrNNXFmuAPF4bQeU?fpt=ed25519-sha-256&amp;amp;cost=131072&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Asset&lt;/p&gt;

    &lt;p&gt;For a CREATE Tx&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;data&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;desc&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Laundromat Fantastique&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;461B Grand Palace Road&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;international_laundromat_identifier&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;bx45-am-333&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;known_issues&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;No known issues. It&apos;s fantastique!&quot;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;it should just have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; key&lt;/p&gt;

    &lt;p&gt;For TRANSFER tx&lt;/p&gt;

    &lt;p&gt;the asset key will have: The id of the tx which has the asset&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;id&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;38100137cea87fb9bd751e2372abb2c73e7d5bcf39d940a5516a324d9c7fb88d&quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;metadata&lt;/p&gt;

    &lt;p&gt;Bust be any valid associative array or dict (in python) or Null.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;1510850314&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;weather_conditions&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;So hot that our crayons melted.&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;location&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;Death Valley, California&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;latitude&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;36.457N&quot;&lt;/span&gt;,
          &lt;span class=&quot;s2&quot;&gt;&quot;longitude&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;116.865W&quot;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt;  We use the bigchainDB transaction spec v2.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;constructing-a-transaction&quot;&gt;Constructing a Transaction&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Set a variable named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version&lt;/code&gt; to a &lt;a href=&quot;#&quot;&gt;valid version value&lt;/a&gt;. (We need to remove this)&lt;/li&gt;
  &lt;li&gt;Set a variable named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;operation&lt;/code&gt; to a &lt;a href=&quot;#&quot;&gt;valid operation value&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Set a variable named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;asset&lt;/code&gt; to a &lt;a href=&quot;#&quot;&gt;valid asset value&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Set a variable named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metadata&lt;/code&gt; to a &lt;a href=&quot;#&quot;&gt;valid metadata value&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Generate or get all the required &lt;a href=&quot;#&quot;&gt;public keys&lt;/a&gt; &lt;/li&gt;
  &lt;li&gt;Construct a &lt;a href=&quot;#&quot;&gt;list&lt;/a&gt; named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;outputs&lt;/code&gt; of all the &lt;a href=&quot;#&quot;&gt;outputs&lt;/a&gt; that should be in the transaction. (Note: Each output includes a &lt;a href=&quot;https://github.com/bigchaindb/BEPs/tree/master/13#transaction-components-conditions&quot;&gt;condition&lt;/a&gt;.)&lt;/li&gt;
  &lt;li&gt;Construct a &lt;a href=&quot;#&quot;&gt;list&lt;/a&gt; named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unfulfilled_inputs&lt;/code&gt; of all the &lt;a href=&quot;#&quot;&gt;inputs&lt;/a&gt; that should be in the transaction. All &lt;em&gt;fulfillment&lt;/em&gt; strings should be set to  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt;  (We’re building an “unfulfilled transaction” first.)&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Construct an &lt;a href=&quot;#&quot;&gt;associative array&lt;/a&gt;  (dict) named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unfulfilled_tx&lt;/code&gt; of the form:&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{
     &quot;id&quot;: null,
     &quot;version&quot;: version,
     &quot;inputs&quot;: unfulfilled_inputs,
     &quot;outputs&quot;: outputs,
     &quot;operation&quot;: operation,
     &quot;asset&quot;: asset,
     &quot;metadata&quot;: metadata
 }&lt;/code&gt;&lt;/p&gt;

    &lt;p&gt;Note how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unfulfilled_tx&lt;/code&gt; includes a key-value pair for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;id&quot;&lt;/code&gt; key. The value must be your &lt;a href=&quot;#&quot;&gt;ctnull&lt;/a&gt; (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt; in Python).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Convert unfulfilled_tx to a serialized json named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;utx_json&lt;/code&gt;.
    &lt;ol&gt;
      &lt;li&gt;unicode, sorted keys&lt;/li&gt;
    &lt;/ol&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; import rapidjson
    
 &lt;span class=&quot;c&quot;&gt;# input_dict is a dictionary&lt;/span&gt;
 json_str &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; rapidjson.dumps&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;input_dict,
                             &lt;span class=&quot;nv&quot;&gt;skipkeys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;False,
                             &lt;span class=&quot;nv&quot;&gt;ensure_ascii&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;False,
                             &lt;span class=&quot;nv&quot;&gt;sort_keys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs&lt;/code&gt; as a deep copy of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unfulfilled_inputs&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;For each input in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs&lt;/code&gt;:
    &lt;ol&gt;
      &lt;li&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fulfills&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;None&lt;/code&gt; (because this is a CREATE transaction, for example), then let &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string1 = utx_json&lt;/code&gt;, otherwise let &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string1 = utx_json + output_tx_id + output_index&lt;/code&gt; where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;output_tx_id&lt;/code&gt; is the transaction ID of the output that this input fulfills and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; means concatenate the strings.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Convert string1 to bytes&lt;/a&gt; and call the result &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes1&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Compute the SHA3-256 hash&lt;/a&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes1&lt;/code&gt; and leave the result as bytes (i.e. don’t convert to a hex string). Call the result &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes_to_sign&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;fulfill the associated crypto-condition &lt;a href=&quot;https://github.com/rfcs/crypto-conditions#implementations&quot;&gt;using an implementation of crypto-conditions&lt;/a&gt;. You will need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes_to_sign&lt;/code&gt; and one or more private keys (which are used to sign &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytes_to_sign&lt;/code&gt;). The end result is usually some kind of fulfilled condition object. Compute the fulfillment string of that fulfilled condition object, and put that as the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;fulfillment&quot;&lt;/code&gt; for the input in question.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;Construct a new &lt;a href=&quot;#&quot;&gt;associative array&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx&lt;/code&gt; by making a deep copy of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unfulfilled_tx&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx&lt;/code&gt;, change the value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;inputs&quot;&lt;/code&gt; to the just-computed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inputs&lt;/code&gt; (an array of fulfilled inputs).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Compute the transaction ID of tx&lt;/a&gt;. Call it &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The final result (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tx&lt;/code&gt;) is a valid fulfilled transaction (in the form of an associative array). To put it in the body of an HTTP POST request, you’ll have to &lt;a href=&quot;#&quot;&gt;convert it to a JSON string&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Wed, 01 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2023/02/01/UsingPythonSDK.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2023/02/01/UsingPythonSDK.html</guid>
      </item>
    
      <item>
        <title>NexRes Grafana Dashboard Pipeline</title>
        <description>&lt;p&gt;During the early stage of development, it is often convenient to target a specific NexRes metric with an all-in-one metric visualization tool. This is easily achieved with the NexRes Dynamic Dashboard (NDD), which abstracts status metrics from NexRes and is presented by Grafana and Prometheus combination. In this post, I will go through how NDD has been designed, what the NDD pipeline looks like, and what is the future of NDD. So, let’s get started it!&lt;/p&gt;

&lt;h2 id=&quot;pain-points&quot;&gt;Pain Points&lt;/h2&gt;
&lt;p&gt;Before NDD was developed, NexRes developers could only access status metrics by the log file. Since the current NexRes uses four replica nodes and one client node, the developer needs to open up 5 log files together to monitor the status of NexRes. In addition, log files are static, which means it is not loading in real time. These pain points dramatically reduce the development performance and easily lead to human error. As for all the issues mentioned above, we need a tool to visualize NexRes metrics for better development.&lt;/p&gt;
&lt;p&gt;
    &lt;img src=&quot;/assets/images/dashboardPipeline/log.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 40%&quot; /&gt;
    &lt;br /&gt;
&lt;/p&gt;

&lt;h2 id=&quot;nexres-dynamic-dashboard-pipeline&quot;&gt;NexRes Dynamic Dashboard Pipeline&lt;/h2&gt;
&lt;p&gt;NexRes Dynamic Dashboard is our solution. NDD is a Grafana base dashboard for Nexres. It aims to provide a simple real-time interface for developers to monitor and diagnose Nexres. The data metrics is stored in the Prometheus time-series database and queried by Grafana using PromeQL. The system usage data is provided by Prometheus third-party exporter Node Exporter. Here is a simple pipeline archtecture image.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/dashboardPipeline/pipeline.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 40%&quot; /&gt;
    &lt;br /&gt;
&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Prometheus is an open-source monitoring and alerting system that is widely used to monitor the performance of cloud-native applications. The Prometheus server collects metrics from the monitored applications and stores them in a time-series database, allowing users to query the data and create alerts based on specified conditions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Grafana is an open-source platform for data visualization and monitoring. It allows users to create and share dashboards that display real-time data from various sources, such as Prometheus, InfluxDB, and Elasticsearch.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Prometheus-cpp is an open-source C++ library that provides an API for exposing and collecting metrics in a way that is compatible with Prometheus. It allows developers to instrument their C++ applications and servers with Prometheus-style metrics and to expose those metrics to Prometheus servers for collection and visualization.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Node Exporter is a standalone tool that provides an HTTP server that exposes Prometheus-compatible metrics about the host machine to be consumed by the Prometheus server. It runs as a daemon process on a host machine and collects a wide variety of metrics about the host’s hardware and operating system, including CPU and memory usage, disk and network I/O, and more.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;reason-for-choosing-prometheus&quot;&gt;Reason for choosing Prometheus&lt;/h2&gt;
&lt;p&gt;The reason we choose Prometehus is because it using pull mode to store the data. Pull mode refers to the way in which the Prometheus server fetches metrics from the targets it is monitoring. In pull mode, the Prometheus server periodically sends HTTP requests to a list of target URLs to scrape metrics from those targets.&lt;/p&gt;

&lt;p&gt;With pull-based monitoring, the Prometheus server is in control of when and how often it gathers metrics from the targets it is monitoring. This allows for centralized control over the monitoring NexRes, and makes it easy to change the monitoring configuration for all targets at once.&lt;/p&gt;

&lt;p&gt;Pull-based monitoring can scale more easily than push-based monitoring, as the Prometheus server is able to handle a large number of targets without being overwhelmed. As NexRes replica number can rapidly increase to above 100 nodes, this determation is base on future requirement.&lt;/p&gt;

&lt;p&gt;The other reason for choosing prometheus is it support third parity exporter that able to show system status metrics and can be integrated to NexRes by using prometheus-cpp library.&lt;/p&gt;

&lt;h2 id=&quot;nexres-and-prometheus&quot;&gt;NexRes and Prometheus&lt;/h2&gt;
&lt;p&gt;The Prometheus integration with your application is to use a third-party library called prometheus-cpp. This library provides a C++ client for Prometheus that can be used to instrument your application and expose metrics in the Prometheus format. As prometheus-cpp support bazel build tool, this made the integration even easilier since NexRes is also using bazel.&lt;/p&gt;

&lt;p&gt;To allow Prometheus periodically collect the metrics from NexRes and store them in its time-series database, we developed “prometheus_handler” under statitics class to expose metrics in a format that Prometheus can scrape. Each replica is using different port for exposing their metrics, this allow Prometheus to collect all replicas data simultaneously.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/dashboardPipeline/prometheus_handler.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 40%&quot; /&gt;
    &lt;br /&gt;
&lt;/p&gt;

&lt;p&gt;Once the setup is finished, we need to connect Grafana to Prometheus for display NexRes metrics.&lt;/p&gt;

&lt;h2 id=&quot;grafana-and-prometheus&quot;&gt;Grafana and Prometheus&lt;/h2&gt;
&lt;p&gt;Prometheus and Grafana are two popular tools used for monitoring and observability. Grafana is a visualization tool that can be used to create dashboards and graphs based on the data stored in Prometheus.&lt;/p&gt;

&lt;p&gt;To use Prometheus and Grafana together, a common setup is to have Prometheus scraping metrics from various systems and then feeding that data into Grafana for visualization. This setup is often referred to as a “Prometheus-Grafana pipeline”. Here is the structure of this pipeline.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/dashboardPipeline/dashboard_structure.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 60%&quot; /&gt;
    &lt;br /&gt;
&lt;/p&gt;

&lt;p&gt;To create a Prometheus-Grafana pipeline, the first step is to install and configure Prometheus. This typically involves specifying the systems that Prometheus should scrape metrics from and setting up a storage backend for the collected metrics.&lt;/p&gt;

&lt;p&gt;Once Prometheus is up and running, the next step is to install and configure Grafana. This involves setting up a data source that points to the Prometheus instance, as well as creating dashboards and graphs to visualize the data.&lt;/p&gt;

&lt;p&gt;Once both Prometheus and Grafana are properly configured, they can be used together to monitor and visualize metrics from NexRes. Since all metrics should be properly collected if the NexRes and Prometheus has been connected. Developer can simply using PromQL in Grafana to query NexRes data and build the dashboard.&lt;/p&gt;

&lt;p&gt;Please follow this &lt;a href=&quot;https://resilientdb.com/blog/2022/12/06/DeployGrafanaDashboardOnOracleCloud.html&quot;&gt;blog&lt;/a&gt; to setup Grafana and Prometheus on your system.&lt;/p&gt;

&lt;h2 id=&quot;future-improvements&quot;&gt;Future Improvements&lt;/h2&gt;
&lt;h3 id=&quot;support-more-time-series-databases-in-nexres&quot;&gt;Support more time-series databases in NexRes&lt;/h3&gt;
&lt;p&gt;As the current phase of NexRes, the Prometheus time-series database is integrated. Since Grafana support various type of time-series databases, such as InfluxDB, OpenTSDB, Graphite, etc. To prevent unexpected things and be more user-friendly, we can develop an abstract layer in NexRes to support various databases. For example, there is “prometheus_handler” under the statistics class, we can have another class called “data_handler” and make “prometheus_handler” to be the subclass of “data_handler”. Following the same pattern, we can build “influx_handler”, and “graphite_handler” under this “data_handler” to support many time-series databases.&lt;/p&gt;

&lt;h3 id=&quot;introduce-more-performance-numbers-to-the-dashboard&quot;&gt;Introduce more performance numbers to the dashboard&lt;/h3&gt;
&lt;p&gt;Go though this &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1a-OGYYoTHMGTZ079Z-bjQP5-aCiXUMHPuszrmkjK7So/edit?usp=sharing&quot;&gt;google sheet&lt;/a&gt;, find out the metrics in TODO list that could introduce to NexRes.&lt;/p&gt;

&lt;h3 id=&quot;change-embedded-grafana-to-https-connection&quot;&gt;Change embedded Grafana to HTTPs connection&lt;/h3&gt;
&lt;p&gt;Currently, the Grafana dashboard integrated in nesres.github.io is using http connection. This is a temporality solution that put http connection in https page is a not a secure method. We need to solve this problem in future interation.&lt;/p&gt;

&lt;h3 id=&quot;integrate-dashboard-into-nexres-node-manager&quot;&gt;Integrate dashboard into Nexres node manager&lt;/h3&gt;
&lt;p&gt;While Nexres Node Manager is finished, combine the functionality of cloud deployment installer with node manager.&lt;/p&gt;

&lt;h3 id=&quot;deploy-prometheus-configuration-by-endpoint-setup&quot;&gt;Deploy Prometheus configuration by endpoint setup&lt;/h3&gt;
&lt;p&gt;This improvement also related to node manager. The current Prometheus configuration file only support 4 nexres replicas. If this number increase in the future, the configuration file and Grafana need to adject according to replica number.&lt;/p&gt;

&lt;h3 id=&quot;explore-grafana-technique-for-better-visualization&quot;&gt;Explore Grafana technique for better visualization&lt;/h3&gt;
&lt;p&gt;Introduce better visualization to Grafana dashboard.&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Dec 2022 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2022/12/12/NexResGrafanaDashboardPipeline.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2022/12/12/NexResGrafanaDashboardPipeline.html</guid>
      </item>
    
      <item>
        <title>RCC in NexRes</title>
        <description>&lt;p&gt;Here we illustrate why and how to implement RCC in NexRes, compare the RCC implementations in ResDB and NexRes 
and show the experiment results we got for RCC in NexRes.&lt;/p&gt;

&lt;h3 id=&quot;the-bottleneck-in-primary-backup-bft-protocols&quot;&gt;The bottleneck in primary-backup BFT protocols&lt;/h3&gt;

&lt;p&gt;In traditional primary-backup protocols like PBFT&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, a single primary broadcasts client requests to all other replicas. Thus, as the following figure shows, there is an unbalanced overhead of sending messages between primary and backup replicas. As the number of replicas increases, the imbalance is exacerbated. And the system performance bottleneck can be the primary’s outgoing bandwidth when the system is of large scale.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/rcc/ratio.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 70%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 1. Unbalanced Overhead Between Primary and Backup Replicas
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;resilient-concurrent-consensus-rcc&quot;&gt;Resilient Concurrent Consensus (RCC)&lt;/h3&gt;

&lt;p&gt;The Resilient Concurrent Consensus paradigm RCC has been proposed to turn any primary-backup consensus protocol into concurrent consensus by running multiple instances concurrently. RCC is designed with performance in mind and ensures increased resilience against failures&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;RCC runs multiple primary-backup consensus instances concurrently, distributing the overhead of broadcasting client requests to other replicas and overcoming the performance bottleneck caused by the primary’s outgoing performance. As the following figure shows, in theory, running concurrent instances has an impressionable positive impact on system throughput.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/rcc/theory.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 2. The Promise of Concurrent Consensus
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;resdb-vs-nexres&quot;&gt;ResDB vs NexRes&lt;/h3&gt;

&lt;p&gt;As a global-scale sustainable blockchain fabric, ResilientDB offers a high-throughput yielding distributed ledger built upon scale-centric design principles to democratize and decentralize computation. And RCC has been implemented in ResDB, the older version of ResilientDB. In ResDB, only one thread is assigned to one instance and CPU resources cannot be fully utilized for &lt;em&gt;PBFT&lt;/em&gt; or RCC with a small number of instances. So, even though in the Resdb, RCC shows better performance than PBFT, which is consistent with our theoretical expectation, the actual bottleneck of PBFT is CPU utilization rather than bandwidth.&lt;/p&gt;

&lt;p&gt;NexRes, the next generation of ResilientDB, assigns multiple threads to one instance, fully utilizing CPU resources to process messages. Then, CPU utilization is not the bottleneck for PBFT in NexRes. Running PBFT in NexRes is capable of saturating the primary’s network bandwidth, which meets the prerequisite for leveraging RCC to improve system throughput.&lt;/p&gt;

&lt;h3 id=&quot;implementation&quot;&gt;Implementation&lt;/h3&gt;

&lt;p&gt;In this section, we will give a brief overview of the implementation of RCC in NexRes. To implement RCC with concurrent instances in Nexres, adjustments in five modules are required: &lt;em&gt;Configuration, Client, Primary, Backup Replica, and Total Ordering&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&quot;configuration&quot;&gt;Configuration&lt;/h4&gt;

&lt;p&gt;To implement RCC in NexRes, first, we need to make changes in the configuration file, which specifies the number of instances and the primaries in the configuration file.&lt;/p&gt;

&lt;p&gt;In the current implementation, we have the first &lt;strong&gt;m&lt;/strong&gt; replicas to be primaries in &lt;strong&gt;m&lt;/strong&gt;-instance RCC.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;region&quot;: [
    {
      &quot;replicaInfo&quot;: [
					## omitted
      ],
      &quot;regionId&quot;: 1
    }
  ],
  &quot;selfRegionId&quot;: 1,
  &quot;instance&quot;: 4	 # number of instances
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;client&quot;&gt;Client&lt;/h4&gt;

&lt;p&gt;Clients send requests to all primaries evenly rather than a single primary as it does in PBFT.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_num_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;replica_client_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;primary&quot;&gt;Primary&lt;/h4&gt;

&lt;p&gt;Running concurrent instances, replicas in RCC should be able to identify the instance of each message. Thus, for proposal messages, we need to use a field called &lt;strong&gt;&lt;em&gt;instance&lt;/em&gt;&lt;/strong&gt; to identify the instance of a proposal. With such a field, replicas can map messages to correct corresponding instances.&lt;/p&gt;

&lt;p&gt;When broadcasting proposals, a primary needs to indicate its instance in the proposals.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;client_request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetSelfInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;replica_client_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BroadCast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;backup-replica&quot;&gt;Backup Replica&lt;/h4&gt;

&lt;p&gt;When receiving a proposal of instance &lt;em&gt;i&lt;/em&gt;,  a backup replica needs to check if it is exactly from the primary of instance &lt;em&gt;i&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;language-c++ highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance_num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetConfigData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance_num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instance_num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LOG&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;the request is not from a correct primary. sender:&quot;&lt;/span&gt;
               &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sender_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; seq:&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;total-ordering&quot;&gt;Total Ordering&lt;/h4&gt;

&lt;p&gt;Before executing committed client requests, RCC orders the committed requests between different instances in the same round. So we need a mechanism to determine the execution order of committed transactions in one round. Now we adopt the simplest one, ordering transactions in the same round based on instance id, from the lowest instance to the highest one.&lt;/p&gt;

&lt;h3 id=&quot;experiment-and-results&quot;&gt;Experiment and Results&lt;/h3&gt;

&lt;h4 id=&quot;experiment-setup&quot;&gt;Experiment Setup&lt;/h4&gt;

&lt;p&gt;The experiments are done in AWS. The configuration of the machines we used is shown as follows:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;t3.2xlarge&lt;/li&gt;
  &lt;li&gt;8-vCPUs&lt;/li&gt;
  &lt;li&gt;32-GiB Memory&lt;/li&gt;
  &lt;li&gt;Maximum Bandwidth: 600MB/s&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The experiments used up to 96 replicas and 4 clients.&lt;/p&gt;

&lt;h4 id=&quot;experiment-1---scalability&quot;&gt;Experiment 1 - Scalability&lt;/h4&gt;

&lt;p&gt;The first experiment is designed to compare the best-case throughput and outgoing bandwidth of RCC and PBFT of different replicas. The throughput and outgoing bandwidth of RCC and PBFT with different numbers of replicas are recorded. The replica number is set to 4, 16, 32, 64, and 96. The batch size is set to 400 and 800.&lt;/p&gt;

&lt;p&gt;We denote RCC with batchsize B by RCC-B, and so does PBFT. As the system scales, throughput decreases. RCC-800 outperforms RCC-400, PBFT-800 and PBFT-400, when there are 96 replicas. From the right figure, we can see that PBFT-400 and PBFT-800 are bottlenecked by outgoing bandwidth. And the reason why RCC-400 has a lower performance than RCC-800 is that RCC-400 processes double number of consensus messages. Though RCC-400 gets rid of the bandwidth bottleneck, we’ve found RCC-400 happens to be bottlenecked by computing capability when there are 96 replicas by monitoring its CPU utilization, which is close to the maximal value i.e., 800%.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/rcc/exp1.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 3. RCC Scalability Compared to PBFT
    &lt;/em&gt;
&lt;/p&gt;

&lt;h4 id=&quot;experiment-2---batching&quot;&gt;Experiment 2 - Batching&lt;/h4&gt;

&lt;p&gt;This experiment aims to test and record the throughput and outgoing bandwidth usage of PBFT and RCC with 64 or 96 replicas with different batch sizes. The batch size is set to 50, 100, 200, 400, and 800.&lt;/p&gt;

&lt;p&gt;Experiment results show that increasing batch size benefits PBFT and RCC throughput when batch size increases from 50 to 400. Nonetheless, it makes no difference for PBFT when increasing batch size from 400 to 800, since PBFT is bottlenecked by outgoing bandwidth shown in Figure 6, while the throughput of RCC still increases.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/rcc/exp2.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 4. Batching in RCC and PBFT
    &lt;/em&gt;
&lt;/p&gt;

&lt;!-- #### Experiment 3 - Concurrent Consensus

This experiment tests and records the throughput and outgoing bandwidth of RCC with 64 or 96 replicas with different numbers of instances. The batch size is set to 400 and 800.

In RCC, after we increase the number of concurrent instances to 4, which has overcome the primary bandwidth bottleneck, increasing number of instances has little influence on throughput. We draw the conclusion that as long as we overcome the bandwidth bottleneck, increasing the number of instances shows inobvious effect since the system is bottlenecked by other factors such as computional capabilty and execution.

&lt;p&gt;
    &lt;img src=&quot;/assets/images/rcc/exp3.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 90%&quot;/&gt;
    &lt;br&gt;
    &lt;em&gt;Figure 5. Effect of Concurrent Consensus on RCC
    &lt;/em&gt;
&lt;/p&gt; --&gt;

&lt;h4 id=&quot;experiment-3---larger-transaction-size&quot;&gt;Experiment 3 - Larger Transaction Size&lt;/h4&gt;

&lt;p&gt;In this experiment, we test and record the throughput and outgoing bandwidth of RCC and PBFT, adopting transactions with different sizes but the same execution time. We test systems with 64 and 96 replicas, 1x, 8x, 16x, 24x, and 32x transaction sizes. We set the batchsize to 100.&lt;/p&gt;

&lt;p&gt;As we can see from the figure, as the transaction size increases, limited by outgoing bandwidth, PBFT throughput decreases 
greatly. RCC also shows a throughput performance, but the throughput ratio between RCC and PBFT grows. We can safely draw the conclusion that RCC has a throughput advantage when processing transactions with large sizes.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/rcc/exp4.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 5. Performance of RCC and PBFT with Larger Transaction Size
    &lt;/em&gt;
&lt;/p&gt;

&lt;h4 id=&quot;experiment-4---concurrent-consensus&quot;&gt;Experiment 4 - Concurrent Consensus&lt;/h4&gt;

&lt;p&gt;This experiment tests and records the throughput and outgoing bandwidth of RCC with 64 or 96 replicas with different numbers of instances. The batch size is set to 100 and we adopt a 32x transaction size.&lt;/p&gt;

&lt;p&gt;In RCC, when there are 1, 2, or 4 instances, system performance is bottlenecked by the primaries’ outgoing bandwidth. As the number of instances increases, throughput increases linearly. The more instances RCC has, the more primaries share the overhead of broadcasting client transactions. With at least 8 instances, the primaries’ outgoing bandwidth is not 
saturated and the system throughput increases slightly with the instance number.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;/assets/images/rcc/exp5.png&quot; alt=&quot;Cover photo&quot; style=&quot;width: 90%&quot; /&gt;
    &lt;br /&gt;
    &lt;em&gt;Figure 6. Effect of Concurrent Consensus on RCC
    &lt;/em&gt;
&lt;/p&gt;

&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;strong&gt;Castro, Miguel, and Barbara Liskov. “&lt;em&gt;Practical byzantine fault tolerance.&lt;/em&gt;” OsDI. Vol. 99. No. 1999. 1999.&lt;/strong&gt; &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;&lt;strong&gt;Gupta, Suyash, Jelle Hellings, and Mohammad Sadoghi. “&lt;em&gt;Rcc: Resilient concurrent consensus for high-throughput secure transaction processing.&lt;/em&gt;” 2021 IEEE 37th International Conference on Data Engineering (ICDE). IEEE, 2021.&lt;/strong&gt; &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Tue, 06 Dec 2022 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2022/12/06/RccInNexRes.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2022/12/06/RccInNexRes.html</guid>
      </item>
    
      <item>
        <title>NexRes Grafana Dashboard Installation</title>
        <description>&lt;p&gt;Nexres Grafana Dashboard is a Grafana base dashboard for Nexres. It aims to provide a simple real-time interface for developers to monitor and diagnose Nexres. The data is stored in the Prometheus time-series database and queried by Grafana using PromeQL. The system usage data is provided by Prometheus third-party exporter Node Exporter.&lt;/p&gt;

&lt;h1 id=&quot;requirements&quot;&gt;Requirements&lt;/h1&gt;
&lt;p&gt;Using Nexres dynamic dashboard requires the installation of Prometheus, Node Exporter, Prometheus-cpp, and Grafana. It has been successfully tested with Bazel building in C++17 on Ubuntu 20.04.4 LTS (Windows 11 WSL) and Visual Studio Code.&lt;/p&gt;

&lt;h1 id=&quot;installation&quot;&gt;Installation&lt;/h1&gt;
&lt;h2 id=&quot;install-prometheus&quot;&gt;Install Prometheus&lt;/h2&gt;
&lt;p&gt;go to https://prometheus.io/download/ download prometheus&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tar xvfz (your-prometheus-tar-file)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;install-node_exporter&quot;&gt;Install node_exporter&lt;/h2&gt;
&lt;p&gt;go to https://github.com/prometheus/node_exporter download the lastest version of node_exporter from release&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;tar xvfz (your-node-exporter-tar-file)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;install-grafana&quot;&gt;Install grafana&lt;/h2&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo add-apt-repository &quot;deb https://packages.grafana.com/oss/deb stable main&quot;
sudo apt update 
sudo apt install grafana
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;start-grafana&quot;&gt;Start grafana&lt;/h2&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo service grafana-server start
sudo service grafana-server enable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Default grafana port is 3000&lt;/p&gt;

&lt;h1 id=&quot;start-the-dashboard&quot;&gt;Start the dashboard&lt;/h1&gt;
&lt;h2 id=&quot;prometheus&quot;&gt;Prometheus&lt;/h2&gt;
&lt;p&gt;Default prometheus port is 9090&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./prometheus
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;node_exporter&quot;&gt;Node_exporter&lt;/h2&gt;
&lt;p&gt;Default node exporter port is 9100&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./node_exporter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;local-test&quot;&gt;Local Test&lt;/h1&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Change the exporter endpoint from the prometheus config (&lt;a href=&quot;https://github.com/resilientdb/resilientdb/blob/master/monitoring/prometheus/prometheus.yml&quot;&gt;example&lt;/a&gt;) to the localhost:port
port number can be found from the &lt;a href=&quot;https://github.com/resilientdb/resilientdb/blob/master/service/tools/kv/server_tools/start_kv_service_monitoring.sh&quot;&gt;script&lt;/a&gt; (e.g. 8090)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Start prometheus, grafana, and node_exporter&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Start the KV service using the &lt;a href=&quot;https://github.com/resilientdb/resilientdb/blob/master/service/tools/kv/server_tools/start_kv_service_monitoring.sh&quot;&gt;script&lt;/a&gt;:  service/tools/kv/server_tools/start_kv_service_monitoring.sh&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Open the prometheus to check the service status: http://localhost:9090/targets?search=&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set up your grafana dashboard from http://locahost:3000/
A grafana dashboard template can be found &lt;a href=&quot;https://github.com/resilientdb/resilientdb/blob/master/documents/file/Nexres-1654906717062.json&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;remote-deploy&quot;&gt;Remote Deploy&lt;/h1&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Set the exporter endpoint from the prometheus config with each deploy node (&lt;a href=&quot;https://github.com/resilientdb/resilientdb/blob/master/monitoring/prometheus/prometheus.yml&quot;&gt;example&lt;/a&gt;)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set node_exporter in each of the deploy node&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set the grafana export point in the deploy script &lt;a href=&quot;https://github.com/resilientdb/resilientdb/blob/master/scripts/deploy/script/deploy.sh#L21&quot;&gt;scripts/deploy/script/deploy.sh#L21&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Deploy the nodes&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

</description>
        <pubDate>Tue, 06 Dec 2022 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2022/12/06/NexResGrafanaDashboardInstallation.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2022/12/06/NexResGrafanaDashboardInstallation.html</guid>
      </item>
    
      <item>
        <title>Deploy Grafana Dashboard On Oracle Cloud</title>
        <description>&lt;p&gt;This article will guide you on deploying NexRes Grafana Dashboard on an Oracle Cloud instance. Since Prometheus and node exporter cannot directly install using apt-get, installing these components is complicated and tedious. NexRes_Grafana_Installer provides an effortless experience to automatically deploy all the components for NexRes Grafana Dashboard on Oracle Cloud. Now let us dive in!&lt;/p&gt;

&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;p&gt;This installer only tested on Oracle Cloud instance in ubuntu 20.04. Please adjust the script if you want to run it on AWS or local. Besure nexres is already installed on your instance and fully tested.&lt;/p&gt;

&lt;h2 id=&quot;clone-nexres_grafana_installer&quot;&gt;Clone nexres_grafana_installer&lt;/h2&gt;
&lt;p&gt;Clone the repositry in your home directry&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;https://github.com/jyu25utk/nexres_grafana_installer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;adjust-start_nexressh&quot;&gt;Adjust start_nexres.sh&lt;/h2&gt;
&lt;p&gt;In default, if you cloned resilientdb repositry (nexres) in your home directry. The full directry address should be “/home/ubuntu/resilientdb”. If your nexres working directry is same as I mentioned above, jump to next step.&lt;/p&gt;

&lt;p&gt;Otherwise, modify the “start_nexres.sh” file before you process to the next step. Change the following pathes according to your nexres configuration.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;SERVER_PATH=/home/ubuntu/resilientdb/bazel-bin/kv_server/kv_server
SERVER_CONFIG=/home/ubuntu/resilientdb/example/kv_config.config
WORK_PATH=/home/ubuntu/resilientdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;install&quot;&gt;Install!&lt;/h2&gt;
&lt;p&gt;Simply run command&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo sh install_dashboard.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;All components should automaticly install to your system!&lt;/p&gt;

&lt;p&gt;Make sure to restart your instance using&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo reboot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;test-your-dashboard&quot;&gt;Test your dashboard&lt;/h2&gt;
&lt;p&gt;Find your public ip address, access your grafana interface by using broswer go to&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;(public ip address):3000&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Setup your grafana dashboard as same as the local one&lt;/p&gt;

&lt;p&gt;Access prometheus management interface by using broswer go to&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;(public ip address):9090&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Tue, 06 Dec 2022 00:00:00 +0000</pubDate>
        <link>https://blog.expolab.org//2022/12/06/DeployGrafanaDashboardOnOracleCloud.html</link>
        <guid isPermaLink="true">https://blog.expolab.org//2022/12/06/DeployGrafanaDashboardOnOracleCloud.html</guid>
      </item>
    
  </channel>
</rss>