From db4d278b409f644a69c6ee72762ad2ac52589809 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Thu, 10 Feb 2022 20:39:10 +1100 Subject: [PATCH 01/10] Extract `hello_world` example from the book into a standalone project Related to #544. Follows the example set in #731. Tested with `mdbook serve`. Also adds the `hello_world` and `subcurrency` examples to the Sway workspace so that we can test both projects under CI. --- Cargo.toml | 7 +- docs/src/getting-started/forc_project.md | 90 +++-------------------- examples/hello_world/Cargo.toml | 20 +++++ examples/hello_world/Forc.toml | 9 +++ examples/hello_world/my-contract-abi.json | 1 + examples/hello_world/src/main.sw | 25 +++++++ examples/hello_world/tests/harness.rs | 43 +++++++++++ examples/subcurrency/tests/harness.rs | 1 - 8 files changed, 116 insertions(+), 80 deletions(-) create mode 100644 examples/hello_world/Cargo.toml create mode 100644 examples/hello_world/Forc.toml create mode 100644 examples/hello_world/my-contract-abi.json create mode 100644 examples/hello_world/src/main.sw create mode 100644 examples/hello_world/tests/harness.rs diff --git a/Cargo.toml b/Cargo.toml index b301ce8b3de..11939e84b9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,12 @@ members = [ "sway-types", "sway-utils", "test", - "test-sig-gen-util" + "test-sig-gen-util", + + # These are standalone forc example projects, but because running `forc + # test` calls `cargo test` within this workspace, we must add them here. + "examples/hello_world", + "examples/subcurrency", ] [profile.dev.package.sway-server] diff --git a/docs/src/getting-started/forc_project.md b/docs/src/getting-started/forc_project.md index 128347a6bdc..a54131a679f 100644 --- a/docs/src/getting-started/forc_project.md +++ b/docs/src/getting-started/forc_project.md @@ -22,15 +22,7 @@ $ tree . `Forc.toml` is the _manifest file_ (similar to `Cargo.toml` for Cargo or `package.json` for Node), and defines project metadata such as the project name and dependencies. ```toml -[project] -name = "hello_world" -author = "user" -entry = "main.sw" -license = "Apache-2.0" - -[dependencies] -core = { git = "http://github.com/FuelLabs/sway-lib-core", version = "v0.0.1" } -std = { git = "http://github.com/FuelLabs/sway-lib-std", version = "v0.0.1" } +{{#include ../../../examples/hello_world/Forc.toml}} ``` Here are the contents of the only Sway file in the project, and the main entry point, `src/main.sw`: @@ -39,7 +31,7 @@ Here are the contents of the only Sway file in the project, and the main entry p script; fn main() { - + } ``` @@ -71,7 +63,14 @@ Bytecode size is 28 bytes. [Return { id: ContractId([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), val: 0, pc: 488, is: 464 }] ``` -Use `forc json-abi` to output the ABI of the contract. To write this to a `.json` file (which is necessary for running tests below), pipe it using something like `forc json-abi > my_contract.json`. There is currently not a convention for where ABI files should be placed; one common choice is loose in the root directory. +Use `forc json-abi` to output the ABI of the contract. To write this to a `.json` file (which is necessary for running tests below), pipe it using something like: + +```console +forc json-abi > my-contract-abi.json +``` + +There is currently not a convention for where ABI files should be placed; one +common choice is loose in the root directory. ## Testing a Sway Project with Forc @@ -96,78 +95,13 @@ These tests can be run using either `cargo test`, or `forc test` which will look For example, let's write tests against the following contract, written in Sway. This can be done in the pregenerated `src/main.sw` or in a new file in `src`. In the case of the latter, update the `entry` field in `Forc.toml` to point at the new contract. ```sway -contract; - -use std::storage::*; -use std::constants::*; - -abi TestContract { - fn initialize_counter(gas_: u64, amount_: u64, coin_: b256, value: u64) -> u64; - fn increment_counter(gas_: u64, amount_: u64, coin_: b256, amount: u64) -> u64; -} - -const SLOT = 0x0000000000000000000000000000000000000000000000000000000000000000; - -impl TestContract for Contract { - fn initialize_counter(gas_: u64, amount_: u64, color_: b256, value: u64) -> u64 { - store(SLOT, value); - value - } - - fn increment_counter(gas_: u64, amount_: u64, color_: b256, amount: u64) -> u64 { - let storedVal: u64 = get(SLOT); - let value = storedVal + amount; - store(SLOT, value); - value - } -} +{{#include ../../../examples/hello_world/src/main.sw}} ``` Our `tests/harness.rs` file could look like: ```rust -use fuel_tx::Salt; -use fuels_abigen_macro::abigen; -use fuels_contract::contract::Contract; -use rand::rngs::StdRng; -use rand::{Rng, SeedableRng}; - -// Generate Rust bindings from our contract JSON ABI -abigen!(MyContract, "./my-contract-abi.json"); - -#[tokio::test] -async fn harness() { - let rng = &mut StdRng::seed_from_u64(2322u64); - - // Build the contract - let salt: [u8; 32] = rng.gen(); - let salt = Salt::from(salt); - let compiled = Contract::compile_sway_contract("./", salt).unwrap(); - - // Launch a local network and deploy the contract - let (client, contract_id) = Contract::launch_and_deploy(&compiled).await.unwrap(); - - let contract_instance = MyContract::new(compiled, client); - - // Call `initialize_counter()` method in our deployed contract. - // Note that, here, you get type-safety for free! - let result = contract_instance - .initialize_counter(42) - .call() - .await - .unwrap(); - - assert_eq!(42, result); - - // Call `increment_counter()` method in our deployed contract. - let result = contract_instance - .increment_counter(10) - .call() - .await - .unwrap(); - - assert_eq!(52, result); -} +{{#include ../../../examples/hello_world/tests/harness.rs}} ``` Then, in the root of our project, running `forc test` or `cargo test` will run the test above, compiling and deploying the contract to a local Fuel network, and calling the ABI methods against the contract deployed in there: diff --git a/examples/hello_world/Cargo.toml b/examples/hello_world/Cargo.toml new file mode 100644 index 00000000000..034cff7fe3e --- /dev/null +++ b/examples/hello_world/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["mindtree"] +edition = "2021" +license = "Apache-2.0" +name = "hello_world" +version = "0.1.0" + +[dependencies] +fuel-gql-client = { version = "0.2", default-features = false } +fuel-tx = "0.3" +fuels-abigen-macro = "0.3" +fuels-contract = "0.3" +fuels-core = "0.3" +rand = "0.8" +tokio = { version = "1.12", features = ["rt", "macros"] } + +[[test]] +harness = true +name = "integration_tests" +path = "tests/harness.rs" diff --git a/examples/hello_world/Forc.toml b/examples/hello_world/Forc.toml new file mode 100644 index 00000000000..bde7e581f15 --- /dev/null +++ b/examples/hello_world/Forc.toml @@ -0,0 +1,9 @@ +[project] +author = "mindtree" +entry = "main.sw" +license = "Apache-2.0" +name = "examples/hello_world" + +[dependencies] +core = { git = "http://github.com/FuelLabs/sway-lib-core" } +std = { git = "http://github.com/FuelLabs/sway-lib-std" } diff --git a/examples/hello_world/my-contract-abi.json b/examples/hello_world/my-contract-abi.json new file mode 100644 index 00000000000..849d69e8308 --- /dev/null +++ b/examples/hello_world/my-contract-abi.json @@ -0,0 +1 @@ +[{"inputs":[{"components":null,"name":"gas_","type":"u64"},{"components":null,"name":"amount_","type":"u64"},{"components":null,"name":"color_","type":"b256"},{"components":null,"name":"value","type":"u64"}],"name":"initialize_counter","outputs":[{"components":null,"name":"","type":"u64"}],"type":"function"},{"inputs":[{"components":null,"name":"gas_","type":"u64"},{"components":null,"name":"amount_","type":"u64"},{"components":null,"name":"color_","type":"b256"},{"components":null,"name":"amount","type":"u64"}],"name":"increment_counter","outputs":[{"components":null,"name":"","type":"u64"}],"type":"function"}] diff --git a/examples/hello_world/src/main.sw b/examples/hello_world/src/main.sw new file mode 100644 index 00000000000..584c3901176 --- /dev/null +++ b/examples/hello_world/src/main.sw @@ -0,0 +1,25 @@ +contract; + +use std::storage::*; +use std::constants::*; + +abi TestContract { + fn initialize_counter(gas_: u64, amount_: u64, coin_: b256, value: u64) -> u64; + fn increment_counter(gas_: u64, amount_: u64, coin_: b256, amount: u64) -> u64; +} + +const SLOT = 0x0000000000000000000000000000000000000000000000000000000000000000; + +impl TestContract for Contract { + fn initialize_counter(gas_: u64, amount_: u64, color_: b256, value: u64) -> u64 { + store(SLOT, value); + value + } + + fn increment_counter(gas_: u64, amount_: u64, color_: b256, amount: u64) -> u64 { + let storedVal: u64 = get(SLOT); + let value = storedVal + amount; + store(SLOT, value); + value + } +} diff --git a/examples/hello_world/tests/harness.rs b/examples/hello_world/tests/harness.rs new file mode 100644 index 00000000000..2a602221f3c --- /dev/null +++ b/examples/hello_world/tests/harness.rs @@ -0,0 +1,43 @@ +use fuel_tx::Salt; +use fuels_abigen_macro::abigen; +use fuels_contract::contract::Contract; +use rand::rngs::StdRng; +use rand::{Rng, SeedableRng}; + +// Generate Rust bindings from our contract JSON ABI +// FIXME: Incorrect path, see https://github.com/FuelLabs/fuels-rs/issues/94 +abigen!(MyContract, "./examples/hello_world/my-contract-abi.json"); + +#[tokio::test] +async fn harness() { + let rng = &mut StdRng::seed_from_u64(2322u64); + + // Build the contract + let salt: [u8; 32] = rng.gen(); + let salt = Salt::from(salt); + let compiled = Contract::compile_sway_contract("./", salt).unwrap(); + + // Launch a local network and deploy the contract + let (client, _contract_id) = Contract::launch_and_deploy(&compiled).await.unwrap(); + + let contract_instance = MyContract::new(compiled, client); + + // Call `initialize_counter()` method in our deployed contract. + // Note that, here, you get type-safety for free! + let result = contract_instance + .initialize_counter(42) + .call() + .await + .unwrap(); + + assert_eq!(42, result.value); + + // Call `increment_counter()` method in our deployed contract. + let result = contract_instance + .increment_counter(10) + .call() + .await + .unwrap(); + + assert_eq!(52, result.value); +} diff --git a/examples/subcurrency/tests/harness.rs b/examples/subcurrency/tests/harness.rs index a6167187ee0..bba801d2e8f 100644 --- a/examples/subcurrency/tests/harness.rs +++ b/examples/subcurrency/tests/harness.rs @@ -1,4 +1,3 @@ - #[tokio::test] async fn harness() { assert_eq!(true, true); From 9c4506d7a4a4a15fd2a6a0dffb1d42b365a6bb40 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 11 Feb 2022 00:31:40 +1100 Subject: [PATCH 02/10] Fix hello_world example project name in forc manifest --- examples/hello_world/Forc.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hello_world/Forc.toml b/examples/hello_world/Forc.toml index bde7e581f15..68811f91f53 100644 --- a/examples/hello_world/Forc.toml +++ b/examples/hello_world/Forc.toml @@ -2,7 +2,7 @@ author = "mindtree" entry = "main.sw" license = "Apache-2.0" -name = "examples/hello_world" +name = "hello_world" [dependencies] core = { git = "http://github.com/FuelLabs/sway-lib-core" } From 43b45ac3bcdfe4f5d600c8d7e3bd7887b21c119e Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 11 Feb 2022 00:32:01 +1100 Subject: [PATCH 03/10] Move fizzbuzz and wallet_smart_contract examples to standalone projects --- Cargo.toml | 2 + docs/src/examples/fizzbuzz.md | 28 +------------- docs/src/examples/wallet_smart_contract.md | 37 +------------------ examples/fizzbuzz/Cargo.toml | 20 ++++++++++ examples/fizzbuzz/Forc.toml | 9 +++++ examples/fizzbuzz/src/main.sw | 26 +++++++++++++ examples/fizzbuzz/tests/harness.rs | 4 ++ examples/wallet_smart_contract/Cargo.toml | 20 ++++++++++ examples/wallet_smart_contract/Forc.toml | 9 +++++ examples/wallet_smart_contract/src/main.sw | 36 ++++++++++++++++++ .../wallet_smart_contract/tests/harness.rs | 4 ++ 11 files changed, 132 insertions(+), 63 deletions(-) create mode 100644 examples/fizzbuzz/Cargo.toml create mode 100644 examples/fizzbuzz/Forc.toml create mode 100644 examples/fizzbuzz/src/main.sw create mode 100644 examples/fizzbuzz/tests/harness.rs create mode 100644 examples/wallet_smart_contract/Cargo.toml create mode 100644 examples/wallet_smart_contract/Forc.toml create mode 100644 examples/wallet_smart_contract/src/main.sw create mode 100644 examples/wallet_smart_contract/tests/harness.rs diff --git a/Cargo.toml b/Cargo.toml index 11939e84b9e..406095ca43c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,10 @@ members = [ # These are standalone forc example projects, but because running `forc # test` calls `cargo test` within this workspace, we must add them here. + "examples/fizzbuzz", "examples/hello_world", "examples/subcurrency", + "examples/wallet_smart_contract", ] [profile.dev.package.sway-server] diff --git a/docs/src/examples/fizzbuzz.md b/docs/src/examples/fizzbuzz.md index a9692d37e84..0c0d3d0afe8 100644 --- a/docs/src/examples/fizzbuzz.md +++ b/docs/src/examples/fizzbuzz.md @@ -5,31 +5,5 @@ and receive back its fizzbuzzability as an enum. Note that the deserialization s so the caller knows what to do with the bytes. ```sway -contract; - -enum FizzBuzzResult { - Fizz: (), - Buzz: (), - FizzBuzz: (), - Other: u64, -} - -abi FizzBuzz { - fn fizzbuzz(gas: u64, coins: u64, asset_id: b256, input: u64) -> FizzBuzzResult; -} - -impl FizzBuzz for Contract { - fn fizzbuzz(gas: u64, coins: u64, asset_id: b256, input: u64) -> FizzBuzzResult { - if input % 15 == 0 { - FizzBuzzResult::FizzBuzz - } else if input % 3 == 0 { - FizzBuzzResult::Fizz - } else if input % 5 == 0 { - FizzBuzzResult::Buzz - } else { - FizzBuzzResult::Other(input) - } - } -} - +{{#include ../../../examples/fizzbuzz/src/main.sw}} ``` diff --git a/docs/src/examples/wallet_smart_contract.md b/docs/src/examples/wallet_smart_contract.md index 04d2f50e9f7..ee8d9610d00 100644 --- a/docs/src/examples/wallet_smart_contract.md +++ b/docs/src/examples/wallet_smart_contract.md @@ -3,40 +3,5 @@ _Contract storage in the language syntax is a work-in-progress feature, and the following example does not currently compile._ ```sway -contract; - -use std::*; - -const OWNER_ADDRESS: b256 = 0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861; -const ETH_ID: b256 = 0x0000000000000000000000000000000000000000000000000000000000000000; - -storage { - balance: u64, -} - -abi Wallet { - fn receive_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, unused: ()); - fn send_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, req: SendFundsRequest); -} - -impl Wallet for Contract { - fn receive_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, unused: ()) { - if asset_id == ETH_ID { - let balance = storage.balance.write(); - deref balance = balance + coins_to_forward; - }; - } - - fn send_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, req: SendFundsRequest) { - assert(sender() == OWNER_ADDRESS); - assert(storage.balance > req.amount_to_send); - storage.balance = storage.balance - req.amount_to_send; - transfer_coins(asset_id, req.recipient_address, req.amount_to_send); - } -} - -struct SendFundsRequest { - amount_to_send: u64, - recipient_address: b256, -} +{{#include ../../../examples/wallet_smart_contract/src/main.sw}} ``` diff --git a/examples/fizzbuzz/Cargo.toml b/examples/fizzbuzz/Cargo.toml new file mode 100644 index 00000000000..f7f938d4463 --- /dev/null +++ b/examples/fizzbuzz/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["mindtree"] +edition = "2021" +license = "Apache-2.0" +name = "fizzbuzz" +version = "0.1.0" + +[dependencies] +fuel-gql-client = { version = "0.2", default-features = false } +fuel-tx = "0.3" +fuels-abigen-macro = "0.3" +fuels-contract = "0.3" +fuels-core = "0.3" +rand = "0.8" +tokio = { version = "1.12", features = ["rt", "macros"] } + +[[test]] +harness = true +name = "integration_tests" +path = "tests/harness.rs" diff --git a/examples/fizzbuzz/Forc.toml b/examples/fizzbuzz/Forc.toml new file mode 100644 index 00000000000..4ae40c1129f --- /dev/null +++ b/examples/fizzbuzz/Forc.toml @@ -0,0 +1,9 @@ +[project] +author = "mindtree" +entry = "main.sw" +license = "Apache-2.0" +name = "fizzbuzz" + +[dependencies] +core = { git = "http://github.com/FuelLabs/sway-lib-core" } +std = { git = "http://github.com/FuelLabs/sway-lib-std" } diff --git a/examples/fizzbuzz/src/main.sw b/examples/fizzbuzz/src/main.sw new file mode 100644 index 00000000000..09a42f81faa --- /dev/null +++ b/examples/fizzbuzz/src/main.sw @@ -0,0 +1,26 @@ +contract; + +enum FizzBuzzResult { + Fizz: (), + Buzz: (), + FizzBuzz: (), + Other: u64, +} + +abi FizzBuzz { + fn fizzbuzz(gas: u64, coins: u64, asset_id: b256, input: u64) -> FizzBuzzResult; +} + +impl FizzBuzz for Contract { + fn fizzbuzz(gas: u64, coins: u64, asset_id: b256, input: u64) -> FizzBuzzResult { + if input % 15 == 0 { + FizzBuzzResult::FizzBuzz + } else if input % 3 == 0 { + FizzBuzzResult::Fizz + } else if input % 5 == 0 { + FizzBuzzResult::Buzz + } else { + FizzBuzzResult::Other(input) + } + } +} diff --git a/examples/fizzbuzz/tests/harness.rs b/examples/fizzbuzz/tests/harness.rs new file mode 100644 index 00000000000..bba801d2e8f --- /dev/null +++ b/examples/fizzbuzz/tests/harness.rs @@ -0,0 +1,4 @@ +#[tokio::test] +async fn harness() { + assert_eq!(true, true); +} diff --git a/examples/wallet_smart_contract/Cargo.toml b/examples/wallet_smart_contract/Cargo.toml new file mode 100644 index 00000000000..c71bfe0ca0a --- /dev/null +++ b/examples/wallet_smart_contract/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["mindtree"] +edition = "2021" +license = "Apache-2.0" +name = "wallet_smart_contract" +version = "0.1.0" + +[dependencies] +fuel-gql-client = { version = "0.2", default-features = false } +fuel-tx = "0.3" +fuels-abigen-macro = "0.3" +fuels-contract = "0.3" +fuels-core = "0.3" +rand = "0.8" +tokio = { version = "1.12", features = ["rt", "macros"] } + +[[test]] +harness = true +name = "integration_tests" +path = "tests/harness.rs" diff --git a/examples/wallet_smart_contract/Forc.toml b/examples/wallet_smart_contract/Forc.toml new file mode 100644 index 00000000000..e3aa984412e --- /dev/null +++ b/examples/wallet_smart_contract/Forc.toml @@ -0,0 +1,9 @@ +[project] +author = "mindtree" +entry = "main.sw" +license = "Apache-2.0" +name = "wallet_smart_contract" + +[dependencies] +core = { git = "http://github.com/FuelLabs/sway-lib-core" } +std = { git = "http://github.com/FuelLabs/sway-lib-std" } diff --git a/examples/wallet_smart_contract/src/main.sw b/examples/wallet_smart_contract/src/main.sw new file mode 100644 index 00000000000..7d8a36863e5 --- /dev/null +++ b/examples/wallet_smart_contract/src/main.sw @@ -0,0 +1,36 @@ +contract; + +use std::*; + +const OWNER_ADDRESS: b256 = 0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861; +const ETH_ID: b256 = 0x0000000000000000000000000000000000000000000000000000000000000000; + +storage { + balance: u64, +} + +abi Wallet { + fn receive_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, unused: ()); + fn send_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, req: SendFundsRequest); +} + +impl Wallet for Contract { + fn receive_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, unused: ()) { + if asset_id == ETH_ID { + let balance = storage.balance.write(); + deref balance = balance + coins_to_forward; + }; + } + + fn send_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, req: SendFundsRequest) { + assert(sender() == OWNER_ADDRESS); + assert(storage.balance > req.amount_to_send); + storage.balance = storage.balance - req.amount_to_send; + transfer_coins(asset_id, req.recipient_address, req.amount_to_send); + } +} + +struct SendFundsRequest { + amount_to_send: u64, + recipient_address: b256, +} diff --git a/examples/wallet_smart_contract/tests/harness.rs b/examples/wallet_smart_contract/tests/harness.rs new file mode 100644 index 00000000000..bba801d2e8f --- /dev/null +++ b/examples/wallet_smart_contract/tests/harness.rs @@ -0,0 +1,4 @@ +#[tokio::test] +async fn harness() { + assert_eq!(true, true); +} From 3fd37faf89b3646729dfd8a5559ca85c20c0e5de Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 11 Feb 2022 01:36:59 +1100 Subject: [PATCH 04/10] Add `build-all-examples` script and associated CI passes This script walks the examples directory and, for every directory containing a `forc.toml` file, runs `forc build` for that directory. Examples that encounter a failure of some kind have their `stdout` and `stderr` piped through so we can easily identify cause of failure in CI. This also removes the examples from the workspace. Currently unsure whether or not the added CI pass to install `forc` will result in `forc` actually being available on the PATH in the CI worker, but will find out soon. Still need to work out how to run `forc test` for each project without having cargo complain about building within the parent sway workspace. --- .github/workflows/ci.yml | 12 ++++++ Cargo.toml | 8 +--- examples/build-all-examples/Cargo.toml | 6 +++ examples/build-all-examples/src/main.rs | 56 +++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 examples/build-all-examples/Cargo.toml create mode 100644 examples/build-all-examples/src/main.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index caa3d6a5dc6..0022b88b917 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -70,6 +70,18 @@ jobs: command: run args: --release --bin test + - name: Install forc + uses: actions-rs/cargo@v1 + with: + command: install + args: --path ./forc + + - name: Build sway examples + uses: actions-rs/cargo@v1 + with: + command: run + args: --bin build-all-examples + publish: # Only do this job if publishing a release needs: build diff --git a/Cargo.toml b/Cargo.toml index 406095ca43c..74790eac693 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = [ "docstrings", + "examples/build-all-examples", "forc", "parser", "sway-core", @@ -12,13 +13,6 @@ members = [ "sway-utils", "test", "test-sig-gen-util", - - # These are standalone forc example projects, but because running `forc - # test` calls `cargo test` within this workspace, we must add them here. - "examples/fizzbuzz", - "examples/hello_world", - "examples/subcurrency", - "examples/wallet_smart_contract", ] [profile.dev.package.sway-server] diff --git a/examples/build-all-examples/Cargo.toml b/examples/build-all-examples/Cargo.toml new file mode 100644 index 00000000000..6415fd9e5f6 --- /dev/null +++ b/examples/build-all-examples/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "build-all-examples" +description = "Runs `forc build` for all projects under the Sway `examples` directory." +version = "0.1.0" +edition = "2021" +publish = false diff --git a/examples/build-all-examples/src/main.rs b/examples/build-all-examples/src/main.rs new file mode 100644 index 00000000000..e1d9b80dd3f --- /dev/null +++ b/examples/build-all-examples/src/main.rs @@ -0,0 +1,56 @@ +//! Runs `forc build` for all projects under the Sway `examples` directory. +//! +//! NOTE: This expects both `forc` and `cargo` to be available in `PATH`. + +use std::{ + fs, + io::{self, Write}, + path::Path, +}; + +fn main() { + let proj_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let examples_dir = proj_dir + .parent() + .expect("failed to find examples directory"); + let mut failed = false; + for res in fs::read_dir(examples_dir).expect("failed to walk examples directory") { + let entry = match res { + Ok(entry) => entry, + _ => continue, + }; + let path = entry.path(); + if !path.is_dir() || !dir_contains_forc_manifest(&path) { + continue; + } + + let output = std::process::Command::new("forc") + .args(["build", "--path"]) + .arg(&path) + .output() + .expect("failed to run `forc build` for example project"); + + // Print output on failure so we can read it in CI. + if !output.status.success() { + io::stdout().write_all(&output.stdout).unwrap(); + io::stdout().write_all(&output.stderr).unwrap(); + failed = true; + } + } + if failed { + eprintln!("One or more example projects failed to build"); + std::process::exit(1); + } +} + +// Check if the given directory contains `Forc.toml` at its root. +fn dir_contains_forc_manifest(path: &Path) -> bool { + if let Ok(entries) = fs::read_dir(path) { + for entry in entries.flatten() { + if entry.path().file_name().and_then(|s| s.to_str()) == Some("Forc.toml") { + return true; + } + } + } + false +} From ee5984ad6b9a1b803da3eef1e515fe398e46b3fd Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 11 Feb 2022 11:28:14 +1100 Subject: [PATCH 05/10] Add a clear build summary at the end of `build-all-examples` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, it's tricky to get an idea of how many successes/failures there were without combing through the stdout/stderr. This adds a little summary to the end that looks something like this: ``` Build all examples summary: [✓]: /home/mindtree/programming/rust/fuel/sway/examples/fizzbuzz succeeded! [✓]: /home/mindtree/programming/rust/fuel/sway/examples/hello_world succeeded! [x]: /home/mindtree/programming/rust/fuel/sway/examples/wallet_smart_contract failed! [✓]: /home/mindtree/programming/rust/fuel/sway/examples/subcurrency succeeded! 3 successes, 1 failure ``` --- examples/build-all-examples/src/main.rs | 44 +++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/examples/build-all-examples/src/main.rs b/examples/build-all-examples/src/main.rs index e1d9b80dd3f..55a875f3d0f 100644 --- a/examples/build-all-examples/src/main.rs +++ b/examples/build-all-examples/src/main.rs @@ -5,7 +5,7 @@ use std::{ fs, io::{self, Write}, - path::Path, + path::{Path, PathBuf}, }; fn main() { @@ -13,7 +13,10 @@ fn main() { let examples_dir = proj_dir .parent() .expect("failed to find examples directory"); - let mut failed = false; + + // Track discovered projects and whether or not they were successful. + let mut summary: Vec<(PathBuf, bool)> = vec![]; + for res in fs::read_dir(examples_dir).expect("failed to walk examples directory") { let entry = match res { Ok(entry) => entry, @@ -31,14 +34,43 @@ fn main() { .expect("failed to run `forc build` for example project"); // Print output on failure so we can read it in CI. - if !output.status.success() { + let success = if !output.status.success() { io::stdout().write_all(&output.stdout).unwrap(); io::stdout().write_all(&output.stderr).unwrap(); - failed = true; + false + } else { + true + }; + + summary.push((path, success)); + } + + println!("\nBuild all examples summary:"); + let mut successes = 0; + for (path, success) in &summary { + let (checkmark, status) = if *success { + ("[✓]", "succeeded") + } else { + ("[x]", "failed") + }; + println!(" {}: {} {}!", checkmark, path.display(), status); + if *success { + successes += 1; } } - if failed { - eprintln!("One or more example projects failed to build"); + let failures = summary.len() - successes; + let successes_str = if successes == 1 { + "success" + } else { + "successes" + }; + let failures_str = if failures == 1 { "failure" } else { "failures" }; + println!( + "{} {}, {} {}", + successes, successes_str, failures, failures_str + ); + + if failures > 0 { std::process::exit(1); } } From f9ba8c3ff8ed50a42746814bea136fb9b2ab6c7f Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 11 Feb 2022 11:40:42 +1100 Subject: [PATCH 06/10] Set build-all-examples script version to 0.0.0 --- examples/build-all-examples/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/build-all-examples/Cargo.toml b/examples/build-all-examples/Cargo.toml index 6415fd9e5f6..e1264d144c1 100644 --- a/examples/build-all-examples/Cargo.toml +++ b/examples/build-all-examples/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "build-all-examples" description = "Runs `forc build` for all projects under the Sway `examples` directory." -version = "0.1.0" +version = "0.0.0" edition = "2021" publish = false From 9fb07f4729d9b5b202cceb9f4a994be5aa18c535 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 11 Feb 2022 12:20:30 +1100 Subject: [PATCH 07/10] Exclude examples from workspace, Fix hello_world test harness path --- Cargo.toml | 6 ++++++ examples/hello_world/tests/harness.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 74790eac693..7a226cf86e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,12 @@ members = [ "test", "test-sig-gen-util", ] +exclude = [ + "examples/fizzbuzz", + "examples/hello_world", + "examples/subcurrency", + "examples/wallet_smart_contract", +] [profile.dev.package.sway-server] debug = 2 diff --git a/examples/hello_world/tests/harness.rs b/examples/hello_world/tests/harness.rs index 2a602221f3c..de1e8b6a312 100644 --- a/examples/hello_world/tests/harness.rs +++ b/examples/hello_world/tests/harness.rs @@ -6,7 +6,7 @@ use rand::{Rng, SeedableRng}; // Generate Rust bindings from our contract JSON ABI // FIXME: Incorrect path, see https://github.com/FuelLabs/fuels-rs/issues/94 -abigen!(MyContract, "./examples/hello_world/my-contract-abi.json"); +abigen!(MyContract, "./my-contract-abi.json"); #[tokio::test] async fn harness() { From 4da1beeef23dca1b3e9ab18debd370d5c8d3e3c3 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 11 Feb 2022 19:51:11 +1100 Subject: [PATCH 08/10] Temporarily comment out storage related code in wallet example This example should be updated after #646 lands. --- examples/wallet_smart_contract/src/main.sw | 27 +++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/examples/wallet_smart_contract/src/main.sw b/examples/wallet_smart_contract/src/main.sw index 7d8a36863e5..36510138617 100644 --- a/examples/wallet_smart_contract/src/main.sw +++ b/examples/wallet_smart_contract/src/main.sw @@ -1,13 +1,18 @@ +// NOTE: Storage is a work in progress (see +// https://github.com/FuelLabs/sway/pull/646), but once it is implemented, +// declaring storage should look like this. + contract; use std::*; +use std::chain::assert; const OWNER_ADDRESS: b256 = 0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861; const ETH_ID: b256 = 0x0000000000000000000000000000000000000000000000000000000000000000; -storage { - balance: u64, -} +// storage { +// balance: u64, +// } abi Wallet { fn receive_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, unused: ()); @@ -16,17 +21,17 @@ abi Wallet { impl Wallet for Contract { fn receive_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, unused: ()) { - if asset_id == ETH_ID { - let balance = storage.balance.write(); - deref balance = balance + coins_to_forward; - }; + // if asset_id == ETH_ID { + // let balance = storage.balance.write(); + // deref balance = balance + coins_to_forward; + // }; } fn send_funds(gas_to_forward: u64, coins_to_forward: u64, asset_id: b256, req: SendFundsRequest) { - assert(sender() == OWNER_ADDRESS); - assert(storage.balance > req.amount_to_send); - storage.balance = storage.balance - req.amount_to_send; - transfer_coins(asset_id, req.recipient_address, req.amount_to_send); + // assert(sender() == OWNER_ADDRESS); + // assert(storage.balance > req.amount_to_send); + // storage.balance = storage.balance - req.amount_to_send; + // transfer_coins(asset_id, req.recipient_address, req.amount_to_send); } } From e6db1241b134be8f452fb3aade89fc572be6a1fc Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Fri, 11 Feb 2022 20:21:39 +1100 Subject: [PATCH 09/10] Install forc with `--debug` to share build artifacts Currently it takes CI another 7 mins to build and install forc from scratch. This should allow `cargo` to re-use the artifacts it has already built during the sway building and testing steps earlier in the CI job. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0022b88b917..8fe232e53f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,7 +74,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: install - args: --path ./forc + args: --debug --path ./forc - name: Build sway examples uses: actions-rs/cargo@v1 From 542f0a1673e46f16925130d4a52eea5850604fee Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Sat, 12 Feb 2022 10:34:55 +1100 Subject: [PATCH 10/10] Change author field in examples from mindtree -> Fuel Labs --- examples/fizzbuzz/Cargo.toml | 2 +- examples/fizzbuzz/Forc.toml | 2 +- examples/hello_world/Cargo.toml | 2 +- examples/hello_world/Forc.toml | 2 +- examples/wallet_smart_contract/Cargo.toml | 2 +- examples/wallet_smart_contract/Forc.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/fizzbuzz/Cargo.toml b/examples/fizzbuzz/Cargo.toml index f7f938d4463..5af10f184b3 100644 --- a/examples/fizzbuzz/Cargo.toml +++ b/examples/fizzbuzz/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["mindtree"] +authors = ["Fuel Labs "] edition = "2021" license = "Apache-2.0" name = "fizzbuzz" diff --git a/examples/fizzbuzz/Forc.toml b/examples/fizzbuzz/Forc.toml index 4ae40c1129f..8dd56118e67 100644 --- a/examples/fizzbuzz/Forc.toml +++ b/examples/fizzbuzz/Forc.toml @@ -1,5 +1,5 @@ [project] -author = "mindtree" +author = "Fuel Labs " entry = "main.sw" license = "Apache-2.0" name = "fizzbuzz" diff --git a/examples/hello_world/Cargo.toml b/examples/hello_world/Cargo.toml index 034cff7fe3e..2008cdf553b 100644 --- a/examples/hello_world/Cargo.toml +++ b/examples/hello_world/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["mindtree"] +authors = ["Fuel Labs "] edition = "2021" license = "Apache-2.0" name = "hello_world" diff --git a/examples/hello_world/Forc.toml b/examples/hello_world/Forc.toml index 68811f91f53..3e011bfa290 100644 --- a/examples/hello_world/Forc.toml +++ b/examples/hello_world/Forc.toml @@ -1,5 +1,5 @@ [project] -author = "mindtree" +author = "Fuel Labs " entry = "main.sw" license = "Apache-2.0" name = "hello_world" diff --git a/examples/wallet_smart_contract/Cargo.toml b/examples/wallet_smart_contract/Cargo.toml index c71bfe0ca0a..1fffeac9b5b 100644 --- a/examples/wallet_smart_contract/Cargo.toml +++ b/examples/wallet_smart_contract/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["mindtree"] +authors = ["Fuel Labs "] edition = "2021" license = "Apache-2.0" name = "wallet_smart_contract" diff --git a/examples/wallet_smart_contract/Forc.toml b/examples/wallet_smart_contract/Forc.toml index e3aa984412e..efb2c31e759 100644 --- a/examples/wallet_smart_contract/Forc.toml +++ b/examples/wallet_smart_contract/Forc.toml @@ -1,5 +1,5 @@ [project] -author = "mindtree" +author = "Fuel Labs " entry = "main.sw" license = "Apache-2.0" name = "wallet_smart_contract"