You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There are two different ways we can approach this:
12
12
1. Read the first 4 pairs of characters and do some base math to determine the u32 integer.
13
-
2. Convert the transaction into a collection bytes first and then just work with the methods available for that type.
13
+
2. Convert the transaction into a collection of bytes first and then work with the methods available for that type.
14
14
15
-
Now that we have a basic understanding of hexadecimal format and bytes, we're going to take approach #2 and leverage an external library. It will be easier and more efficient to work with an array of `u8` integers to traverse the byte data, rather than read from a string and do unnecessary math. The library can handle the conversion for us. It will also be easier to work with as we decode the rest of the transaction.
15
+
Now that we have a basic understanding of hexadecimal format and bytes, we're going to take approach #2 and leverage an external library.
16
+
It will be easier and more efficient to work with an array of `u8` integers to traverse the byte sequence, rather than read from a string and do unnecessary math.
17
+
The library can handle the conversion for us.
18
+
It will also be easier to work with as we decode the rest of the transaction.
16
19
17
-
So the first thing we want to do is convert our hexadecimal string into a collection of bytes. We'll use the popular [`hex` crate](https://docs.rs/hex/latest/hex/).
20
+
The first thing we want to do is convert our hexadecimal string into a collection of bytes.
21
+
We'll use the popular [`hex` crate](https://docs.rs/hex/latest/hex/).
22
+
23
+
Let's add a dependency to our `Cargo.toml` file.
24
+
Note the `hex` crate set to version `0.4` at the bottom under the `[dependencies]` section:
18
25
19
-
Let's add a dependency to our `Cargo.toml` file. Note the `hex` crate set to version `0.4` at the bottom under the `[dependencies]` section:
20
26
```toml
21
27
[package]
22
28
name = "bitcoin-transaction-decoder"
@@ -29,9 +35,11 @@ edition = "2021"
29
35
hex = "0.4"
30
36
```
31
37
32
-
Now, the hex library's top-level module `hex` should be available to use in our `main.rs` file. *Note: As we'll see in future sections of this course, if we want to use submodules of a crate, we'll have to import them with a `use` statement.*
38
+
Now, the hex library's top-level module `hex` should be available to use in our `main.rs` file.
39
+
*Note: As we'll see in future sections of this course, if we want to use submodules of a crate, we'll have to import them with a `use` statement.*
33
40
34
41
If we look through the documentation at https://docs.rs/hex/latest/hex/, we see that we can convert the hex to bytes by calling the `decode` method from the `hex` module like so:
We'll keep returning `1` at the bottom of the function for now so the compiler doesn't complain a `u32` wasn't returned. *Note: Rust will simply return the last expression without a semi-colon so the `return` keyword is not needed.*
44
-
45
-
Let's run this now and see what happens. Run `$ cargo run` from the terminal.
51
+
We'll keep returning `1` at the bottom of the function for now so the compiler doesn't complain a `u32` wasn't returned.
52
+
*Note: Rust will simply return the last expression without a semi-colon so the `return` keyword is not needed.*
53
+
Let's run this now and see what happens.
54
+
Execute `$ cargo run` from the terminal.
46
55
47
-
So far, so good. That should compile fine. Let's now get the first 4 bytes from the returned collection. The returned data is a `vec` - short for Vector - which is something like a `list` in Python or an array in javascript. Of course, it's more nuanced in Rust. We'll dive deeper into some of the differences in the next few lessons. But with a `vec` we can grab the first 4 items doing something like `vec[0..4]` where `0..4` represents a range from 0 to 4, not including 4. This might be a pattern you're already familiar with.
56
+
So far, so good.
57
+
That should compile fine.
58
+
Let's now get the first 4 bytes from the returned collection.
59
+
The returned data is a `vec` - short for Vector - which is something like a `list` in Python or an array in javascript.
60
+
Of course, it's more nuanced in Rust.
61
+
We'll dive deeper into some of the differences in the next few lessons.
62
+
With a `vec` we can grab the first 4 items by doing something like `vec[0..4]` where `0..4` represents a range from 0 to 4, not including 4.
63
+
This might be a pattern you're already familiar with.
What happens when we run `$ cargo run`? Well, we get an error. Take some time to read through it. You should see something like the following:
76
+
What happens when we execute `$ cargo run`?
77
+
78
+
Well, we get an error.
79
+
Take some time to read through it.
80
+
You should see something like the following:
81
+
61
82
```console
62
83
error[E0608]: cannot index into a value of type `Result<Vec<u8>, FromHexError>`
63
84
```
64
85
65
-
Let's examine what `hex::decode` returns. [Here is the doc](https://docs.rs/hex/latest/hex/fn.decode.html) for the `decode` method. Remember, we want to work with a Vector of bytes so a `vec<u8>` is the data type we're looking for. However, if we look at the return type of the `decode` function we see that the data structure we want is wrapped *inside* of a `Result` type.
86
+
Let's examine what `hex::decode` returns.
87
+
[Here is the doc](https://docs.rs/hex/latest/hex/fn.decode.html) for the `decode` method.
88
+
Remember, we want to work with a Vector of bytes so a `vec<u8>` is the data type we're looking for.
89
+
However, if we look at the return type of the `decode` function we see that the data structure we want is wrapped *inside* of a `Result` type.
66
90
67
-
The `Result` type is a common `enum` that you will see in Rust code. Enums are a way to describe a mutually exclusive set of options for a particular variable. If you think about it, it's possible that the `hex::decode` function fails to return a proper collection of bytes. For example, what if one of the characters is not a hex character? So we get two possibilities from a `Result`, an `Ok` response or an `Err` response.
91
+
The `Result` type is a common `enum` that you will see in Rust code.
92
+
Enums are a way to describe a mutually exclusive set of values for a particular variable.
93
+
If you think about it, the `hex::decode` function can fail to return a proper collection of bytes.
94
+
For example, what if one of the characters is not a hex character?
95
+
So we get two possibilities from a `Result`, an `Ok` response or an `Err` response.
96
+
The former represents a successful computation whereas the latter indicates an error occurred.
68
97
69
-
So how should we work with this? There are a few different ways to work with an enum. We'll explore different ways of handling a `Result` later on in this course, but for now we'll use the `unwrap` method. Every `Result` enum has an [`unwrap`](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap) method that you can call. This will return the underlying data type if the result is an `Ok` type or it will `panic` and the program will crash if the result is an `Err` type. Crashing your program is probably not the best way to handle an error, unless you're confident that an `Err` result *should* not be possible. But we'll look into better ways of error handling later on.
98
+
There are a few different ways to work with an enum.
99
+
Every `Result` enum has an [`unwrap`](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap) method that you can call.
100
+
This will return the underlying data type if the result is an `Ok` type or it will `panic` and the program will crash if the result is an `Err` type.
101
+
Crashing your program is probably not the best way to handle an error, unless you're confident that an `Err` result *should* not be possible.
102
+
For now we'll use the `unwrap` method.
103
+
We'll explore different ways of handling a `Result` and doing proper error handling later on in this course.
104
+
105
+
For now, let's our function so that we are actually working with the underlying vector of bytes and not the wrapped `Result` type:
70
106
71
-
For now, let's update this so that we are actually working with the underlying vector of bytes and not the wrapped `Result` type:
How does the program run now? Let's see by running `cargo run`.
116
+
How does the program run now?
117
+
Let's see by running `cargo run`.
82
118
83
119
We're going to get another compile error and it's going to be a confusing one:
84
-
`error[E0277]: the size for values of type [u8] cannot be known at compilation time`
85
120
86
-
This will make more sense as we develop a better understanding of the difference between arrays, slices and vectors in Rust as well as the difference between the stack and the heap. We'll get a better handle on these concepts as we continue on in the course, but let's get a brief overview of these concepts in the next lesson.
121
+
```console
122
+
error[E0277]: the size for values of type [u8] cannot be known at compilation time
123
+
```
124
+
125
+
This will make more sense as we develop a better understanding of the difference between arrays, slices and vectors in Rust as well as the difference between the stack and the heap.
126
+
Let's get a brief overview of these concepts in the next lesson.
87
127
88
128
### Quiz
89
-
*Notice the last line of this function. What will the compiler complain is wrong with this function? And why?*
129
+
*Notice the last line of this function.
130
+
What will the compiler complain is wrong with this function?
0 commit comments