@@ -14,11 +14,9 @@ description:
14
14
15
15
## Summary
16
16
17
- - Most programs support ** multiple discrete instruction handlers** - you decide
18
- when writing your program what these instruction handlers are and what data
19
- must accompany them when writing your program what these instruction handlers
20
- are and what data
21
- - Rust ** enums** are often used to represent discrete program instruction
17
+ - Most programs support ** multiple discrete instruction handlers** (sometimes
18
+ just referred to as 'instructions') - these are functions inside your program
19
+ - Rust ** enums** are often used to represent each instruction handler
22
20
- You can use the ` borsh ` crate and the ` derive ` attribute to provide Borsh
23
21
deserialization and serialization functionality to Rust structs
24
22
- Rust ` match ` expressions help create conditional code paths based on the
@@ -27,18 +25,18 @@ description:
27
25
## Lesson
28
26
29
27
One of the most basic elements of a Solana program is the logic for handling
30
- instruction data. Most programs support multiple related functions and use
31
- differences in instruction data to determine which code path to execute. For
32
- example, two different data formats in the instruction data passed to the
33
- program may represent instructions for creating a new piece of data vs deleting
34
- the same piece of data .
28
+ instruction data. Most programs support multiple functions, also called
29
+ instruction handlers. For example, a program may have different instruction
30
+ handlers for creating a new piece of data versus deleting the same piece of
31
+ data. Programs use differences in instruction data to determine which
32
+ instruction handler to execute .
35
33
36
34
Since instruction data is provided to your program's entry point as a byte
37
35
array, it's common to create a Rust data type to represent instructions in a way
38
36
that's more usable throughout your code. This lesson will walk through how to
39
37
set up such a type, how to deserialize the instruction data into this format,
40
- and how to execute the proper code path based on the instruction passed into the
41
- program's entry point.
38
+ and how to execute the proper instruction handler based on the instruction
39
+ passed into the program's entry point.
42
40
43
41
### Rust basics
44
42
@@ -53,10 +51,10 @@ Variable assignment in Rust happens with the `let` keyword.
53
51
let age = 33 ;
54
52
```
55
53
56
- Variables in Rust by default are immutable, meaning a variable's value cannot be
57
- changed once it has been set. To create a variable that we'd like to change at
58
- some point in the future, we use the ` mut ` keyword. Defining a variable with
59
- this keyword means that the value stored in it can change.
54
+ By default, variables in Rust are immutable, meaning a variable's value cannot
55
+ be changed once it has been set. To create a variable that we'd like to change
56
+ at some point in the future, we use the ` mut ` keyword. Defining a variable with
57
+ this keyword means that its stored value can change.
60
58
61
59
``` rust
62
60
// compiler will throw error
@@ -68,15 +66,15 @@ let mut mutable_age = 33;
68
66
mutable_age = 34 ;
69
67
```
70
68
71
- The Rust compiler guarantees that immutable variables truly cannot change so
72
- that you don’t have to keep track of it yourself. This makes your code easier to
73
- reason through and simplifies debugging.
69
+ The Rust compiler guarantees that immutable variables cannot change, so you
70
+ don’t have to keep track of it yourself. This makes your code easier to reason
71
+ through and simplifies debugging.
74
72
75
73
#### Structs
76
74
77
75
A struct, or structure, is a custom data type that lets you package together and
78
76
name multiple related values that make up a meaningful group. Each piece of data
79
- in a struct can be of different types and each has a name associated with it.
77
+ in a struct can be of different types, and each has a name associated with it.
80
78
These pieces of data are called ** fields** . They behave similarly to properties
81
79
in other languages.
82
80
@@ -117,8 +115,8 @@ enum LightStatus {
117
115
}
118
116
```
119
117
120
- The ` LightStatus ` enum has two possible variants in this situation: it's either
121
- ` On ` or ` Off ` .
118
+ The ` LightStatus ` enum has two possible variants in this situation: it's
119
+ either ` On ` or ` Off ` .
122
120
123
121
You can also embed values into enum variants, similar to adding fields to a
124
122
struct.
@@ -139,10 +137,10 @@ requires also setting the value of `color`.
139
137
140
138
#### Match statements
141
139
142
- Match statements are very similar to ` switch ` statements in C/C++ . The ` match `
143
- statement allows you to compare a value against a series of patterns and then
144
- execute code based on which pattern matches the value. Patterns can be made of
145
- literal values, variable names, wildcards, and more. The match statement must
140
+ Match statements are very similar to ` switch ` statements in other languages . The
141
+ ` match ` statement allows you to compare a value against a series of patterns and
142
+ then execute code based on which pattern matches the value. Patterns can be made
143
+ of literal values, variable names, wildcards, and more. The match statement must
146
144
include all possible scenarios, otherwise the code will not compile.
147
145
148
146
``` rust
@@ -206,9 +204,9 @@ example.answer();
206
204
#### Traits and attributes
207
205
208
206
You won't be creating your own traits or attributes at this stage, so we won't
209
- provide an in depth explanation of either. However, you will be using the
207
+ provide an in- depth explanation of either. However, you will be using the
210
208
` derive ` attribute macro and some traits provided by the ` borsh ` crate, so it's
211
- important you have a high level understanding of each.
209
+ important you have a high- level understanding of each.
212
210
213
211
Traits describe an abstract interface that types can implement. If a trait
214
212
defines a function ` bark() ` and a type then adopts that trait, the type must
@@ -227,10 +225,10 @@ concrete example of this shortly.
227
225
228
226
Now that we've covered the Rust basics, let's apply them to Solana programs.
229
227
230
- More often than not, programs will have more than one function . For example, you
231
- may have a program that acts as the backend for a note-taking app. Assume this
232
- program accepts instructions for creating a new note, updating an existing note,
233
- and deleting an existing note.
228
+ More often than not, programs will have more than one instruction handler . For
229
+ example, you may have a program that acts as the backend for a note-taking app.
230
+ Assume this program accepts instructions for creating a new note, updating an
231
+ existing note, and deleting an existing note.
234
232
235
233
Since instructions have discrete types, they're usually a great fit for an enum
236
234
data type.
@@ -293,18 +291,18 @@ accepts the instruction data as an argument and returns the appropriate instance
293
291
of the enum with the deserialized data.
294
292
295
293
It's standard practice to structure your program to expect the first byte (or
296
- other fixed number of bytes) to be an identifier for which instruction the
297
- program should run. This could be an integer or a string identifier. For this
298
- example, we'll use the first byte and map integers 0, 1, and 2 to instructions
299
- create, update, and delete, respectively.
294
+ other fixed number of bytes) to be an identifier for which instruction handler
295
+ the program should run. This could be an integer or a string identifier. For
296
+ this example, we'll use the first byte and map integers 0, 1, and 2 to the
297
+ instruction handlers for create, update, and delete, respectively.
300
298
301
299
``` rust
302
300
impl NoteInstruction {
303
301
// Unpack inbound buffer to associated Instruction
304
302
// The expected format for input is a Borsh serialized vector
305
303
pub fn unpack (input : & [u8 ]) -> Result <Self , ProgramError > {
306
304
// Take the first byte as the variant to
307
- // determine which instruction to execute
305
+ // determine which instruction handler to execute
308
306
let (& variant , rest ) = input . split_first (). ok_or (ProgramError :: InvalidInstructionData )? ;
309
307
// Use the temporary payload struct to deserialize
310
308
let payload = NoteInstructionPayload :: try_from_slice (rest ). unwrap ();
@@ -380,7 +378,7 @@ pub fn process_instruction(
380
378
For simple programs where there are only one or two instructions to execute, it
381
379
may be fine to write the logic inside the match statement. For programs with
382
380
many different possible instructions to match against, your code will be much
383
- more readable if the logic for each instruction is written in a separate
381
+ more readable if the logic for each instruction handler is written in a separate
384
382
function and simply called from inside the ` match ` statement.
385
383
386
384
### Program file structure
@@ -391,11 +389,11 @@ important to maintain a project structure that remains readable and extensible.
391
389
This involves encapsulating code into functions and data structures as we've
392
390
done so far. But it also involves grouping related code into separate files.
393
391
394
- For example, a good portion of the code we've worked through so far has to do
395
- with defining and deserializing instructions. That code should live in its own
396
- file rather than be written in the same file as the entry point. By doing so, we
397
- would then have 2 files, one with the program entry point and the other with the
398
- instruction code :
392
+ For example, a good portion of the code we've worked through so far involves
393
+ defining and deserializing instructions. That code should live in its own file
394
+ rather than be written in the same file as the entry point. By doing so, we
395
+ would then have two files, one with the program entry point and the other with
396
+ the instruction handler :
399
397
400
398
- ** lib.rs**
401
399
- ** instruction.rs**
@@ -541,11 +539,11 @@ pub mod instruction;
541
539
use instruction :: {MovieInstruction };
542
540
```
543
541
544
- Next, let's define a new function ` add_movie_review ` that takes as arguments
542
+ Next, let's define a new function ` add_movie_review ` that takes the arguments
545
543
` program_id ` , ` accounts ` , ` title ` , ` rating ` , and ` description ` . It should also
546
- return an instance of ` ProgramResult ` Inside this function, let's simply log our
547
- values for now and we'll revisit the rest of the implementation of the function
548
- in the next lesson.
544
+ return an instance of ` ProgramResult ` . Inside this function, let's simply log
545
+ our values for now and we'll revisit the rest of the implementation of the
546
+ function in the next lesson.
549
547
550
548
``` rust
551
549
pub fn add_movie_review (
@@ -596,7 +594,7 @@ instruction data passed in when a transaction is submitted!
596
594
Build and deploy your program from Solana Program just like in the last lesson.
597
595
If you haven't changed the program ID since going through the last lesson, it
598
596
will automatically deploy to the same ID. If you'd like it to have a separate
599
- address you can generate a new program ID from the playground before deploying.
597
+ address, you can generate a new program ID from the playground before deploying.
600
598
601
599
You can test your program by submitting a transaction with the right instruction
602
600
data. For that, feel free to use
0 commit comments