Skip to content

Commit be5ecbd

Browse files
bitzoicironcev
andauthored
Implement TryFrom<Bytes> for b256 (#6958)
## Description `impl From<Bytes> for b256` has been removed and replaced with `impl TryFrom<Bytes> for b256` increasing saftey when converting between the two types. `impl Into<Bytes> for b256` and `impl TryInto<b256> for Bytes` have also been added. This PR breaks the following implementation: ```sway let mut my_bytes = Bytes::new(); my_bytes.push(1u8); let result: b256 = b256::from(my_bytes); ``` The implementation should now be: ```sway let mut my_bytes = Bytes::new(); my_bytes.push(1u8); // Option 1 let result_1: Option<b256> = b256::try_from(my_bytes); // Option 2 let result_2 = my_bytes.try_into(); ``` Closes #6994. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: Igor Rončević <ironcev@hotmail.com>
1 parent ba46576 commit be5ecbd

File tree

7 files changed

+197
-1
lines changed

7 files changed

+197
-1
lines changed

.github/workflows/ci.yml

+10
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,10 @@ jobs:
485485
run: cargo run --locked --release -p forc -- build --experimental partial_eq --release --locked --path ./test/src/sdk-harness
486486
- name: Cargo Test sway-lib-std - Experimental Feature 'partial_eq'
487487
run: cargo test --locked --release --manifest-path ./test/src/sdk-harness/Cargo.toml -- --nocapture
488+
- name: Build All Tests - Experimental Feature 'try_from_bytes_for_b256'
489+
run: cargo run --locked --release -p forc -- build --experimental try_from_bytes_for_b256 --release --locked --path ./test/src/sdk-harness
490+
- name: Cargo Test sway-lib-std - Experimental Feature 'try_from_bytes_for_b256'
491+
run: cargo test --locked --release --manifest-path ./test/src/sdk-harness/Cargo.toml -- --nocapture
488492

489493
forc-run-benchmarks:
490494
runs-on: buildjet-4vcpu-ubuntu-2204
@@ -555,6 +559,8 @@ jobs:
555559
run: forc build --experimental error_type --path sway-lib-core && forc test --experimental error_type --path sway-lib-core
556560
- name: Run Core Unit Tests - Experimental feature 'partial_eq'
557561
run: forc build --experimental partial_eq --path sway-lib-core && forc test --experimental partial_eq --path sway-lib-core
562+
- name: Run Core Unit Tests - Experimental feature 'try_from_bytes_for_b256'
563+
run: forc build --experimental try_from_bytes_for_b256 --path sway-lib-core && forc test --experimental try_from_bytes_for_b256 --path sway-lib-core
558564
- name: Run Std Unit Tests
559565
run: forc build --path sway-lib-std && forc test --path sway-lib-std
560566
- name: Run Std Unit Tests - Experimental feature 'storage_domains'
@@ -563,6 +569,8 @@ jobs:
563569
run: forc build --experimental error_type --path sway-lib-std && forc test --experimental error_type --path sway-lib-std
564570
- name: Run Std Unit Tests - Experimental feature 'partial_eq'
565571
run: forc build --experimental partial_eq --path sway-lib-std && forc test --experimental partial_eq --path sway-lib-std
572+
- name: Run Std Unit Tests - Experimental feature 'try_from_bytes_for_b256'
573+
run: forc build --experimental try_from_bytes_for_b256 --path sway-lib-std && forc test --experimental try_from_bytes_for_b256 --path sway-lib-std
566574
- name: Run In Language Unit Tests
567575
run: forc build --path test/src/in_language_tests && forc test --path test/src/in_language_tests
568576
- name: Run In Language Unit Tests - Experimental feature 'storage_domains'
@@ -571,6 +579,8 @@ jobs:
571579
run: forc build --experimental error_type --path test/src/in_language_tests && forc test --experimental error_type --path test/src/in_language_tests
572580
- name: Run In Language Unit Tests - Experimental feature 'partial_eq'
573581
run: forc build --experimental partial_eq --path test/src/in_language_tests && forc test --experimental partial_eq --path test/src/in_language_tests
582+
- name: Run In Language Unit Tests - Experimental feature 'try_from_bytes_for_b256'
583+
run: forc build --experimental try_from_bytes_for_b256 --path test/src/in_language_tests && forc test --experimental try_from_bytes_for_b256 --path test/src/in_language_tests
574584

575585
forc-pkg-fuels-deps-check:
576586
runs-on: buildjet-4vcpu-ubuntu-2204

sway-features/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ features! {
177177
"https://github.com/FuelLabs/sway/issues/6883",
178178
const_generics = false,
179179
"https://github.com/FuelLabs/sway/issues/6860",
180+
try_from_bytes_for_b256 = false,
181+
"https://github.com/FuelLabs/sway/issues/6994",
180182
}
181183

182184
#[derive(Clone, Debug, Default, Parser)]

sway-lib-std/src/bytes.sw

+40
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,7 @@ impl From<b256> for Bytes {
10051005
}
10061006
}
10071007

1008+
#[cfg(experimental_try_from_bytes_for_b256 = false)]
10081009
impl From<Bytes> for b256 {
10091010
// NOTE: this cas be lossy! Added here as the From trait currently requires it,
10101011
// but the conversion from `Bytes` ->`b256` should be implemented as
@@ -1019,6 +1020,45 @@ impl From<Bytes> for b256 {
10191020
}
10201021
}
10211022

1023+
#[cfg(experimental_try_from_bytes_for_b256 = true)]
1024+
impl TryFrom<Bytes> for b256 {
1025+
fn try_from(bytes: Bytes) -> Option<Self> {
1026+
if bytes.len() != 32 {
1027+
return None;
1028+
}
1029+
let mut value = 0x0000000000000000000000000000000000000000000000000000000000000000;
1030+
let ptr = __addr_of(value);
1031+
bytes.buf.ptr().copy_to::<b256>(ptr, 1);
1032+
1033+
Some(value)
1034+
}
1035+
}
1036+
1037+
impl Into<Bytes> for b256 {
1038+
fn into(self) -> Bytes {
1039+
// Artificially create bytes with capacity and len
1040+
let mut bytes = Bytes::with_capacity(32);
1041+
bytes.len = 32;
1042+
// Copy bytes from contract_id into the buffer of the target bytes
1043+
__addr_of(self).copy_bytes_to(bytes.buf.ptr, 32);
1044+
1045+
bytes
1046+
}
1047+
}
1048+
1049+
impl TryInto<b256> for Bytes {
1050+
fn try_into(self) -> Option<b256> {
1051+
if self.len != 32 {
1052+
return None;
1053+
}
1054+
let mut value = 0x0000000000000000000000000000000000000000000000000000000000000000;
1055+
let ptr = __addr_of(value);
1056+
self.buf.ptr().copy_to::<b256>(ptr, 1);
1057+
1058+
Some(value)
1059+
}
1060+
}
1061+
10221062
impl From<raw_slice> for Bytes {
10231063
/// Creates a `Bytes` from a `raw_slice`.
10241064
///

sway-lib-std/src/bytes_conversions/b256.sw

+33
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,41 @@ impl b256 {
141141
/// assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20);
142142
/// }
143143
/// ```
144+
#[cfg(experimental_try_from_bytes_for_b256 = false)]
144145
pub fn from_be_bytes(bytes: Bytes) -> Self {
145146
assert(bytes.len() == 32);
146147
bytes.into()
147148
}
149+
150+
/// Converts a sequence of big-endian bytes to a `b256`.
151+
///
152+
/// # Arguments
153+
///
154+
/// * `bytes`: [Bytes] - The 32 bytes that compose the `b256`.
155+
///
156+
/// # Returns
157+
///
158+
/// * [b256] - The resulting `b256` value.
159+
///
160+
/// # Examples
161+
///
162+
/// ```sway
163+
/// fn foo() {
164+
/// let mut bytes = Bytes::with_capacity(32);
165+
/// let mut i: u8 = 0;
166+
/// while i < 32_u8 {
167+
/// bytes.push(i + 1);
168+
/// i += 1_u8;
169+
/// }
170+
///
171+
/// let x = b256::from_be_bytes(bytes);
172+
///
173+
/// assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20);
174+
/// }
175+
/// ```
176+
#[cfg(experimental_try_from_bytes_for_b256 = true)]
177+
pub fn from_be_bytes(bytes: Bytes) -> Self {
178+
assert(bytes.len() == 32);
179+
bytes.try_into().unwrap()
180+
}
148181
}

sway-lib-std/src/bytes_conversions/u256.sw

+36
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,47 @@ impl u256 {
144144
/// assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20_u256);
145145
/// }
146146
/// ```
147+
#[cfg(experimental_try_from_bytes_for_b256 = false)]
147148
pub fn from_be_bytes(bytes: Bytes) -> Self {
148149
assert(bytes.len() == 32);
149150
let b: b256 = bytes.into();
150151
asm(r1: b) {
151152
r1: u256
152153
}
153154
}
155+
156+
/// Converts a sequence of big-endian bytes to a `u256`.
157+
///
158+
/// # Arguments
159+
///
160+
/// * `bytes`: [Bytes] - The 32 bytes that compose the `u256`.
161+
///
162+
/// # Returns
163+
///
164+
/// * [u256] - The resulting `u256` value.
165+
///
166+
/// # Examples
167+
///
168+
/// ```sway
169+
/// fn foo() {
170+
/// let mut bytes = Bytes::with_capacity(32);
171+
/// let mut i: u8 = 0;
172+
/// while i < 32_u8 {
173+
/// bytes.push(i + 1);
174+
/// i += 1_u8;
175+
/// }
176+
///
177+
/// let x = u256::from_be_bytes(bytes);
178+
///
179+
/// assert(x == 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20_u256);
180+
/// }
181+
/// ```
182+
#[cfg(experimental_try_from_bytes_for_b256 = true)]
183+
pub fn from_be_bytes(bytes: Bytes) -> Self {
184+
assert(bytes.len() == 32);
185+
let b: b256 = bytes.try_into().unwrap();
186+
asm(r1: b) {
187+
r1: u256
188+
}
189+
}
154190
}

test/src/e2e_vm_tests/test_programs/should_fail/invalid_cfg_arg/stdout.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ warning
1111
|
1212
1 | predicate;
1313
2 | #[cfg(c)] a
14-
| --- Unexpected attribute value: "c" for attribute: "cfg" expected value "target" or "program_type" or "experimental_new_encoding" or "experimental_storage_domains" or "experimental_references" or "experimental_error_type" or "experimental_partial_eq" or "experimental_const_generics"
14+
| --- Unexpected attribute value: "c" for attribute: "cfg" expected value "target" or "program_type" or "experimental_new_encoding" or "experimental_storage_domains" or "experimental_references" or "experimental_error_type" or "experimental_partial_eq" or "experimental_const_generics" or "experimental_try_from_bytes_for_b256"
1515
|
1616
____
1717

test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw

+75
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,7 @@ fn bytes_from_b256() {
864864
}
865865

866866
#[test]
867+
#[cfg(experimental_try_from_bytes_for_b256 = false)]
867868
fn bytes_into_b256() {
868869
let mut initial_bytes = Bytes::with_capacity(32);
869870

@@ -881,6 +882,44 @@ fn bytes_into_b256() {
881882
}
882883

883884
#[test]
885+
#[cfg(experimental_try_from_bytes_for_b256 = true)]
886+
fn bytes_try_into_b256() {
887+
let mut initial_bytes = Bytes::with_capacity(32);
888+
889+
let mut i = 0;
890+
while i < 32 {
891+
// 0x33 is 51 in decimal
892+
initial_bytes.push(51u8);
893+
i += 1;
894+
}
895+
896+
let value: b256 = initial_bytes.try_into().unwrap();
897+
let expected: b256 = 0x3333333333333333333333333333333333333333333333333333333333333333;
898+
899+
assert(value == expected);
900+
901+
let empty_bytes = Bytes::new();
902+
let empty_result: Option<b256> = empty_bytes.try_into();
903+
assert(empty_result.is_none());
904+
905+
let mut small_bytes = Bytes::new();
906+
small_bytes.push(1u8);
907+
let small_result: Option<b256> = small_bytes.try_into();
908+
assert(small_result.is_none());
909+
910+
let mut large_bytes = Bytes::new();
911+
let mut i = 0;
912+
while i < 33 {
913+
// 0x33 is 51 in decimal
914+
large_bytes.push(51u8);
915+
i += 1;
916+
}
917+
let large_result: Option<b256> = large_bytes.try_into();
918+
assert(large_result.is_none());
919+
}
920+
921+
#[test]
922+
#[cfg(experimental_try_from_bytes_for_b256 = false)]
884923
fn bytes_b256_from() {
885924
let control = 0x3333333333333333333333333333333333333333333333333333333333333333;
886925
let mut bytes = Bytes::with_capacity(32);
@@ -897,6 +936,42 @@ fn bytes_b256_from() {
897936
assert(result_b256 == control);
898937
}
899938

939+
#[test]
940+
#[cfg(experimental_try_from_bytes_for_b256 = true)]
941+
fn bytes_b256_try_from() {
942+
let control = 0x3333333333333333333333333333333333333333333333333333333333333333;
943+
let mut bytes = Bytes::with_capacity(32);
944+
945+
let mut i = 0;
946+
while i < 32 {
947+
// 0x33 is 51 in decimal
948+
bytes.push(51u8);
949+
i += 1;
950+
}
951+
952+
let result_b256: b256 = b256::try_from(bytes).unwrap();
953+
assert(result_b256 == control);
954+
955+
let empty_bytes = Bytes::new();
956+
let empty_result = b256::try_from(empty_bytes);
957+
assert(empty_result.is_none());
958+
959+
let mut small_bytes = Bytes::new();
960+
small_bytes.push(1u8);
961+
let small_result = b256::try_from(small_bytes);
962+
assert(small_result.is_none());
963+
964+
let mut large_bytes = Bytes::new();
965+
let mut i = 0;
966+
while i < 33 {
967+
// 0x33 is 51 in decimal
968+
large_bytes.push(51u8);
969+
i += 1;
970+
}
971+
let large_result = b256::try_from(large_bytes);
972+
assert(large_result.is_none());
973+
}
974+
900975
#[test]
901976
fn bytes_b256_into() {
902977
let initial = 0x3333333333333333333333333333333333333333333333333333333333333333;

0 commit comments

Comments
 (0)