From 32d2b5affddaf19bb5e0a4f23958293821ad161c Mon Sep 17 00:00:00 2001 From: AndrePanin Date: Wed, 10 Apr 2024 12:06:10 +0200 Subject: [PATCH 1/2] Intermediate course edits --- docs/03-intermediate/01-course-content.md | 4 +- .../02-message-receiving/handle_reply.md | 49 ++++---- .../testing_handle_reply.md | 15 +-- .../handle-reply-wait-wake.md | 47 ++++---- .../03-wait-wake-system/testing_wait_for.md | 4 +- .../03-wait-wake-system/testing_wait_wake.md | 4 +- .../03-wait-wake-system/wait_for.md | 19 ++- .../03-wait-wake-system/wait_wake.md | 16 ++- .../delayed-message-example.md | 15 +-- .../04-delayed-message/delayed-message.md | 19 ++- .../testing-delayed-message.md | 6 +- .../03-intermediate/05-homework/assignment.md | 108 +++++++++--------- docs/03-intermediate/index.md | 2 +- 13 files changed, 155 insertions(+), 153 deletions(-) diff --git a/docs/03-intermediate/01-course-content.md b/docs/03-intermediate/01-course-content.md index f3ab766..6b8af44 100644 --- a/docs/03-intermediate/01-course-content.md +++ b/docs/03-intermediate/01-course-content.md @@ -5,7 +5,7 @@ hide_table_of_contents: true # Course content -This course serves as a continuation of the basic course and delves deeper into the implementation of programs using Gear technologies. Specifically, it focuses on how programs can communicate with each other, receive and process requests, and handle scenarios where one party does not respond. +This course serves as a continuation of the [basic course](https://academy.gear.foundation/courses/basic_course), delving deeper into the implementation of programs using [Gear](https://gear-tech.io/) technologies. Specifically, it focuses on how programs can communicate with each other, receive and process requests, and handle scenarios where one party does not respond. The course material is structured into three sections: @@ -22,6 +22,6 @@ The course material is structured into three sections: 3. Handling of Delayed Messages: - In-depth exploration of delayed messages; -- Resolution of issues related to lack of response through the use of delayed messages; +- Resolution of issues related to the absence of responses through the use of delayed messages; - Testing of the program featuring delayed messages. diff --git a/docs/03-intermediate/02-message-receiving/handle_reply.md b/docs/03-intermediate/02-message-receiving/handle_reply.md index 786b384..163e4f3 100644 --- a/docs/03-intermediate/02-message-receiving/handle_reply.md +++ b/docs/03-intermediate/02-message-receiving/handle_reply.md @@ -5,20 +5,22 @@ hide_table_of_contents: true # Message receiving -In this lesson, you will learn how a program can efficiently handle request messages. We will illustrate this concept with an example of interaction between two programs. Before delving into the analysis of the program code, it is useful to illustrate the operation of our programs schematically. +In this lesson, you will learn how a program can efficiently handle request messages. This concept will be illustrated through an example of interaction between two programs. + +Before analyzing the program code in detail, it will be helpful to first present a schematic overview of how our programs operate: ![gif 1](../img/02/handle_reply.gif) -1. The user sends some `Action` message to program №1, which is processed by `handle()`; -2. This message is then passed to programme №2; -3. Programme №1 sends an `Event` message to the user indicating that the message was successfully passed to Programme №2; -4. Programme №2 receives the message from Programme №1 processes it and responds; -5. Programme №1 receives the reply message from Programme №2 via the `handle_reply()` entry point; -6. Finally, from the `handle_reply()` function, send the message to the user. +1. The user sends an `Action` message to Program #1, which is processed by the `handle()` function. +2. This message is then passed to Program #2. +3. Program #1 sends an `Event` message to the user, indicating that the message was successfully passed to Program #2. +4. Program #2 receives the message from Program #1, processes it, and responds. +5. Program #1 receives the reply message from Program #2 via the `handle_reply()` entry point. +6. Finally, from the `handle_reply()` function, Program #1 sends the response to the user. ## First program -The task of the first program is to communicate with the second program, so the following structure will be needed: +The primary task of the first program is to communicate with the second program, requiring the following structure: ```rust struct Session { @@ -27,7 +29,7 @@ struct Session { } ``` -The following actions and events will also be necessary to simulate a dialogue between programs: +The following actions and events will be necessary to simulate a dialogue between the programs: ```rust #[derive(TypeInfo, Encode, Decode)] @@ -52,7 +54,7 @@ pub enum Event { } ``` -During initialization, it is necessary to pass the address of the second program: +During initialization, it is necessary to pass the address of the second program. ```rust #[no_mangle] @@ -69,9 +71,9 @@ extern "C" fn init() { Let's focus on processing requests in the `handle()` function: -1. Receive the message with the function `msg::load()`; -2. Send a message to the second program using the `msg::send()`; -3. An important step is to store the identifier of the message returned by `msg::send()`, allowing the `handle_reply()` function to identify which message received a response; +1. Receive the message with the `msg::load()` function. +2. Send a message to the second program using `msg::send()`. +3. An important step is to store the identifier of the message returned by `msg::send()`. This allows the `handle_reply()` function to identify which message received a response. 4. Finally, send a reply message indicating that the message was sent to the second program. ```rust @@ -85,13 +87,13 @@ extern "C" fn handle() { } ``` -The Gear program handles the reply to the message using the `handle_reply()` function. Now, let's examine how to manage the response message from the second program: +The Gear program utilizes the `handle_reply()` function to handle replies to messages. Let’s delve into managing the response message from the second program: -1. Utilize the `msg::reply_to()` function to obtain the identifier of the message for which the `handle_reply()` function is invoked. -2. Verify that the message identifier matches the identifier of the message sent from the `handle()` function, ensuring that the response corresponds to that specific message. -3. Finally, send a reply message to the sender's address. +1. Use the `msg::reply_to()` function to retrieve the identifier of the message for which the `handle_reply()` function was invoked. +2. Ensure that the message identifier matches the identifier of the message sent from the `handle()` function. This step verifies that the response corresponds to the specific message sent earlier. +3. Finally, send a reply message to the original sender’s address. -**It is important to emphasize that calling `msg::reply()` inside the `handle_reply` function is not allowed.** +**It is crucial to note that calling `msg::reply()` inside the `handle_reply()` function is not permitted.** ```rust #[no_mangle] @@ -106,14 +108,13 @@ extern "C" fn handle_reply() { } ``` -Just a reminder that the sender of the message will receive two messages: -- The first message is sent from the `handle()` function to indicate that the message has been sent to the second program. -- The second message will come from the `handle_reply()` function with the response from the second program. - +Just a reminder: the sender of the message will receive two messages: +- The first message, originating from the `handle()` function, indicates that the message has been forwarded to the second program. +- The second message, sent by the `handle_reply()` function, contains the response from the second program. -## Second program +## Second Program -The first program is straightforward; it can accept various variants of actions and respond to them with corresponding events. These responses can range from simple replies such as `Action::HowAreYou` and `Event::Fine` to more complex logic, such as generating a random number. +The first program is straightforward; it can accept various types of actions and respond with corresponding events. These responses can range from simple replies, such as `Action::HowAreYou` and `Event::Fine`, to more complex logic, such as generating a random number. ```rust #![no_std] diff --git a/docs/03-intermediate/02-message-receiving/testing_handle_reply.md b/docs/03-intermediate/02-message-receiving/testing_handle_reply.md index 1a6f1b5..38029e6 100644 --- a/docs/03-intermediate/02-message-receiving/testing_handle_reply.md +++ b/docs/03-intermediate/02-message-receiving/testing_handle_reply.md @@ -5,20 +5,21 @@ hide_table_of_contents: true # Testing -Let's verify the functionality of the programs discussed in the preceding section by employing the `gtest` library, a subject you should be familiar with from the basic course. +Let's verify the functionality of the programs discussed in the preceding section by using the `gtest` library, which you should already be familiar with from the basic course. -The first thing to do is to create a testing environment: +1. Create a testing environment: ```rust let system = System::new(); ``` -Get first program of the root crate with provided `system` and the second program instance from wasm file. +2. Retrieve the first program from the root crate using the provided `system` and the second program instance from the wasm file. + ```rust let first_program = Program::current(&system); let second_program = Program::from_file(&system, "target/wasm32-unknown-unknown/release/second_program.opt.wasm"); ``` -Initialize the second program by sending an empty message and then initialize the first program by passing the address of the second program to it. +3. Initialize the second program by sending an empty message, and then initialize the first program by passing the address of the second program to it. ```rust let result = second_program.send_bytes(USER, []); @@ -26,7 +27,7 @@ let second_program_address: ActorId = SECOND_PROGRAM_ADDRESS.into(); let res = first_program.send(USER, second_program_address); ``` -Send the message with `Action::MakeRandomNumber {range: 1}` to the first program and check for the response `Event::MessageSent`, which means that the message was successfully sent to the second program address; +4. Send a message with `Action::MakeRandomNumber { range: 1 }` to the first program and check for the response `Event::MessageSent`, indicating that the message was successfully sent to the second program's address. ```rust let result = first_program.send(USER, Action::MakeRandomNumber {range: 1}); @@ -38,7 +39,7 @@ assert!(result.contains(&log)); ``` -Retrieve the user's mailbox with the specified ID and verify that a reply message has been sent back to the user +5. Retrieve the user's mailbox with the specified ID and verify that a reply message has been sent back to the user. ```rust let mailbox = system.get_mailbox(USER); @@ -101,4 +102,4 @@ fn success_test() { } ``` -It will be good practice if you implement these programmes and test on your own. +It will be beneficial for you to implement these programs and test them on your own. \ No newline at end of file diff --git a/docs/03-intermediate/03-wait-wake-system/handle-reply-wait-wake.md b/docs/03-intermediate/03-wait-wake-system/handle-reply-wait-wake.md index d1457fb..3b5192a 100644 --- a/docs/03-intermediate/03-wait-wake-system/handle-reply-wait-wake.md +++ b/docs/03-intermediate/03-wait-wake-system/handle-reply-wait-wake.md @@ -3,17 +3,17 @@ sidebar_position: 2 hide_table_of_contents: true --- -# Handle reply with wait() and wake() +# Handle Reply with wait() and wake() -Now let's use the knowledge about `exec::wait()`/`exec::wake()` functions and try to improve the program that was shown in the previous lesson. +Now, let's apply our understanding of the `exec::wait()`/`exec::wake()` functions to enhance the program introduced in the previous lesson: ![gif 2](../img/03/wait_wake.gif) -As you can see, the user will no longer receive two separate messages; instead, a single reply will be sent at the end of the entire process. +The user will now receive a single reply at the end of the entire process, instead of two separate messages. -## First program +## First Program -As the second programme remains unchanged, let's proceed directly to examining the modifications in the first program: +Since the second program remains unchanged, let's take a closer look at the changes in the first program: ```rust type MessageSentId = MessageId; @@ -25,11 +25,12 @@ struct Session { message_status: MessageStatus, } ``` -New fields have been created -- `msg_ids` — a tuple consisting of two elements: MessageSentId and OriginalMessageId; - - `MessageSentId` - identifier of the message to be sent to the second program address; - - `OriginalMessageId` - identifier of the message to be sent to the first program (required for using the wake() function). -- `message_status` - session status (required to track session activity stages). + +New fields have been introduced: +- `msg_ids` — a tuple consisting of two elements: `MessageSentId` and `OriginalMessageId`; + - `MessageSentId` is the identifier of the message sent to the second program's address. + - `OriginalMessageId` is the identifier of the message sent to the first program (required for using the `wake()` function). +- `message_status` - the session status (required to track the stages of session activity). ```rust enum MessageStatus { @@ -38,11 +39,12 @@ enum MessageStatus { Received(Event), } ``` -- `Waiting` — the session is in a waiting state; -- `Sent` - the intermediate state of the session in which the message was sent to the second program, but the response has not yet been received; -- `Received(String)` - the session state in which the reply message was received. -Considering the new fields in the program structure, initialization appears as follows: +- `Waiting` — the session is in a waiting state. +- `Sent` - the intermediate session state in which the message was sent to the second program, but the response has not yet been received. +- `Received(String)` - the session state when the reply message has been received. + +With these new fields in the program structure, initialization is as follows: ```rust #[no_mangle] @@ -58,7 +60,7 @@ extern "C" fn init() { } ``` -This time, let's incorporate debugging into our program to gain a comprehensive understanding of the entire process. +To gain a comprehensive understanding of the process, let's incorporate debugging into our program. ```rust #[no_mangle] @@ -95,9 +97,9 @@ extern "C" fn handle() { } ``` -At the very beginning, as you may have noticed, the session is in `MessageStatus::Waiting` state. When a match occurs, the code switches to the first option. The program sends a message, sets the session status to `MessageStatus::Sent` and records the identifiers of the current and sent message. Then `exec::wait()` is called, which pauses message processing and adds the current message to the waiting list until `exec::wake(message_id)` is called or the gas runs out. Subsequent waking of a message requires its id, so `msg::id()` is stored in `session.msg_ids`. +Initially, the session is in `MessageStatus::Waiting` state. Upon a match, the code switches to the first option. The program sends a message, sets the session status to `MessageStatus::Sent`, and records the identifiers of the current and sent messages. Then, `exec::wait()` is called, pausing message processing and adding the current message to the waiting list until `exec::wake(message_id)` is called or the gas runs out. The ID of the waking message is crucial, hence `msg::id()` is stored in `session.msg_ids`. -Let's move on to the `handle_reply()` function: +Moving to the `handle_reply()` function: ```rust #[no_mangle] @@ -117,10 +119,9 @@ extern "C" fn handle_reply() { } ``` -Сondition `if reply_to == session.msg_ids.0 && session.message_status == MessageStatus::Sent` gives a guarantee that the expected message has arrived and arrived at the right moment, i.e. at the correct session status. -After that the status is set to `MessageStatus::Received(reply_message)` and the response message is saved. The ID of the original message is retrieved, and the `exec::wake()` function is called. This function retrieves the message from the waiting list, and the suspended message is resumed in the `handle()` function. +The condition `if reply_to == session.msg_ids.0 && session.message_status == MessageStatus::Sent` ensures the expected message has arrived at the right moment, i.e., when the session is in the correct status. The status is then set to `MessageStatus::Received(reply_message)`, and the reply message is saved. The ID of the original message is retrieved, and the `exec::wake()` function is called. This function takes the message from the waiting list, and the suspended message resumes in the `handle()` function. -*Important note*: when `exec::wake()` is called, the message is taken from the waiting list, it returns to the `handle()` entrypoint, and message processing will start handling the message from the beginning, i.e. the program code will get into the `match` again: +*Important note*: When `exec::wake()` is called, and the message returns to the `handle()` entry point, processing starts from the beginning. The program enters the `match` again: ```rust // ... @@ -133,9 +134,9 @@ match &session.message_status { } // ... ``` -However, this time it will go into the third variant, send a response and set the status to `MessageStatus::Waiting`. -Now, let's examine this process as a whole: +However, this time, it proceeds to the third variant, sends a response, and sets the status to `MessageStatus::Waiting`. -![Code part 2](../img/03/wait_wake_code.gif) +Now, let's review this process as a whole: +![Code part 2](../img/03/wait_wake_code.gif) diff --git a/docs/03-intermediate/03-wait-wake-system/testing_wait_for.md b/docs/03-intermediate/03-wait-wake-system/testing_wait_for.md index 63d461c..dbf6737 100644 --- a/docs/03-intermediate/03-wait-wake-system/testing_wait_for.md +++ b/docs/03-intermediate/03-wait-wake-system/testing_wait_for.md @@ -5,7 +5,7 @@ hide_table_of_contents: true # Testing wait_for() -Let's use the function `system.spend_blocks()`, which allows to spend blocks and return all results: +Utilize the function `system.spend_blocks()` to advance through blocks and retrieve all results: ```rust use gstd::ActorId; @@ -50,7 +50,7 @@ fn test() { } ``` -Upon running the test, you will encounter the following debug messages. Examine them attentively to ensure that the program executed as intended. +When running the test, observe the following debug messages carefully to verify the program executed as planned. ```console [DEBUG test] [handle(0x0fc8..ced9)] 0x0100..0000: !!!! HANDLE !!!! diff --git a/docs/03-intermediate/03-wait-wake-system/testing_wait_wake.md b/docs/03-intermediate/03-wait-wake-system/testing_wait_wake.md index 21cc2ff..fb164ba 100644 --- a/docs/03-intermediate/03-wait-wake-system/testing_wait_wake.md +++ b/docs/03-intermediate/03-wait-wake-system/testing_wait_wake.md @@ -5,7 +5,7 @@ hide_table_of_contents: true # Testing wait() and wake() -Let's use `system.init_logger()` to start the environment in debug mode and see the debugs written. +To begin, use `system.init_logger()` to initiate the environment in debug mode, enabling you to see the debug messages. ```rust use gstd::ActorId; @@ -41,7 +41,7 @@ fn test() { } ``` -Upon running the test, you will encounter the following debug messages. Examine them attentively to ensure that the program executed as intended. +When you run the test, pay close attention to the following debug messages. Carefully review them to verify that the program has executed as expected. ```console [DEBUG test] [handle(0x0fc8..ced9)] 0x0100..0000: !!!! HANDLE !!!! diff --git a/docs/03-intermediate/03-wait-wake-system/wait_for.md b/docs/03-intermediate/03-wait-wake-system/wait_for.md index 2b900db..b5a4b19 100644 --- a/docs/03-intermediate/03-wait-wake-system/wait_for.md +++ b/docs/03-intermediate/03-wait-wake-system/wait_for.md @@ -3,18 +3,18 @@ sidebar_position: 4 hide_table_of_contents: true --- -# Breakdowns in communication +# Breakdowns in Communication -Sometimes the second program may not answer for any reason and it is necessary to be able to handle this case correctly. +Sometimes, the second program may not respond for various reasons, and it's crucial to handle such scenarios appropriately. ## wait_for() -Let's try to solve this problem using `wait_for(DURATION_IN_BLOCK)`. -*Reminder: this function itself wakes up the message from the waiting list after a certain number of blocks, if `exec::wake()` was not called.* +To address this issue, let's use `wait_for(DURATION_IN_BLOCKS)`. +*Reminder: This function automatically wakes up the message from the waiting list after a specified number of blocks if `exec::wake()` has not been called.* -## Second program +## Second Program -Let's add `exec::wait()` so that the second program does not reply to incoming messages: +Add `exec::wait()` to the second program so that it does not reply to incoming messages. ```rust #[no_mangle] @@ -25,9 +25,9 @@ extern "C" fn handle() { ``` -## First program +## First Program -In the first program, the `handle()` function will be modified. Instead of `exec::wait()`, we will use `exec::wait_for(3)`. This ensures that if `exec::wake()` in `handle_reply()` is not called within 3 blocks, message processing will automatically resume. +In the first program, the `handle()` function will be modified. Instead of `exec::wait()`, let's use `exec::wait_for(3)`. This ensures that if `exec::wake()` in `handle_reply()` is not called within 3 blocks, message processing will automatically resume. ```rust #[no_mangle] @@ -73,5 +73,4 @@ extern "C" fn handle() { } ``` -In this case the program will go to `handle()` again, but this time the session status will be `MessageStatus::Sent`, so a message will be sent to the user that there was no response and the status will be set to `MessageStatus::Waiting`. - +In such a case, the program will return to `handle()`, but this time with the session status as `MessageStatus::Sent`. Consequently, a message will be sent to the user indicating the absence of a response, and the status will be updated to `MessageStatus::Waiting`. \ No newline at end of file diff --git a/docs/03-intermediate/03-wait-wake-system/wait_wake.md b/docs/03-intermediate/03-wait-wake-system/wait_wake.md index 0165b7c..3d0d9a7 100644 --- a/docs/03-intermediate/03-wait-wake-system/wait_wake.md +++ b/docs/03-intermediate/03-wait-wake-system/wait_wake.md @@ -5,21 +5,19 @@ hide_table_of_contents: true # wait() and wake() -In order to enhance message handling in the Gear program, utilizing the `exec::wait()` and `exec::wake()` functions can be advantageous: +To enhance message handling in Gear programs, the `exec::wait()` and `exec::wake()` functions are invaluable tools: ## Wait -`exec::wait()`: Pauses the current message handling process, completing it with a special result and placing the message into the waiting queue. The message can later be awakened using the corresponding `exec::wake()` function. When a message enters the waiting state with `exec::wait()`, all changes made by the program before the wait call are preserved. These changes are stored in the program's persistent storage, ensuring they are not lost when message handling is paused. While a message is in the waiting state, all remaining gas is allocated to that message in the waiting queue. If the gas is depleted while the message is waiting, it will not be awakened, potentially causing the program to become stuck in an intermediate state. It is crucial to understand that each block of a message's presence in the queue incurs a charge in the form of gas. +`exec::wait()`: This function pauses the current message handling process, completing it with a special result and placing the message into the waiting queue. The message can later be reactivated using the `exec::wake()` function. When a message is put into the waiting state with `exec::wait()`, all changes made by the program before the wait call are preserved. These changes are stored in the program's persistent storage, ensuring they are not lost when message handling is paused. While in the waiting state, all remaining gas is allocated to the message in the waiting queue. If the gas is depleted while the message is waiting, it will not be awakened, potentially causing the program to become stuck in an intermediate state. It is essential to note that each block of a message's presence in the queue incurs a gas charge. -Therefore, Gear also provides the ability to enter a waiting state for a certain number of blocks using the `exec::wait_for` and `exec::wait_up_to` functions: +To address this, Gear provides functions for entering a waiting state for a specified number of blocks: -- `exec::wait_for(duration)`: With this function, the message pauses and waits for a specific number of blocks to pass. After this time has elapsed, if the message hasn't already been awakened, it will wake up on its own. However, if the message doesn't have enough gas to cover the cost of waiting for the specified number of blocks, the function will cause an panic. +- `exec::wait_for(duration)`: This function pauses the message for a specific number of blocks. If the message has not been awakened by other means, it will automatically wake up after this period. However, if there isn’t enough gas to cover the waiting period, the function will trigger a panic. -- `exec::wait_up_to(duration)`: This function allows the message to wait for a duration of time, but it only waits for as many blocks as it has enough gas to pay for. It ensures that the waiting time does not exceed the specified duration. +- `exec::wait_up_to(duration)`: Allows the message to wait for a period, but only for as many blocks as it has gas to afford. This ensures that the wait does not exceed the available resources. ## Wake -`exec::exec::wake()`: Resume the execution of a message that was previously paused using the wait function. When the wake function is called with a valid message_id, it will take the message out of the waiting queue and put it back into the processing queue. - -**It is important to note that message execution starts from the very beginning. The message comes to the handle entry point and executes all the logic from the beginning.** - +`exec::wake()`: Resumes the execution of a message that was previously paused with the `exec::wait()` function. Calling the wake function with a valid message ID takes the message out of the waiting queue and places it back in the processing queue. +**Important: Message execution restarts from the beginning. The message enters at the `handle` entry point and executes all logic from the start.** \ No newline at end of file diff --git a/docs/03-intermediate/04-delayed-message/delayed-message-example.md b/docs/03-intermediate/04-delayed-message/delayed-message-example.md index 33be414..a13f1ca 100644 --- a/docs/03-intermediate/04-delayed-message/delayed-message-example.md +++ b/docs/03-intermediate/04-delayed-message/delayed-message-example.md @@ -3,11 +3,11 @@ sidebar_position: 2 hide_table_of_contents: true --- -# Program with delayed message +# Program with Delayed Message -Let's try to rewrite the program from the previous lesson using the acquired knowledge about delayed messages. +Let's revise the program from the previous lesson, incorporating our knowledge about delayed messages. -In this case there will be two types of message: +In this scenario, there are two types of messages: ```rust #[derive(TypeInfo, Encode, Decode, Debug)] @@ -43,7 +43,7 @@ pub enum Event { } ``` -Add `ActorId` to `msg_ids` to store the address of the sender of the message: +Add `ActorId` to `msg_ids` to store the address of the message sender. ```rust struct Session { @@ -53,7 +53,7 @@ struct Session { } ``` -In this case the initialization will look as follows: +The initialization will then proceed as follows: ```rust #[no_mangle] @@ -69,7 +69,7 @@ extern "C" fn init() { } ``` -After sending the message to the second program, send a delayed message `msg::send_delayed(exec::program_id(), Action::CheckReply, 0, 3)`, with a delay of three blocks. +After sending the message to the second program, send a delayed message using `msg::send_delayed(exec::program_id(), Action::CheckReply, 0, 3)`, setting a delay of three blocks. ```rust #[no_mangle] @@ -115,4 +115,5 @@ extern "C" fn handle() { debug!("HANDLE: END"); } ``` -Upon receiving the `Action::CheckReply` message, the handler will inspect the session's status. If the message source is the program itself and the status is `Status::Sent`, a notification will be dispatched to the sender indicating the absence of a response message. + +Upon receiving the `Action::CheckReply` message, the handler will review the session's status. If the message originated from the program itself and the status is `Status::Sent`, a notification will be sent to the sender to report the absence of a response message. \ No newline at end of file diff --git a/docs/03-intermediate/04-delayed-message/delayed-message.md b/docs/03-intermediate/04-delayed-message/delayed-message.md index 215ed2c..1dee642 100644 --- a/docs/03-intermediate/04-delayed-message/delayed-message.md +++ b/docs/03-intermediate/04-delayed-message/delayed-message.md @@ -3,19 +3,18 @@ sidebar_position: 1 hide_table_of_contents: true --- -# Delayed message +# Delayed Message -The conventional approach adopted by programs on other blockchains involves dependency on external, centralized resources. Consequently, the execution of code within these programs and any corresponding alterations to the blockchain's state are contingent upon being triggered by an on-chain transaction. +Conventional approaches by programs on other blockchains rely on external, centralized resources. Thus, the execution of code within these programs and any corresponding changes to the blockchain's state depend on being triggered by an on-chain transaction. -The external transaction functions as a trigger to activate the program and commence its logic. For example, an individual can initiate an auction by dispatching a message to the auction program. Following the expiration of the auction period, the program will require processing the auction's outcome. However, this processing will remain pending until an individual dispatches the appropriate message to the program, thereby initiating this action. +An external transaction acts as a trigger to activate the program and start its logic. For instance, someone can initiate an auction by sending a message to the auction program. After the auction period expires, the program needs to process the auction's outcome. However, this process awaits until someone sends the correct message to the program, triggering this action. -Gear Protocol solves this issue by introducing delayed messaging functionality. The programs in Gear Networks are able to execute themselves an unlimited number of blocks, as long as enough gas for execution is kept available. As a result the need for including centralized components in dApps is eliminated, allowing them to function totally on-chain. +The Gear Protocol addresses this challenge by introducing delayed messaging functionality. Programs within the Gear-powered networks can execute autonomously over an unlimited number of blocks, provided there is sufficient gas for execution. This advancement eliminates the need for centralized components in dApps, enabling them to operate entirely on-chain. -`msg::send_delayed` function allows sending a message after a specified delay. The function takes the following parameters: -- `program` - the program (or user) to which the message will be sent; -- `payload` - the payload of the message; +The `msg::send_delayed` function facilitates sending a message after a specified delay, accepting the following parameters: +- `program` - the program (or user) to which the message will be directed; +- `payload` - the content of the message; - `value` - the amount of tokens to be sent with the message; -- `delay `- the delay in blocks after which the message will be sent. - -The delayed message will be executed after the specified delay measured in blocks. For example, on a network with a block producing time of 3 seconds, a delay of 20 is equal to 1 minute. +- `delay` - the number of blocks after which the message will be dispatched. +The delayed message executes after the predetermined delay measured in blocks. For example, in a network where blocks are produced every 3 seconds, a delay of 20 equates to 1 minute. diff --git a/docs/03-intermediate/04-delayed-message/testing-delayed-message.md b/docs/03-intermediate/04-delayed-message/testing-delayed-message.md index de54553..6a8ca0b 100644 --- a/docs/03-intermediate/04-delayed-message/testing-delayed-message.md +++ b/docs/03-intermediate/04-delayed-message/testing-delayed-message.md @@ -5,7 +5,7 @@ hide_table_of_contents: true # Testing -Let's verify the functionality of the program discussed in the preceding section: +Let's verify the functionality of the program discussed in the preceding section. ```rust use gstd::ActorId; @@ -61,7 +61,7 @@ fn test() { } ``` -The following debug messages will be displayed in the console: +The following debug messages will appear in the console: ```console [DEBUG test] [handle(0x0fc8..ced9)] 0x0100..0000: !!!! HANDLE !!!! @@ -84,4 +84,4 @@ The following debug messages will be displayed in the console: [DEBUG test] [handle(0x058e..8c20)] 0x0100..0000: HANDLE: END ``` -Note that the message identifier is now different, this is distinct from when `wake()`/`wait()` was used. +Observe that the message identifier has changed; this differs from the behavior observed with `wake()`/`wait()`. \ No newline at end of file diff --git a/docs/03-intermediate/05-homework/assignment.md b/docs/03-intermediate/05-homework/assignment.md index 213115d..f3b319f 100644 --- a/docs/03-intermediate/05-homework/assignment.md +++ b/docs/03-intermediate/05-homework/assignment.md @@ -7,45 +7,45 @@ hide_table_of_contents: true ## Task Description -In this homework you are to write the Wordle Game. +For this homework, you are tasked with writing the Wordle game. -Wordle is an engaging word-guessing game that has gained popularity due to its simplicity and addictive gameplay. The objective of the game is to guess the hidden word within a limited number of attempts. +Wordle is a captivating word-guessing game that has become popular for its simplicity and addictive gameplay. The goal is to guess a hidden word within a limited number of attempts. -The game board consists of six rows, each allowing the player to input a word. Upon entering a word, the player receives feedback indicating whether a letter is present in the hidden word and if it's in the correct position. If a letter is present but in the wrong position, it may be displayed in a different color or with a distinct symbol to indicate this. Players can use these hints to deduce which letters to include in the word and where to place them. +The game board consists of six rows, each allowing the player to input a word. Upon entering a word, the player receives feedback indicating the presence of letters in the hidden word and their correct positions. If a letter is present but in the wrong position, it may be highlighted in a different color or marked with a distinct symbol. Players utilize these clues to deduce the correct letters and their placements. -Players must rely on their knowledge and intuition to guess the word within the fewest attempts possible. The time constraint and limited number of attempts make the game exhilarating and suspenseful. +The game challenges players to guess the word with the fewest attempts, under time constraints and limited attempts, adding excitement and suspense. -## Project Structure + ## Project Structure -In order to create a dynamic and interactive word-guessing game, we propose dividing the gaming process into two distinct programs. The first program will manage the core functionalities of the game, including selecting a random word from a predetermined bank and evaluating user guesses. Meanwhile, the second program will act as a coordinator, handling user interactions, maintaining game state, and managing time constraints. By dividing the gameplay between two programs, we aim to create a modular and flexible system that enhances the overall gaming experience. Let's delve deeper into the functionalities and interactions of these two programs. +To develop a dynamic and interactive word-guessing game, we propose dividing the game process into two distinct programs. The first program will handle the core functionalities, such as selecting a random word from a list and evaluating guesses. The second program will manage user interactions, keep track of the game state, and enforce time constraints. This division aims to create a modular, flexible system that enhances the gaming experience. 1. **Description of the First Program**: - - The first program contains two main functions: "start the game" and "check the word." - - Inside the program, there's a word bank from which a random word is chosen at the beginning of the game. - - The "start the game" function initiates the beginning of the game and selects a random word from the word bank. - - The "check the word" function compares the word submitted by the user with the hidden word and provides information about the correct letter positions. + - Contains "start the game" and "check the word" functions. + - A word bank exists within the program for selecting a random word at the game's start. + - "Start the game" function initiates the game and selects a random word. + - "Check the word" function assesses the player's guess against the hidden word, providing feedback on correct letter positions. 2. **Description of the Second Program**: - - The second program is responsible for interacting with the first program and managing the gameplay. - - It should keep track of previous user responses and monitor the number of attempts. - - Additionally, the second program tracks time elapsed since the start of the game to manage time constraints and events. + - Manages interactions with the first program and oversees the gameplay. + - Tracks previous responses and the number of attempts. + - Monitors the elapsed time since the game started to manage time constraints and events. -3. **Interaction between the Programs**: - - The user starts the game by sending the appropriate message to the second program. - - The second program calls the "start the game" function of the first program. - - The user submits their guesses to the second program, which passes them to the "check the word" function of the first program. - - The first program returns information about the correctness of the guess and the positions of letters. - - The second program analyzes the result and takes further actions, including tracking the number of attempts and game time. +3. **Interaction Between the Programs**: + - The user initiates the game by sending a message to the second program. + - The second program invokes the first program's "start the game" function. + - The user submitts their guesses to the second program, which forwards them to the first program's "check the word" function. + - The first program returns feedback on the guess's accuracy and letter positions. + - The second program analyzes the result, tracking attempts and time. - 4. **Key Implementation Aspects**: - - The second program must have mechanisms for storing data about previous user moves and tracking time. - - To manage the gameplay, the second program must effectively interact with the first program by exchanging data and receiving responses. +4. **Key Implementation Aspects**: + - The second program requires mechanisms to store data about previous moves and track time. + - Efficient interaction with the first program through data exchange and response handling is crucial. -## First program +## First Program -The first program has already been implemented, let's look at its functionality. +The first program is already implemented. Its functionality includes: -Metadata will contain the following types of information: +Metadata contains: ```rust pub struct WordleMetadata; @@ -60,12 +60,12 @@ impl Metadata for WordleMetadata { } ``` -The program will have two functions: +Functions: -- `StartGame` - action to start the game; generates a random word and returns the reply as `GameStarted{user: ActorId}`; -- `CheckWord` - action to check the word and returns the reply as `WordChecked { user: ActorId, correct_positions: Vec,contained_in_word: Vec }`, where in the `correct_positions` returns the indices of letters that are in their place, and `contained_in_word` returns the indices of letters that are contained in the word but are in the wrong place. +- `StartGame` - starts the game, selects a random word and returns the reply as `GameStarted{user: ActorId}`. +- `CheckWord` - checks the word and returns the reply as `WordChecked { user: ActorId, correct_positions: Vec,contained_in_word: Vec }`, where in the `correct_positions` returns the indices of letters that are in their place, and `contained_in_word` returns the indices of letters that are contained in the word but are in the wrong place. -The whole code of the first programme looks as follows: +The complete code of the first program looks as follows: ```rust pub enum Action { @@ -168,49 +168,46 @@ pub fn get_random_value(range: u8) -> u8 { } ``` -For instance, consider a scenario where the secret word is *house*. If the user submits the word *human*, the correct_positions would be `[0]`, indicating that the letter "h" is in the correct position (at index 0) in the secret word. Also, `content_in_word` will be `[1]`, indicating that the letter "u" is present in the secret word, but not in the correct position. +For instance, consider a scenario where the secret word is *house*. If the user submits the word *human*, the `correct_positions` would be `[0]`, indicating that the letter "h" is in the correct position (at index 0) in the secret word. Also, `contained_in_word` will be `[1]`, indicating that the letter "u" is present in the secret word but not in the correct position. ![Example Homework](../img/05/example_hw_1.png) -Now, let's examine another scenario where the user inputs the word *horse*. In this case, correct_positions would be `[0, 1, 3, 4]`, indicating that the letters "h", "o", "s", and "e" are in the correct positions (at indices 0, 1, 3, and 4) in the secret word. However, `contained_in_word` would be empty. +Now, let's examine another scenario where the user inputs the word *horse*. In this case, `correct_positions` would be `[0, 1, 3, 4]`, indicating that the letters "h", "o", "s", and "e" are in the correct positions (at indices 0, 1, 3, and 4) in the secret word. However, `contained_in_word` would be empty. ![Example Homework](../img/05/example_hw_2.png) -Finally, if the user correctly guesses the secret word *house*, correct_positions would contain all indices from 0 to 4, indicating that all letters are in the correct positions. This signifies the end of the game. +Finally, if the user correctly guesses the secret word *house*, `correct_positions` would contain all indices from 0 to 4, indicating that all letters are in the correct positions. This signifies the end of the game. ![Example Homework](../img/05/example_hw_3.png) -Through these examples, we observe how the program evaluates user guesses and provides feedback based on the positions of correct letters in the secret word. +Through these examples, we see how the program evaluates user guesses and provides feedback based on the positions of correct letters in the secret word. ## The Homework Assignment -Your assignment is to create a second program that acts as an intermediary between the user and the first program. +Create a second program that interfaces between the user and the first program. -1. **Initialization Function (`init()`)**: - - This function should be created to receive the address of the first program and store it. +1. **Initialization Function (`init()`):** + - Receives and stores the first program's address. -2. **Handle Function (`handle()`)**: -`handle()` function must be able to handle three actions: `StartGame`, `CheckWord`, `CheckGameStatus`. +2. **Handle Function (`handle()`):** + - Manages actions: `StartGame`, `CheckWord`, `CheckGameStatus`. Let's examine the functionality of each action: -- StartGame: - +- `StartGame`: - The program checks if a game already exists for the user; - It sends a "StartGame" message to the first program; - Utilizes the `exec::wait()` or `exec::wait_for()` function to await a response; - - Sends a delayed message with action "CheckGameStatus" to monitor the game's progress (its logic will be described below); - - A reply is sent to notify the user that the game has successfully started. - -- CheckWord: + - Sends a delayed message with action `CheckGameStatus` to monitor the game's progress (its logic will be described below); + - A reply is sent to notify the user that the game has beeen successfully started. +- `CheckWord`: - Ensures that a game exists and is in the correct status; - Validates that the submitted word length is five and is in lowercase; - Sends a "CheckWord" message to the first program; - Utilizes the `exec::wait()` or `exec::wait_for()` function to await a reply; - Sends a reply to notify the user that the move was successful. -- CheckGameStatus: - +- `CheckGameStatus`: - The game should have a time limit from its start, so a delayed message is sent to check the game status. If the game is not finished within the specified time limit, it ends the game by transitioning it to the desired status. Specify a delay equal to 200 blocks (10 minutes) for the delayed message. @@ -219,20 +216,25 @@ Let's examine the functionality of each action: - Receives reply messages. - Utilizes `msg::reply_to()` to determine the message identifier, i.e., which message was replied to. - Processes and stores the result depending on the reply: - - If a "GameStarted" response is received, it updates the game status to indicate that the game was successfully started. - - If a "WordChecked" response is received, it saves the response, increments the number of tries, and checks if the word was guessed. If the word has been guessed, it switches the game status to "GameOver(Win)". If all attempts are used up and the word is not guessed, it switches the game status to "GameOver(Lose)". + - If a `GameStarted` response is received, it updates the game status to indicate that the game was successfully started. + - If a `WordChecked` response is received, it saves the response, increments the number of tries, and checks if the word was guessed. + - If the word has been guessed, it switches the game status to `GameOver(Win)`. + - If all attempts are used up and the word is not guessed, it switches the game status to `GameOver(Lose)`. - Calls `wake()` with the identifier of the received message to acknowledge the response. + +3. **Handle Reply Function (`handle_reply()`):** + - Processes reply messages and updates the game status based on responses from the first program. + 4. **State Function (`state()`)**: - It is necessary to implement the state() function in order to get all the information about the game. ## Testing -All program actions must be checked in tests using the [`gtest`](https://docs.gear.rs/gtest/) crate. - -- Check all strategies of the game program; -- Check delayed message logic; -- Check negative scenarios and handling of invalid inputs. +All program actions should be checked in tests using the [`gtest`](https://docs.gear.rs/gtest/) crate. +- Verify all strategies of the game program. +- Test the delayed message logic. +- Address negative scenarios and invalid inputs handling. ## Afterword diff --git a/docs/03-intermediate/index.md b/docs/03-intermediate/index.md index 4cb8d2f..d2e859d 100644 --- a/docs/03-intermediate/index.md +++ b/docs/03-intermediate/index.md @@ -5,4 +5,4 @@ hide_table_of_contents: true # Intermediate Course -This course is designed to delve deeper into the Program on Vara development. It is recommended to start with this course after completing the basic course. +This course offers a continuation of studies in the Program on Vara development, building upon the foundational knowledge acquired in the [basic course](https://academy.gear.foundation/courses/basic_course). It is designed for those who have completed the introductory level and are ready to delve deeper into the subject matter. \ No newline at end of file From 5766c60523d322ab64ba8d9465a4f42db7830f0e Mon Sep 17 00:00:00 2001 From: AndrePanin Date: Wed, 10 Apr 2024 12:13:34 +0200 Subject: [PATCH 2/2] removed pronounce --- docs/03-intermediate/02-message-receiving/handle_reply.md | 2 +- .../03-wait-wake-system/handle-reply-wait-wake.md | 4 ++-- .../04-delayed-message/delayed-message-example.md | 2 +- docs/03-intermediate/05-homework/assignment.md | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/03-intermediate/02-message-receiving/handle_reply.md b/docs/03-intermediate/02-message-receiving/handle_reply.md index 163e4f3..87d1344 100644 --- a/docs/03-intermediate/02-message-receiving/handle_reply.md +++ b/docs/03-intermediate/02-message-receiving/handle_reply.md @@ -7,7 +7,7 @@ hide_table_of_contents: true In this lesson, you will learn how a program can efficiently handle request messages. This concept will be illustrated through an example of interaction between two programs. -Before analyzing the program code in detail, it will be helpful to first present a schematic overview of how our programs operate: +Before analyzing the program code in detail, it will be helpful to first present a schematic overview of how Gear programs operate: ![gif 1](../img/02/handle_reply.gif) diff --git a/docs/03-intermediate/03-wait-wake-system/handle-reply-wait-wake.md b/docs/03-intermediate/03-wait-wake-system/handle-reply-wait-wake.md index 3b5192a..684ab20 100644 --- a/docs/03-intermediate/03-wait-wake-system/handle-reply-wait-wake.md +++ b/docs/03-intermediate/03-wait-wake-system/handle-reply-wait-wake.md @@ -5,7 +5,7 @@ hide_table_of_contents: true # Handle Reply with wait() and wake() -Now, let's apply our understanding of the `exec::wait()`/`exec::wake()` functions to enhance the program introduced in the previous lesson: +Now, let's apply understanding of the `exec::wait()`/`exec::wake()` functions to enhance the program introduced in the previous lesson: ![gif 2](../img/03/wait_wake.gif) @@ -60,7 +60,7 @@ extern "C" fn init() { } ``` -To gain a comprehensive understanding of the process, let's incorporate debugging into our program. +To gain a comprehensive understanding of the process, let's incorporate debugging into the program. ```rust #[no_mangle] diff --git a/docs/03-intermediate/04-delayed-message/delayed-message-example.md b/docs/03-intermediate/04-delayed-message/delayed-message-example.md index a13f1ca..c6fd326 100644 --- a/docs/03-intermediate/04-delayed-message/delayed-message-example.md +++ b/docs/03-intermediate/04-delayed-message/delayed-message-example.md @@ -5,7 +5,7 @@ hide_table_of_contents: true # Program with Delayed Message -Let's revise the program from the previous lesson, incorporating our knowledge about delayed messages. +Let's revise the program from the previous lesson, incorporating new knowledge about delayed messages. In this scenario, there are two types of messages: diff --git a/docs/03-intermediate/05-homework/assignment.md b/docs/03-intermediate/05-homework/assignment.md index f3b319f..dfeea0f 100644 --- a/docs/03-intermediate/05-homework/assignment.md +++ b/docs/03-intermediate/05-homework/assignment.md @@ -17,7 +17,7 @@ The game challenges players to guess the word with the fewest attempts, under ti ## Project Structure -To develop a dynamic and interactive word-guessing game, we propose dividing the game process into two distinct programs. The first program will handle the core functionalities, such as selecting a random word from a list and evaluating guesses. The second program will manage user interactions, keep track of the game state, and enforce time constraints. This division aims to create a modular, flexible system that enhances the gaming experience. +To develop a dynamic and interactive word-guessing game, divide the game process into two distinct programs. The first program will handle the core functionalities, such as selecting a random word from a list and evaluating guesses. The second program will manage user interactions, keep track of the game state, and enforce time constraints. This division aims to create a modular, flexible system that enhances the gaming experience. 1. **Description of the First Program**: - Contains "start the game" and "check the word" functions. @@ -180,7 +180,7 @@ Finally, if the user correctly guesses the secret word *house*, `correct_positio ![Example Homework](../img/05/example_hw_3.png) -Through these examples, we see how the program evaluates user guesses and provides feedback based on the positions of correct letters in the secret word. +Through these examples, one can see how the program evaluates user guesses and provides feedback based on the positions of correct letters in the secret word. ## The Homework Assignment