Awesome Open Source
Awesome Open Source


Clojars Project

A Clojure library which acts as an application host for Tendermint's ABCI --- allowing the exposure of plain functions as replicable state machines.

io.datopia/abci uses io.datopia/stickler to provide pure-data representations of the protobuf-encoded messages received from the Tendermint node process --- maps in, maps out.


Change Log.

Supported Tendermint Versions

io.datopia/abci Tendermint
0.1.* 0.26.0

Toy Example / Walkthrough

The simplest possible service looks something like:

(ns my.abci
  (:require [            :as host]
            [ :as mw]))

(def service
  (-> (constantly ::mw/default)
      ;; Wrap handler invocations w/ (manifold.deferred/future).
      ;; Substitute ::mw/default for a default success response,
      ;; appropriate to the incoming request.
      ;; Return a Closeable, per aleph.tcp/start-server.

While this isn't a particularly dynamic application, we can successfully point a Tendermint node process at it and indefinitely operate a no-op blockchain.

Requests & Responses

Let's transform our handler from (constantly ::mw/default) to something slightly different:

(fn [req]
  (pprint req)

Once the Tendermint node connects, our first message:

{:stickler/msg          :abci/Request
 :info                  {:stickler/msg  :abci/RequestInfo
                         :version       "0.26.0-c086d0a3"
                         :block-version 7
                         :p2p-version   4} :info
 ;; The node initiates 3 distinct connections: :info, :query, :consensus        :info}

The minimal success response to the above:

{:stickler/msg :abci/Response
 :info         {:stickler/msg :abci/ResponseInfo
                :data         "NO_INFO"}}

Let's update our service to construct this response explictly, while using middleware to strip incoming :abci/Request envelopes - and wrap responses in :abci/Response envelopes. While this won't alter how our service functions, it may make it a little clearer.

(defn handler [{msg-type :stickler/msg :as req}]
  (pprint req)
  (case msg-type
    :abci/RequestInfo {:stickler/msg :abci/ResponseInfo
                       :data         "NO_INFO"}

(def service
  (-> handler
      ;; Combines mw/wrap-request-envelope and mw/wrap-response-envelope

Without the envelopes, our incoming request sequence:

{:stickler/msg   :abci/RequestInfo
 :version        "0.26.0-c086d0a3"
 :block-version  7
 :p2p-version    4 :info}

{:stickler/msg   :abci/RequestFlush :info}

{:stickler/msg   :abci/RequestInitChain
 :time           {:stickler/msg :google.protobuf/Timestamp
                  :seconds      1544530118
                  :nanos        776243100}
 :chain-id       "test-chain-anZqUW"
 [{:stickler/msg :abci/ValidatorUpdate
   :pub-key      {:stickler/msg :abci/PubKey
                  :type         "ed25519"
                  :data         <bytes>}
   :power        10}]
 ... :consensus}


The project's abci.edn resource describes the full complement of messages. As Tendermint uses Go-specific extensions in its protobuf files, abci.edn is generated by io.datopia/stickler from the types.proto maintained by jabci.


  • Moe Aboulkheir



Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
clojure (1,953
blockchain (802
distributed-systems (291
consensus (56
tendermint (28

Find Open Source By Browsing 7,000 Topics Across 59 Categories