-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add minimal blocking ABCI crate #794
Changes from 18 commits
cbb855f
f766e16
247e054
14a5cd1
1f1ce87
de60b30
71fb034
569f6ae
4497249
e877c90
d4eaa56
7cee7a9
b429e5b
e237a9a
7e106f8
88f3247
a7d2903
98d0368
7950597
ad2501a
d935482
fefa9bc
723c506
a77b8da
17ee9d9
a30d19d
56a339f
5f8cbe2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
[workspace] | ||
|
||
members = [ | ||
"abci", | ||
"light-client", | ||
"light-node", | ||
"p2p", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
[package] | ||
name = "tendermint-abci" | ||
version = "0.1.0" | ||
authors = ["Thane Thomson <[email protected]>"] | ||
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 } |
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
//! 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. | ||
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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you expand why the default pattern in here is preferred over not having a default implementation for these methods? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was modelling it on what the |
||
} | ||
|
||
/// 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() | ||
} | ||
|
||
/// Executes the relevant application method based on the type of the | ||
/// request, and produces the corresponding response. | ||
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)) | ||
} | ||
}), | ||
} | ||
} | ||
} |
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 {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it can be called just this and published as a new breaking version of https://crates.io/crates/abci -- @xla @liamsi can help with that