Quellcode durchsuchen

substrate: remove scratch buffer from functions returning simple values

These are the simple cases.

Signed-off-by: Sean Young <sean@mess.org>
Sean Young vor 5 Jahren
Ursprung
Commit
ea0f3bd2b2
2 geänderte Dateien mit 211 neuen und 166 gelöschten Zeilen
  1. 138 121
      src/emit/substrate.rs
  2. 73 45
      tests/substrate.rs

+ 138 - 121
src/emit/substrate.rs

@@ -424,55 +424,82 @@ impl SubstrateTarget {
 
         contract.module.add_function(
             "ext_address",
-            contract.context.void_type().fn_type(&[], false),
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
         contract.module.add_function(
             "ext_balance",
-            contract.context.void_type().fn_type(&[], false),
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
         contract.module.add_function(
             "ext_minimum_balance",
-            contract.context.void_type().fn_type(&[], false),
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
         contract.module.add_function(
             "ext_block_number",
-            contract.context.void_type().fn_type(&[], false),
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
         contract.module.add_function(
             "ext_now",
-            contract.context.void_type().fn_type(&[], false),
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
         contract.module.add_function(
             "ext_tombstone_deposit",
-            contract.context.void_type().fn_type(&[], false),
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
         contract.module.add_function(
-            "ext_gas_price",
-            contract.context.void_type().fn_type(&[u64_val], false),
+            "ext_weight_to_fee",
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u64_val, u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
         contract.module.add_function(
             "ext_gas_left",
-            contract.context.void_type().fn_type(&[], false),
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
         contract.module.add_function(
             "ext_caller",
-            contract.context.void_type().fn_type(&[], false),
+            contract
+                .context
+                .void_type()
+                .fn_type(&[u8_ptr, u32_ptr], false),
             Some(Linkage::External),
         );
 
@@ -2860,14 +2887,18 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
         if let Some(value) = value {
             contract.builder.build_store(value_ptr, value);
         } else {
-            contract.builder.build_call(
-                contract.module.get_function("ext_minimum_balance").unwrap(),
-                &[],
-                "minimum_balance",
+            let scratch_len = contract.scratch_len.unwrap().as_pointer_value();
+
+            contract.builder.build_store(
+                scratch_len,
+                contract
+                    .context
+                    .i32_type()
+                    .const_int(contract.ns.value_length as u64, false),
             );
 
             contract.builder.build_call(
-                contract.module.get_function("ext_scratch_read").unwrap(),
+                contract.module.get_function("ext_minimum_balance").unwrap(),
                 &[
                     contract
                         .builder
@@ -2877,12 +2908,7 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                             "",
                         )
                         .into(),
-                    contract.context.i32_type().const_zero().into(),
-                    contract
-                        .context
-                        .i32_type()
-                        .const_int(contract.ns.value_length as u64, false)
-                        .into(),
+                    scratch_len.into(),
                 ],
                 "minimum_balance",
             );
@@ -3227,79 +3253,73 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
 
     /// Substrate value is usually 128 bits
     fn balance<'b>(&self, contract: &Contract<'b>, _addr: IntValue<'b>) -> IntValue<'b> {
-        let value = contract
-            .builder
-            .build_alloca(contract.value_type(), "balance");
+        let scratch_buf = contract.builder.build_pointer_cast(
+            contract.scratch.unwrap().as_pointer_value(),
+            contract.context.i8_type().ptr_type(AddressSpace::Generic),
+            "scratch_buf",
+        );
+        let scratch_len = contract.scratch_len.unwrap().as_pointer_value();
 
-        contract.builder.build_call(
-            contract.module.get_function("ext_balance").unwrap(),
-            &[],
-            "balance",
+        contract.builder.build_store(
+            scratch_len,
+            contract
+                .context
+                .i32_type()
+                .const_int(contract.ns.value_length as u64, false),
         );
 
         contract.builder.build_call(
-            contract.module.get_function("ext_scratch_read").unwrap(),
-            &[
-                contract
-                    .builder
-                    .build_pointer_cast(
-                        value,
-                        contract.context.i8_type().ptr_type(AddressSpace::Generic),
-                        "",
-                    )
-                    .into(),
-                contract.context.i32_type().const_zero().into(),
-                contract
-                    .context
-                    .i32_type()
-                    .const_int(contract.ns.value_length as u64, false)
-                    .into(),
-            ],
+            contract.module.get_function("ext_balance").unwrap(),
+            &[scratch_buf.into(), scratch_len.into()],
             "balance",
         );
 
         contract
             .builder
-            .build_load(value, "balance")
+            .build_load(
+                contract.builder.build_pointer_cast(
+                    scratch_buf,
+                    contract.value_type().ptr_type(AddressSpace::Generic),
+                    "",
+                ),
+                "balance",
+            )
             .into_int_value()
     }
 
-    /// Substrate value is usually 128 bits
+    /// Substrate address is usually 256 bits
     fn get_address<'b>(&self, contract: &Contract<'b>) -> IntValue<'b> {
-        let value = contract
-            .builder
-            .build_alloca(contract.address_type(), "self_address");
+        let scratch_buf = contract.builder.build_pointer_cast(
+            contract.scratch.unwrap().as_pointer_value(),
+            contract.context.i8_type().ptr_type(AddressSpace::Generic),
+            "scratch_buf",
+        );
+        let scratch_len = contract.scratch_len.unwrap().as_pointer_value();
 
-        contract.builder.build_call(
-            contract.module.get_function("ext_address").unwrap(),
-            &[],
-            "self_address",
+        contract.builder.build_store(
+            scratch_len,
+            contract
+                .context
+                .i32_type()
+                .const_int(contract.ns.address_length as u64, false),
         );
 
         contract.builder.build_call(
-            contract.module.get_function("ext_scratch_read").unwrap(),
-            &[
-                contract
-                    .builder
-                    .build_pointer_cast(
-                        value,
-                        contract.context.i8_type().ptr_type(AddressSpace::Generic),
-                        "",
-                    )
-                    .into(),
-                contract.context.i32_type().const_zero().into(),
-                contract
-                    .context
-                    .i32_type()
-                    .const_int(contract.ns.address_length as u64, false)
-                    .into(),
-            ],
-            "self_address",
+            contract.module.get_function("ext_address").unwrap(),
+            &[scratch_buf.into(), scratch_len.into()],
+            "address",
         );
 
         contract
             .builder
-            .build_load(value, "self_address")
+            .build_load(
+                contract.builder.build_pointer_cast(
+                    scratch_buf,
+                    contract.address_type().ptr_type(AddressSpace::Generic),
+                    "",
+                ),
+                "self_address",
+            )
             .into_int_value()
     }
 
@@ -3505,38 +3525,38 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
     ) -> BasicValueEnum<'b> {
         macro_rules! get_seal_value {
             ($name:literal, $func:literal, $width:expr) => {{
-                let value = contract
-                    .builder
-                    .build_alloca(contract.context.custom_width_int_type($width), $name);
+                let scratch_buf = contract.builder.build_pointer_cast(
+                    contract.scratch.unwrap().as_pointer_value(),
+                    contract.context.i8_type().ptr_type(AddressSpace::Generic),
+                    "scratch_buf",
+                );
+                let scratch_len = contract.scratch_len.unwrap().as_pointer_value();
+
+                contract.builder.build_store(
+                    scratch_len,
+                    contract
+                        .context
+                        .i32_type()
+                        .const_int($width as u64 / 8, false),
+                );
 
                 contract.builder.build_call(
                     contract.module.get_function($func).unwrap(),
-                    &[],
+                    &[scratch_buf.into(), scratch_len.into()],
                     $name,
                 );
 
-                contract.builder.build_call(
-                    contract.module.get_function("ext_scratch_read").unwrap(),
-                    &[
-                        contract
-                            .builder
-                            .build_pointer_cast(
-                                value,
-                                contract.context.i8_type().ptr_type(AddressSpace::Generic),
-                                "",
-                            )
-                            .into(),
-                        contract.context.i32_type().const_zero().into(),
+                contract.builder.build_load(
+                    contract.builder.build_pointer_cast(
+                        scratch_buf,
                         contract
                             .context
-                            .i32_type()
-                            .const_int($width as u64 / 8, false)
-                            .into(),
-                    ],
+                            .custom_width_int_type($width)
+                            .ptr_type(AddressSpace::Generic),
+                        "",
+                    ),
                     $name,
-                );
-
-                contract.builder.build_load(value, $name)
+                )
             }};
         };
 
@@ -3649,41 +3669,38 @@ impl<'a> TargetRuntime<'a> for SubstrateTarget {
                         .into_int_value()
                 };
 
-                let value_length = contract.ns.value_length as u32 * 8;
+                let scratch_buf = contract.builder.build_pointer_cast(
+                    contract.scratch.unwrap().as_pointer_value(),
+                    contract.context.i8_type().ptr_type(AddressSpace::Generic),
+                    "scratch_buf",
+                );
+                let scratch_len = contract.scratch_len.unwrap().as_pointer_value();
 
-                let value = contract.builder.build_alloca(
-                    contract.context.custom_width_int_type(value_length),
-                    "price",
+                contract.builder.build_store(
+                    scratch_len,
+                    contract
+                        .context
+                        .i32_type()
+                        .const_int(contract.ns.value_length as u64, false),
                 );
 
                 contract.builder.build_call(
-                    contract.module.get_function("ext_gas_price").unwrap(),
-                    &[gas.into()],
+                    contract.module.get_function("ext_weight_to_fee").unwrap(),
+                    &[gas.into(), scratch_buf.into(), scratch_len.into()],
                     "gas_price",
                 );
 
-                contract.builder.build_call(
-                    contract.module.get_function("ext_scratch_read").unwrap(),
-                    &[
-                        contract
-                            .builder
-                            .build_pointer_cast(
-                                value,
-                                contract.context.i8_type().ptr_type(AddressSpace::Generic),
-                                "",
-                            )
-                            .into(),
-                        contract.context.i32_type().const_zero().into(),
+                contract.builder.build_load(
+                    contract.builder.build_pointer_cast(
+                        scratch_buf,
                         contract
                             .context
-                            .i32_type()
-                            .const_int(value_length as u64 / 8, false)
-                            .into(),
-                    ],
+                            .custom_width_int_type(contract.ns.value_length as u32 * 8)
+                            .ptr_type(AddressSpace::Generic),
+                        "",
+                    ),
                     "price",
-                );
-
-                contract.builder.build_load(value, "price")
+                )
             }
             ast::Expression::Builtin(_, _, ast::Builtin::Sender, _) => {
                 get_seal_value!("caller", "ext_caller", 256)

+ 73 - 45
tests/substrate.rs

@@ -105,7 +105,7 @@ enum SubstrateExternal {
     ext_hash_blake2_256,
     ext_block_number,
     ext_now,
-    ext_gas_price,
+    ext_weight_to_fee,
     ext_gas_left,
     ext_caller,
     ext_tombstone_deposit,
@@ -156,6 +156,31 @@ impl Externals for TestRuntime {
         index: usize,
         args: RuntimeArgs,
     ) -> Result<Option<RuntimeValue>, Trap> {
+        macro_rules! set_seal_value {
+            ($name:literal, $dest_ptr:expr, $len_ptr:expr, $buf:expr) => {{
+                println!("{}: {}", $name, hex::encode($buf));
+
+                let len = self
+                    .vm
+                    .memory
+                    .get_value::<u32>($len_ptr)
+                    .expect(&format!("{} len_ptr should be valid", $name));
+
+                if (len as usize) < $buf.len() {
+                    panic!("{} input is {} buffer is {}", $name, $buf.len(), len);
+                }
+
+                if let Err(e) = self.vm.memory.set($dest_ptr, $buf) {
+                    panic!("{}: {}", $name, e);
+                }
+
+                self.vm
+                    .memory
+                    .set_value($len_ptr, $buf.len() as u32)
+                    .expect(&format!("{} len_ptr should be valid", $name));
+            }};
+        }
+
         match FromPrimitive::from_usize(index) {
             Some(SubstrateExternal::ext_input) => {
                 let dest_ptr: u32 = args.nth_checked(0)?;
@@ -675,97 +700,100 @@ impl Externals for TestRuntime {
 
                 let scratch = self.vm.value.to_le_bytes().to_vec();
 
-                println!("ext_value_transferred: {}", hex::encode(&scratch));
-
-                let len = self
-                    .vm
-                    .memory
-                    .get_value::<u32>(len_ptr)
-                    .expect("ext_value_transferred len_ptr should be valid");
-
-                if (len as usize) < scratch.len() {
-                    panic!(
-                        "input is {} ext_value_transferred buffer {}",
-                        self.vm.input.len(),
-                        len
-                    );
-                }
-
-                if let Err(e) = self.vm.memory.set(dest_ptr, &scratch) {
-                    panic!("ext_value_transferred: {}", e);
-                }
-
-                self.vm
-                    .memory
-                    .set_value(len_ptr, scratch.len() as u32)
-                    .expect("ext_value_transferred len_ptr should be valid");
+                set_seal_value!("ext_value_transferred", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
             Some(SubstrateExternal::ext_address) => {
-                self.vm.scratch = self.vm.address.to_vec();
+                let dest_ptr: u32 = args.nth_checked(0)?;
+                let len_ptr: u32 = args.nth_checked(1)?;
+
+                let scratch = self.vm.address.to_vec();
 
-                println!("ext_address: {}", hex::encode(&self.vm.scratch));
+                set_seal_value!("ext_address", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
             Some(SubstrateExternal::ext_caller) => {
-                self.vm.scratch = self.vm.caller.to_vec();
+                let dest_ptr: u32 = args.nth_checked(0)?;
+                let len_ptr: u32 = args.nth_checked(1)?;
 
-                println!("ext_caller: {}", hex::encode(&self.vm.scratch));
+                let scratch = self.vm.caller.to_vec();
+
+                set_seal_value!("ext_caller", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
             Some(SubstrateExternal::ext_balance) => {
-                self.vm.scratch = self.accounts[&self.vm.address].1.to_le_bytes().to_vec();
+                let dest_ptr: u32 = args.nth_checked(0)?;
+                let len_ptr: u32 = args.nth_checked(1)?;
 
-                println!("ext_balance: {}", hex::encode(&self.vm.scratch));
+                let scratch = self.accounts[&self.vm.address].1.to_le_bytes().to_vec();
+
+                set_seal_value!("ext_balance", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
             Some(SubstrateExternal::ext_minimum_balance) => {
-                self.vm.scratch = 500u128.to_le_bytes().to_vec();
+                let dest_ptr: u32 = args.nth_checked(0)?;
+                let len_ptr: u32 = args.nth_checked(1)?;
 
-                println!("ext_minimum_balance: {}", hex::encode(&self.vm.scratch));
+                let scratch = 500u128.to_le_bytes().to_vec();
+
+                set_seal_value!("ext_minimum_balance", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
             Some(SubstrateExternal::ext_block_number) => {
-                self.vm.scratch = 950_119_597u32.to_le_bytes().to_vec();
+                let dest_ptr: u32 = args.nth_checked(0)?;
+                let len_ptr: u32 = args.nth_checked(1)?;
 
-                println!("ext_block_number: {}", hex::encode(&self.vm.scratch));
+                let scratch = 950_119_597u32.to_le_bytes().to_vec();
+
+                set_seal_value!("ext_block_number", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
             Some(SubstrateExternal::ext_now) => {
-                self.vm.scratch = 1594035638000u64.to_le_bytes().to_vec();
+                let dest_ptr: u32 = args.nth_checked(0)?;
+                let len_ptr: u32 = args.nth_checked(1)?;
 
-                println!("ext_now: {}", hex::encode(&self.vm.scratch));
+                let scratch = 1594035638000u64.to_le_bytes().to_vec();
+
+                set_seal_value!("ext_now", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
             Some(SubstrateExternal::ext_gas_left) => {
-                self.vm.scratch = 2_224_097_461u64.to_le_bytes().to_vec();
+                let dest_ptr: u32 = args.nth_checked(0)?;
+                let len_ptr: u32 = args.nth_checked(1)?;
 
-                println!("ext_gas_left: {}", hex::encode(&self.vm.scratch));
+                let scratch = 2_224_097_461u64.to_le_bytes().to_vec();
+
+                set_seal_value!("ext_gas_left", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
-            Some(SubstrateExternal::ext_gas_price) => {
+            Some(SubstrateExternal::ext_weight_to_fee) => {
                 let units: u64 = args.nth_checked(0)?;
+                let dest_ptr: u32 = args.nth_checked(1)?;
+                let len_ptr: u32 = args.nth_checked(2)?;
 
-                self.vm.scratch = (59_541_253_813_967u128 * units as u128)
+                let scratch = (59_541_253_813_967u128 * units as u128)
                     .to_le_bytes()
                     .to_vec();
 
-                println!("ext_gas_price: {}", hex::encode(&self.vm.scratch));
+                set_seal_value!("ext_weight_to_fee", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
             Some(SubstrateExternal::ext_tombstone_deposit) => {
-                self.vm.scratch = 93_603_701_976_053u128.to_le_bytes().to_vec();
+                let dest_ptr: u32 = args.nth_checked(0)?;
+                let len_ptr: u32 = args.nth_checked(1)?;
+
+                let scratch = 93_603_701_976_053u128.to_le_bytes().to_vec();
 
-                println!("ext_tombstone_deposit: {}", hex::encode(&self.vm.scratch));
+                set_seal_value!("ext_tombstone_deposit", dest_ptr, len_ptr, &scratch);
 
                 Ok(None)
             }
@@ -878,7 +906,7 @@ impl ModuleImportResolver for TestRuntime {
             "ext_terminate" => SubstrateExternal::ext_terminate,
             "ext_block_number" => SubstrateExternal::ext_block_number,
             "ext_now" => SubstrateExternal::ext_now,
-            "ext_gas_price" => SubstrateExternal::ext_gas_price,
+            "ext_weight_to_fee" => SubstrateExternal::ext_weight_to_fee,
             "ext_gas_left" => SubstrateExternal::ext_gas_left,
             "ext_caller" => SubstrateExternal::ext_caller,
             "ext_tombstone_deposit" => SubstrateExternal::ext_tombstone_deposit,