Skip to content
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 rustfmt and Github CI #2

Merged
merged 1 commit into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Continuous Integration Checks

on: [ push, pull_request ]

jobs:
build:
strategy:
matrix:
toolchain: [ stable, beta ]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What MSRV will the VSS client support? Can we start enforcing it here in CI from the getgo?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't gotten a chance to look into that, when i do, will start enforcing it.

Copy link
Contributor

@tnull tnull May 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Mind creating a tracking issue for it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created : #4

include:
- toolchain: stable
check-fmt: true
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Install Protobuf compiler (protoc)
run: sudo apt-get update && sudo apt-get -y install protobuf-compiler
- name: Install Rust ${{ matrix.toolchain }} toolchain
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile=minimal --default-toolchain ${{ matrix.toolchain }}
rustup override set ${{ matrix.toolchain }}
- name: Build on Rust ${{ matrix.toolchain }}
G8XSU marked this conversation as resolved.
Show resolved Hide resolved
run: cargo build --verbose --color always
- name: Check formatting
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably also want to add another step enforcing buildable docs for the public API, i.e.,

cargo check --release
cargo doc --release

In combination with adding

#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]

To your lib.rs file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍
For now adding only broken_intra_doc_links and private_intra_doc_links
Some of the auto-generated code doesn't comply with all the checks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mh, but isn't that simply a function of the docs missing in https://github.com/lightningdevkit/vss-server/blob/main/app/src/main/proto/vss.proto? Should they be added there rather than omitting the check here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"for now",
will add it eventually. I can add at warn level for now.
(already have some changes in pipeline for proto file)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright!

if: matrix.check-fmt
run: rustup component add rustfmt && cargo fmt --all -- --check
- name: Test on Rust ${{ matrix.toolchain }}
run: cargo test
- name: Cargo check release on Rust ${{ matrix.toolchain }}
run: cargo check --release
- name: Cargo check doc on Rust ${{ matrix.toolchain }}
run: cargo doc --release
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
/vss-accessor/src/proto/
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[workspace]
members = [
"vss-accessor",
]
6 changes: 6 additions & 0 deletions rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
hard_tabs = true # use tab characters for indentation, spaces for alignment
use_field_init_shorthand = true
max_width = 120
use_small_heuristics = "Max"
chain_width = 80
fn_args_layout = "Compressed"
16 changes: 16 additions & 0 deletions vss-accessor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "vss-accessor"
version = "0.1.0"
edition = "2021"
build = "build.rs"

[dependencies]

[dev-dependencies]

[build-dependencies]
prost-build = { version = "0.11.3" }
reqwest = { version = "0.11.13", features = ["blocking"] }

[features]
genproto = []
34 changes: 34 additions & 0 deletions vss-accessor/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
extern crate prost_build;

use std::fs::File;
use std::path::Path;
use std::{env, fs};

/// To generate updated proto objects:
/// 1. Place `vss.proto` file in `src/proto/`
/// 2. run `cargo build --features=genproto`
fn main() {
#[cfg(feature = "genproto")]
generate_protos();
}

#[cfg(feature = "genproto")]
fn generate_protos() {
download_file(
"https://raw.githubusercontent.com/lightningdevkit/vss-server/ff4b5fc6a079ed8719eb8be7ec35ca1d01c1cc55/app/src/main/proto/vss.proto",
"src/proto/vss.proto",
).unwrap();

prost_build::compile_protos(&["src/proto/vss.proto"], &["src/"]).unwrap();
let from_path = Path::new(&env::var("OUT_DIR").unwrap()).join("org.vss.rs");
fs::copy(from_path, "src/generated-src/org.vss.rs").unwrap();
}

#[cfg(feature = "genproto")]
fn download_file(url: &str, save_to: &str) -> Result<(), Box<dyn std::error::Error>> {
let mut response = reqwest::blocking::get(url)?;
fs::create_dir_all(Path::new(save_to).parent().unwrap())?;
let mut out_file = File::create(save_to)?;
response.copy_to(&mut out_file)?;
Ok(())
}
251 changes: 251 additions & 0 deletions vss-accessor/src/generated-src/org.vss.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetObjectRequest {
/// store_id is a keyspace identifier.
/// Ref: <https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store>)
/// All APIs operate within a single store_id.
/// It is up to clients to use single or multiple stores for their use-case.
/// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
/// Authorization and billing can also be performed at the store_id level.
#[prost(string, tag = "1")]
pub store_id: ::prost::alloc::string::String,
/// Key for which the value is to be fetched.
///
/// Consistency Guarantee:
/// Get(read) operations against a key are consistent reads and will reflect all previous writes,
/// since Put/Write provides read-after-write and read-after-update consistency guarantees.
///
/// Read Isolation:
/// Get/Read operations against a key are ensured to have read-committed isolation.
/// Ref: <https://en.wikipedia.org/wiki/Isolation_(database_systems>)#Read_committed
#[prost(string, tag = "2")]
pub key: ::prost::alloc::string::String,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetObjectResponse {
/// Fetched value and version along with the corresponding key in the request.
#[prost(message, optional, tag = "2")]
pub value: ::core::option::Option<KeyValue>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PutObjectRequest {
/// store_id is a keyspace identifier.
/// Ref: <https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store>)
/// All APIs operate within a single store_id.
/// It is up to clients to use single or multiple stores for their use-case.
/// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
/// Authorization and billing can also be performed at the store_id level.
#[prost(string, tag = "1")]
pub store_id: ::prost::alloc::string::String,
/// global_version is a sequence-number/version of the whole store. This can be used for versioning
/// and ensures that multiple updates in case of multiple devices can only be done linearly, even
/// if those updates did not directly conflict with each other based on keys/transaction_items.
///
/// If present, the write will only succeed if the current server-side global_version against
/// the store_id is same as in the request.
/// Clients are expected to store (client-side) the global version against store_id.
/// The request must contain their client-side value of global_version if global versioning and
/// conflict detection is desired.
///
/// For the first write of the store, global version should be '0'. If the write succeeds, clients
/// must increment their global version (client-side) by 1.
/// The server increments global_version (server-side) for every successful write, hence this
/// client-side increment is required to ensure matching versions. This updated global version
/// should be used in subsequent PutObjectRequests for the store.
///
/// Requests with a conflicting version will fail with `CONFLICT_EXCEPTION` as ErrorCode.
#[prost(int64, optional, tag = "2")]
pub global_version: ::core::option::Option<i64>,
/// Items to be written as a result of this PutObjectRequest.
///
/// In an item, each key is supplied with its corresponding value and version.
/// Clients can choose to encrypt the keys client-side in order to obfuscate their usage patterns.
/// If the write is successful, the previous value corresponding to the key will be overwritten.
///
/// Multiple items in transaction_items of a single PutObjectRequest are written in
/// a database-transaction in an all-or-nothing fashion.
/// Items in a single PutObjectRequest must have distinct keys.
///
/// Clients are expected to store a version against every key.
/// The write will succeed if the current DB version against the key is the same as in the request.
/// When initiating a PutObjectRequest, the request should contain their client-side version for
/// that key-value.
///
/// For the first write of any key, the version should be '0'. If the write succeeds, the client
/// must increment their corresponding key versions (client-side) by 1.
/// The server increments key versions (server-side) for every successful write, hence this
/// client-side increment is required to ensure matching versions. These updated key versions should
/// be used in subsequent PutObjectRequests for the keys.
///
/// Requests with a conflicting version will fail with `CONFLICT_EXCEPTION` as ErrorCode.
///
/// Considerations for transactions:
/// Transaction writes of multiple items have a performance overhead, hence it is recommended to use
/// them only if required by the client application to ensure logic/code correctness.
/// That is, transaction_items are not a substitute for batch-write of multiple unrelated items.
/// When a write of multiple unrelated items is desired, it is recommended to use separate
/// PutObjectRequests.
///
/// Consistency guarantee:
/// All PutObjectRequests are strongly consistent i.e. they provide read-after-write and
/// read-after-update consistency guarantees.
#[prost(message, repeated, tag = "3")]
pub transaction_items: ::prost::alloc::vec::Vec<KeyValue>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PutObjectResponse {}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListKeyVersionsRequest {
/// store_id is a keyspace identifier.
/// Ref: <https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store>)
/// All APIs operate within a single store_id.
/// It is up to clients to use single or multiple stores for their use-case.
/// This can be used for client-isolation/ rate-limiting / throttling on the server-side.
/// Authorization and billing can also be performed at the store_id level.
#[prost(string, tag = "1")]
pub store_id: ::prost::alloc::string::String,
/// A key_prefix is a string of characters at the beginning of the key. Prefixes can be used as
/// a way to organize key-values in a similar way to directories.
///
/// If key_prefix is specified, the response results will be limited to those keys that begin with
/// the specified prefix.
///
/// If no key_prefix is specified or it is empty (""), all the keys are eligible to be returned in
/// the response.
#[prost(string, optional, tag = "2")]
pub key_prefix: ::core::option::Option<::prost::alloc::string::String>,
/// page_size is used by clients to specify the maximum number of results that can be returned by
/// the server.
/// The server may further constrain the maximum number of results returned in a single page.
/// If the page_size is 0 or not set, the server will decide the number of results to be returned.
#[prost(int32, optional, tag = "3")]
pub page_size: ::core::option::Option<i32>,
/// page_token is a pagination token.
///
/// To query for the first page of ListKeyVersions, page_token must not be specified.
///
/// For subsequent pages, use the value that was returned as `next_page_token` in the previous
/// page's ListKeyVersionsResponse.
#[prost(string, optional, tag = "4")]
pub page_token: ::core::option::Option<::prost::alloc::string::String>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ListKeyVersionsResponse {
/// Fetched keys and versions.
/// Even though this API reuses KeyValue struct, the value sub-field will not be set by the server.
#[prost(message, repeated, tag = "1")]
pub key_versions: ::prost::alloc::vec::Vec<KeyValue>,
/// next_page_token is a pagination token, used to retrieve the next page of results.
/// Use this value to query for next_page of paginated ListKeyVersions operation, by specifying
/// this value as the `page_token` in the next request.
///
/// If next_page_token is empty (""), then the "last page" of results has been processed and
/// there is no more data to be retrieved.
///
/// If next_page_token is not empty, it does not necessarily mean that there is more data in the
/// result set. The only way to know when you have reached the end of the result set is when
/// next_page_token is empty.
///
/// Caution: Clients must not assume a specific number of key_versions to be present in a page for
/// paginated response.
#[prost(string, optional, tag = "2")]
pub next_page_token: ::core::option::Option<::prost::alloc::string::String>,
/// global_version is a sequence-number/version of the whole store.
///
/// global_version is only returned in response for the first page of the ListKeyVersionsResponse
/// and is guaranteed to be read before reading any key-versions.
///
/// In case of refreshing the complete key-version view on the client-side, correct usage for
/// the returned global_version is as following:
/// 1. Read global_version from the first page of paginated response and save it as local variable.
/// 2. Update all the key_versions on client-side from all the pages of paginated response.
/// 3. Update global_version on client_side from the local variable saved in step-1.
/// This ensures that on client-side, all current key_versions were stored at global_version or later.
/// This guarantee is helpful for ensuring the versioning correctness if using the global_version
/// in PutObject API and can help avoid the race conditions related to it.
#[prost(int64, optional, tag = "3")]
pub global_version: ::core::option::Option<i64>,
}
/// When HttpStatusCode is not ok (200), the response `content` contains a serialized ErrorResponse
/// with the relevant ErrorCode and message
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ErrorResponse {
/// The error code uniquely identifying an error condition.
/// It is meant to be read and understood programmatically by code that detects/handles errors by
/// type.
#[prost(enumeration = "ErrorCode", tag = "1")]
pub error_code: i32,
/// The error message containing a generic description of the error condition in English.
/// It is intended for a human audience only and should not be parsed to extract any information
/// programmatically. Client-side code may use it for logging only.
#[prost(string, tag = "2")]
pub message: ::prost::alloc::string::String,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct KeyValue {
/// Key against which the value is stored.
#[prost(string, tag = "1")]
pub key: ::prost::alloc::string::String,
/// Version field is used for key-level versioning.
/// For first write of key, version should be '0'. If the write succeeds, clients must increment
/// their corresponding key version (client-side) by 1.
/// The server increments key version (server-side) for every successful write, hence this
/// client-side increment is required to ensure matching versions. These updated key versions should
/// be used in subsequent PutObjectRequests for the keys.
#[prost(int64, tag = "2")]
pub version: i64,
/// Object value in bytes which is stored (in put) and fetched (in get).
/// Clients must encrypt this blob client-side before sending it over the wire to server in order
/// to preserve privacy and security.
#[prost(bytes = "vec", tag = "3")]
pub value: ::prost::alloc::vec::Vec<u8>,
}
/// ErrorCodes to be used in ErrorResponse
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum ErrorCode {
/// Default protobuf Enum value. Will not be used as ErrorCode by server.
Unknown = 0,
/// CONFLICT_EXCEPTION is used when the request contains mismatched version (either key or global)
/// in PutObjectRequest. For more info refer PutObjectRequest.
ConflictException = 1,
/// INVALID_REQUEST_EXCEPTION is used in the following cases:
/// - The request was missing a required argument.
/// - The specified argument was invalid, incomplete or in the wrong format.
/// - The request body of api cannot be deserialized into corresponding protobuf object.
InvalidRequestException = 2,
/// An internal server error occurred, client is probably at no fault and can safely retry this
/// error with exponential backoff.
InternalServerException = 3,
}
impl ErrorCode {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
ErrorCode::Unknown => "UNKNOWN",
ErrorCode::ConflictException => "CONFLICT_EXCEPTION",
ErrorCode::InvalidRequestException => "INVALID_REQUEST_EXCEPTION",
ErrorCode::InternalServerException => "INTERNAL_SERVER_EXCEPTION",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"UNKNOWN" => Some(Self::Unknown),
"CONFLICT_EXCEPTION" => Some(Self::ConflictException),
"INVALID_REQUEST_EXCEPTION" => Some(Self::InvalidRequestException),
"INTERNAL_SERVER_EXCEPTION" => Some(Self::InternalServerException),
_ => None,
}
}
}
2 changes: 2 additions & 0 deletions vss-accessor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(rustdoc::private_intra_doc_links)]