diff --git a/forc-plugins/forc-client/tests/deploy.rs b/forc-plugins/forc-client/tests/deploy.rs index 3f786293792..04b5a261a86 100644 --- a/forc-plugins/forc-client/tests/deploy.rs +++ b/forc-plugins/forc-client/tests/deploy.rs @@ -107,7 +107,7 @@ async fn simple_deploy() { node.kill().unwrap(); let expected = vec![DeployedContract { id: ContractId::from_str( - "428896412bda8530282a7b8fca5d20b2a73f30037612ca3a31750cf3bf0e976a", + "822c8d3672471f64f14f326447793c7377b6e430122db23b622880ccbd8a33ef", ) .unwrap(), }]; diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index c459a5cd6fa..b430929dcf8 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -1717,6 +1717,224 @@ impl<'eng> FnCompiler<'eng> { Ok(increase_len(&mut s.current_block, context, len, 8 - offset)) } + fn grow_if_needed( + s: &mut FnCompiler<'_>, + context: &mut Context, + ptr: Value, + cap: Value, + len: Value, + needed_size: Value, + ) -> (Value, Value) { + assert!(ptr.get_type(context).unwrap().is_ptr(context)); + assert!(cap.get_type(context).unwrap().is_uint64(context)); + + let ptr_u8 = Type::new_ptr(context, Type::get_uint8(context)); + + // merge block has two arguments: ptr, cap + let merge_block = s.function.create_block(context, None); + let merge_block_ptr = Value::new_argument( + context, + BlockArgument { + block: merge_block, + idx: 0, + ty: ptr_u8, + }, + ); + merge_block.add_arg(context, merge_block_ptr); + let merge_block_cap = Value::new_argument( + context, + BlockArgument { + block: merge_block, + idx: 1, + ty: Type::get_uint64(context), + }, + ); + merge_block.add_arg(context, merge_block_cap); + + let true_block_begin = s.function.create_block(context, None); + let false_block_begin = s.function.create_block(context, None); + + // if len + needed_size > cap + let needed_cap = s.current_block.append(context).binary_op( + BinaryOpKind::Add, + len, + needed_size, + ); + let needs_realloc = s.current_block.append(context).cmp( + Predicate::GreaterThan, + needed_cap, + cap, + ); + s.current_block.append(context).conditional_branch( + needs_realloc, + true_block_begin, + false_block_begin, + vec![], + vec![], + ); + + // needs realloc block + // new_cap = cap * 2 + // aloc new_cap + // mcp hp old_ptr len + // hp: ptr u8 + s.current_block = true_block_begin; + let u8 = Type::get_uint8(context); + let ptr_u8 = Type::new_ptr(context, u8); + + let two = Constant::new_uint(context, 64, 2); + let two = Value::new_constant(context, two); + let new_cap = + s.current_block + .append(context) + .binary_op(BinaryOpKind::Mul, cap, two); + + let new_ptr = s.current_block.append(context).asm_block( + vec![ + AsmArg { + name: Ident::new_no_span("new_cap".into()), + initializer: Some(new_cap), + }, + AsmArg { + name: Ident::new_no_span("old_ptr".into()), + initializer: Some(ptr), + }, + AsmArg { + name: Ident::new_no_span("len".into()), + initializer: Some(len), + }, + ], + vec![ + AsmInstruction { + op_name: Ident::new_no_span("aloc".into()), + args: vec![Ident::new_no_span("new_cap".into())], + immediate: None, + metadata: None, + }, + AsmInstruction { + op_name: Ident::new_no_span("mcp".into()), + args: vec![ + Ident::new_no_span("hp".into()), + Ident::new_no_span("old_ptr".into()), + Ident::new_no_span("len".into()), + ], + immediate: None, + metadata: None, + }, + ], + ptr_u8, + Some(Ident::new_no_span("hp".into())), + ); + + s.current_block + .append(context) + .branch(merge_block, vec![new_ptr, new_cap]); + + // dont need realloc block + s.current_block = false_block_begin; + s.current_block + .append(context) + .branch(merge_block, vec![ptr, cap]); + + s.current_block = merge_block; + + assert!(merge_block_ptr.get_type(context).unwrap().is_ptr(context)); + assert!(merge_block_cap + .get_type(context) + .unwrap() + .is_uint64(context)); + + (merge_block_ptr, merge_block_cap) + } + + fn to_constant( + _s: &mut FnCompiler<'_>, + context: &mut Context, + needed_size: u64, + ) -> Value { + let needed_size = Constant::new_uint(context, 64, needed_size); + Value::new_constant(context, needed_size) + } + + // Grow the buffer if needed + let (ptr, cap) = match &*item_type { + TypeInfo::Boolean => { + let needed_size = to_constant(self, context, 1); + grow_if_needed(self, context, ptr, cap, len, needed_size) + } + TypeInfo::UnsignedInteger(IntegerBits::Eight) => { + let needed_size = to_constant(self, context, 1); + grow_if_needed(self, context, ptr, cap, len, needed_size) + } + TypeInfo::UnsignedInteger(IntegerBits::Sixteen) => { + let needed_size = to_constant(self, context, 2); + grow_if_needed(self, context, ptr, cap, len, needed_size) + } + TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo) => { + let needed_size = to_constant(self, context, 4); + grow_if_needed(self, context, ptr, cap, len, needed_size) + } + TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) => { + let needed_size = to_constant(self, context, 8); + grow_if_needed(self, context, ptr, cap, len, needed_size) + } + TypeInfo::UnsignedInteger(IntegerBits::V256) | TypeInfo::B256 => { + let needed_size = to_constant(self, context, 32); + grow_if_needed(self, context, ptr, cap, len, needed_size) + } + TypeInfo::StringArray(string_len) => { + let needed_size = to_constant(self, context, string_len.val() as u64); + grow_if_needed(self, context, ptr, cap, len, needed_size) + } + TypeInfo::StringSlice | TypeInfo::RawUntypedSlice => { + let uint64 = Type::get_uint64(context); + let u64_u64_type = Type::new_struct(context, vec![uint64, uint64]); + + // convert "item" to { u64, u64 } + let item = self.current_block.append(context).asm_block( + vec![AsmArg { + name: Ident::new_no_span("item".into()), + initializer: Some(item), + }], + vec![], + u64_u64_type, + Some(Ident::new_no_span("item".into())), + ); + + // save item to local _anon + let name = self.lexical_map.insert_anon(); + let item_local = self + .function + .new_local_var(context, name, u64_u64_type, None, false) + .map_err(|ir_error| { + CompileError::InternalOwned(ir_error.to_string(), Span::dummy()) + })?; + let ptr_to_local_item = + self.current_block.append(context).get_local(item_local); + self.current_block + .append(context) + .store(ptr_to_local_item, item); + + // _anon.1 = len + let needed_size = self.current_block.append(context).get_elem_ptr_with_idx( + ptr_to_local_item, + uint64, + 1, + ); + let needed_size = self.current_block.append(context).load(needed_size); + let eight = to_constant(self, context, 8); + let needed_size = self.current_block.append(context).binary_op( + BinaryOpKind::Add, + needed_size, + eight, + ); + + grow_if_needed(self, context, ptr, cap, len, needed_size) + } + _ => return Err(CompileError::EncodingUnsupportedType { span: item_span }), + }; + + // Append the value into the buffer let new_len = match &*item_type { TypeInfo::Boolean => { assert!(item.get_type(context).unwrap().is_bool(context)); diff --git a/sway-core/src/language/ty/declaration/function.rs b/sway-core/src/language/ty/declaration/function.rs index f2ff28b6331..c28d862846f 100644 --- a/sway-core/src/language/ty/declaration/function.rs +++ b/sway-core/src/language/ty/declaration/function.rs @@ -565,9 +565,15 @@ impl TyFunctionSig { } pub fn is_concrete(&self, engines: &Engines) -> bool { - self.return_type.is_concrete(engines) - && self.parameters.iter().all(|p| p.is_concrete(engines)) - && self.type_parameters.iter().all(|p| p.is_concrete(engines)) + self.return_type.is_concrete(engines, IncludeNumeric::No) + && self + .parameters + .iter() + .all(|p| p.is_concrete(engines, IncludeNumeric::No)) + && self + .type_parameters + .iter() + .all(|p| p.is_concrete(engines, IncludeNumeric::No)) } /// Returns a String representing the function. diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index 0a2ffbcc99f..9c324cf1289 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -247,21 +247,25 @@ fn type_check_encode_append( }; // only supported types - match &*engines.te().get(item_type) { - TypeInfo::Boolean - | TypeInfo::UnsignedInteger(IntegerBits::Eight) - | TypeInfo::UnsignedInteger(IntegerBits::Sixteen) - | TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo) - | TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) - | TypeInfo::UnsignedInteger(IntegerBits::V256) - | TypeInfo::B256 - | TypeInfo::StringArray(_) - | TypeInfo::StringSlice - | TypeInfo::RawUntypedSlice => {} - _ => { - return Err(handler.emit_err(CompileError::EncodingUnsupportedType { span: item_span })) - } - }; + if item_type.is_concrete(engines, IncludeNumeric::Yes) { + match &*engines.te().get(item_type) { + TypeInfo::Boolean + | TypeInfo::UnsignedInteger(IntegerBits::Eight) + | TypeInfo::UnsignedInteger(IntegerBits::Sixteen) + | TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo) + | TypeInfo::UnsignedInteger(IntegerBits::SixtyFour) + | TypeInfo::UnsignedInteger(IntegerBits::V256) + | TypeInfo::B256 + | TypeInfo::StringArray(_) + | TypeInfo::StringSlice + | TypeInfo::RawUntypedSlice => {} + _ => { + return Err( + handler.emit_err(CompileError::EncodingUnsupportedType { span: item_span }) + ) + } + }; + } let kind = ty::TyIntrinsicFunctionKind { kind, diff --git a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs index f5cfc5c1ff3..7be712a0c00 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/typed_expression/method_application.rs @@ -46,11 +46,25 @@ pub(crate) fn type_check_method_application( .by_ref() .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)); + // Ignore errors in method parameters // On the second pass we will throw the errors if they persist. let arg_handler = Handler::default(); let arg_opt = ty::TyExpression::type_check(&arg_handler, ctx, arg).ok(); + + // Check this type needs a second pass let has_errors = arg_handler.has_errors(); + let is_not_concrete = arg_opt + .as_ref() + .map(|x| { + x.return_type + .extract_inner_types(engines, IncludeSelf::Yes) + .iter() + .any(|x| !x.is_concrete(engines, IncludeNumeric::Yes)) + }) + .unwrap_or_default(); + let needs_second_pass = has_errors || is_not_concrete; + if index == 0 { // We want to emit errors in the self parameter and ignore TraitConstraintNotSatisfied with Placeholder // which may be recoverable on the second pass. @@ -66,7 +80,8 @@ pub(crate) fn type_check_method_application( }); handler.append(arg_handler); } - args_opt_buf.push_back((arg_opt, has_errors)); + + args_opt_buf.push_back((arg_opt, needs_second_pass)); } // resolve the method name to a typed function declaration and type_check @@ -115,6 +130,7 @@ pub(crate) fn type_check_method_application( } else { index }; + let ctx = if let Some(param) = method.parameters.get(param_index) { // We now try to type check it again, this time with the type annotation. ctx.by_ref() @@ -127,6 +143,7 @@ pub(crate) fn type_check_method_application( .with_help_text("") .with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown, None)) }; + args_buf.push_back( ty::TyExpression::type_check(handler, ctx, arg) .unwrap_or_else(|err| ty::TyExpression::error(err, span.clone(), engines)), diff --git a/sway-core/src/type_system/id.rs b/sway-core/src/type_system/id.rs index 9403fcb03ef..9410fd2d6ac 100644 --- a/sway-core/src/type_system/id.rs +++ b/sway-core/src/type_system/id.rs @@ -27,6 +27,11 @@ pub enum IncludeSelf { No, } +pub enum IncludeNumeric { + Yes, + No, +} + /// A identifier to uniquely refer to our type terms #[derive(PartialEq, Eq, Hash, Clone, Copy, Ord, PartialOrd, Debug)] pub struct TypeId(usize); @@ -456,17 +461,26 @@ impl TypeId { })) } - pub(crate) fn is_concrete(&self, engines: &Engines) -> bool { + pub(crate) fn is_concrete(&self, engines: &Engines, include_numeric: IncludeNumeric) -> bool { let nested_types = (*self).extract_nested_types(engines); - !nested_types.into_iter().any(|x| { - matches!( + !nested_types.into_iter().any(|x| match include_numeric { + IncludeNumeric::Yes => matches!( + x, + TypeInfo::UnknownGeneric { .. } + | TypeInfo::Custom { .. } + | TypeInfo::Placeholder(..) + | TypeInfo::TraitType { .. } + | TypeInfo::TypeParam(..) + | TypeInfo::Numeric + ), + IncludeNumeric::No => matches!( x, TypeInfo::UnknownGeneric { .. } | TypeInfo::Custom { .. } | TypeInfo::Placeholder(..) | TypeInfo::TraitType { .. } | TypeInfo::TypeParam(..) - ) + ), }) } diff --git a/sway-core/src/type_system/priv_prelude.rs b/sway-core/src/type_system/priv_prelude.rs index bb40d738d00..b28ac22152d 100644 --- a/sway-core/src/type_system/priv_prelude.rs +++ b/sway-core/src/type_system/priv_prelude.rs @@ -16,6 +16,6 @@ pub use super::{ type_parameter::TypeParameter, }, engine::TypeEngine, - id::{IncludeSelf, TypeId}, + id::{IncludeNumeric, IncludeSelf, TypeId}, info::{AbiEncodeSizeHint, AbiName, TypeInfo, TypeSourceInfo}, }; diff --git a/sway-lib-core/src/codec.sw b/sway-lib-core/src/codec.sw index cc43cdbf2eb..9ab99efc188 100644 --- a/sway-lib-core/src/codec.sw +++ b/sway-lib-core/src/codec.sw @@ -12,6 +12,17 @@ impl Buffer { buffer: __encode_buffer_empty(), } } + + fn with_capacity(cap: u64) -> Self { + let ptr = asm(cap: cap) { + aloc cap; + hp: raw_ptr + }; + + Buffer { + buffer: (ptr, cap, 0), + } + } } impl AsRawSlice for Buffer { @@ -4984,6 +4995,85 @@ where // END TUPLES_DECODE use ::ops::*; +pub fn contract_call( + contract_id: b256, + method_name: str, + args: TArgs, + coins: u64, + asset_id: b256, + gas: u64, +) -> T +where + T: AbiDecode, + TArgs: AbiEncode, +{ + let first_parameter = encode(method_name); + let second_parameter = encode(args); + let params = encode(( + contract_id, + asm(a: first_parameter.ptr()) { + a: u64 + }, + asm(a: second_parameter.ptr()) { + a: u64 + }, + )); + + __contract_call(params.ptr(), coins, asset_id, gas); + let ptr = asm() { + ret: raw_ptr + }; + let len = asm() { + retl: u64 + }; + + let mut buffer = BufferReader::from_parts(ptr, len); + T::abi_decode(buffer) +} + +pub fn decode_script_data() -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_script_data(); + T::abi_decode(buffer) +} + +pub fn decode_predicate_data() -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_predicate_data(); + T::abi_decode(buffer) +} + +pub fn decode_predicate_data_by_index(index: u64) -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_predicate_data_by_index(index); + T::abi_decode(buffer) +} + +pub fn decode_first_param() -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_first_parameter(); + T::abi_decode(buffer) +} + +pub fn decode_second_param() -> T +where + T: AbiDecode, +{ + let mut buffer = BufferReader::from_second_parameter(); + T::abi_decode(buffer) +} + +// Tests + + fn assert_encoding(value: T, expected: SLICE) where T: AbiEncode, @@ -5062,15 +5152,99 @@ fn to_slice(array: T) -> raw_slice { raw_slice::from_parts::(__addr_of(array), len) } -fn assert_eq(a: T, b: T) +fn assert_eq(a: T, b: T, revert_code: u64) where T: Eq, { if a != b { - __revert(0) + __revert(revert_code) } } +fn assert_neq(a: T, b: T, revert_code: u64) +where + T: Eq, +{ + if a == b { + __revert(revert_code) + } +} + +fn assert_no_write_after_buffer(value_to_append: T, size_of_t: u64) +where + T: AbiEncode, +{ + // This red zone should not be overwritten + let red_zone1 = asm(size: 1024) { + aloc size; + hp: raw_ptr + }; + red_zone1.write(0xFFFFFFFFFFFFFFFF); + + // Create encoding buffer with capacity for one item + let mut buffer = Buffer::with_capacity(size_of_t); + let ptr1 = buffer.buffer.0; + + // Append one item + let buffer = value_to_append.abi_encode(buffer); + assert_eq(ptr1, buffer.buffer.0, 1); // no buffer grow is expected + assert_eq(buffer.buffer.1, size_of_t, 2); // capacity must be still be one item + assert_eq(buffer.buffer.2, size_of_t, 3); // buffer has one item + + // This red zone should not be overwritten + let red_zone2 = asm(size: 1024) { + aloc size; + hp: raw_ptr + }; + red_zone2.write(0xFFFFFFFFFFFFFFFF); + + // Append another item + let buffer = value_to_append.abi_encode(buffer); + assert_neq(ptr1, buffer.buffer.0, 4); // must have allocated new buffer + assert_eq(buffer.buffer.1, size_of_t * 2, 5); // capacity for two items + assert_eq(buffer.buffer.2, size_of_t * 2, 6); // buffer has two items + + // Check that red zones were not overwritten + assert_eq(red_zone1.read::(), 0xFFFFFFFFFFFFFFFF, 7); + assert_eq(red_zone2.read::(), 0xFFFFFFFFFFFFFFFF, 8); +} + +#[test] +fn ok_encoding_should_not_write_outside_buffer() { + assert_no_write_after_buffer::(true, 1); + + // numbers + assert_no_write_after_buffer::(1, 1); + assert_no_write_after_buffer::(1, 2); + assert_no_write_after_buffer::(1, 4); + assert_no_write_after_buffer::(1, 8); + assert_no_write_after_buffer::( + 0x0000000000000000000000000000000000000000000000000000000000000001u256, + 32, + ); + assert_no_write_after_buffer::( + 0x0000000000000000000000000000000000000000000000000000000000000001, + 32, + ); + + // arrays + assert_no_write_after_buffer::<[u8; 1]>([1], 1); + assert_no_write_after_buffer::<[u8; 2]>([1, 1], 2); + assert_no_write_after_buffer::<[u8; 3]>([1, 1, 1], 3); + assert_no_write_after_buffer::<[u8; 4]>([1, 1, 1, 1], 4); + assert_no_write_after_buffer::<[u8; 5]>([1, 1, 1, 1, 1], 5); + + // string arrays + assert_no_write_after_buffer::(__to_str_array("h"), 1); + assert_no_write_after_buffer::(__to_str_array("he"), 2); + assert_no_write_after_buffer::(__to_str_array("hello world"), 11); + + // string slices + assert_no_write_after_buffer::("h", 9); + assert_no_write_after_buffer::("he", 10); + assert_no_write_after_buffer::("hello world", 19); +} + #[test] fn ok_abi_encoding() { // bool @@ -5177,85 +5351,9 @@ fn ok_abi_encoding() { assert_encoding([255u8; 5], [255u8; 5]); let array = abi_decode::<[u8; 1]>(to_slice([255u8])); - assert_eq(array[0], 255u8); + assert_eq(array[0], 255u8, 0); let array = abi_decode::<[u8; 2]>(to_slice([255u8, 254u8])); - assert_eq(array[0], 255u8); - assert_eq(array[1], 254u8); -} - -pub fn contract_call( - contract_id: b256, - method_name: str, - args: TArgs, - coins: u64, - asset_id: b256, - gas: u64, -) -> T -where - T: AbiDecode, - TArgs: AbiEncode, -{ - let first_parameter = encode(method_name); - let second_parameter = encode(args); - let params = encode(( - contract_id, - asm(a: first_parameter.ptr()) { - a: u64 - }, - asm(a: second_parameter.ptr()) { - a: u64 - }, - )); - - __contract_call(params.ptr(), coins, asset_id, gas); - let ptr = asm() { - ret: raw_ptr - }; - let len = asm() { - retl: u64 - }; - - let mut buffer = BufferReader::from_parts(ptr, len); - T::abi_decode(buffer) -} - -pub fn decode_script_data() -> T -where - T: AbiDecode, -{ - let mut buffer = BufferReader::from_script_data(); - T::abi_decode(buffer) -} - -pub fn decode_predicate_data() -> T -where - T: AbiDecode, -{ - let mut buffer = BufferReader::from_predicate_data(); - T::abi_decode(buffer) -} - -pub fn decode_predicate_data_by_index(index: u64) -> T -where - T: AbiDecode, -{ - let mut buffer = BufferReader::from_predicate_data_by_index(index); - T::abi_decode(buffer) -} - -pub fn decode_first_param() -> T -where - T: AbiDecode, -{ - let mut buffer = BufferReader::from_first_parameter(); - T::abi_decode(buffer) -} - -pub fn decode_second_param() -> T -where - T: AbiDecode, -{ - let mut buffer = BufferReader::from_second_parameter(); - T::abi_decode(buffer) + assert_eq(array[0], 255u8, 0); + assert_eq(array[1], 254u8, 0); } diff --git a/sway-lib-std/src/alloc.sw b/sway-lib-std/src/alloc.sw index 9841fe5e1e1..bd3dd7cc095 100644 --- a/sway-lib-std/src/alloc.sw +++ b/sway-lib-std/src/alloc.sw @@ -112,10 +112,9 @@ pub fn realloc(ptr: raw_ptr, count: u64, new_count: u64) -> raw_ptr { /// } /// ``` pub fn alloc_bytes(count: u64) -> raw_ptr { - asm(size: count, ptr) { + asm(size: count) { aloc size; - move ptr hp; - ptr: raw_ptr + hp: raw_ptr } } diff --git a/sway-lib-std/src/bytes.sw b/sway-lib-std/src/bytes.sw index 0b3b99d9bf7..1887b46e41c 100644 --- a/sway-lib-std/src/bytes.sw +++ b/sway-lib-std/src/bytes.sw @@ -74,14 +74,16 @@ impl From for RawBytes { /// assert(raw_bytes.capacity == 3); /// ``` fn from(slice: raw_slice) -> Self { - Self { - ptr: slice.ptr(), - cap: slice.number_of_bytes(), + let cap = slice.number_of_bytes(); + let ptr = alloc_bytes(cap); + if cap > 0 { + slice.ptr().copy_to::(ptr, cap); } + Self { ptr, cap } } } -/// A type used to represent raw bytes. +/// A type used to represent raw bytes. It has ownership over its buffer. pub struct Bytes { /// A barebones struct for the bytes. buf: RawBytes, @@ -723,11 +725,11 @@ impl Bytes { impl core::ops::Eq for Bytes { fn eq(self, other: Self) -> bool { - if self.len != other.len() { + if self.len != other.len { return false; } - asm(result, r2: self.buf.ptr(), r3: other.ptr(), r4: self.len) { + asm(result, r2: self.buf.ptr, r3: other.buf.ptr, r4: self.len) { meq result r2 r3 r4; result: bool } @@ -737,7 +739,7 @@ impl core::ops::Eq for Bytes { impl AsRawSlice for Bytes { /// Returns a raw slice of all of the elements in the type. fn as_raw_slice(self) -> raw_slice { - asm(ptr: (self.buf.ptr(), self.len)) { + asm(ptr: (self.buf.ptr, self.len)) { ptr: raw_slice } } @@ -750,7 +752,7 @@ impl From for Bytes { let mut bytes = Self::with_capacity(32); bytes.len = 32; // Copy bytes from contract_id into the buffer of the target bytes - __addr_of(b).copy_bytes_to(bytes.buf.ptr(), 32); + __addr_of(b).copy_bytes_to(bytes.buf.ptr, 32); bytes } @@ -826,9 +828,7 @@ impl From for raw_slice { /// assert(slice.number_of_bytes() == 3); /// ``` fn from(bytes: Bytes) -> raw_slice { - asm(ptr: (bytes.buf.ptr(), bytes.len)) { - ptr: raw_slice - } + bytes.as_raw_slice() } } @@ -906,38 +906,46 @@ impl From for Vec { impl Clone for Bytes { fn clone(self) -> Self { let len = self.len(); - let mut c = Self::with_capacity(len); - c.len = len; - self.ptr().copy_bytes_to(c.ptr(), len); - c + let buf = RawBytes::with_capacity(len); + if len > 0 { + self.ptr().copy_bytes_to(buf.ptr(), len); + } + Bytes { buf, len } } } impl AbiEncode for Bytes { fn abi_encode(self, buffer: Buffer) -> Buffer { - let mut buffer = self.len.abi_encode(buffer); - - let mut i = 0; - while i < self.len { - let item = self.get(i).unwrap(); - buffer = item.abi_encode(buffer); - i += 1; - } - - buffer + self.as_raw_slice().abi_encode(buffer) } } impl AbiDecode for Bytes { fn abi_decode(ref mut buffer: BufferReader) -> Bytes { - let len = u64::abi_decode(buffer); - let data = buffer.read_bytes(len); - Bytes { - buf: RawBytes { - ptr: data.ptr(), - cap: len, - }, - len, - } + raw_slice::abi_decode(buffer).into() } } + +#[test] +fn ok_bytes_buffer_ownership() { + let mut original_array = [1u8, 2u8, 3u8, 4u8]; + let slice = raw_slice::from_parts::(__addr_of(original_array), 4); + + // Check Bytes duplicates the original slice + let mut bytes = Bytes::from(slice); + bytes.set(0, 5); + assert(original_array[0] == 1); + + // At this point, slice equals [5, 2, 3, 4] + let encoded_slice = encode(bytes); + + // `Bytes` should duplicate the underlying buffer, + // so when we write to it, it should not change + // `encoded_slice` + let mut bytes = abi_decode::(encoded_slice); + bytes.set(0, 6); + assert(bytes.get(0) == Some(6)); + + let mut bytes = abi_decode::(encoded_slice); + assert(bytes.get(0) == Some(5)); +} diff --git a/sway-lib-std/src/string.sw b/sway-lib-std/src/string.sw index 97b6cf76df3..abe9673dbdc 100644 --- a/sway-lib-std/src/string.sw +++ b/sway-lib-std/src/string.sw @@ -7,7 +7,7 @@ use ::convert::*; use ::hash::{Hash, Hasher}; use ::option::Option; -/// A UTF-8 encoded growable string. +/// A UTF-8 encoded growable string. It has ownership over its buffer. /// /// # Additional Information /// @@ -40,7 +40,7 @@ impl String { /// } /// ``` pub fn as_bytes(self) -> Bytes { - self.bytes + self.bytes.clone() } /// Gets the amount of memory on the heap allocated to the `String`. @@ -113,7 +113,9 @@ impl String { /// } /// ``` pub fn from_ascii(bytes: Bytes) -> Self { - Self { bytes } + Self { + bytes: bytes.clone(), + } } /// Converts a string slice containing ASCII encoded bytes to a `String` @@ -236,7 +238,9 @@ impl String { impl From for String { fn from(b: Bytes) -> Self { - Self { bytes: b } + Self { + bytes: b.clone(), + } } } @@ -308,7 +312,7 @@ impl From for raw_slice { /// } /// ``` fn from(s: String) -> raw_slice { - raw_slice::from(s.as_bytes()) + s.bytes.as_raw_slice() } } @@ -326,29 +330,14 @@ impl Hash for String { impl AbiEncode for String { fn abi_encode(self, buffer: Buffer) -> Buffer { - // Encode the length - let mut buffer = self.bytes.len().abi_encode(buffer); - - // Encode each byte of the string - let mut i = 0; - while i < self.bytes.len() { - let item = self.bytes.get(i).unwrap(); - buffer = item.abi_encode(buffer); - i += 1; - } - - buffer + self.bytes.abi_encode(buffer) } } impl AbiDecode for String { fn abi_decode(ref mut buffer: BufferReader) -> Self { - // Get length and string data - let len = u64::abi_decode(buffer); - let data = buffer.read_bytes(len); - // Create string from the ptr and len as parts of a raw_slice String { - bytes: Bytes::from(raw_slice::from_parts::(data.ptr(), len)), + bytes: Bytes::abi_decode(buffer), } } } diff --git a/sway-lib-std/src/vec.sw b/sway-lib-std/src/vec.sw index 9c585f45185..5b7830b848c 100644 --- a/sway-lib-std/src/vec.sw +++ b/sway-lib-std/src/vec.sw @@ -131,14 +131,16 @@ impl RawVec { impl From for RawVec { fn from(slice: raw_slice) -> Self { - Self { - ptr: slice.ptr(), - cap: slice.len::(), + let cap = slice.len::(); + let ptr = alloc::(cap); + if cap > 0 { + slice.ptr().copy_to::(ptr, cap); } + Self { ptr, cap } } } -/// A contiguous growable array type, written as `Vec`, short for 'vector'. +/// A contiguous growable array type, written as `Vec`, short for 'vector'. It has ownership over its buffer. pub struct Vec { buf: RawVec, len: u64, @@ -702,3 +704,27 @@ impl Iterator for VecIter { self.values.get(self.index - 1) } } + +#[test] +fn ok_vec_buffer_ownership() { + let mut original_array = [1u8, 2u8, 3u8, 4u8]; + let slice = raw_slice::from_parts::(__addr_of(original_array), 4); + + // Check Vec duplicates the original slice + let mut bytes = Vec::::from(slice); + bytes.set(0, 5); + assert(original_array[0] == 1); + + // At this point, slice equals [5, 2, 3, 4] + let encoded_slice = encode(bytes); + + // `Vec` should duplicate the underlying buffer, + // so when we write to it, it should not change + // `encoded_slice` + let mut bytes = abi_decode::>(encoded_slice); + bytes.set(0, 6); + assert(bytes.get(0) == Some(6)); + + let mut bytes = abi_decode::>(encoded_slice); + assert(bytes.get(0) == Some(5)); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json index b76fb86d956..3f7bf138e5c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json @@ -7,7 +7,7 @@ "typeArguments": null }, "name": "BOOL", - "offset": 6944 + "offset": 6968 }, { "configurableType": { @@ -16,7 +16,7 @@ "typeArguments": null }, "name": "U8", - "offset": 7088 + "offset": 7112 }, { "configurableType": { @@ -25,7 +25,7 @@ "typeArguments": null }, "name": "ANOTHER_U8", - "offset": 6872 + "offset": 6896 }, { "configurableType": { @@ -34,7 +34,7 @@ "typeArguments": null }, "name": "U16", - "offset": 7032 + "offset": 7056 }, { "configurableType": { @@ -43,7 +43,7 @@ "typeArguments": null }, "name": "U32", - "offset": 7072 + "offset": 7096 }, { "configurableType": { @@ -52,7 +52,7 @@ "typeArguments": null }, "name": "U64", - "offset": 7080 + "offset": 7104 }, { "configurableType": { @@ -61,7 +61,7 @@ "typeArguments": null }, "name": "U256", - "offset": 7040 + "offset": 7064 }, { "configurableType": { @@ -70,7 +70,7 @@ "typeArguments": null }, "name": "B256", - "offset": 6912 + "offset": 6936 }, { "configurableType": { @@ -79,7 +79,7 @@ "typeArguments": [] }, "name": "CONFIGURABLE_STRUCT", - "offset": 6984 + "offset": 7008 }, { "configurableType": { @@ -88,7 +88,7 @@ "typeArguments": [] }, "name": "CONFIGURABLE_ENUM_A", - "offset": 6952 + "offset": 6976 }, { "configurableType": { @@ -97,7 +97,7 @@ "typeArguments": [] }, "name": "CONFIGURABLE_ENUM_B", - "offset": 6968 + "offset": 6992 }, { "configurableType": { @@ -106,7 +106,7 @@ "typeArguments": null }, "name": "ARRAY_BOOL", - "offset": 6880 + "offset": 6904 }, { "configurableType": { @@ -115,7 +115,7 @@ "typeArguments": null }, "name": "ARRAY_U64", - "offset": 6888 + "offset": 6912 }, { "configurableType": { @@ -124,7 +124,7 @@ "typeArguments": null }, "name": "TUPLE_BOOL_U64", - "offset": 7016 + "offset": 7040 }, { "configurableType": { @@ -133,7 +133,7 @@ "typeArguments": null }, "name": "STR_4", - "offset": 7008 + "offset": 7032 }, { "configurableType": { @@ -142,7 +142,7 @@ "typeArguments": null }, "name": "NOT_USED", - "offset": 7000 + "offset": 7024 } ], "encoding": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/slice/slice_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/slice/slice_contract/src/main.sw index c86ce974d88..070cff38a82 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/slice/slice_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/slice/slice_contract/src/main.sw @@ -12,7 +12,8 @@ impl MyContract for Contract { #[test] fn test_success() { - let caller = abi(MyContract, CONTRACT_ID); + let contract_id = 0x3a9a75a3dc04f160ec6e286144eeffb6dd73fc0b4235b1793aa656be02e69d9b; // AUTO-CONTRACT-ID . + let caller = abi(MyContract, contract_id); let data = 1u64; let slice = raw_slice::from_parts::(__addr_of(&data), 1); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/string_slice/string_slice_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/string_slice/string_slice_contract/src/main.sw index 0a57dc67e6e..5e907a202b1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/string_slice/string_slice_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/string_slice/string_slice_contract/src/main.sw @@ -12,7 +12,8 @@ impl MyContract for Contract { #[test] fn test_success() { - let caller = abi(MyContract, CONTRACT_ID); + let contract_id = 0xeea596d8fc4e55fb622fd36131eff0401ccfd9f2a211f7ce2d93f816ec0cb23f; // AUTO-CONTRACT-ID . + let caller = abi(MyContract, contract_id); let result = caller.test_function("a"); assert(result == "a") } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json index 58d148218d5..95064cff5f6 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/u256_abi/json_abi_oracle_new_encoding.json @@ -7,7 +7,7 @@ "typeArguments": null }, "name": "SOME_U256", - "offset": 672 + "offset": 704 } ], "encoding": "1", diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw index 09d9a08f021..e81345968e4 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/array_of_structs_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x14ed3cd06c2947248f69d54bfa681fe40d26267be84df7e19e253622b7921bbe; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xfef18ef24b6cbfd66238fecc3c2704976fdf3177442712a3402b2ab666f12039; +const CONTRACT_ID = 0xb6a63cfbfdef36702cbec327c15629ec88c1c4acc5a3a350b127de8aebc49293; // AUTO-CONTRACT-ID ../../test_contracts/array_of_structs_contract --release fn main() -> u64 { let addr = abi(TestContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw index 51a2c5dfbb8..c23eb640723 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/asset_ops_test/src/main.sw @@ -9,12 +9,12 @@ use test_fuel_coin_abi::*; #[cfg(experimental_new_encoding = false)] const FUEL_COIN_CONTRACT_ID = 0xec2277ebe007ade87e3d797c3b1e070dcd542d5ef8f038b471f262ef9cebc87c; #[cfg(experimental_new_encoding = true)] -const FUEL_COIN_CONTRACT_ID = 0x1a88d0982d216958d18378b6784614b75868a542dc05f8cc85cf3da44268c76c; +const FUEL_COIN_CONTRACT_ID = 0x1a88d0982d216958d18378b6784614b75868a542dc05f8cc85cf3da44268c76c; // AUTO-CONTRACT-ID ../../test_contracts/test_fuel_coin_contract --release #[cfg(experimental_new_encoding = false)] const BALANCE_CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; #[cfg(experimental_new_encoding = true)] -const BALANCE_CONTRACT_ID = 0x04594851a2bd620dffc360f3976d747598b9184218dc55ff3e839f417ca345ac; +const BALANCE_CONTRACT_ID = 0x0d5fb0c109082f5784f6cd5979d9d25cab2d7307baf4a7661dea7d285c970e9f; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release fn main() -> bool { let default_gas = 1_000_000_000_000; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw index 34bec41ab32..db944a5f3f0 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/bal_opcode/src/main.sw @@ -5,7 +5,7 @@ use balance_test_abi::BalanceTest; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x04594851a2bd620dffc360f3976d747598b9184218dc55ff3e839f417ca345ac; +const CONTRACT_ID = 0x0d5fb0c109082f5784f6cd5979d9d25cab2d7307baf4a7661dea7d285c970e9f; // AUTO-CONTRACT-ID ../../test_contracts/balance_test_contract --release fn main() -> bool { let balance_test_contract = abi(BalanceTest, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw index ef06da8933a..34b3e375761 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_abi_with_tuples/src/main.sw @@ -6,7 +6,7 @@ use abi_with_tuples::{MyContract, Location, Person}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xfdc14550c8aee742cd556d0ab7f378b7be0d3b1e6e086c097352e94590d4ed02; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xfc32e1cb0635642004594eb3503279b3f4aee3d0b0de0e1aa78dcd7de2389239; +const CONTRACT_ID = 0x5517b7a26c5cbd631796958996ab33708b05282e5e366037efc5ff914682c2d6; // AUTO-CONTRACT-ID ../../test_contracts/abi_with_tuples_contract --release fn main() -> bool { let the_abi = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index 3bb81c8e7e4..42605631ca1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -4,7 +4,7 @@ use basic_storage_abi::{BasicStorage, Quad}; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x94db39f409a31b9f2ebcadeea44378e419208c20de90f5d8e1e33dc1523754cb; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xa638dae2693fab5fc57f3b61af1a4aae594006f2846175b9954769e3fa243a23; +const CONTRACT_ID = 0xe3e3a00062ed46de91902cda85348b27b371158bb1d5b9a6ccebe7307be59ff4; // AUTO-CONTRACT-ID ../../test_contracts/basic_storage --release fn main() -> u64 { let addr = abi(BasicStorage, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw index cbb435e9b52..08b24d73c5d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_contract_with_type_aliases/src/main.sw @@ -5,7 +5,7 @@ use contract_with_type_aliases_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x0cbeb6efe3104b460be769bdc4ea101ebf16ccc16f2d7b667ec3e1c7f5ce35b5; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x8bc9728375407f59c86f5b8da0660c414c9225a19e978bebe085a4b954ff29d1; +const CONTRACT_ID = 0x0bd9f9710b0815ce83f1b81614027e3c1ef300ea579b30824b323147dd369ecf; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release fn main() { let caller = abi(MyContract, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw index 6fc782ec42f..15b7895f1d1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw @@ -6,7 +6,7 @@ use dynamic_contract_call::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xd1b4047af7ef111c023ab71069e01dc2abfde487c0a0ce1268e4f447e6c6e4c2; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x4b5acfce4ff139e32b4d5466cb85d30496d0c69593dbf8cf214dedda395ddc08; +const CONTRACT_ID = 0xf9ff73e9e0ddc3517fd6fe493847b0572db0d8e7c3672c590103112b4a0d4e5a; // AUTO-CONTRACT-ID ../../test_contracts/increment_contract --release fn main() -> bool { let the_abi = abi(Incrementor, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw index 4c0d8e66f0f..85f714468c2 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_storage_enum/src/main.sw @@ -5,7 +5,7 @@ use storage_enum_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc601d11767195485a6654d566c67774134668863d8c797a8c69e8778fb1f89e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xbb67310c9d6f3a1147583a4bf5a28c51299601c5fb09cb370724f2d490ec5c0c; +const CONTRACT_ID = 0x7bd5d774e220fa89a3c1b38005f921eb3189a47e3a316175545b7413f6901ec4; // AUTO-CONTRACT-ID ../../test_contracts/storage_enum_contract --release fn main() -> u64 { let caller = abi(StorageEnum, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw index 6a054b04052..dc2ca052d0b 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_auth_test/src/main.sw @@ -5,7 +5,7 @@ use auth_testing_abi::AuthTesting; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xc2eec20491b53aab7232cbd27c31d15417b4e9daf0b89c74cc242ef1295f681f; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xeb42a6ba3f230441d7ade26f54cfb9f64fe8dd6397cc685fefc7f3d082d4d2ce; +const CONTRACT_ID = 0xf3b68b9e2ade5b886f4d2bd22bbfd928d418f9532a3a185956c1ca472a04dc0e; // AUTO-CONTRACT-ID ../../test_contracts/auth_testing_contract --release // should be false in the case of a script fn main() -> bool { diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw index e70c006208e..94b86c30fdc 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/caller_context_test/src/main.sw @@ -6,7 +6,7 @@ use context_testing_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x6054c11cda000f5990373a4d61929396165be4dfdd61d5b7bd26da60ab0d8577; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0x968479b51e9a6c210df98ba289f586331a502a5be2c2073ef65f82bada5695a9; +const CONTRACT_ID = 0x73061043a4ada05fd79d45d33f4afe5a8e83726beda5310741008aa772512d97; // AUTO-CONTRACT-ID ../../test_contracts/context_testing_contract --release fn main() -> bool { let gas: u64 = u64::max(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw index ce6698c04ca..fd353f9c22d 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/nested_struct_args_caller/src/main.sw @@ -5,7 +5,7 @@ use nested_struct_args_abi::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0xe63d33a1b3a6903808b379f6a41a72fa8a370e8b76626775e7d9d2f9c4c5da40; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xbefd6660ae89502652b2ab4e536edf3403208e308a329c06af6017dec242cc37; +const CONTRACT_ID = 0x35f286cf49aa8ecab05e8f41852cb461145ec6e39205dbd073726922a49803e1; // AUTO-CONTRACT-ID ../../test_contracts/nested_struct_args_contract --release fn main() -> bool { let caller = abi(NestedStructArgs, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw index 786e17542cf..f33caa545e1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw @@ -6,7 +6,7 @@ use std::hash::*; #[cfg(experimental_new_encoding = false)] const CONTRACT_ID = 0x3bc28acd66d327b8c1b9624c1fabfc07e9ffa1b5d71c2832c3bfaaf8f4b805e9; #[cfg(experimental_new_encoding = true)] -const CONTRACT_ID = 0xad4be8f8c517abaa781d488695e36f8dcaf4d609fc2723af4424ec78263163c1; +const CONTRACT_ID = 0xe44ef1c461fec5318ddf2d4b93308ebe5c8a354134d85b08770c0da0ad939d82; // AUTO-CONTRACT-ID ../../test_contracts/storage_access_contract --release fn main() -> bool { let caller = abi(StorageAccess, CONTRACT_ID); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/unit_tests/workspace_test/contract_multi_test/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/unit_tests/workspace_test/contract_multi_test/src/main.sw index 61e416f17bd..ced5fee81dd 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/unit_tests/workspace_test/contract_multi_test/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/unit_tests/workspace_test/contract_multi_test/src/main.sw @@ -17,14 +17,16 @@ fn test_foo() { #[test(should_revert)] fn test_fail() { - let caller = abi(MyContract, CONTRACT_ID); + let contract_id = 0x822c8d3672471f64f14f326447793c7377b6e430122db23b622880ccbd8a33ef; // AUTO-CONTRACT-ID . + let caller = abi(MyContract, contract_id); let result = caller.test_function {}(); assert(result == false) } #[test] fn test_success() { - let caller = abi(MyContract, CONTRACT_ID); + let contract_id = 0x822c8d3672471f64f14f326447793c7377b6e430122db23b622880ccbd8a33ef; // AUTO-CONTRACT-ID . + let caller = abi(MyContract, contract_id); let result = caller.test_function {}(); assert(result == true) } diff --git a/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw index 3d69727a4a2..d5107addd94 100644 --- a/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/bytes_inline_tests/src/main.sw @@ -888,7 +888,7 @@ fn bytes_from_raw_slice() { }; let mut bytes = Bytes::from(slice); - assert(bytes.ptr() == slice.ptr()); + assert(bytes.ptr() != slice.ptr()); // Bytes should own its buffer assert(bytes.len() == slice.number_of_bytes()); } @@ -921,7 +921,7 @@ fn bytes_raw_slice_into() { let bytes: Bytes = slice.into(); - assert(bytes.ptr() == slice.ptr()); + assert(bytes.ptr() != slice.ptr()); // Bytes should own its buffer assert(bytes.len() == slice.number_of_bytes()); } diff --git a/test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw index ec1313fa345..079a28ee78d 100644 --- a/test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/string_inline_tests/src/main.sw @@ -55,7 +55,6 @@ fn string_clear_empty() { #[test] fn string_from_ascii() { let mut bytes = Bytes::new(); - bytes.push(0u8); bytes.push(1u8); bytes.push(2u8); @@ -63,11 +62,15 @@ fn string_from_ascii() { bytes.push(4u8); let mut string_from_ascii = String::from_ascii(bytes); - assert(bytes.capacity() == string_from_ascii.capacity()); + assert(bytes.len() == string_from_ascii.capacity()); + let bytes = string_from_ascii.as_bytes(); assert(bytes.get(0).unwrap() == 0u8); assert(bytes.get(1).unwrap() == 1u8); assert(bytes.get(2).unwrap() == 2u8); + assert(bytes.get(3).unwrap() == 3u8); + assert(bytes.get(4).unwrap() == 4u8); + assert(bytes.get(5) == None); } #[test] @@ -147,7 +150,7 @@ fn string_ptr() { let mut string_from_ascii = String::from_ascii(bytes); assert(!string_from_ascii.ptr().is_null()); - assert(string_from_ascii.ptr() == bytes.ptr()); + assert(string_from_ascii.ptr() != bytes.ptr()); } #[test] diff --git a/test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw index 5ac6a8fef32..78e2df5d1e5 100644 --- a/test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw +++ b/test/src/in_language_tests/test_programs/vec_inline_tests/src/main.sw @@ -641,7 +641,7 @@ fn vec_from_raw_slice() { }; let mut vec: Vec = Vec::from(slice); - assert(vec.ptr() == slice.ptr()); + assert(vec.ptr() != slice.ptr()); // Vec should own its buffer assert(vec.len() == slice.len::()); } @@ -683,7 +683,7 @@ fn vec_raw_slice_into() { let vec: Vec = slice.into(); - assert(vec.ptr() == slice.ptr()); + assert(vec.ptr() != slice.ptr()); // Vec should own its buffer assert(vec.len() == slice.len::()); } diff --git a/test/update-contract-ids.sh b/test/update-contract-ids.sh new file mode 100755 index 00000000000..23c82db18a9 --- /dev/null +++ b/test/update-contract-ids.sh @@ -0,0 +1,48 @@ +#! /bin/bash + +# CHANGES=$(git status --porcelain | wc -l) +# if [ "$CHANGES" != "0" ]; then +# echo "git state is not clean. commit or restore first." +# exit +# fi + +BOLD_RED='\033[1;31m' +BOLD_GREEN="\033[1;32m" +BOLD_YELLOW='\033[1;33m' +BOLD_WHITE='\033[1;97m' +NC='\033[0m' + +function join_by { + local d=${1-} f=${2-} + if shift 2; then + printf %s "$f" "${@/#/$d}" + fi +} + +grep --include \*.sw -Hno "// AUTO-CONTRACT-ID" . -R | while read line ; do + PARTS=($(echo $line | sed 's/:/ /g')) + FOLDER=$(dirname ${PARTS[0]}) + FILE=${PARTS[0]} + LINE=${PARTS[1]} + + CONTRACT_ARGS=($(sed "$LINE!d" $FILE)) + CONTRACT_ARGS=$(join_by " " ${CONTRACT_ARGS[@]:6}) + + if [[ $CONTRACT_ARGS ]]; then + PROJ=$(realpath "$FOLDER/..") + echo -e "${BOLD_WHITE}$PROJ${NC}" + + pushd "$FOLDER/.." >> /dev/null + CONTRACT_ID=$(cargo r -p forc --release -- contract-id --path $CONTRACT_ARGS 2> /dev/null | grep -oP '0x[a-zA-Z0-9]{64}') + + if [[ $CONTRACT_ID ]]; then + popd >> /dev/null + sed -i "${LINE}s/0x[a-zA-Z0-9]*/$CONTRACT_ID/g" $FILE + echo -e " ${BOLD_GREEN}ok${NC} ($CONTRACT_ID)" + else + echo -e " ${BOLD_RED}error${NC}" + cargo r -p forc --release -- contract-id --release + popd >> /dev/null + fi + fi +done