What are the differences between using pub_interface & public functions in contract implementation?

Hi team, I know you guys’re pretty busy at the moment.

But I have some questions on Enigma contracts.

First, What are the differences between using public_interface trait, then implement that trait for the public functions which will interact with UI part vs implement directly public functions right in contract implementation (not using pub_interface)?

Secondly, if I use pub_interface trait, implement it later, is there a way to point to &mut self if I call private functions in the public functions?
for ex.:

if I call Self::_private_func_A(....), the rust compiler will fire an error that I’m missing 1st argument (means theself one).

Please kindly help!
Thanks.

Hi @arookie,

I’m still learning rust, but here’s my take on your questions …

  1. the pub_interface as it’s used in the examples is an attribute macro that decorates the ContractInterface trait.
  2. reviewing the pub_interface code, which is part of the Enigma eng_wasm_derive crate, I can see there’s quite a bit going on there in terms of how it enables the secret contract definition and invocation.

I believe if you implemented public functions right in the contract implementation without the pub_interface attribute you wouldn’t be able to call your secret contract functions.

Can you post more of your code? I think you might want to try:

pub fn insert_data_collection(&mut self, dcType: String, ... {
   let owner: String = dc_owner.to_hex();
   self._private_func_A(&self, ...);
}

but I’m making some assumptions that might be incorrect.

1 Like

hi @laura, thank for your fast reply :smiley:

So basically the pub_interface trait provided us the features such as secret contract & UI invocation.
And if I only define the public functions right in a contract & didn’t use pub_interface, I just can call them within in my contract & for console testing only, right?

Then, I will use pub_interface trait and implement it later.
Let me make it more clear so that you can take a closer look on it.
I have a data struct below:

#[derive(Serialize, Deserialize)]
pub struct Creator {
    creator: H256,
    dataCollections: Vec<DataCollection>,   // Vector Data Collections
    status: String,
    CreatedAt: DateTime<Utc>,
}

If I implement the public function right in contract implementation, it will look like this:

pub fn insert_data_collection(&mut self, dcType: String, format: String, dc_owner: H256) {
    let owner: String = dc_owner.to_hex();
    self.dataCollections.push(DataCollection {
        dcType,
        format,
        owner
    });
    write_state!(DATACOLLECTIONS => &self.dataCollections);
}

And if I use the pub_interface trait, I will modify function above into the private function in the contract then in the contract implementation for public ones, I will call that private function.

impl CreatorInterface for Contract {
    //.........
    
    fn append_data_collection(dcType: String, format: String, dc_owner: H256) {
        // do sth....

        // call the private function above
        Self::insert_data_collection(dcType, format, dc_owner); // NOTE: the Rust compiler will throw the error missing parameters! I suspect that it is the self one
    }
}

Because in the private function I modified the data, that’s why I define &mut self.

I need a way so that I can modify self data / call the private function from here.

1 Like

Thanks for all of that info @arookie!

The Enigma secret contracts don’t use the Rust std library which implements the implicit passing of the self reference to methods.

You probably have this statement at the top of your source?

#![no_std]

You’d want to manually pass a reference to your insert_data_collection method, which looks like that would be a specific Creator object or instance.

So the call to insert the data collection might look something like this:

   let mut creator = Self::get_creator(dc_owner);
   // call the private function above
   Self::insert_data_collection(&creator, dcType, format, dc_owner);

where Self::get_creator(dc_owner) would be implemented as a private function in the Contract impl (reading contract state and getting the specific Creator by matching against the dc_owner address).

On why the std Rust library isn’t used with Enigma secret contracts, I found this in Part 2 of the Engima Getting Started blog:

While Rust’s standard library comes with a wide array of useful and well-tested abstractions, not all environments support these features, SGX being one of these environments.

Here’s some more info on the no_std embedded Rust environment that’s pretty interesting: https://rust-embedded.github.io/book/intro/no-std.html

Yes, I believe you’re correct in saying that if you omit the pub_interface you can call the functions within the contract and use for console testing. Except if you’re using eng_wasm to read/write contract state. The eng_wasm crate is the Enigma library for creating secret contracts. Since a key feature of Enigma secret contracts is that they’re stateful, it probably makes the most sense to keep the pub_interface and eng_wasm code and test in the full Enigma discovery environment :slight_smile: .

2 Likes