Sfoglia il codice sorgente

Add ecrecover() builtin for EVM (#1543)

Fixes https://github.com/hyperledger/solang/issues/1536

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 2 anni fa
parent
commit
41eab115cf

+ 60 - 0
src/codegen/expression.rs

@@ -2186,6 +2186,66 @@ fn expr_builtin(
                 expr: Box::new(codegen_expr),
             }
         }
+        ast::Builtin::ECRecover => {
+            // TODO:
+            // EVM: call precompile 1 (code below is untested)
+            // let args = args
+            //     .iter()
+            //     .map(|v| expression(v, cfg, contract_no, func, ns, vartab, opt))
+            //     .collect::<Vec<Expression>>();
+            //
+            // let payload = abi_encode(loc, args, ns, vartab, cfg, false).0;
+            //
+            // let instr = Instr::ExternalCall {
+            //     loc: *loc,
+            //     contract_function_no: None,
+            //     address: Some(Expression::NumberLiteral {
+            //         loc: *loc,
+            //         ty: Type::Address(false),
+            //         value: BigInt::one(),
+            //     }),
+            //     accounts: None,
+            //     seeds: None,
+            //     payload,
+            //     value: Expression::NumberLiteral {
+            //         loc: *loc,
+            //         ty: ns.value_type(),
+            //         value: 0.into(),
+            //     },
+            //     success: None,
+            //     gas: Expression::NumberLiteral {
+            //         loc: *loc,
+            //         ty: ns.value_type(),
+            //         value: 0.into(),
+            //     },
+            //     callty: CallTy::Regular,
+            //     flags: None,
+            // };
+            //
+            // cfg.add(vartab, instr);
+            //
+            // let mut res = abi_decode(
+            //     loc,
+            //     &Expression::ReturnData { loc: *loc },
+            //     &[Type::Address(false)],
+            //     ns,
+            //     vartab,
+            //     cfg,
+            //     None,
+            // );
+            //
+            // res.remove(0)
+
+            // Polkadot: call ecdsa_recover(): https://docs.rs/pallet-contracts/latest/pallet_contracts/api_doc/trait.Version0.html#tymethod.ecdsa_recover
+            // Solana: see how neon implements this
+            cfg.add(vartab, Instr::Unimplemented { reachable: true });
+
+            Expression::NumberLiteral {
+                loc: *loc,
+                ty: Type::Bool,
+                value: 0.into(),
+            }
+        }
         _ => {
             let arguments: Vec<Expression> = args
                 .iter()

+ 1 - 0
src/sema/ast.rs

@@ -1662,6 +1662,7 @@ pub enum Builtin {
     Accounts,
     UserTypeWrap,
     UserTypeUnwrap,
+    ECRecover,
 }
 
 #[derive(PartialEq, Eq, Clone, Debug)]

+ 17 - 1
src/sema/builtin.rs

@@ -33,7 +33,7 @@ pub struct Prototype {
 }
 
 // A list of all Solidity builtins functions
-static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
+static BUILTIN_FUNCTIONS: Lazy<[Prototype; 25]> = Lazy::new(|| {
     [
         Prototype {
             builtin: Builtin::Assert,
@@ -306,6 +306,22 @@ static BUILTIN_FUNCTIONS: Lazy<[Prototype; 24]> = Lazy::new(|| {
             doc: "unwrap user defined type",
             constant: true,
         },
+        Prototype {
+            builtin: Builtin::ECRecover,
+            namespace: None,
+            method: vec![],
+            name: "ecrecover",
+            params: vec![
+                Type::Bytes(32),
+                Type::Uint(8),
+                Type::Bytes(32),
+                Type::Bytes(32),
+            ],
+            ret: vec![Type::Address(false)],
+            target: vec![Target::EVM],
+            doc: "Recover the address associated with the public key from elliptic curve signature",
+            constant: false,
+        },
     ]
 });
 

+ 8 - 0
tests/contract_testcases/evm/ecrecover.sol

@@ -0,0 +1,8 @@
+contract signed {
+	function recoverSignerFromSignature(uint8 v, bytes32 r, bytes32 s, bytes32 hash) pure external {
+		address signer = ecrecover(hash, v, r, s);
+		require(signer != address(0), "ECDSA: invalid signature");
+	}
+}
+
+// ---- Expect: diagnostics ----

+ 1 - 1
tests/evm.rs

@@ -249,7 +249,7 @@ fn ethereum_solidity_tests() {
         })
         .sum();
 
-    assert_eq!(errors, 1018);
+    assert_eq!(errors, 1012);
 }
 
 fn set_file_contents(source: &str, path: &Path) -> (FileResolver, Vec<String>) {