An open API service indexing awesome lists of open source software.

https://github.com/datopia/abci-host

Clojure host/server for Tendermint's ABCI protocol.
https://github.com/datopia/abci-host

abci blockchain clojure consensus distributed-systems tendermint

Last synced: 2 months ago
JSON representation

Clojure host/server for Tendermint's ABCI protocol.

Awesome Lists containing this project

README

          

# org.datopia/abci

[![Clojars
Project](http://clojars.org/org.datopia/abci/latest-version.svg)](http://clojars.org/org.datopia/abci)

A Clojure library which acts as an application host
for
[Tendermint](https://tendermint.com)'s
[ABCI](https://tendermint.com/docs/introduction/what-is-tendermint.html#abci-overview) ---
allowing the exposure of plain functions as replicable state machines.

`org.datopia/abci`
uses [org.datopia/stickler](https://github.com/datopia/stickler) to provide
pure-data representations of
the [protobuf](https://developers.google.com/protocol-buffers/)-encoded messages
received from the Tendermint node process --- maps in, maps out.

## Documentation

- [API docs](https://datopia.github.io/abci-host/).
- [K/V store example project](example).

### [Change Log](CHANGELOG.md).

## Project -> Tendermint Version Mapping

| org.datopia/abci | Tendermint |
| ----------------- | ----------------- |
| 0.2.0 | 0.38.5 (CometBFT) |
| 0.1.0 | 0.34.12 |

There's a previous, deprecated artifact:

| io.datopia/abci | |
| ----------------- | ------------- |
| 0.1.* | 0.26.0 |

## Toy Example / Walkthrough

The simplest possible service looks something like:

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

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

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:

```clojure
(fn [req]
(pprint req)
::mw/default)
```

Once the Tendermint node connects, our first message:

```clojure
{:stickler/msg :abci/Request
:info {:stickler/msg :abci/RequestInfo
:version "0.26.0-c086d0a3"
:block-version 7
:p2p-version 4}
:stickler.one-of/value :info
;; The node initiates 3 distinct connections: :info, :query, :consensus
:abci.host/conn :info}
```

The minimal success response to the above:

```clojure
{: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.

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

(def service
(-> handler
mw/wrap-synchronous
mw/wrap-default
;; Combines mw/wrap-request-envelope and mw/wrap-response-envelope
mw/wrap-envelope
host/start))
```

Without the envelopes, our incoming request sequence:

```clojure
{:stickler/msg :abci/RequestInfo
:version "0.26.0-c086d0a3"
:block-version 7
:p2p-version 4
:abci.host/conn :info}

{:stickler/msg :abci/RequestFlush
:abci.host/conn :info}

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

...
```

The
project's
[abci.edn resource](https://github.com/datopia/abci-host/blob/master/resources/org.datopia.abci/abci.edn)
describes the full complement of messages. As Tendermint uses Go-specific
extensions in its protobuf files, `abci.edn` is generated by
[org.datopia/stickler](https://github.com/datopia/stickler) from
the [types.proto](https://github.com/jTendermint/jabci/blob/develop/src/main/proto/types.proto) maintained
by [jabci](https://github.com/jTendermint/jabci).

## Contributors

- Moe Aboulkheir

## License

[MIT](https://github.com/datopia/abci-host/blob/master/LICENSE)