Skip to content

Commit

Permalink
Add public RLP and HTTP API support (#15)
Browse files Browse the repository at this point in the history
* Add public RLP
* Add HDNode docs
* Clean up address namespace
* Add network interface for blocks and transactions
  • Loading branch information
sterliakov authored Dec 23, 2023
1 parent be48e61 commit 2f82a7d
Show file tree
Hide file tree
Showing 15 changed files with 2,039 additions and 359 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
run: cargo rdme --check

- name: Run tests with coverage
run: RUST_BACKTRACE=1 cargo tarpaulin --out Xml
run: RUST_BACKTRACE=1 cargo tarpaulin --out Xml --all-features

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
Expand Down
12 changes: 5 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ Possible header types:
- `Breaking Changes` for any backwards-incompatible changes.

## [Unreleased]
<!--

### Features
- Added a new struct `MyStruct` with the following methods:
- `my_method()`
- `other_method()`
-->
- Made RLP encoding components public and rewrite it with more conscious syntax.
- Added network support for Transaction and Block retrieval.

## v0.0.1 (2023-10-01)
## v0.0.1-alpha.1 (2023-10-01)

- Initial Release on [crates.io] :tada:

[crates.io]: https://crates.io/crates/thor-devkit.rs
[crates.io]: https://crates.io/crates/thor-devkit
22 changes: 11 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,28 @@ targets = ["x86_64-unknown-linux-gnu"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
alloy-rlp = { version = "0.3.3", features = ["derive"] }
bip32 = { version = "0.5.1", default-features=false, features = [ "alloc", "secp256k1-ffi"] }
blake2 = "0.10.6"
ethereum-types = "0.14.0"
itertools = "0.12.0"
tiny-keccak = { version = "2.0.0", features = ["keccak"] }
secp256k1 = { version = "0.27.0", features = [ "recovery" ] }
tiny-bip39 = "1.0.0"
ethabi = "18.0.0"
rustc-hex = "2.1.0"
open-fastrlp = { version = "0.1.4", features = ["std", "ethereum-types"] }
bytes = "1.5.0"
reqwest = { version = "0.11", features = ["json"], optional = true }
serde = { version = "^1.0", features=["derive"], optional = true }
serde_json = { version = "^1.0", optional = true }
serde_with = { version = "^3.4", features = ["hex"], optional = true }

[dev-dependencies]
# version_sync: to ensure versions in `Cargo.toml` and `README.md` are in sync
version-sync = "0.9.4"

# cargo-bump: to bump package version and tag a commit at the same time.
# actually, the docs recommend installing this globally:
# $ git clone https://github.com/rnag/cargo-bump && cd cargo-bump && cargo install --path . && cd .. && rm -rf cargo-bump
# logging utilities
# log = "^0.4"
# sensible-env-logger = "0.1.0"
# tokio: for `async` support
# tokio = { version = "^1.0", features = ["macros", "rt-multi-thread"] }
rand = { version = "0.8.5", features = ["getrandom"] }
tokio = { version = "1", features = ["full"] }

[features]
default = ['http']
serde = ["dep:serde", "dep:serde_json", "dep:serde_with"]
http = ["dep:reqwest", "serde"]
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ Check out the [Contributing][] section in the docs for more info.

### License

This project is proudly licensed under the GNU General Public License v3 ([LICENSE](LICENSE)).
This project is proudly licensed under the Lesser GNU General Public License v3 ([LICENSE](https://github.com/sterliakov/thor-devkit.rs/blob/master/LICENSE)).

`thor-devkit` can be distributed according to the GNU General Public License v3. Contributions
`thor-devkit` can be distributed according to the Lesser GNU General Public License v3. Contributions
will be accepted under the same license.

<!-- cargo-rdme end -->
Expand Down
38 changes: 18 additions & 20 deletions src/address.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
//! VeChain address operations and verifications.
use crate::rlp::{Decodable, Encodable, RLPError};
use crate::utils::keccak;
use alloy_rlp::{Decodable, Encodable};
use ethereum_types::Address as WrappedAddress;
pub use secp256k1::{PublicKey, SecretKey as PrivateKey};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::{
ops::{Deref, DerefMut},
result::Result,
str::FromStr,
};

#[cfg_attr(feature = "serde", serde_with::serde_as)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(remote = "ethereum_types::H160"))]
struct _Address(#[cfg_attr(feature = "serde", serde_as(as = "crate::utils::unhex::Hex"))] [u8; 20]);

/// VeChain address.
#[cfg_attr(feature = "serde", serde_with::serde_as)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Address(WrappedAddress);
pub struct Address(#[cfg_attr(feature = "serde", serde_as(as = "_Address"))] WrappedAddress);

impl DerefMut for Address {
// type Target = WrappedAddress;

fn deref_mut(&mut self) -> &mut WrappedAddress {
&mut self.0
}
Expand All @@ -29,18 +36,18 @@ impl Deref for Address {
}
}
impl Encodable for Address {
fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
use crate::transactions::lstrip;
alloy_rlp::Bytes::copy_from_slice(&lstrip(self.0)).encode(out)
fn encode(&self, out: &mut dyn open_fastrlp::BufMut) {
use crate::rlp::lstrip;
bytes::Bytes::copy_from_slice(&lstrip(self.0)).encode(out)
}
}
impl Decodable for Address {
fn decode(buf: &mut &[u8]) -> Result<Self, alloy_rlp::Error> {
use crate::transactions::static_left_pad;
let bytes = alloy_rlp::Bytes::decode(buf)?;
fn decode(buf: &mut &[u8]) -> Result<Self, RLPError> {
use crate::rlp::static_left_pad;
let bytes = bytes::Bytes::decode(buf)?;
Ok(Self(WrappedAddress::from_slice(
&static_left_pad::<20>(&bytes).map_err(|e| match e {
alloy_rlp::Error::Overflow => alloy_rlp::Error::ListLengthMismatch {
RLPError::Overflow => RLPError::ListLengthMismatch {
expected: Self::WIDTH,
got: bytes.len(),
},
Expand Down Expand Up @@ -102,12 +109,3 @@ impl AddressConvertible for secp256k1::PublicKey {
Address(WrappedAddress::from_slice(&suffix))
}
}

/// Invalid public key format reasons
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AddressValidationError {
/// Not of length 20
InvalidLength,
/// Not a hex string
InvalidHex,
}
49 changes: 45 additions & 4 deletions src/hdnode.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
//! VeChain-tailored Hierarchically deterministic nodes support
//! VeChain-tailored hierarchically deterministic nodes support
//!
//! `Reference <https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki>`
//! [In-deep explanation](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
//!
//! This module glues together several important components involved in key derivation
//! from different sources. You can construct an [`HDNode`] in multiple ways, allowing,
//! for example, generating a private key from mnemonic or generating a random key.
use bip32::{
ChainCode, ChildNumber, DerivationPath, ExtendedKey, ExtendedKeyAttrs, ExtendedPrivateKey,
Expand All @@ -22,6 +26,9 @@ enum HDNodeVariant {
use HDNodeVariant::{Full, Restricted};

/// Hierarchically deterministic node.
///
/// To construct a wallet, use the [`HDNode::build`] method. It exposes access to the builder
/// that supports multiple construction methods and validates the arguments.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HDNode(HDNodeVariant);

Expand All @@ -41,14 +48,14 @@ impl HDNode {
}

pub fn public_key(&self) -> ExtendedPublicKey<PublicKey> {
//! Get underlying public key.
//! Get underlying extended public key.
match &self.0 {
Full(privkey) => privkey.public_key(),
Restricted(pubkey) => pubkey.clone(),
}
}
pub fn private_key(&self) -> Result<ExtendedPrivateKey<PrivateKey>, HDNodeError> {
//! Get underlying private key.
//! Get underlying extended private key.
match &self.0 {
Full(privkey) => Ok(privkey.clone()),
Restricted(_) => Err(HDNodeError::Crypto),
Expand Down Expand Up @@ -140,6 +147,36 @@ impl From<bip32::Error> for HDNodeError {
}

/// Builder for HDNode: use this to construct a node from different sources.
///
/// The following sources are supported:
/// - Binary seed. 64 bytes of raw entropy to use for key generation.
/// - [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic
/// with optional password. This method is compatible with derivation in Sync2 wallet.
/// - Master private key bytes and chain code
/// - Extended private key
/// - Master public key bytes and chain code
/// - Extended public key
///
/// First two methods accept a derivation path to use (defaults to VeChain path).
///
/// For example, here's what you could do:
///
/// ```rust
/// use thor_devkit::hdnode::{Mnemonic, Language, HDNode};
/// use rand::RngCore;
/// use rand::rngs::OsRng;
///
/// let mnemonic = Mnemonic::from_phrase(
/// "ignore empty bird silly journey junior ripple have guard waste between tenant",
/// Language::English,
/// )
/// .expect("Should be constructible");
/// let wallet = HDNode::build().mnemonic(mnemonic).build().expect("Must be buildable");
/// // OR
/// let mut entropy = [0u8; 64];
/// OsRng.fill_bytes(&mut entropy);
/// let other_wallet = HDNode::build().seed(entropy).build().expect("Must be buildable");
/// ```
#[derive(Clone, Default)]
pub struct HDNodeBuilder<'a> {
path: Option<DerivationPath>,
Expand Down Expand Up @@ -211,7 +248,9 @@ impl<'a> HDNodeBuilder<'a> {
) -> Self {
//! Create an HDNode from private key bytes and chain code.
//!
//! <div class="warning">
//! Beware that this node cannot be used to derive new private keys.
//! </div>
self.ext_pubkey = Some(ExtendedKey {
prefix: Prefix::XPUB,
attrs: ExtendedKeyAttrs {
Expand All @@ -227,7 +266,9 @@ impl<'a> HDNodeBuilder<'a> {
pub fn public_key(mut self, ext_key: ExtendedKey) -> Self {
//! Create an HDNode from extended public key structure.
//!
//! <div class="warning">
//! Beware that this node cannot be used to derive new private keys.
//! </div>
self.ext_pubkey = Some(ext_key);
self
}
Expand Down
14 changes: 9 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,19 @@
//!
//! ## License
//!
//! This project is proudly licensed under the GNU General Public License v3 ([LICENSE](LICENSE)).
//! This project is proudly licensed under the Lesser GNU General Public License v3 ([LICENSE](https://github.com/sterliakov/thor-devkit.rs/blob/master/LICENSE)).
//!
//! `thor-devkit` can be distributed according to the GNU General Public License v3. Contributions
//! `thor-devkit` can be distributed according to the Lesser GNU General Public License v3. Contributions
//! will be accepted under the same license.
pub mod address;
mod address;
pub use address::{Address, AddressConvertible, PrivateKey, PublicKey};
pub mod hdnode;
#[cfg(feature = "http")]
pub mod network;
pub mod rlp;
pub mod transactions;
mod utils;
pub use ethabi;
pub use ethereum_types::U256;
pub use utils::{blake2_256, decode_hex, keccak};
pub use rustc_hex::FromHexError as AddressValidationError;
pub use utils::{blake2_256, keccak};
Loading

0 comments on commit 2f82a7d

Please sign in to comment.