From 1d8911de346806fd81ab2a0a43af69fc8026bb28 Mon Sep 17 00:00:00 2001 From: Marshall Belles Date: Fri, 24 Sep 2021 11:09:37 -0400 Subject: [PATCH 1/5] Submitting milestones 1,2,3 for the Flow-Rust-SDK --- .../issue-20/milestone-1/flow-rust-sdk-team | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 submissions/issue-20/milestone-1/flow-rust-sdk-team diff --git a/submissions/issue-20/milestone-1/flow-rust-sdk-team b/submissions/issue-20/milestone-1/flow-rust-sdk-team new file mode 100644 index 00000000..875ccb7d --- /dev/null +++ b/submissions/issue-20/milestone-1/flow-rust-sdk-team @@ -0,0 +1,65 @@ +## Flow-Rust-SDK - Milestone 1 + +This PR is for issue #20. + +### Current Status +The Flow-Rust-SDK is feature complete, meaning that as a user you can accomplish any task you need to do. +There is still a good amount of work to be done on the documentation of how to accomplish common tasks. +All user tasks are abstracted away from the gRPC API layer, meaning that (for most things) you don't have +to deal with complex RLP encoding yourself. + +- [Version 1.0.x released on Crates.io](https://crates.io/crates/flow-rust-sdk). +- [Documentation on SDK utilization is under way](https://docs.rs/flow-rust-sdk/latest/flow_rust_sdk) + + +Blocks: + +- [x] retrieve a block by ID +- [x] retrieve a block by height +- [x] retrieve the latest block + + +Collections: + +- [x] retrieve a collection by ID + + +Events: + +- [x] retrieve events by name in the block height range + + +Scripts: + +- [x] submit a script and parse the response +- [x] submit a script with arguments and parse the response + + +Accounts: + +- [x] retrieve an account by address +- [x] create a new account +- [x] deploy a new contract to the account +- [x] remove a contract from the account +- [x] update an existing contract on the account + + +Transactions: + +- [x] retrieve a transaction by ID +- [x] sign a transaction (single payer, proposer, authorizer or combination of multiple) +- [x] submit a signed transaction +- [x] sign a transaction with arguments and submit it + + + +### Milestones +- 1 [x] Implement the gRPC layer of the SDK, allowing communication with the Flow blockchain +- 2 [x] Accomplish transaction signing in a way that handles the complex algorithm / hashing / encoding for the user. +- 3 [x] Meet and exceed Flow SDK guidelines +- 4 [ ] Complete documentation and common usage examples are available + +Authors include: + + @marshallbelles + @bluesign From b9443dc64cd532b4b59e68ae5279a374888ff646 Mon Sep 17 00:00:00 2001 From: Marshall Belles Date: Fri, 24 Sep 2021 11:12:45 -0400 Subject: [PATCH 2/5] updating milestone --- .../issue-20/{milestone-1 => milestone-3}/flow-rust-sdk-team | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename submissions/issue-20/{milestone-1 => milestone-3}/flow-rust-sdk-team (100%) diff --git a/submissions/issue-20/milestone-1/flow-rust-sdk-team b/submissions/issue-20/milestone-3/flow-rust-sdk-team similarity index 100% rename from submissions/issue-20/milestone-1/flow-rust-sdk-team rename to submissions/issue-20/milestone-3/flow-rust-sdk-team From 5709a797849fe3535e34011f7aeab2891c8f6c2a Mon Sep 17 00:00:00 2001 From: Marshall Belles Date: Fri, 24 Sep 2021 11:13:26 -0400 Subject: [PATCH 3/5] updating milestone sh-add ~/Marshall-DEV.pem >/dev/null 2>&1 --- submissions/issue-20/milestone-3/flow-rust-sdk-team | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submissions/issue-20/milestone-3/flow-rust-sdk-team b/submissions/issue-20/milestone-3/flow-rust-sdk-team index 875ccb7d..ae4ccbf4 100644 --- a/submissions/issue-20/milestone-3/flow-rust-sdk-team +++ b/submissions/issue-20/milestone-3/flow-rust-sdk-team @@ -1,4 +1,4 @@ -## Flow-Rust-SDK - Milestone 1 +## Flow-Rust-SDK - Milestone 1, 2, 3 This PR is for issue #20. From 2dc20cf6599624a59091c34b60ab15ebcf7179d3 Mon Sep 17 00:00:00 2001 From: Marshall Belles Date: Sun, 17 Oct 2021 18:14:33 -0400 Subject: [PATCH 4/5] setting up all milestones --- .../milestone-1/flow-rust-sdk-team.md | 43 +++++ .../milestone-2/flow-rust-sdk-team.md | 159 ++++++++++++++++++ .../issue-20/milestone-3/flow-rust-sdk-team | 65 ------- .../milestone-3/flow-rust-sdk-team.md | 44 +++++ .../milestone-4/flow-rust-sdk-team.md | 14 ++ 5 files changed, 260 insertions(+), 65 deletions(-) create mode 100644 submissions/issue-20/milestone-1/flow-rust-sdk-team.md create mode 100644 submissions/issue-20/milestone-2/flow-rust-sdk-team.md delete mode 100644 submissions/issue-20/milestone-3/flow-rust-sdk-team create mode 100644 submissions/issue-20/milestone-3/flow-rust-sdk-team.md create mode 100644 submissions/issue-20/milestone-4/flow-rust-sdk-team.md diff --git a/submissions/issue-20/milestone-1/flow-rust-sdk-team.md b/submissions/issue-20/milestone-1/flow-rust-sdk-team.md new file mode 100644 index 00000000..87914abf --- /dev/null +++ b/submissions/issue-20/milestone-1/flow-rust-sdk-team.md @@ -0,0 +1,43 @@ +## Flow-Rust-SDK - Milestone 1 + +This PR is for issue #20. + + +### Milestone 1 Completion: +- 1 [x] Implement the gRPC layer of the SDK, allowing communication with the Flow blockchain + +Inside the [lib.rs](https://github.com/MarshallBelles/flow-rust-sdk/blob/release/src/lib.rs) a gRPC client has been defined as a struct on line 38: `FlowConnection` which accepts a network transport layer of type ``. A default implementation for type `tonic::transport::Channel` is implemented starting on line 43, using the [Tonic gRPC library](https://crates.io/crates/tonic) to facilitate communications. + +You can test this connection by instantiating the struct with the helper function `FlowConnection::new("grpc://address");`. + +A more full example of usage: +```rs +use flow_rust_sdk::*; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // instantiate a new connection: + let mut connection = FlowConnection::new("grpc://localhost:3569").await?; + // Substitute emulator service account address as the payer, and keys if needed. + let payer = "f8d6e0586b0a20c7"; + let payer_private_key = "324db577a741a9b7a2eb6cef4e37e72ff01a554bdbe4bd77ef9afe1cb00d3cec"; + let public_keys = vec!["ef100c2a8d04de602cd59897e08001cf57ca153cb6f9083918cde1ec7de77418a2c236f7899b3f786d08a1b4592735e3a7461c3e933f420cf9babe350abe0c5a".to_owned()]; + + // Use the connection defined above to send a transaction to the blockchain, created and signed within the helper function `create_account` + let acct = connection.create_account( + public_keys.to_vec(), + &payer.to_owned(), + &payer_private_key.to_owned(), + 0, + ) + .await + .expect("Could not create account"); + println!("new account address: {:?}", hex::encode(acct.address)); + Ok(()) +} +``` + +Authors include: + + @marshallbelles + @bluesign diff --git a/submissions/issue-20/milestone-2/flow-rust-sdk-team.md b/submissions/issue-20/milestone-2/flow-rust-sdk-team.md new file mode 100644 index 00000000..8c265893 --- /dev/null +++ b/submissions/issue-20/milestone-2/flow-rust-sdk-team.md @@ -0,0 +1,159 @@ +## Flow-Rust-SDK - Milestone 2 + +This PR is for issue #20. + + +### Milestone 2 Completion: +- 2: Accomplish transaction signing in a way that handles the complex algorithm / hashing / encoding for the user. + +Transactional signing and RLP encoding turned out to be the most difficult and time-consuming task of this project. +@bluesign provided a significant amount of help by sharing knowledge gained while working on his Swift SDK. + +Transaction signing is implemented in the Flow-Rust-SDK lib.rs [starting on line 466](https://github.com/MarshallBelles/flow-rust-sdk/blob/344d7d8f7aa2aa67c47455e54bedf4723138a981/src/lib.rs#L466). + +The transaction payload RLP encoding takes place [on line 414](https://github.com/MarshallBelles/flow-rust-sdk/blob/344d7d8f7aa2aa67c47455e54bedf4723138a981/src/lib.rs#L414) and the transaction envelope is encoded [on line 370](https://github.com/MarshallBelles/flow-rust-sdk/blob/344d7d8f7aa2aa67c47455e54bedf4723138a981/src/lib.rs#L370). + + +Before signing a transaction, you must first define and build one. This is demonstrated in the `create_account` function starting [on line 176](https://github.com/MarshallBelles/flow-rust-sdk/blob/344d7d8f7aa2aa67c47455e54bedf4723138a981/src/lib.rs#L176): +```rs +// The following is copied from the library. +// To execute the code shown below, copy the example at: https://github.com/MarshallBelles/flow-rust-sdk-example/blob/main/src/main.rs +// our default values passed into the transaction +let payer = "f8d6e0586b0a20c7"; +let payer_private_key = "324db577a741a9b7a2eb6cef4e37e72ff01a554bdbe4bd77ef9afe1cb00d3cec"; +let public_keys = vec!["ef100c2a8d04de602cd59897e08001cf57ca153cb6f9083918cde1ec7de77418a2c236f7899b3f786d08a1b4592735e3a7461c3e933f420cf9babe350abe0c5a".to_owned()]; + +// Define the transaction to be executed. +// Here we are using AuthAccount to create a new account and assign keys +let create_account_template = b" + transaction(publicKeys: [String], contracts: {String: String}) { + prepare(signer: AuthAccount) { + let acct = AuthAccount(payer: signer) + + for key in publicKeys { + acct.addPublicKey(key.decodeHex()) + } + + for contract in contracts.keys { + acct.contracts.add(name: contract, code: contracts[contract]!.decodeHex()) + } + } + }"; + +// we get the latest block for the transaction +let latest_block: BlockResponse = self.get_block(None, None, Some(false)).await?; +// and then we need to get the authorizer account +let account: flow::Account = self.get_account(payer.clone()) + .await? + .account + .unwrap(); +// because then we need the proposal key details +let proposer = TransactionProposalKey { + address: hex::decode(payer).unwrap(), + key_id, + sequence_number: account.keys[key_id as usize].sequence_number as u64, +}; +// here we process the key arguments +let keys_arg = process_keys_args(account_keys); +// empty contracts for this example +let contracts_arg = Argument::dictionary(vec![]); +// the following two lines handles the arguments and turns them into JSON strings for the transaction. +let keys_arg = json!(keys_arg); +let contracts_arg = json!(contracts_arg); +// build the transaction +let transaction: Transaction = build_transaction( + create_account_template.to_vec(), + vec![ + serde_json::to_vec(&keys_arg)?, + serde_json::to_vec(&contracts_arg)?, + ], + latest_block.block.unwrap().id, + 1000, + proposer, + vec![payer.clone()], + payer.clone(), +) +.await?; + +// After building the transaction, we need to sign the transaction. +// Here we define the signature +let signature = Sign { + address: payer.clone(), + key_id, + private_key: payer_private_key.clone(), +}; + +// now we can sign the transaction +let transaction: Option = sign_transaction(transaction, vec![], vec![&signature]).await?; + +// and send it to the blockchain +let transaction: SendTransactionResponse = self.send_transaction(transaction).await?; + +// from here the library polls the blockchain for the transaction result +``` + +The part above where we `sign_transaction` looks like this: +```rs +pub async fn sign_transaction( + built_transaction: Transaction, + payload_signatures: Vec<&Sign>, + envelope_signatures: Vec<&Sign>, +) -> Result, Box> { + let mut payload: Vec = vec![]; + let mut envelope: Vec = vec![]; + // for each of the payload private keys, sign the transaction + for signer in payload_signatures { + let encoded_payload: &[u8] = &payload_from_transaction(built_transaction.clone()); + let mut domain_tag: Vec = b"FLOW-V0.0-transaction".to_vec(); + // we need to pad 0s at the end of the domain_tag + padding(&mut domain_tag, 32); + + let fully_encoded: Vec = [&domain_tag, encoded_payload].concat(); + let mut addr = hex::decode(signer.address.clone()).unwrap(); + padding(&mut addr, 8); + + payload.push(TransactionSignature { + address: addr, + key_id: signer.key_id, + signature: sign(fully_encoded, signer.private_key.clone())?, + }); + } + // for each of the envelope private keys, sign the transaction + for signer in envelope_signatures { + let encoded_payload: &[u8] = + &envelope_from_transaction(built_transaction.clone(), &payload); + let mut domain_tag: Vec = b"FLOW-V0.0-transaction".to_vec(); + // we need to pad 0s at the end of the domain_tag + padding(&mut domain_tag, 32); + + let fully_encoded: Vec = [&domain_tag, encoded_payload].concat(); + let mut addr = hex::decode(signer.address.clone()).unwrap(); + padding(&mut addr, 8); + + envelope.push(TransactionSignature { + address: addr, + key_id: signer.key_id, + signature: sign(fully_encoded, signer.private_key.clone())?, + }); + } + let signed_transaction = Some(Transaction { + script: built_transaction.script, + arguments: built_transaction.arguments, + reference_block_id: built_transaction.reference_block_id, + gas_limit: built_transaction.gas_limit, + proposal_key: built_transaction.proposal_key, + authorizers: built_transaction.authorizers, + payload_signatures: payload, + envelope_signatures: envelope, + payer: built_transaction.payer, + }); + Ok(signed_transaction) +} +``` + +You can see in the snippet above that both payload and envelope signatures are handled for the user in a manner that reduces the complexity and does not require an advanced understanding of RLP encoding. + +Authors include: + + @marshallbelles + @bluesign diff --git a/submissions/issue-20/milestone-3/flow-rust-sdk-team b/submissions/issue-20/milestone-3/flow-rust-sdk-team deleted file mode 100644 index ae4ccbf4..00000000 --- a/submissions/issue-20/milestone-3/flow-rust-sdk-team +++ /dev/null @@ -1,65 +0,0 @@ -## Flow-Rust-SDK - Milestone 1, 2, 3 - -This PR is for issue #20. - -### Current Status -The Flow-Rust-SDK is feature complete, meaning that as a user you can accomplish any task you need to do. -There is still a good amount of work to be done on the documentation of how to accomplish common tasks. -All user tasks are abstracted away from the gRPC API layer, meaning that (for most things) you don't have -to deal with complex RLP encoding yourself. - -- [Version 1.0.x released on Crates.io](https://crates.io/crates/flow-rust-sdk). -- [Documentation on SDK utilization is under way](https://docs.rs/flow-rust-sdk/latest/flow_rust_sdk) - - -Blocks: - -- [x] retrieve a block by ID -- [x] retrieve a block by height -- [x] retrieve the latest block - - -Collections: - -- [x] retrieve a collection by ID - - -Events: - -- [x] retrieve events by name in the block height range - - -Scripts: - -- [x] submit a script and parse the response -- [x] submit a script with arguments and parse the response - - -Accounts: - -- [x] retrieve an account by address -- [x] create a new account -- [x] deploy a new contract to the account -- [x] remove a contract from the account -- [x] update an existing contract on the account - - -Transactions: - -- [x] retrieve a transaction by ID -- [x] sign a transaction (single payer, proposer, authorizer or combination of multiple) -- [x] submit a signed transaction -- [x] sign a transaction with arguments and submit it - - - -### Milestones -- 1 [x] Implement the gRPC layer of the SDK, allowing communication with the Flow blockchain -- 2 [x] Accomplish transaction signing in a way that handles the complex algorithm / hashing / encoding for the user. -- 3 [x] Meet and exceed Flow SDK guidelines -- 4 [ ] Complete documentation and common usage examples are available - -Authors include: - - @marshallbelles - @bluesign diff --git a/submissions/issue-20/milestone-3/flow-rust-sdk-team.md b/submissions/issue-20/milestone-3/flow-rust-sdk-team.md new file mode 100644 index 00000000..1d7fa4b2 --- /dev/null +++ b/submissions/issue-20/milestone-3/flow-rust-sdk-team.md @@ -0,0 +1,44 @@ +## Flow-Rust-SDK - Milestone 3 + +This PR is for issue #20. + + +### Milestone 3 Completion: +- 3 [x] Meet and exceed Flow SDK guidelines + +The Flow SDK Guidelines are defined [here](https://github.com/onflow/sdks). + +Each of the provided stories have examples: + +Blocks: +- [Retrieve a block by ID](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Retrieve-a-block-by-ID) +- [Retrieve a block by height](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Retrieve-a-block-by-height) +- [Retrieve the latest block](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Retrieve-the-latest-block) + +Collections: +- [Retrieve a collection by ID](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Retrieve-a-collection-by-ID) + +Events: +- [Retrieve events by name in the block height range](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Retrieve-events-by-name-in-the-block-height-range) + +Scripts: +- [Submit a script and parse the response](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Submit-a-script-and-parse-the-response) +- [Submit a script with arguments and parse the response](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Submit-a-script-with-arguments-and-parse-the-response) + +Accounts: +- [Retrieve an account by address](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Retrieve-an-account-by-address) +- [Create a new account](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Create-a-new-account) +- [Deploy a new contract to the account](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Deploy-a-new-contract-to-the-account) +- [Remove a contract from the account](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Remove-a-contract-from-the-account) +- [Update an existing contract on the account](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Update-an-existing-contract-on-the-account) + +Transactions: +- [Retrieve a transaction by ID](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Transactions) +- [Sign a transaction (single payer, proposer, authorizer or combination of multiple)](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Transactions) +- [Submit a signed transaction](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Transactions) +- [Sign a transaction with arguments and submit it](https://github.com/MarshallBelles/flow-rust-sdk/wiki/Transactions) + +Authors include: + + @marshallbelles + @bluesign diff --git a/submissions/issue-20/milestone-4/flow-rust-sdk-team.md b/submissions/issue-20/milestone-4/flow-rust-sdk-team.md new file mode 100644 index 00000000..0de92103 --- /dev/null +++ b/submissions/issue-20/milestone-4/flow-rust-sdk-team.md @@ -0,0 +1,14 @@ +## Flow-Rust-SDK - Milestone 4 [WIP] + +This PR is for issue #20. + + +### Milestone 4 Completion: +- 4 [ ] Complete documentation and common usage examples are available + +This is a WIP. + +Authors include: + + @marshallbelles + @bluesign From 97bd17437098983deee9fa5b8b599ad025f4276e Mon Sep 17 00:00:00 2001 From: Marshall Belles Date: Sun, 17 Oct 2021 18:16:00 -0400 Subject: [PATCH 5/5] Milestone 1 --- submissions/issue-20/milestone-1/flow-rust-sdk-team.md | 1 + 1 file changed, 1 insertion(+) diff --git a/submissions/issue-20/milestone-1/flow-rust-sdk-team.md b/submissions/issue-20/milestone-1/flow-rust-sdk-team.md index 87914abf..88e69ff8 100644 --- a/submissions/issue-20/milestone-1/flow-rust-sdk-team.md +++ b/submissions/issue-20/milestone-1/flow-rust-sdk-team.md @@ -3,6 +3,7 @@ This PR is for issue #20. + ### Milestone 1 Completion: - 1 [x] Implement the gRPC layer of the SDK, allowing communication with the Flow blockchain