diff --git a/docs/book/src/basics/built_in_types.md b/docs/book/src/basics/built_in_types.md index 3ea05f5cda1..f7e500589b2 100644 --- a/docs/book/src/basics/built_in_types.md +++ b/docs/book/src/basics/built_in_types.md @@ -17,6 +17,7 @@ Sway has the following primitive types: 1. `u16` (16-bit unsigned integer) 1. `u32` (32-bit unsigned integer) 1. `u64` (64-bit unsigned integer) +1. `u256` (256-bit unsigned integer) 1. `str[]` (fixed-length string) 1. `str` (string slices) 1. `bool` (Boolean `true` or `false`) @@ -44,12 +45,14 @@ Numbers can be declared with binary syntax, hexadecimal syntax, base-10 syntax, The default numeric type is `u64`. The FuelVM's word size is 64 bits, and the cases where using a smaller numeric type saves space are minimal. -If a 64-bit arithmetic operation produces an overflow or an underflow, +If a 64-bit or 256-bit arithmetic operation produces an overflow or an underflow, computation gets reverted automatically by FuelVM. 8/16/32-bit arithmetic operations are emulated using their 64-bit analogues with additional overflow/underflow checks inserted, which generally results in somewhat higher gas consumption. + +The same does not happen with 256-bit operations, including `b256`, which uses specialized operations and are as performant as possible. ## Boolean Type diff --git a/docs/book/src/basics/comments_and_logging.md b/docs/book/src/basics/comments_and_logging.md index e59d44d61b1..0ed7fbc93fe 100644 --- a/docs/book/src/basics/comments_and_logging.md +++ b/docs/book/src/basics/comments_and_logging.md @@ -81,7 +81,7 @@ Note that `ra` will include the value being logged. The additional registers `rc -`LogData` is generated for _reference_ types which include all types except for _non_reference_ types. +`LogData` is generated for _reference_ types which include all types except for _non_reference_ types; and for _non-reference_ types bigger than 64-bit integers, for example, `u256`; For example, logging a `b256` variable `b` that holds the value `0x1111111111111111111111111111111111111111111111111111111111111111` using `log(b)` may generate the following receipt: diff --git a/docs/book/src/reference/compiler_intrinsics.md b/docs/book/src/reference/compiler_intrinsics.md index 63c849f2992..ebeda03ac06 100644 --- a/docs/book/src/reference/compiler_intrinsics.md +++ b/docs/book/src/reference/compiler_intrinsics.md @@ -80,7 +80,7 @@ __eq(lhs: T, rhs: T) -> bool **Description:** Returns whether `lhs` and `rhs` are equal. -**Constraints:** `T` is `bool`, `u8`, `u16`, `u32`, `u64`, or `raw_ptr`. +**Constraints:** `T` is `bool`, `u8`, `u16`, `u32`, `u64`, `u256`, `b256` or `raw_ptr`. ___ @@ -90,7 +90,7 @@ __gt(lhs: T, rhs: T) -> bool **Description:** Returns whether `lhs` is greater than `rhs`. -**Constraints:** `T` is `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is `u8`, `u16`, `u32`, `u64`, `u256`, `b256`. ___ ```sway @@ -99,7 +99,7 @@ __lt(lhs: T, rhs: T) -> bool **Description:** Returns whether `lhs` is less than `rhs`. -**Constraints:** `T` is `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is `u8`, `u16`, `u32`, `u64`, `u256`, `b256`. ___ ```sway @@ -178,7 +178,7 @@ __add(lhs: T, rhs: T) -> T **Description:** Adds `lhs` and `rhs` and returns the result. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`. ___ @@ -188,7 +188,7 @@ __sub(lhs: T, rhs: T) -> T **Description:** Subtracts `rhs` from `lhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`. ___ @@ -198,7 +198,7 @@ __mul(lhs: T, rhs: T) -> T **Description:** Multiplies `lhs` by `rhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`. ___ @@ -208,7 +208,7 @@ __div(lhs: T, rhs: T) -> T **Description:** Divides `lhs` by `rhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`. ___ @@ -218,7 +218,7 @@ __and(lhs: T, rhs: T) -> T **Description:** Bitwise AND `lhs` and `rhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`, `b256`. ___ @@ -228,7 +228,7 @@ __or(lhs: T, rhs: T) -> T **Description:** Bitwise OR `lhs` and `rhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`, `b256`. ___ @@ -238,7 +238,7 @@ __xor(lhs: T, rhs: T) -> T **Description:** Bitwise XOR `lhs` and `rhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`, `b256`. ___ ```sway @@ -247,7 +247,7 @@ __mod(lhs: T, rhs: T) -> T **Description:** Modulo of `lhs` by `rhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`. ___ ```sway @@ -256,7 +256,7 @@ __rsh(lhs: T, rhs: u64) -> T **Description:** Logical right shift of `lhs` by `rhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`, `b256`. ___ ```sway @@ -265,7 +265,7 @@ __lsh(lhs: T, rhs: u64) -> T **Description:** Logical left shift of `lhs` by `rhs`. -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`, `b256`. ___ ```sway @@ -314,5 +314,5 @@ __not(op: T) -> T **Description:** Bitwise NOT of `op` -**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`. +**Constraints:** `T` is an integer type, i.e. `u8`, `u16`, `u32`, `u64`, `u256`, `b256`. ___ diff --git a/docs/book/src/reference/solidity_differences.md b/docs/book/src/reference/solidity_differences.md index cd224339636..9eeb786f81b 100644 --- a/docs/book/src/reference/solidity_differences.md +++ b/docs/book/src/reference/solidity_differences.md @@ -8,11 +8,11 @@ The underlying virtual machine targeted by Sway is the FuelVM, specified [here]( ## Word Size -Words in the FuelVM are 64 bits (8 bytes), rather than the 256 bits (32 bytes) of the EVM. Therefore, primitive integers only go up to `u64`, and hashes (the `b256` type) are not in registers but rather in memory. A `b256` is therefore a pointer to a 32-byte memory region containing the hash value. +Words in the FuelVM are 64 bits (8 bytes), rather than the 256 bits (32 bytes) of the EVM. Therefore, all primitive integers smaller and including `u64` are stored in registers; `u256`, being bigger than the registers, and hashes (the `b256` type) are not stored in registers but rather in memory. They are therefore pointers to a 32-byte memory region containing the their data. ## Unsigned Integers Only -Only unsigned integers are provided as primitives: `u8`, `u16`, `u32`, and `u64`. Signed integer arithmetic is not available in the FuelVM. Signed integers and signed integer arithmetic can be implemented in high-level libraries if needed. +Only unsigned integers are provided as primitives: `u8`, `u16`, `u32`, `u64`, and `u256`. Signed integer arithmetic is not available in the FuelVM. Signed integers and signed integer arithmetic can be implemented in high-level libraries if needed. ## Global Revert diff --git a/docs/reference/src/documentation/language/built-ins/index.md b/docs/reference/src/documentation/language/built-ins/index.md index 4a47055188b..a3ec2dcf7e0 100644 --- a/docs/reference/src/documentation/language/built-ins/index.md +++ b/docs/reference/src/documentation/language/built-ins/index.md @@ -13,7 +13,8 @@ Sway has the following primitive types: 2. `u16` (16-bit unsigned integer) 3. `u32` (32-bit unsigned integer) 4. `u64` (64-bit unsigned integer) - 5. `hexadecimal`, `binary` & `base-10` syntax + 5. `u256` (256-bit unsigned integer) + 6. `hexadecimal`, `binary` & `base-10` syntax 2. [Boolean](boolean.md) 1. `bool` (true or false) 3. [Strings](string.md) diff --git a/docs/reference/src/documentation/operations/log.md b/docs/reference/src/documentation/operations/log.md index c24b94227c1..24c19e0864c 100644 --- a/docs/reference/src/documentation/operations/log.md +++ b/docs/reference/src/documentation/operations/log.md @@ -9,7 +9,7 @@ Each call to `log` appends 1 of 2 types of a [`receipt`](https://fuellabs.github - [`Log`](https://fuellabs.github.io/fuel-specs/master/protocol/abi/receipts.html#log-receipt) - Generated for _non-reference_ types: `bool`, `u8`, `u16`, `u32`, and `u64` - [`LogData`](https://fuellabs.github.io/fuel-specs/master/protocol/abi/receipts.html#logdata-receipt) - - Generated for _reference_ types + - Generated for _reference_ types and `u256` The [Rust](https://fuellabs.github.io/fuels-rs/latest/) & [Typescript](https://fuellabs.github.io/fuels-ts/) SDKs may be used to decode the data. diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 8076dc5f2b7..cf662159f01 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -76,6 +76,15 @@ struct TestContext { deployed_contracts: Arc>>, } +fn print_receipt(receipt: &Receipt) { + if let Receipt::ReturnData { + data: Some(data), .. + } = receipt + { + println!("Data: {:?}", data); + } +} + impl TestContext { async fn deploy_contract(&self, contract_path: String) -> Result { let mut deployed_contracts = self.deployed_contracts.lock().await; @@ -90,7 +99,7 @@ impl TestContext { }, ) } - async fn run(&self, test: TestDescription, output: &mut String) -> Result<()> { + async fn run(&self, test: TestDescription, output: &mut String, verbose: bool) -> Result<()> { let context = self; let TestDescription { name, @@ -143,6 +152,12 @@ impl TestContext { let result = harness::runs_in_vm(compiled.clone(), script_data)?; let result = match result { harness::VMExecutionResult::Fuel(state, receipts) => { + if verbose { + for receipt in receipts.iter() { + print_receipt(receipt); + } + } + match state { ProgramState::Return(v) => TestResult::Return(v), ProgramState::ReturnData(digest) => { @@ -320,24 +335,27 @@ impl TestContext { *output = out; result.map(|tested_pkgs| { - let failed: Vec = tested_pkgs - .into_iter() - .flat_map(|tested_pkg| { - tested_pkg - .tests - .into_iter() - .filter(|test| !test.passed()) - .map(move |test| { - format!( - "{}: Test '{}' failed with state {:?}, expected: {:?}", - tested_pkg.built.descriptor.name, - test.name, - test.state, - test.condition, - ) - }) - }) - .collect(); + let mut failed = vec![]; + for pkg in tested_pkgs { + for test in pkg.tests.into_iter() { + if verbose { + println!("Test: {} {}", test.name, test.passed()); + for log in test.logs.iter() { + println!("{:?}", log); + } + } + + if !test.passed() { + failed.push(format!( + "{}: Test '{}' failed with state {:?}, expected: {:?}", + pkg.built.descriptor.name, + test.name, + test.state, + test.condition, + )); + } + } + } if !failed.is_empty() { println!("FAILED!! output:\n{}", output); @@ -423,11 +441,11 @@ pub async fn run(filter_config: &FilterConfig, run_config: &RunConfig) -> Result let result = if !filter_config.first_only { context - .run(test, &mut output) + .run(test, &mut output, run_config.verbose) .instrument(tracing::trace_span!("E2E", i)) .await } else { - context.run(test, &mut output).await + context.run(test, &mut output, run_config.verbose).await }; if let Err(err) = result { diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/u256/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/u256/u256_only_hex_literal/Forc.lock similarity index 100% rename from test/src/e2e_vm_tests/test_programs/should_fail/u256/Forc.lock rename to test/src/e2e_vm_tests/test_programs/should_fail/u256/u256_only_hex_literal/Forc.lock diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/u256/u256_only_hex_literal/Forc.toml similarity index 100% rename from test/src/e2e_vm_tests/test_programs/should_pass/language/u256/Forc.toml rename to test/src/e2e_vm_tests/test_programs/should_fail/u256/u256_only_hex_literal/Forc.toml diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/u256/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/u256/u256_only_hex_literal/src/main.sw similarity index 100% rename from test/src/e2e_vm_tests/test_programs/should_fail/u256/src/main.sw rename to test/src/e2e_vm_tests/test_programs/should_fail/u256/u256_only_hex_literal/src/main.sw diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/u256/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/u256/u256_only_hex_literal/test.toml similarity index 100% rename from test/src/e2e_vm_tests/test_programs/should_fail/u256/test.toml rename to test/src/e2e_vm_tests/test_programs/should_fail/u256/u256_only_hex_literal/test.toml diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/Forc.lock similarity index 100% rename from test/src/e2e_vm_tests/test_programs/should_pass/language/u256/Forc.lock rename to test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/Forc.lock diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/u256/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/Forc.toml similarity index 68% rename from test/src/e2e_vm_tests/test_programs/should_fail/u256/Forc.toml rename to test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/Forc.toml index 47a2f0891f9..499032884fe 100644 --- a/test/src/e2e_vm_tests/test_programs/should_fail/u256/Forc.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/Forc.toml @@ -5,4 +5,4 @@ license = "Apache-2.0" name = "ops" [dependencies] -std = { path = "../../../../../../sway-lib-std" } +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle.json new file mode 100644 index 00000000000..38a0a212434 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle.json @@ -0,0 +1,34 @@ +{ + "configurables": [], + "functions": [ + { + "attributes": null, + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [ + { + "logId": 0, + "loggedType": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "messagesTypes": [], + "types": [ + { + "components": null, + "type": "u256", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/src/main.sw new file mode 100644 index 00000000000..f0de9d18a38 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/src/main.sw @@ -0,0 +1,6 @@ +script; + +fn main() -> u256 { + log(0x00000000000000000000000000000000000000000000000000000002u256); + 0x00000000000000000000000000000000000000000000000000000001u256 +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/test.toml similarity index 63% rename from test/src/e2e_vm_tests/test_programs/should_pass/language/u256/test.toml rename to test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/test.toml index e0beb8b65ab..5857e81b302 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/test.toml @@ -1,3 +1,3 @@ category = "run" -expected_result = { action = "return_data", value = "0000000000000000000000000000000000000000000000000000000000000017" } +expected_result = { action = "return_data", value = "0000000000000000000000000000000000000000000000000000000000000001" } validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/Forc.lock new file mode 100644 index 00000000000..863f10c5516 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/Forc.lock @@ -0,0 +1,13 @@ +[[package]] +name = 'core' +source = 'path+from-root-969A3D730A6A09C1' + +[[package]] +name = 'ops' +source = 'member' +dependencies = ['std'] + +[[package]] +name = 'std' +source = 'path+from-root-969A3D730A6A09C1' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/Forc.toml new file mode 100644 index 00000000000..499032884fe --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "ops" + +[dependencies] +std = { path = "../../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/json_abi_oracle.json similarity index 100% rename from test/src/e2e_vm_tests/test_programs/should_pass/language/u256/json_abi_oracle.json rename to test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/json_abi_oracle.json diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/src/main.sw similarity index 73% rename from test/src/e2e_vm_tests/test_programs/should_pass/language/u256/src/main.sw rename to test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/src/main.sw index 532f11755b1..5325db3db8e 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/src/main.sw @@ -1,7 +1,7 @@ -script; +library; // returns 3 -fn constants() -> u256 { +fn literals() -> u256 { 0x0000000000000000000000000000000000000000000000000000000000000001u256 + 0x0000000000000000000000000000000000000000000000000000000000000002u256 } @@ -82,7 +82,6 @@ fn shift_operators() -> u256 { (a << 4) >> 2 } - // returns 0 fn comparison_operators() -> u256 { let a = 0x0000000000000000000000000000000000000000000000000000000000000001u256; @@ -116,6 +115,50 @@ fn comparison_operators() -> u256 { return 0x0000000000000000000000000000000000000000000000000000000000000000u256; } -fn main() -> u256 { - constants() + locals() + bitwise_operators() + shift_operators() + comparison_operators() -} \ No newline at end of file +#[test] +fn should_be_able_to_use_literals() { + let result = 0x0000000000000000000000000000000000000000000000000000000000000003u256; + assert_eq(literals(), result); +} + +#[test] +fn should_be_able_to_use_locals() { + let result = 0x0000000000000000000000000000000000000000000000000000000000000001u256; + assert_eq(locals(), result); +} + +#[test] +fn should_be_able_to_use_bitwise_operators() { + let result = 0x000000000000000000000000000000000000000000000000000000000000000Bu256; + assert_eq(bitwise_operators(), result); +} + +#[test] +fn should_be_able_to_use_shift_operators() { + let result = 0x0000000000000000000000000000000000000000000000000000000000000008u256; + assert_eq(shift_operators(), result); +} + +#[test] +fn should_be_able_to_use_comparison_operators() { + let result = 0x0000000000000000000000000000000000000000000000000000000000000000u256; + assert_eq(comparison_operators(), result); +} + +#[test(should_revert)] +fn should_revert_on_overflow() -> u256 { + let a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFu256; + a + 0x0000000000000000000000000000000000000000000000000000000000000001u256 +} + +#[test(should_revert)] +fn should_revert_on_underflow() -> u256 { + let a = 0x0000000000000000000000000000000000000000000000000000000000000000u256; + a - 0x0000000000000000000000000000000000000000000000000000000000000001u256 +} + +#[test(should_revert)] +fn should_revert_on_div_zero() -> u256 { + let a = 0x0000000000000000000000000000000000000000000000000000000000000000u256; + a / 0x0000000000000000000000000000000000000000000000000000000000000000u256 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/test.toml new file mode 100644 index 00000000000..f1958c1b086 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_operators/test.toml @@ -0,0 +1 @@ +category = "unit_tests_pass" \ No newline at end of file