Browse Source

Bugfix 1076: Destructing referenced types need a load (#1097)

Cyrill Leutwiler 2 years ago
parent
commit
1d49046569

+ 26 - 21
src/codegen/statements.rs

@@ -946,32 +946,37 @@ fn cast_and_try_load(
 ) -> Expression {
     let casted_expr = expr.cast(to_ty, ns);
 
-    if let Type::StorageRef(_, ty) = casted_expr.ty() {
-        if let Expression::Subscript(_, _, ty, ..) = &casted_expr {
-            if ty.is_storage_bytes() {
-                return casted_expr;
+    match casted_expr.ty() {
+        Type::StorageRef(_, ty) => {
+            if let Expression::Subscript(_, _, ty, ..) = &casted_expr {
+                if ty.is_storage_bytes() {
+                    return casted_expr;
+                }
             }
-        }
 
-        if matches!(to_ty, Type::StorageRef(..)) {
-            // If we want a storage reference, there is no need to load from storage
-            return casted_expr;
-        }
+            if matches!(to_ty, Type::StorageRef(..)) {
+                // If we want a storage reference, there is no need to load from storage
+                return casted_expr;
+            }
 
-        let anonymous_no = vartab.temp_anonymous(&ty);
-        cfg.add(
-            vartab,
-            Instr::LoadStorage {
-                res: anonymous_no,
-                ty: (*ty).clone(),
-                storage: casted_expr,
-            },
-        );
+            let anonymous_no = vartab.temp_anonymous(&ty);
+            cfg.add(
+                vartab,
+                Instr::LoadStorage {
+                    res: anonymous_no,
+                    ty: (*ty).clone(),
+                    storage: casted_expr,
+                },
+            );
 
-        return Expression::Variable(*loc, (*ty).clone(), anonymous_no);
+            Expression::Variable(*loc, (*ty).clone(), anonymous_no)
+        }
+        Type::Ref(ty) => match *ty {
+            Type::Array(_, _) => casted_expr,
+            _ => Expression::Load(pt::Loc::Builtin, *ty, casted_expr.into()),
+        },
+        _ => casted_expr,
     }
-
-    casted_expr
 }
 
 /// Resolve try catch statement

+ 1 - 1
tests/substrate_tests/contracts.rs

@@ -300,7 +300,7 @@ fn mangle_overloaded_function_names_in_abi() {
         .collect();
 
     assert!(messages_a.contains(&"foo".to_string()));
-    assert!(!messages_a.contains(&"foo_".to_string()));
+    assert!(!messages_a.contains(&"foo_bool".to_string()));
 
     let messages_b: Vec<String> = runtime
         .programs

+ 1 - 0
tests/substrate_tests/mod.rs

@@ -22,6 +22,7 @@ mod loops;
 mod mappings;
 mod modifier;
 mod primitives;
+mod statements;
 mod storage;
 mod strings;
 mod structs;

+ 73 - 0
tests/substrate_tests/statements.rs

@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::build_solidity;
+use parity_scale_codec::Encode;
+
+#[test]
+fn destruct_from_array() {
+    #[derive(Encode)]
+    struct Arg {
+        values: Vec<u32>,
+        fakes: Vec<bool>,
+        id: Vec<u8>,
+    }
+
+    let mut runtime = build_solidity(
+        "
+        contract BlindAuction {
+            function reveal(
+                uint32[] values,
+                bool[] fakes,
+                bytes memory id
+            ) public pure returns (bool) {
+                (uint32 value, bool fake) = (values[0], fakes[0]);
+                return id == abi.encodePacked(value, fake);
+            }
+        }",
+    );
+
+    let values = vec![1];
+    let fakes = vec![true];
+    let id = vec![1, 0, 0, 0, 1];
+    runtime.function("reveal", Arg { values, fakes, id }.encode());
+    assert_eq!(runtime.vm.output, true.encode());
+}
+
+#[test]
+fn destruct_from_struct() {
+    #[derive(Encode)]
+    struct S1(Vec<u32>);
+
+    #[derive(Encode)]
+    struct S2(Vec<bool>);
+
+    #[derive(Encode)]
+    struct Arg {
+        values: S1,
+        fakes: S2,
+        id: Vec<u8>,
+    }
+
+    let mut runtime = build_solidity(
+        "
+        contract BlindAuction {
+            struct S1 { uint32[] u; }
+            struct S2 { bool[] b; }
+        
+            function reveal(
+                S1 values,
+                S2 fakes,
+                bytes memory id
+            ) external pure returns (bool) {
+                (uint32 value, bool fake) = (values.u[0], fakes.b[0]);
+                return id == abi.encodePacked(value, fake);
+            }
+        }",
+    );
+
+    let values = S1(vec![1]);
+    let fakes = S2(vec![true]);
+    let id = vec![1, 0, 0, 0, 1];
+    runtime.function("reveal", Arg { values, fakes, id }.encode());
+    assert_eq!(runtime.vm.output, true.encode());
+}