Skip to content

Commit

Permalink
stdtx: Initial crate
Browse files Browse the repository at this point in the history
Originally developed here as the `cosmos-stdtx` crate:

tendermint/tmkms#401

This imports the code, renames it to the more convenient `stdtx` crate,
and updates links and path references to other crates in this repo.
  • Loading branch information
tony-iqlusion committed Jan 27, 2020
1 parent c57c74f commit 0843048
Show file tree
Hide file tree
Showing 23 changed files with 2,195 additions and 13 deletions.
540 changes: 528 additions & 12 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"harp",
"hkd32",
"secrecy",
"stdtx",
"subtle-encoding",
"tai64",
"zeroize",
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ This repository contains the following crates:
| [harp] | ![][harp-crate] | Minimalist HTTP library |
| [hkd32] | ![][hkd32-crate] | HMAC-based Hierarchical Key Derivation |
| [secrecy] | ![][secrecy-crate] | Simple secret-keeping library |
| [stdtx] | ![][stdtx-crate] | Cosmos StdTx builder/signer/serializer |
| [subtle-encoding] | ![][subtle-encoding-crate] | Hex, Bech32, and Base64 in constant-time(ish) |
| [tai64] | ![][tai64-crate] | TAI64(N) timestamp format |
| [zeroize] | ![][zeroize-crate] | Securely zero memory |
Expand Down Expand Up @@ -90,6 +91,8 @@ without any additional terms or conditions.
[hkd32-crate]: https://img.shields.io/crates/v/hkd32.svg
[secrecy]: https://github.com/iqlusioninc/crates/tree/develop/secrecy
[secrecy-crate]: https://img.shields.io/crates/v/secrecy.svg
[stdtx]: https://github.com/iqlusioninc/crates/tree/develop/stdtx
[stdtx-crate]: https://img.shields.io/crates/v/stdtx.svg
[subtle-encoding]: https://github.com/iqlusioninc/crates/tree/develop/subtle-encoding
[subtle-encoding-crate]: https://img.shields.io/crates/v/subtle-encoding.svg
[tai64]: https://github.com/iqlusioninc/crates/tree/develop/tai64
Expand Down
2 changes: 1 addition & 1 deletion hkd32/src/pathbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ impl FromStr for PathBuf {
let mut result = Self::new();

// Special case for the root path
if s.len() == 1 && s.chars().nth(0) == Some(DELIMITER) {
if s.len() == 1 && s.starts_with(DELIMITER) {
return Ok(result);
}

Expand Down
35 changes: 35 additions & 0 deletions stdtx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[package]
name = "stdtx"
description = "Extensible schema-driven Cosmos StdTx builder and Amino serializer"
version = "0.0.0" # Also update html_root_url in lib.rs when bumping this
authors = ["Tony Arcieri <[email protected]>"]
license = "Apache-2.0"
homepage = "https://github.com/iqlusioninc/crates/"
repository = "https://github.com/iqlusioninc/crates/tree/develop/stdtx"
readme = "README.md"
categories = ["cryptography", "encoding"]
keywords = ["amino", "crypto", "cosmos", "transaction", "tendermint"]
edition = "2018"

[badges]
circle-ci = { repository = "tendermint/kms" }

[dependencies]
anomaly = { version = "0.1", path = "../anomaly" }
ecdsa = { version = "0.4", features = ["k256"] }
prost-amino = "0.5"
prost-amino-derive = "0.5"
rust_decimal = "1.1"
serde = { version = "1", features = ["serde_derive"] }
serde_json = "1"
sha2 = "0.8"
thiserror = "1"
toml = "0.5"

[dependencies.subtle-encoding]
version = "0.5"
features = ["bech32-preview"]
path = "../subtle-encoding"

[dev-dependencies]
signatory-secp256k1 = "0.18"
67 changes: 67 additions & 0 deletions stdtx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# stdtx.rs 🌌 <a href="https://www.iqlusion.io"><img src="https://storage.googleapis.com/iqlusion-production-web/img/logo/iqlusion-rings-sm.png" alt="iqlusion" width="24" height="24"></a>

[![Crate][crate-image]][crate-link]
[![Docs][docs-image]][docs-link]
[![Build Status][build-image]][build-link]
[![Safety Dance][safety-image]][safety-link]
[![Apache 2.0 Licensed][license-image]][license-link]
![MSRV][msrv-image]
[![Gitter Chat][gitter-image]][gitter-link]

Extensible schema-driven [Cosmos] [StdTx] builder and [Amino] serializer.

## About

**stdtx.rs** is a Rust library for composing transactions in the [StdTx]
format used by several [Tendermint]-based networks.

It includes support for cryptographically signing transactions and serializing
them in the [Amino] encoding format.

Definitions of transaction types are easily extensible, and can be defined at
runtime by loading them from a TOML definition file. This allows
**stdtx.rs** to be used with any [Tendermint]-based software which
uses the [StdTx] format without requiring upstream modifications.

## Minimum Supported Rust Version

- Rust **1.39+**

## License

Copyright © 2020 Tony Arcieri

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file 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/stdtx.svg
[crate-link]: https://crates.io/crates/stdtx
[docs-image]: https://docs.rs/stdtx/badge.svg
[docs-link]: https://docs.rs/stdtx/
[build-image]: https://github.com/iqlusioninc/crates/workflows/Rust/badge.svg?branch=develop&event=push
[build-link]: https://github.com/iqlusioninc/crates/actions
[safety-image]: https://img.shields.io/badge/unsafe-forbidden-success.svg
[safety-link]: https://github.com/rust-secure-code/safety-dance/
[license-image]: https://img.shields.io/badge/license-Apache2.0-blue.svg
[license-link]: https://github.com/iqlusioninc/crates/blob/develop/LICENSE
[msrv-image]: https://img.shields.io/badge/rustc-1.39+-blue.svg
[gitter-image]: https://badges.gitter.im/iqlusioninc/community.svg
[gitter-link]: https://gitter.im/iqlusioninc/community

[//]: # (general links)

[Cosmos]: https://cosmos.network/
[StdTx]: https://godoc.org/github.com/cosmos/cosmos-sdk/x/auth/types#StdTx
[Tendermint]: https://tendermint.com/
[Amino]: https://github.com/tendermint/go-amino
53 changes: 53 additions & 0 deletions stdtx/src/address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//! Address types (account or validator)
use crate::error::{Error, ErrorKind};
use anomaly::ensure;
use std::convert::TryInto;
use subtle_encoding::bech32;

/// Size of an address
pub const ADDRESS_SIZE: usize = 20;

/// Address type
#[derive(Clone, Debug)]
pub struct Address(pub [u8; ADDRESS_SIZE]);

impl Address {
/// Parse an address from its Bech32 form
pub fn from_bech32(addr_bech32: impl AsRef<str>) -> Result<(String, Address), Error> {
let (hrp, addr) = bech32::decode(addr_bech32.as_ref())?;

ensure!(
addr.len() == ADDRESS_SIZE,
ErrorKind::Address,
"invalid length for decoded address: {} (expected {})",
addr.len(),
ADDRESS_SIZE
);

Ok((hrp, Address(addr.as_slice().try_into().unwrap())))
}

/// Encode this address as Bech32
pub fn to_bech32(&self, hrp: &str) -> String {
bech32::encode(hrp, &self.0)
}
}

impl AsRef<[u8]> for Address {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

impl From<[u8; ADDRESS_SIZE]> for Address {
fn from(addr: [u8; ADDRESS_SIZE]) -> Address {
Address(addr)
}
}

impl From<Address> for [u8; ADDRESS_SIZE] {
fn from(addr: Address) -> [u8; ADDRESS_SIZE] {
addr.0
}
}
118 changes: 118 additions & 0 deletions stdtx/src/amino_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//! StdTx Amino types
use crate::{Signature, TypeName};
use prost_amino::{encode_length_delimiter, Message};
use prost_amino_derive::Message;
use serde_json::json;

/// StdTx Amino type
#[derive(Clone, Message)]
pub struct StdTx {
/// Messages in transction
#[prost_amino(bytes, repeated, tag = "1")]
pub msg: Vec<Vec<u8>>,

/// Feeds to be paid
#[prost_amino(message)]
pub fee: Option<StdFee>,

/// Signatures
#[prost_amino(message, repeated)]
pub signatures: Vec<StdSignature>,

/// Memo field
#[prost_amino(string)]
pub memo: String,
}

impl StdTx {
/// Encode this [`StdTx`] in Amino encoding identifying it with the given
/// type name (e.g. `cosmos-sdk/StdTx`)
pub fn to_amino_bytes(&self, type_name: &TypeName) -> Vec<u8> {
let mut amino_tx = type_name.amino_prefix();
self.encode(&mut amino_tx).expect("LEB128 encoding error");

let mut amino_encoded = vec![];
encode_length_delimiter(amino_tx.len(), &mut amino_encoded).expect("LEB128 encoding error");
amino_encoded.append(&mut amino_tx);
amino_encoded
}
}

/// StdFee amino type
#[derive(Clone, Message)]
pub struct StdFee {
/// Fee to be paid
#[prost_amino(message, repeated, tag = "1")]
pub amount: Vec<Coin>,

/// Gas requested for transaction
#[prost_amino(uint64)]
pub gas: u64,
}

impl StdFee {
/// Create a [`StdFee`] for a gas-only transaction
pub fn for_gas(gas: u64) -> Self {
StdFee {
amount: vec![],
gas,
}
}
/// Compute `serde_json::Value` representing this fee
pub fn to_json_value(&self) -> serde_json::Value {
let amount = self
.amount
.iter()
.map(|amt| amt.to_json_value())
.collect::<Vec<_>>();

json!({
"amount": amount,
"gas": self.gas.to_string()
})
}
}

/// Coin Amino type
#[derive(Clone, Message)]
pub struct Coin {
/// Denomination of coin
#[prost_amino(string, tag = "1")]
pub denom: String,

/// Amount of the given denomination
#[prost_amino(string)]
pub amount: String,
}

impl Coin {
/// Compute `serde_json::Value` representing this coin
pub fn to_json_value(&self) -> serde_json::Value {
json!({
"denom": self.denom,
"amount": self.amount
})
}
}

/// StdSignature amino type
#[derive(Clone, Message)]
pub struct StdSignature {
/// Public key which can verify this signature
#[prost_amino(bytes, tag = "1", amino_name = "tendermint/PubKeySecp256k1")]
pub pub_key: Vec<u8>,

/// Serialized signature
#[prost_amino(bytes)]
pub signature: Vec<u8>,
}

impl From<Signature> for StdSignature {
fn from(signature: Signature) -> StdSignature {
StdSignature {
pub_key: vec![],
signature: signature.as_ref().to_vec(),
}
}
}
Loading

0 comments on commit 0843048

Please sign in to comment.