Переглянути джерело

Bugfix: Accessing virtual function selectors (#1447)

The added test case panics in current `main` because accessing the
selector of a virtual function which is not used in any other way will
put the function in `all_functions` but not `virtual_functions`.
`check_inheritance` will insert the function into `all_functions`
because we have this symbol, however because we only access the selector
it's not a virtual function to the contract. The fix is that when we
walk `all_functions` to find the externally callable ones, do not assume
every function marked `virtual` is present in the `virtual_functions` of
this contract.

Signed-off-by: xermicus <cyrill@parity.io>
Cyrill Leutwiler 2 роки тому
батько
коміт
a12d80385b
2 змінених файлів з 37 додано та 2 видалено
  1. 4 1
      src/codegen/cfg.rs
  2. 33 1
      tests/polkadot_tests/functions.rs

+ 4 - 1
src/codegen/cfg.rs

@@ -2124,7 +2124,10 @@ impl Namespace {
         // If a function is virtual, and it is overriden, do not make it public;
         // Otherwise the runtime function dispatch will have two identical functions to dispatch to.
         if func.is_virtual
-            && Some(self.contracts[contract_no].virtual_functions[&func.signature]) != function_no
+            && self.contracts[contract_no]
+                .virtual_functions
+                .get(&func.signature)
+                != function_no.as_ref()
         {
             return false;
         }

+ 33 - 1
tests/polkadot_tests/functions.rs

@@ -2,7 +2,7 @@
 
 use parity_scale_codec::{Decode, Encode};
 
-use crate::build_solidity;
+use crate::{build_solidity, build_wasm, load_abi};
 
 #[test]
 fn constructors() {
@@ -599,3 +599,35 @@ fn global_functions() {
 
     runtime.function("test", Vec::new());
 }
+
+#[test]
+fn virtual_function_member_access() {
+    let src = r##"
+        interface IERC1155Receiver {
+            @selector([1, 2, 3, 4])
+            function onERC1155Received() external returns (bytes4);
+        }
+    
+        abstract contract ERC1155 {
+            function _doSafeTransferAcceptanceCheck() internal pure returns (bytes4) {
+                return IERC1155Receiver.onERC1155Received.selector;
+            }
+        }
+
+        contract C is ERC1155 {
+            function create() public pure returns (bytes4) {
+                return _doSafeTransferAcceptanceCheck();
+            }
+        }"##;
+
+    // The create function is the only one appearing in the metadata.
+    let abi = load_abi(&build_wasm(src, false, false)[0].1);
+    let messages = abi.spec().messages();
+    assert_eq!(messages.len(), 1);
+    assert_eq!(messages[0].label(), "create");
+
+    // The create function returns the selector of IERC1155Receiver.onERC1155Received
+    let mut runtime = build_solidity(src);
+    runtime.function("create", vec![]);
+    assert_eq!(runtime.output(), vec![1, 2, 3, 4]);
+}