Skip to content

Commit 5793398

Browse files
feat: add from_hex_str for Bytes (#1205)
Co-authored-by: Ahmed Sagdati <[email protected]>
1 parent b9cac99 commit 5793398

File tree

8 files changed

+102
-0
lines changed

8 files changed

+102
-0
lines changed

docs/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
- [Structs and enums](./types/custom_types.md)
5454
- [String](./types/string.md)
5555
- [Bits256](./types/bits256.md)
56+
- [Bytes](./types/bytes.md)
5657
- [B512](./types/B512.md)
5758
- [EvmAddress](./types/evm_address.md)
5859
- [Vectors](./types/vectors.md)

docs/src/types/bytes.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Bytes
2+
3+
In Fuel, a type called `Bytes` represents a collection of tightly-packed bytes. The Rust SDK represents `Bytes` as `Bytes(Vec<u8>)`. Here's an example of using `Bytes` in a contract call:
4+
5+
```rust,ignore
6+
{{#include ../../../packages/fuels/tests/types_contracts.rs:bytes_arg}}
7+
```
8+
9+
If you have a hexadecimal value as a string and wish to convert it to `Bytes`, you may do so with `from_hex_str`:
10+
11+
```rust,ignore
12+
{{#include ../../../packages/fuels-core/src/types/core/bytes.rs:bytes_from_hex_str}}
13+
```

packages/fuels-core/src/types/core/bytes.rs

+48
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
1+
use crate::types::errors::{error, Result};
2+
13
#[derive(Debug, PartialEq, Clone, Eq)]
24
pub struct Bytes(pub Vec<u8>);
35

6+
impl Bytes {
7+
/// Create a new `Bytes` from a string representation of a hex.
8+
/// Accepts both `0x` prefixed and non-prefixed hex strings.
9+
pub fn from_hex_str(hex: &str) -> Result<Self> {
10+
let hex = if let Some(stripped_hex) = hex.strip_prefix("0x") {
11+
stripped_hex
12+
} else {
13+
hex
14+
};
15+
16+
let bytes = hex::decode(hex).map_err(|e| {
17+
error!(
18+
InvalidData,
19+
"Could not convert hex str '{hex}' to Bytes! {e}"
20+
)
21+
})?;
22+
23+
Ok(Bytes(bytes))
24+
}
25+
}
26+
427
impl From<Bytes> for Vec<u8> {
528
fn from(raw_slice: Bytes) -> Vec<u8> {
629
raw_slice.0
@@ -18,3 +41,28 @@ impl PartialEq<Bytes> for Vec<u8> {
1841
*self == other.0
1942
}
2043
}
44+
45+
#[cfg(test)]
46+
mod tests {
47+
use super::*;
48+
49+
#[test]
50+
fn from_hex_str_b256() -> Result<()> {
51+
// ANCHOR: bytes_from_hex_str
52+
let hex_str = "0101010101010101010101010101010101010101010101010101010101010101";
53+
54+
let bytes = Bytes::from_hex_str(hex_str)?;
55+
56+
assert_eq!(bytes.0, vec![1u8; 32]);
57+
58+
// With the `0x0` prefix
59+
let hex_str = "0x0101010101010101010101010101010101010101010101010101010101010101";
60+
61+
let bytes = Bytes::from_hex_str(hex_str)?;
62+
63+
assert_eq!(bytes.0, vec![1u8; 32]);
64+
// ANCHOR_END: bytes_from_hex_str
65+
66+
Ok(())
67+
}
68+
}

packages/fuels/Forc.toml

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ members = [
7979
'tests/types/predicates/address',
8080
'tests/types/predicates/enums',
8181
'tests/types/predicates/predicate_bytes',
82+
'tests/types/predicates/predicate_bytes_hash',
8283
'tests/types/predicates/predicate_generics',
8384
'tests/types/predicates/predicate_raw_slice',
8485
'tests/types/predicates/predicate_std_lib_string',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[project]
2+
authors = ["Fuel Labs <[email protected]>"]
3+
entry = "main.sw"
4+
license = "Apache-2.0"
5+
name = "predicate_bytes_hash"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
predicate;
2+
3+
use std::bytes::Bytes;
4+
use std::hash::{Hash, sha256};
5+
6+
fn main(bytes: Bytes, hash: b256) -> bool {
7+
sha256(bytes) == hash
8+
}

packages/fuels/tests/types_contracts.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1938,9 +1938,11 @@ async fn test_bytes_as_input() -> Result<()> {
19381938
let contract_methods = contract_instance.methods();
19391939

19401940
{
1941+
// ANCHOR: bytes_arg
19411942
let bytes = Bytes(vec![40, 41, 42]);
19421943

19431944
contract_methods.accept_bytes(bytes).call().await?;
1945+
// ANCHOR_END: bytes_arg
19441946
}
19451947
{
19461948
let bytes = Bytes(vec![40, 41, 42]);

packages/fuels/tests/types_predicates.rs

+24
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use fuels::{
55
prelude::*,
66
types::{coin::Coin, message::Message, unresolved_bytes::UnresolvedBytes, AssetId, U256},
77
};
8+
use fuels_core::types::Bits256;
89

910
async fn assert_predicate_spendable(
1011
data: UnresolvedBytes,
@@ -278,6 +279,29 @@ async fn spend_predicate_coins_messages_generics() -> Result<()> {
278279
Ok(())
279280
}
280281

282+
#[tokio::test]
283+
async fn spend_predicate_coins_messages_bytes_hash() -> Result<()> {
284+
abigen!(Predicate(
285+
name = "MyPredicate",
286+
abi = "packages/fuels/tests/types/predicates/predicate_bytes_hash/out/debug/predicate_bytes_hash-abi.json"
287+
288+
));
289+
290+
let bytes = Bytes::from_hex_str(
291+
"0x75a448b91bb82a255757e61ba3eb7afe282c09842485268d4d72a027ec0cffc80500000000",
292+
)?;
293+
294+
let bits256 = Bits256::from_hex_str(
295+
"0x173d69ea3d0aa050d01ff7cc60ccd4579b567c465cd115c6876c2da4a332fb99",
296+
)?;
297+
298+
let data = MyPredicateEncoder::encode_data(bytes, bits256);
299+
300+
assert_predicate_spendable(data, "tests/types/predicates/predicate_bytes_hash").await?;
301+
302+
Ok(())
303+
}
304+
281305
#[tokio::test]
282306
async fn spend_predicate_coins_messages_bytes() -> Result<()> {
283307
abigen!(Predicate(

0 commit comments

Comments
 (0)