-
Notifications
You must be signed in to change notification settings - Fork 359
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* IBC-proto move over * proto-compiler crate * DomainType copied from Tendermint-rs
- Loading branch information
1 parent
d0f8aa1
commit 4be6f3d
Showing
40 changed files
with
4,124 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,4 +4,9 @@ members = [ | |
"modules", | ||
"relayer", | ||
"relayer-cli", | ||
"proto" | ||
] | ||
|
||
exclude = [ | ||
"proto-compiler" | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
target/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
[package] | ||
name = "ibc-proto-compiler" | ||
version = "0.1.0" | ||
authors = ["Greg Szabo <greg@philosobear.com>"] | ||
edition = "2018" | ||
publish = false | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
walkdir = { version = "2.3" } | ||
|
||
[build-dependencies] | ||
prost-build = { version = "0.6" } | ||
walkdir = { version = "2.3" } | ||
git2 = { version = "0.13" } | ||
|
||
[workspace] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
use git2::Repository; | ||
use std::env::var; | ||
use std::path::{Path, PathBuf}; | ||
use walkdir::WalkDir; | ||
|
||
fn main() { | ||
let sdk_dir = var("SDK_DIR").unwrap_or_else(|_| "target/cosmos-sdk".to_string()); | ||
if !Path::new(&sdk_dir).exists() { | ||
let url = "https://github.com/cosmos/cosmos-sdk"; | ||
Repository::clone(url, &sdk_dir).unwrap(); | ||
} | ||
|
||
// Paths | ||
let proto_paths = [ | ||
"../proto/definitions/mock".to_string(), | ||
format!("{}/proto/ibc", sdk_dir), | ||
format!("{}/proto/cosmos/tx", sdk_dir), | ||
format!("{}/proto/cosmos/base", sdk_dir), | ||
]; | ||
let proto_includes_paths = [ | ||
"../proto/definitions".to_string(), | ||
format!("{}/proto", sdk_dir), | ||
format!("{}/third_party/proto", sdk_dir), | ||
]; | ||
|
||
// List available proto files | ||
let mut protos: Vec<PathBuf> = vec![]; | ||
for proto_path in &proto_paths { | ||
protos.append( | ||
&mut WalkDir::new(proto_path) | ||
.into_iter() | ||
.filter_map(|e| e.ok()) | ||
.filter(|e| { | ||
e.file_type().is_file() | ||
&& e.path().extension().is_some() | ||
&& e.path().extension().unwrap() == "proto" | ||
}) | ||
.map(|e| e.into_path()) | ||
.collect(), | ||
); | ||
} | ||
|
||
// List available paths for dependencies | ||
let includes: Vec<PathBuf> = proto_includes_paths.iter().map(PathBuf::from).collect(); | ||
|
||
// Compile all proto files | ||
prost_build::compile_protos(&protos, &includes).unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use std::fs::remove_dir_all; | ||
use std::fs::{copy, create_dir_all}; | ||
use walkdir::WalkDir; | ||
|
||
pub(crate) fn main() { | ||
let ibc_proto_path = "../proto/src/prost"; | ||
|
||
// Remove old compiled files | ||
remove_dir_all(ibc_proto_path).unwrap_or_default(); | ||
create_dir_all(ibc_proto_path).unwrap(); | ||
|
||
// Copy new compiled files (prost does not use folder structures) | ||
let err: Vec<std::io::Error> = WalkDir::new(env!("OUT_DIR")) | ||
.into_iter() | ||
.filter_map(|e| e.ok()) | ||
.filter(|e| e.file_type().is_file()) | ||
.map(|e| { | ||
copy( | ||
e.path(), | ||
std::path::Path::new(&format!( | ||
"{}/{}", | ||
ibc_proto_path, | ||
&e.file_name().to_os_string().to_str().unwrap() | ||
)), | ||
) | ||
}) | ||
.filter_map(|e| e.err()) | ||
.collect(); | ||
|
||
if !err.is_empty() { | ||
for e in err { | ||
dbg!(e); | ||
} | ||
panic!("error while copying compiled files") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
[package] | ||
name = "ibc-proto" | ||
version = "0.3.0" | ||
authors = ["Greg Szabo <greg@informal.systems>"] | ||
edition = "2018" | ||
license = "Apache-2.0" | ||
repository = "https://github.com/informalsystems/ibc-proto/tree/master/ibc_proto" | ||
readme = "README.md" | ||
categories = ["cryptography", "cryptography::cryptocurrencies", "database"] | ||
keywords = ["blockchain", "cosmos", "tendermint", "ibc", "proto"] | ||
exclude = ["definitions"] | ||
|
||
description = """ | ||
ibc-proto is a the Rust implementation of the Cosmos SDK proto structs. | ||
""" | ||
|
||
[package.metadata.docs.rs] | ||
all-features = true | ||
|
||
[dependencies] | ||
prost = { version = "0.6" } | ||
prost-types = { version = "0.6" } | ||
anomaly = "0.2" | ||
bytes = "0.5" | ||
thiserror = "1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
## ibc-proto | ||
|
||
[![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 1.39+][rustc-image] | ||
|
||
Rust crate for interacting with Cosmos SDK | ||
[IBC structs](https://github.com/cosmos/cosmos-sdk/tree/master/proto/ibc). | ||
|
||
[Documentation][docs-link] | ||
|
||
## Requirements | ||
|
||
- Rust 1.39+ | ||
- make, curl | ||
- Cosmos SDK (downloaded automatically if you are using `make`) | ||
|
||
## License | ||
|
||
Copyright © 2020 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/ibc-proto.svg | ||
[crate-link]: https://crates.io/crates/ibc-proto | ||
[docs-image]: https://docs.rs/ibc-proto/badge.svg | ||
[docs-link]: https://docs.rs/ibc-proto/ | ||
[build-image]: https://github.com/informalsystems/ibc-rs/workflows/Rust/badge.svg | ||
[build-link]: https://github.com/informalsystems/ibc-rs/actions?query=workflow%3ARust | ||
[audit-image]: https://github.com/informalsystems/ibc-rs/workflows/Audit-Check/badge.svg | ||
[audit-link]: https://github.com/informalsystems/ibc-rs/actions?query=workflow%3AAudit-Check | ||
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg | ||
[license-link]: https://github.com/informalsystems/ibc-rs/blob/master/LICENSE | ||
[rustc-image]: https://img.shields.io/badge/rustc-1.39+-blue.svg | ||
|
||
[//]: # (general links) | ||
|
||
[Cosmos SDK]: https://github.com/cosmos/cosmos-sdk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
syntax = "proto3"; | ||
package ibc.mock; | ||
|
||
import "ibc/client/client.proto"; | ||
|
||
message Header { | ||
ibc.client.Height height = 1; | ||
} | ||
|
||
message ClientState { | ||
Header header = 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
//! DomainType trait | ||
//! | ||
//! The DomainType trait allows separation of the data sent on the wire (currently encoded using | ||
//! protobuf) from the structures used in Rust. The structures used to encode/decode from/to the | ||
//! wire are called "Raw" types (they mirror the definitions in the specifications) and the Rust | ||
//! types we use internally are called the "Domain" types. These Domain types can implement | ||
//! additional checks and conversions to consume the incoming data easier for a Rust developer. | ||
//! | ||
//! The benefits include decoding the wire into a struct that is inherently valid as well as hiding | ||
//! the encoding and decoding details from the developer. This latter is important if/when we decide | ||
//! to exchange the underlying Prost library with something else. (Another protobuf implementation | ||
//! or a completely different encoding.) Encoding is not the core product of IBC it's a | ||
//! necessary dependency. | ||
//! | ||
//! | ||
//! Decode: bytestream -> Raw -> Domain | ||
//! The `decode` function takes two steps to decode from a bytestream to a DomainType: | ||
//! | ||
//! 1. Decode the bytestream into a Raw type using the Prost library, | ||
//! 2. Transform that Raw type into a Domain type using the TryFrom trait of the DomainType. | ||
//! | ||
//! | ||
//! Encode: Domain -> Raw -> bytestream | ||
//! The `encode` function takes two steps to encode a DomainType into a bytestream: | ||
//! | ||
//! 1. Transform the Domain type into a Raw type using the From trait of the DomainType, | ||
//! 2. Encode the Raw type into a bytestream using the Prost library. | ||
//! | ||
//! | ||
//! Note that in the case of encode, the transformation to Raw type is infallible: | ||
//! Rust structs should always be ready to be encoded to the wire. | ||
//! | ||
//! Note that the Prost library and the TryFrom method have their own set of errors. These are | ||
//! merged into a custom Error type defined in this crate for easier handling. | ||
//! | ||
//! Requirements: | ||
//! * The DomainType trait requires the struct to implement the Clone trait. | ||
//! * Any RawType structure implements the prost::Message trait. (protobuf struct) | ||
//! * The DomainType trait requires that the TryFrom<RawType> implemented on the structure has an | ||
//! error type that implements Into<BoxError>. (The current implementations with anomaly are | ||
//! fine.) | ||
//! | ||
//! How to implement a DomainType struct: | ||
//! 1. Implement your struct based on your expectations for the developer | ||
//! 2. Add `impl DomainType<MyRawType> for MyDomainType {}` blanket implementation of the trait | ||
//! 4. Implement the `TryFrom<MyRawType> for MyDomainType` trait | ||
//! 5. Implement the `From<MyDomainType> for MyRawType` trait | ||
use crate::{Error, Kind}; | ||
use anomaly::BoxError; | ||
use bytes::{Buf, BufMut}; | ||
use prost::{encoding::encoded_len_varint, Message}; | ||
use std::convert::{TryFrom, TryInto}; | ||
|
||
/// DomainType trait allows protobuf encoding and decoding for domain types | ||
pub trait DomainType<T: Message + From<Self> + Default> | ||
where | ||
Self: Sized + Clone + TryFrom<T>, | ||
<Self as TryFrom<T>>::Error: Into<BoxError>, | ||
{ | ||
/// Encodes the DomainType into a buffer. | ||
/// | ||
/// This function replaces the Prost::Message encode() function for DomainTypes. | ||
fn encode<B: BufMut>(&self, buf: &mut B) -> Result<(), Error> { | ||
T::from(self.clone()) | ||
.encode(buf) | ||
.map_err(|e| Kind::EncodeMessage.context(e).into()) | ||
} | ||
|
||
/// Encodes the DomainType with a length-delimiter to a buffer. | ||
/// | ||
/// An error will be returned if the buffer does not have sufficient capacity. | ||
/// | ||
/// This function replaces the Prost::Message encode_length_delimited() function for | ||
/// DomainTypes. | ||
fn encode_length_delimited<B: BufMut>(&self, buf: &mut B) -> Result<(), Error> { | ||
T::from(self.clone()) | ||
.encode_length_delimited(buf) | ||
.map_err(|e| Kind::EncodeMessage.context(e).into()) | ||
} | ||
|
||
/// Decodes an instance of the message from a buffer and then converts it into DomainType. | ||
/// | ||
/// The entire buffer will be consumed. | ||
/// | ||
/// This function replaces the Prost::Message decode() function for DomainTypes. | ||
fn decode<B: Buf>(buf: B) -> Result<Self, Error> { | ||
T::decode(buf).map_or_else( | ||
|e| Err(Kind::DecodeMessage.context(e).into()), | ||
|t| Self::try_from(t).map_err(|e| Kind::TryIntoDomainType.context(e).into()), | ||
) | ||
} | ||
|
||
/// Decodes a length-delimited instance of the message from the buffer. | ||
/// | ||
/// The entire buffer will be consumed. | ||
/// | ||
/// This function replaces the Prost::Message decode_length_delimited() function for | ||
/// DomainTypes. | ||
fn decode_length_delimited<B: Buf>(buf: B) -> Result<Self, Error> { | ||
T::decode_length_delimited(buf).map_or_else( | ||
|e| Err(Kind::DecodeMessage.context(e).into()), | ||
|t| Self::try_from(t).map_err(|e| Kind::TryIntoDomainType.context(e).into()), | ||
) | ||
} | ||
|
||
/// Returns the encoded length of the message without a length delimiter. | ||
/// | ||
/// This function replaces the Prost::Message encoded_len() function for DomainTypes. | ||
fn encoded_len(&self) -> usize { | ||
T::from(self.clone()).encoded_len() | ||
} | ||
|
||
/// Encodes the DomainType into a protobuf-encoded Vec<u8> | ||
fn encode_vec(&self) -> Result<Vec<u8>, Error> { | ||
let mut wire = Vec::with_capacity(self.encoded_len()); | ||
self.encode(&mut wire).map(|_| wire) | ||
} | ||
|
||
/// Decodes a protobuf-encoded instance of the message from a Vec<u8> and then converts it into | ||
/// DomainType. | ||
fn decode_vec(v: &[u8]) -> Result<Self, Error> { | ||
Self::decode(v) | ||
} | ||
|
||
/// Encodes the DomainType with a length-delimiter to a Vec<u8> protobuf-encoded message. | ||
fn encode_length_delimited_vec(&self) -> Result<Vec<u8>, Error> { | ||
let len = self.encoded_len(); | ||
let lenu64 = len.try_into().map_err(|e| Kind::EncodeMessage.context(e))?; | ||
let mut wire = Vec::with_capacity(len + encoded_len_varint(lenu64)); | ||
self.encode_length_delimited(&mut wire).map(|_| wire) | ||
} | ||
|
||
/// Decodes a protobuf-encoded instance of the message with a length-delimiter from a Vec<u8> | ||
/// and then converts it into DomainType. | ||
fn decode_length_delimited_vec(v: &[u8]) -> Result<Self, Error> { | ||
Self::decode_length_delimited(v) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
//! This module defines the various errors that be raised during DomainType conversions. | ||
use anomaly::{BoxError, Context}; | ||
use thiserror::Error; | ||
|
||
/// An error that can be raised by the DomainType conversions. | ||
pub type Error = anomaly::Error<Kind>; | ||
|
||
/// Various kinds of errors that can be raised. | ||
#[derive(Clone, Debug, Error)] | ||
pub enum Kind { | ||
/// TryFrom Prost Message failed during decoding | ||
#[error("error converting message type into domain type")] | ||
TryIntoDomainType, | ||
|
||
/// encoding prost Message into buffer failed | ||
#[error("error encoding message into buffer")] | ||
EncodeMessage, | ||
|
||
/// decoding buffer into prost Message failed | ||
#[error("error decoding buffer into message")] | ||
DecodeMessage, | ||
} | ||
|
||
impl Kind { | ||
/// Add a given source error as context for this error kind | ||
/// | ||
/// This is typically use with `map_err` as follows: | ||
/// | ||
/// ```ignore | ||
/// let x = self.something.do_stuff() | ||
/// .map_err(|e| error::Kind::Config.context(e))?; | ||
/// ``` | ||
pub fn context(self, source: impl Into<BoxError>) -> Context<Self> { | ||
Context::new(self, Some(source.into())) | ||
} | ||
} |
Oops, something went wrong.