From 1c40e28761a5af9e750d07359354e4b872e5a798 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 21 Sep 2021 15:39:09 +0000 Subject: [PATCH] Rust Flow SDK Milestone 1 --- .../fee1-dead/20210919-milestone-1.md | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 submissions/issue-20/milestone-1/fee1-dead/20210919-milestone-1.md diff --git a/submissions/issue-20/milestone-1/fee1-dead/20210919-milestone-1.md b/submissions/issue-20/milestone-1/fee1-dead/20210919-milestone-1.md new file mode 100644 index 00000000..c4b97f52 --- /dev/null +++ b/submissions/issue-20/milestone-1/fee1-dead/20210919-milestone-1.md @@ -0,0 +1,119 @@ +# Design of `flow-sdk`, a Rust Flow SDK + +## gRPC + +The `prost` crate is used to generate rust code from protobuf source files. + +A trait named `GrpcClient` is used to generalize gRPC implementations. +This makes the crate easier to test. + +```rust +trait GrpcClient { + type Output; + fn send(self, input: I) -> Self::Output; +} +``` + +The two generic parameters, `I` and `O` denote the request and the response object +types. For example, a `GrpcClient` capable of handling `Ping` requests will +implement the trait `GrpcClient`. + +The return type of `send` is not the same as `O`, because it could be returning a +`Future` and/or a `Result`. We still expect `Self::Output` to be related to `O` in +some way. + +To make it simpler to implement, there is a trait called `FlowRequest` that is +implemented for every request type for the Flow Access API. +([src](https://github.com/fee1-dead/flow.rs/blob/master/src/requests.rs)) +Note that this depends on the fact that there are no requests with the same input +type and output type (only differs in the request name). This design would need to +be reconsidered when it turns out otherwise. + +Then, the crate defines a wrapper type `FlowClient` which provides helper functions +for `GrpcClient` implementations. A helper functions can be written as: + +```rust +impl FlowClient { + pub fn fn_name<'a>(&'a mut self, args..) -> Inner::Output + where &'a mut Inner: GrpcClient + { + self.send(/* Request Construct */) + } +} +``` + +With the help of a macro, it becomes very simple to add new functions: +([src](https://github.com/fee1-dead/flow.rs/blob/82510b45d3b14b179192a5d2bccec87c932d7819/src/client.rs#L67-L77)) + +```rust +define_reqs! { + /// Shortcut for `self.send(PingRequest {})`. + pub fn ping() PingRequest => PingResponse { + PingRequest {} + } + + /// Returns information of the latest block. + pub fn latest_block_header(is_sealed: bool) + GetLatestBlockHeaderRequest => BlockHeaderResponse + { + GetLatestBlockHeaderRequest { is_sealed } + } +} +``` + +A `FlowClient` instance can be easily created, via the `tonic` and `hyper` crate: + +```rust +pub type TonicFlowClient = FlowClient>; +pub type TonicHyperFlowClient = TonicFlowClient; + +impl TonicHyperFlowClient { + pub fn mainnet() -> Result { + Ok(Self { + inner: Grpc::new( + Channel::from_static("http://access.mainnet.nodes.onflow.org:9000").connect_lazy()?, + ), + }) + } +} +``` + +## User Stories + +Most user stories can be implemented with associated functions for `FlowClient`s. +i.e. a function that the user can call through the Access API. + +Some will require parsing JSON-Cadence Data. (such as "submit a script and parse +the response") I plan to do this with `serde-json` or a crate providing similar +functionality (probably split to a new crate that parses JSON-Cadence) + +Some will require signing, which will use the `k256` crate or another better crate +with the same functionality. + +Blocks: +- retrieve a block by ID - Access API +- retrieve a block by height - Access API +- retrieve the latest block - Access API + +Collections: +- retrieve a collection by ID - Access API + +Events: +- retrieve events by name in the block height range - Access API + +Scripts: +- submit a script and parse the response - Needs parsing +- submit a script with arguments and parse the response - Needs parsing + +Accounts: +- retrieve an account by address - Access API +- create a new account - A transaction with provided cadence template +- deploy a new contract to the account - A transaction with provided cadence template +- remove a contract from the account - A transaction with provided cadence template +- update an existing contract on the account - A transaction with provided cadence template + +Transactions: +- retrieve a transaction by ID - Access API - Arguments of the transaction will eventually be parsed or used as plain text only +- sign a transaction (single payer, proposer, authorizer or combination of multiple) - Requires Cryptography +- submit a signed transaction - Requires Cryptography and Access API +- sign a transaction with arguments and submit it - Requires Cryptography and Access API - Arguments need to be serialized as Cadence-JSON \ No newline at end of file