Skip to content

Commit

Permalink
Add minimal blocking ABCI crate (#794)
Browse files Browse the repository at this point in the history
* Add minimal blocking ABCI library

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Expand API to implement in-memory key/value store app

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add kvstore-rs ABCI app

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add rudimentary README

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Bump proto version dependency to v0.18.0

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Replace manual default structs with Default::default()

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Enable debug logging for all incoming ABCI requests

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Improve CLI UX

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Allow for read buffer size customization

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add crate description

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update README for ABCI crate

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add ABCI integration test for minimal ABCI crate (#797)

* Add integration testing utility for ABCI key/value store

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add hacky bash script to demonstrate parallel execution

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Created abci test harness (#800)

* Created abci test harness

* cargo make additions and docs

Co-authored-by: Greg Szabo <16846635+greg-szabo@users.noreply.github.com>

* Update abci/src/codec.rs

Co-authored-by: Romain Ruetschi <romain@informal.systems>

* Apply suggestion from informalsystems/tendermint-rs#794

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Refactor error handing and expose eyre::Result as crate default Result type

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Refactor to use tracing instead of log

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Add newline

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Remove comment relating to constraints on Codec struct params

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Version tendermint-abci crate in line with other tendermint-rs crates

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Update CHANGELOG

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Expand crate documentation

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Extract request dispatch functionality from Application trait

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Move ABCI server example to crate root

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Fix broken link in docs

Signed-off-by: Thane Thomson <connect@thanethomson.com>

* Replace EchoApp example with KeyValueStoreApp example

Signed-off-by: Thane Thomson <connect@thanethomson.com>

Co-authored-by: Greg Szabo <16846635+greg-szabo@users.noreply.github.com>
Co-authored-by: Romain Ruetschi <romain@informal.systems>
  • Loading branch information
3 people committed Feb 19, 2021
1 parent a7baee9 commit 17fd87b
Show file tree
Hide file tree
Showing 26 changed files with 1,604 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Cargo
# will have compiled files and executables
/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# These are log files emitted by model-based tests
**/*.log

# RPC probe results
/rpc-probe/probe-results/

# Proptest regressions dumps
**/*.proptest-regressions
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]

members = [
"abci",
"light-client",
"light-node",
"p2p",
Expand Down
33 changes: 33 additions & 0 deletions abci/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "tendermint-abci"
version = "0.18.1"
authors = ["Thane Thomson <thane@informal.systems>"]
edition = "2018"
description = """
tendermint-abci provides a simple framework with which to build low-level
applications on top of Tendermint.
"""

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[[bin]]
name = "kvstore-rs"
path = "src/application/kvstore/main.rs"
required-features = [ "binary", "kvstore-app" ]

[features]
client = []
echo-app = []
kvstore-app = []
binary = [ "structopt", "tracing-subscriber" ]

[dependencies]
bytes = "1.0"
eyre = "0.6"
prost = "0.7"
tendermint-proto = { version = "0.18.0", path = "../proto" }
thiserror = "1.0"
tracing = "0.1"

structopt = { version = "0.3", optional = true }
tracing-subscriber = { version = "0.2", optional = true }
116 changes: 116 additions & 0 deletions abci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
## tendermint-abci

[![Crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
[![Build Status][build-image]][build-link]
[![Audit Status][audit-image]][audit-link]
[![Apache 2.0 Licensed][license-image]][license-link]
![Rust Stable][rustc-image]

[ABCI] framework for building low-level applications for Tendermint in Rust.

## Requirements

- The latest stable version of Rust

## API

At present, this crate only exposes a synchronous, blocking API based on Rust's
standard library's networking capabilities. `async` client/server support is
planned in future updates.

The primary trait to be implemented by an ABCI application is the
[`Application`] trait. One of the core ideas here is that an ABCI application
must be able to be cloned for use in different threads, since Tendermint opens
4 connections to the ABCI server. See the [spec][tendermint-abci-spec] for
details.

## Examples

See [`src/application`](./src/application/) for some example applications
written using this crate.

To run the key/value store example application, from the `tendermint-abci`
crate's directory:

```bash
# Set your logging level through RUST_LOG (e.g. RUST_LOG=info)
# Binds to 127.0.0.1:26658
RUST_LOG=debug cargo run --bin kvstore-rs --features binary,kvstore-app

# Reset and run your Tendermint node (binds RPC to 127.0.0.1:26657 by default)
tendermint unsafe_reset_all && tendermint start

# Submit a key/value pair (set "somekey" to "somevalue")
curl 'http://127.0.0.1:26657/broadcast_tx_async?tx="somekey=somevalue"'

#{
# "jsonrpc": "2.0",
# "id": -1,
# "result": {
# "code": 0,
# "data": "",
# "log": "",
# "codespace": "",
# "hash": "17ED61261A5357FEE7ACDE4FAB154882A346E479AC236CFB2F22A2E8870A9C3D"
# }
#}

# Query for the value we just submitted ("736f6d656b6579" is the hex
# representation of "somekey")
curl 'http://127.0.0.1:26657/abci_query?data=0x736f6d656b6579'

#{
# "jsonrpc": "2.0",
# "id": -1,
# "result": {
# "response": {
# "code": 0,
# "log": "exists",
# "info": "",
# "index": "0",
# "key": "c29tZWtleQ==",
# "value": "c29tZXZhbHVl",
# "proofOps": null,
# "height": "189",
# "codespace": ""
# }
# }
#}
```

## License

Copyright © 2021 Informal Systems

Licensed under the Apache License, Version 2.0 (the "License");
you may not use the files in this repository except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

[//]: # (badges)

[crate-image]: https://img.shields.io/crates/v/tendermint-abci.svg
[crate-link]: https://crates.io/crates/tendermint-abci
[docs-image]: https://docs.rs/tendermint-abci/badge.svg
[docs-link]: https://docs.rs/tendermint-abci/
[build-image]: https://github.com/informalsystems/tendermint-rs/workflows/Rust/badge.svg
[build-link]: https://github.com/informalsystems/tendermint-rs/actions?query=workflow%3ARust
[audit-image]: https://github.com/informalsystems/tendermint-rs/workflows/Audit-Check/badge.svg
[audit-link]: https://github.com/informalsystems/tendermint-rs/actions?query=workflow%3AAudit-Check
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg
[license-link]: https://github.com/informalsystems/tendermint-rs/blob/master/LICENSE
[rustc-image]: https://img.shields.io/badge/rustc-stable-blue.svg

[//]: # (general links)

[ABCI]: https://docs.tendermint.com/master/spec/abci/
[`Application`]: ./src/application.rs
[tendermint-abci-spec]: https://github.com/tendermint/spec/blob/master/spec/abci/abci.md
148 changes: 148 additions & 0 deletions abci/src/application.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//! ABCI application interface.

#[cfg(feature = "echo-app")]
pub mod echo;
#[cfg(feature = "kvstore-app")]
pub mod kvstore;

use tendermint_proto::abci::request::Value;
use tendermint_proto::abci::{
response, Request, RequestApplySnapshotChunk, RequestBeginBlock, RequestCheckTx,
RequestDeliverTx, RequestEcho, RequestEndBlock, RequestInfo, RequestInitChain,
RequestLoadSnapshotChunk, RequestOfferSnapshot, RequestQuery, RequestSetOption, Response,
ResponseApplySnapshotChunk, ResponseBeginBlock, ResponseCheckTx, ResponseCommit,
ResponseDeliverTx, ResponseEcho, ResponseEndBlock, ResponseFlush, ResponseInfo,
ResponseInitChain, ResponseListSnapshots, ResponseLoadSnapshotChunk, ResponseOfferSnapshot,
ResponseQuery, ResponseSetOption,
};

/// An ABCI application.
///
/// Applications are `Send` + `Clone` + `'static` because they are cloned for
/// each incoming connection to the ABCI [`Server`]. It is up to the
/// application developer to manage shared state between these clones of their
/// application.
///
/// [`Server`]: crate::Server
pub trait Application: Send + Clone + 'static {
/// Echo back the same message as provided in the request.
fn echo(&self, request: RequestEcho) -> ResponseEcho {
ResponseEcho {
message: request.message,
}
}

/// Provide information about the ABCI application.
fn info(&self, _request: RequestInfo) -> ResponseInfo {
Default::default()
}

/// Called once upon genesis.
fn init_chain(&self, _request: RequestInitChain) -> ResponseInitChain {
Default::default()
}

/// Query the application for data at the current or past height.
fn query(&self, _request: RequestQuery) -> ResponseQuery {
Default::default()
}

/// Check the given transaction before putting it into the local mempool.
fn check_tx(&self, _request: RequestCheckTx) -> ResponseCheckTx {
Default::default()
}

/// Signals the beginning of a new block, prior to any `DeliverTx` calls.
fn begin_block(&self, _request: RequestBeginBlock) -> ResponseBeginBlock {
Default::default()
}

/// Apply a transaction to the application's state.
fn deliver_tx(&self, _request: RequestDeliverTx) -> ResponseDeliverTx {
Default::default()
}

/// Signals the end of a block.
fn end_block(&self, _request: RequestEndBlock) -> ResponseEndBlock {
Default::default()
}

/// Signals that messages queued on the client should be flushed to the server.
fn flush(&self) -> ResponseFlush {
ResponseFlush {}
}

/// Commit the current state at the current height.
fn commit(&self) -> ResponseCommit {
Default::default()
}

/// Allows the Tendermint node to request that the application set an
/// option to a particular value.
fn set_option(&self, _request: RequestSetOption) -> ResponseSetOption {
Default::default()
}

/// Used during state sync to discover available snapshots on peers.
fn list_snapshots(&self) -> ResponseListSnapshots {
Default::default()
}

/// Called when bootstrapping the node using state sync.
fn offer_snapshot(&self, _request: RequestOfferSnapshot) -> ResponseOfferSnapshot {
Default::default()
}

/// Used during state sync to retrieve chunks of snapshots from peers.
fn load_snapshot_chunk(&self, _request: RequestLoadSnapshotChunk) -> ResponseLoadSnapshotChunk {
Default::default()
}

/// Apply the given snapshot chunk to the application's state.
fn apply_snapshot_chunk(
&self,
_request: RequestApplySnapshotChunk,
) -> ResponseApplySnapshotChunk {
Default::default()
}
}

/// Provides a mechanism for the [`Server`] to execute incoming requests while
/// expecting the correct response types.
pub trait RequestDispatcher {
/// Executes the relevant application method based on the type of the
/// request, and produces the corresponding response.
fn handle(&self, request: Request) -> Response;
}

// Implement `RequestDispatcher` for all `Application`s.
impl<A: Application> RequestDispatcher for A {
fn handle(&self, request: Request) -> Response {
tracing::debug!("Incoming request: {:?}", request);
Response {
value: Some(match request.value.unwrap() {
Value::Echo(req) => response::Value::Echo(self.echo(req)),
Value::Flush(_) => response::Value::Flush(self.flush()),
Value::Info(req) => response::Value::Info(self.info(req)),
Value::SetOption(req) => response::Value::SetOption(self.set_option(req)),
Value::InitChain(req) => response::Value::InitChain(self.init_chain(req)),
Value::Query(req) => response::Value::Query(self.query(req)),
Value::BeginBlock(req) => response::Value::BeginBlock(self.begin_block(req)),
Value::CheckTx(req) => response::Value::CheckTx(self.check_tx(req)),
Value::DeliverTx(req) => response::Value::DeliverTx(self.deliver_tx(req)),
Value::EndBlock(req) => response::Value::EndBlock(self.end_block(req)),
Value::Commit(_) => response::Value::Commit(self.commit()),
Value::ListSnapshots(_) => response::Value::ListSnapshots(self.list_snapshots()),
Value::OfferSnapshot(req) => {
response::Value::OfferSnapshot(self.offer_snapshot(req))
}
Value::LoadSnapshotChunk(req) => {
response::Value::LoadSnapshotChunk(self.load_snapshot_chunk(req))
}
Value::ApplySnapshotChunk(req) => {
response::Value::ApplySnapshotChunk(self.apply_snapshot_chunk(req))
}
}),
}
}
}
15 changes: 15 additions & 0 deletions abci/src/application/echo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Trivial ABCI echo application

use crate::Application;

/// Trivial echo application, mainly for testing purposes.
#[derive(Clone)]
pub struct EchoApp;

impl Default for EchoApp {
fn default() -> Self {
Self {}
}
}

impl Application for EchoApp {}
Loading

0 comments on commit 17fd87b

Please sign in to comment.