فهرست منبع

Add release flag (#1227)

Signed-off-by: salaheldinsoliman <salaheldin_sameh@aucegypt.edu>
Co-authored-by: Sean Young <sean@mess.org>
salaheldinsoliman 2 سال پیش
والد
کامیت
1b46d73b32

+ 34 - 7
docs/code_gen_options.rst

@@ -4,8 +4,7 @@ Code Generation Options
 There are compiler flags to control code generation. They can be divided into two categories: 
 
 * Optimizer passes are enabled by default and make the generated code more optimal. 
-* Debugging options are not enabled by default, but they greatly improve
-  developer experience, at the cost of increased gas and storage usage.
+* Debugging options are enabled by default. They can be disabled in release builds, using `--release` CLI option, to decrease gas or compute units usage and code size.
 
 Optimizer Passes
 ----------------
@@ -149,11 +148,21 @@ as a function argument, for instance, the length is unknown.
 Debugging Options
 -----------------
 
-It may be desirable to have access to debug information regarding the contract execution. 
-However, this will lead to more instructions as well as higher gas usage. Hence, it is disabled by default,
-but can be enabled using CLI flags. Just make sure not to use them in production deployments.
+It is desirable to have access to debug information regarding the contract execution in the testing phase.
+Therefore, by default, debugging options are enabled; however, they can be deactivated by utilizing the command-line interface (CLI) flags.
+Debugging options should be disabled in release builds, as debug builds greatly increase contract size and gas consumption.
+Solang provides three debugging options, namely debug prints, logging API return codes, and logging runtime errors. For more flexible debugging,
+Solang supports disabling each debugging feature on its own, as well as disabling them all at once with the ``--release`` flag.
 
-.. _log-api-return-codes:
+.. _no-print:
+
+Print Function
+++++++++++++++
+
+Solang provides a :ref:`print_function` which is enabled by default.
+The ``no-print`` flag will instruct the compiler not to log debugging prints in the environment.
+
+.. _no-log-api-return-codes:
 
 Log runtime API call results
 ++++++++++++++++++++++++++++
@@ -161,9 +170,27 @@ Log runtime API call results
 Runtime API calls are not guaranteed to succeed.
 By design, the low level results of these calls are abstracted away in Solidity.
 For development purposes, it can be desirable to observe the low level return code of such calls.
-The ``--log-api-return-codes`` flag will make the contract print the return code of runtime calls, if there are any.
+The contract will print the return code of runtime calls by default, and this feature can be disabled by providing the 
+``--no-log-api-return-codes`` flag.
 
 .. note::
 
     This is only implemented for the Substrate target.
 
+
+.. _no-log-runtime-errors:
+
+Log Runtime Errors
+++++++++++++++++++
+
+In most cases, contract execution will emit a human readable error message in case a runtime error is encountered.
+The error is printed out alongside with the filename and line number that caused the error.
+This feature is enabled by default, and can be disabled by the ``--no-log-runtime-errors`` flag.
+
+.. _release:
+
+Release builds:
++++++++++++++++
+
+Release builds must not contain any debugging related logic. The ``--release`` flag will turn off all debugging features, 
+thereby reducing the required gas and storage.

+ 2 - 0
docs/language/builtins.rst

@@ -537,6 +537,8 @@ This function does not write the length of the byte array to the buffer.
 Miscellaneous
 _____________
 
+.. _print_function:
+
 print(string)
 +++++++++++++
 

+ 11 - 2
docs/running.rst

@@ -119,8 +119,17 @@ Options:
 \-\-no\-cse
    Disable the :ref:`common-subexpression-elimination` optimization
 
-\-\-log\-api\-return\-codes
-   Disable the :ref:`common-subexpression-elimination` optimization
+\-\-no\-log\-api\-return\-codes
+   Disable the :ref:`no-log-api-return-codes` debugging feature
+
+\-\-no\-log\-runtime\-errors
+   Disable the :ref:`no-log-runtime-errors` debugging feature
+
+\-\-no\-prints
+   Disable the :ref:`no-print` debugging feature
+
+\-\-release
+   Disable all debugging features for :ref:`release`
 
 .. warning::
 

+ 1 - 1
integration/solana/package.json

@@ -4,7 +4,7 @@
   "description": "Integration tests with Solang and Solana",
   "scripts": {
     "test": "tsc; ts-node setup.ts; mocha --parallel *.spec.ts",
-    "build": "solang compile *.sol --target solana -v --log-runtime-errors"
+    "build": "solang compile *.sol --target solana -v"
   },
   "author": "Sean Young <sean@mess.org>",
   "license": "MIT",

+ 1 - 1
integration/substrate/build.sh

@@ -6,6 +6,6 @@ if [[ $dup_contracts ]]; then
 	echo "Found contract with duplicate names: ${dup_contracts}"
 	/bin/false
 else
-	parallel solang compile -v -g --target substrate --log-runtime-errors --log-api-return-codes ::: *.sol test/*.sol
+	parallel solang compile -v -g --target substrate ::: *.sol test/*.sol ; solang compile -v --target substrate --release release_version.sol ;
 fi
 

+ 7 - 0
integration/substrate/release_version.sol

@@ -0,0 +1,7 @@
+contract release {
+    function print_then_error(int8 num) public returns (int8) {
+        print("Hello!");
+        int8 ovf = num + 120;
+        return ovf;
+    }
+}

+ 29 - 0
integration/substrate/release_version.spec.ts

@@ -0,0 +1,29 @@
+import { createConnection, deploy, aliceKeypair, debug_buffer } from "./index";
+import expect from 'expect';
+import { ContractPromise } from "@polkadot/api-contract";
+
+describe('Deploy release_version.sol and test the debug buffer is empty', () => {
+    it('removes all debugging', async function () {
+        let conn = await createConnection();
+        const alice = aliceKeypair();
+        let deployed_contract = await deploy(
+            conn,
+            alice,
+            "release.contract",
+            BigInt(0)
+        );
+        let contract = new ContractPromise(
+            conn,
+            deployed_contract.abi,
+            deployed_contract.address
+        );
+
+        // The --release flag should remove all debugging features, making the debug buffer empty
+        let res = await debug_buffer(conn, contract, `print_then_error`, [20])
+        expect(res).toEqual("")
+
+        let res2 = await debug_buffer(conn, contract, `print_then_error`, [0])
+        expect(res2).toEqual("")
+        conn.disconnect();
+    });
+});

+ 24 - 10
src/bin/solang.rs

@@ -180,11 +180,10 @@ fn main() {
                             .display_order(5),
                     )
                     .arg(
-                        Arg::new("LOGAPIRETURNS")
-                            .help("Log the return codes of runtime API calls in the environment")
-                            .long("log-api-return-codes")
-                            .action(ArgAction::SetTrue)
-                            .display_order(7),
+                        Arg::new("NOLOGAPIRETURNS")
+                            .help("Disable logging the return codes of runtime API calls in the environment")
+                            .long("no-log-api-return-codes")
+                            .action(ArgAction::SetFalse)
                     )
                     .arg(
                         Arg::new("GENERATEDEBUGINFORMATION")
@@ -195,9 +194,19 @@ fn main() {
                             .hide(true),
                     )
                     .arg(
-                        Arg::new("LOGRUNTIMEERRORS")
-                            .help("Log runtime errors in the environment")
-                            .long("log-runtime-errors")
+                        Arg::new("NOLOGRUNTIMEERRORS")
+                            .help("Disable logging runtime errors in the environment")
+                            .long("no-log-runtime-errors")
+                            .action(ArgAction::SetFalse),
+                    ).arg(
+                        Arg::new("NOPRINT")
+                            .help("Disable logging prints in the environment")
+                            .long("no-print")
+                            .action(ArgAction::SetFalse),
+                    ).arg(
+                        Arg::new("RELEASE")
+                            .help("Disable all debugging features such as prints, logging runtime errors, and logging api return codes")
+                            .long("release")
                             .action(ArgAction::SetTrue),
                     ),
             )
@@ -398,9 +407,13 @@ fn compile(matches: &ArgMatches) {
 
     let generate_debug_info = *matches.get_one("GENERATEDEBUGINFORMATION").unwrap();
 
-    let log_api_return_codes = *matches.get_one("LOGAPIRETURNS").unwrap();
+    let release = *matches.get_one::<bool>("RELEASE").unwrap();
+
+    let log_api_return_codes = *matches.get_one::<bool>("NOLOGAPIRETURNS").unwrap() & !release;
+
+    let log_runtime_errors = *matches.get_one::<bool>("NOLOGRUNTIMEERRORS").unwrap() & !release;
 
-    let log_runtime_errors = *matches.get_one::<bool>("LOGRUNTIMEERRORS").unwrap();
+    let log_prints = *matches.get_one::<bool>("NOPRINT").unwrap() & !release;
 
     let mut resolver = imports_arg(matches);
 
@@ -424,6 +437,7 @@ fn compile(matches: &ArgMatches) {
         opt_level,
         log_api_return_codes,
         log_runtime_errors,
+        log_prints,
     };
 
     let mut namespaces = Vec::new();

+ 9 - 7
src/codegen/expression.rs

@@ -877,15 +877,17 @@ pub fn expression(
             args,
             ..
         } => {
-            let expr = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
+            if opt.log_prints {
+                let expr = expression(&args[0], cfg, contract_no, func, ns, vartab, opt);
 
-            let to_print = if ns.target.is_substrate() {
-                add_prefix_and_delimiter_to_print(expr)
-            } else {
-                expr
-            };
+                let to_print = if ns.target.is_substrate() {
+                    add_prefix_and_delimiter_to_print(expr)
+                } else {
+                    expr
+                };
 
-            cfg.add(vartab, Instr::Print { expr: to_print });
+                cfg.add(vartab, Instr::Print { expr: to_print });
+            }
 
             Expression::Poison
         }

+ 2 - 0
src/codegen/mod.rs

@@ -91,6 +91,7 @@ pub struct Options {
     pub opt_level: OptimizationLevel,
     pub log_api_return_codes: bool,
     pub log_runtime_errors: bool,
+    pub log_prints: bool,
 }
 
 impl Default for Options {
@@ -105,6 +106,7 @@ impl Default for Options {
             opt_level: OptimizationLevel::Default,
             log_api_return_codes: false,
             log_runtime_errors: false,
+            log_prints: true,
         }
     }
 }

+ 2 - 0
src/lib.rs

@@ -124,12 +124,14 @@ pub fn compile(
     target: Target,
     log_api_return_codes: bool,
     log_runtime_errors: bool,
+    log_prints: bool,
 ) -> (Vec<(Vec<u8>, String)>, sema::ast::Namespace) {
     let mut ns = parse_and_resolve(filename, resolver, target);
     let opts = codegen::Options {
         log_api_return_codes,
         opt_level: opt_level.into(),
         log_runtime_errors,
+        log_prints,
         ..Default::default()
     };
 

+ 1 - 1
tests/codegen_testcases/solidity/array_of_struct.sol

@@ -12,7 +12,7 @@ contract c {
         uint64[4] f2;
     }
 
-// BEGIN-CHECK: @"c::c::function::foo__c.S"(ptr %14, ptr %0)
+// BEGIN-CHECK: @"c::c::function::foo__c.S"(ptr %0, ptr %1)
     function foo(S s) public pure {
     }
 }

+ 1 - 0
tests/solana.rs

@@ -145,6 +145,7 @@ fn build_solidity(src: &str) -> VirtualMachine {
         Target::Solana,
         false,
         true,
+        true,
     );
 
     ns.print_diagnostics_in_plain(&cache, false);

+ 1 - 0
tests/substrate.rs

@@ -1199,6 +1199,7 @@ pub fn build_solidity_with_options(
         Target::default_substrate(),
         log_api_return_codes,
         log_runtime_errors,
+        true,
     );
 
     ns.print_diagnostics_in_plain(&cache, false);

+ 2 - 0
tests/substrate_tests/inheritance.rs

@@ -37,6 +37,7 @@ fn test_abstract() {
         Target::default_substrate(),
         false,
         false,
+        true,
     );
 
     assert!(!ns.diagnostics.any_errors());
@@ -76,6 +77,7 @@ fn test_abstract() {
         Target::default_substrate(),
         false,
         false,
+        true,
     );
 
     assert!(!ns.diagnostics.any_errors());

+ 1 - 0
tests/undefined_variable_detection.rs

@@ -21,6 +21,7 @@ fn parse_and_codegen(src: &'static str) -> Namespace {
         generate_debug_information: false,
         log_api_return_codes: false,
         log_runtime_errors: false,
+        log_prints: true,
     };
 
     codegen(&mut ns, &opt);