Skip to content

Commit

Permalink
Merge pull request #1330 from Phala-Network/doc-comments
Browse files Browse the repository at this point in the history
Enrich the doc on docs.rs for pink
  • Loading branch information
kvinwang authored Jul 10, 2023
2 parents 35ec059 + 4b8ac40 commit bd467da
Show file tree
Hide file tree
Showing 16 changed files with 856 additions and 113 deletions.
26 changes: 13 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/phactory/src/contracts/support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ impl Contract {
phala_mq::select! {
next_cmd = self.cmd_rcv_mq => match next_cmd {
Ok((_, cmd, origin)) => {
info!("Contract {:?} handling command", self.address());
info!("Contract {:?} handling tx call", self.address());
let Ok(command) = Decode::decode(&mut &cmd.0[..]) else {
error!("Failed to decode command input");
error!("Failed to decode tx input");
return Some(Err(TransactionError::BadInput));
};
env.contract_cluster.handle_command(self.address(), origin, command, &mut context)
Expand Down
2 changes: 1 addition & 1 deletion crates/phactory/src/system/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1675,7 +1675,7 @@ pub fn handle_contract_command_result(
) {
let effects = match result {
Err(err) => {
error!("Run contract command failed: {:?}", err);
error!("Run contract tx call failed: {:?}", err);
return;
}
Ok(Some(effects)) => effects,
Expand Down
2 changes: 1 addition & 1 deletion crates/pink/pink-extension/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pink-extension"
version = "0.4.3"
version = "0.4.4"
edition = "2018"
description = "Phala's ink! for writing phat contracts"
license = "Apache-2.0"
Expand Down
71 changes: 64 additions & 7 deletions crates/pink/pink-extension/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,68 @@
<h1 align="center">
Phala's ink! for writing phat contracts
</h1>
<h1 align="center">Phala's ink! - Writing Enhanced Smart Contracts</h1>

pink! is based on Parity's ink! language and provide some extra functionality to interact with phala's phat contract runtime.
Pink! is a smart contract language extending Parity's `ink!`. It extends the basic functionality with additional features, tailored to interact efficiently with Phala's Phat Contract runtime.

# Getting started
## Getting Started

The orignal `ink!` contract can run under Phala's phat contract platform without any modifacation. So you can follow Parity's `ink!` [documentation](https://paritytech.github.io/ink-docs/) to get started.
Unaltered `ink!` contracts are fully compatible and executable on the Phala's Phat Contract platform. To learn how to start writing contracts with `ink!`, follow the Parity's [ink! documentation](https://paritytech.github.io/ink-docs/).

If you want to use phat contract's specific features, such as phala-mq message, HTTP requests, you can use `pink_extension` to achieve this. See [examples](https://github.com/Phala-Network/phala-blockchain/tree/master/crates/pink/examples) for more detail.
To get started with Pink!, add the following dependency to your `Cargo.toml`:

```toml
[dependencies]
ink = { version = "4", default-features = false }
pink = { package = "pink-extension", version = "0.4", default-features = false }

[features]
std = [
"ink/std",
"pink/std",
]
```

Then, you can use the `http_get!` macro to make a GET request to a remote server:

```ignore
#[ink::message]
fn http_get_example(&self) {
let response = pink::http_get!("https://httpbin.org/get");
assert_eq!(response.status_code, 200);
}
```

## Phat Contract-Specific Features

The Pink! crate is designed to empower you, enabling you to leverage the unique features of the Phat Contract, such as making HTTP requests as demonstrated in our examples. This crate supplies the crucial types and functions needed to seamlessly interact with the Phat Contract runtime.

There are three kind of APIs to communication with the runtime:

- Emitting Events:
These APIs are primarily used in situations where the operation could lead to side effects that need to be deterministically recorded and may be rolled back during the execution of the contract call. For additional information on Emitting Events APIs, please refer to the [PinkEvent documentation](crate::PinkEvent).

- Chain Extension:
These APIs are predominantly used for read-only operations or operations that aren't expected to create deterministic side effects. For an in-depth understanding of Chain Extension APIs, please refer to the [PinkExt documentation](crate::chain_extension::PinkExtBackend).

- System contract:
There is a special contract called the System contract in each cluster. The system contract is instantiated when the cluster is created. Either ink contracts or external accounts can call the system contract to perform certain operations. For more information on the System contract, please refer to the [System documentation](crate::system::SystemForDoc).

For practical implementation examples, explore our [Phat Contract examples](https://github.com/Phala-Network/phat-contract-examples) repository.

## Using JavaScript with Phat Contract

Phat Contract supports JavaScript through the [phat-quickjs](https://github.com/Phala-Network/phat-quickjs) contract.

There are two ways to use JavaScript in your contract:

- You can deploy your phat-quickjs contract instance through a standard deployment process.

- However, for a more convenient approach, most public clusters should already have a public driver quickjs contract deployed. You can obtain the contract code_hash with `System::get_driver("JsDelegate")`.

- For the simplest integration, consider using the [`phat_js`](https://docs.rs/phat_js/) crate. It provides an `eval` function that lets you evaluate JavaScript code snippets directly.
For example:
```ignore
#[ink::message]
fn eval_js_example(&self) {
let result = phat_js::eval("'Hello,' + 'World'", &[]);
assert_eq!(result, phat_js::Output::String("Hello,World".to_string()));
}
```
2 changes: 1 addition & 1 deletion crates/pink/pink-extension/macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pink-extension-macro"
version = "0.4.2"
version = "0.4.4"
edition = "2018"
description = "Macros for writing phat contract"
license = "Apache-2.0"
Expand Down
4 changes: 3 additions & 1 deletion crates/pink/pink-extension/macro/src/chain_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ fn patch_chain_extension_or_err(input: TokenStream2) -> Result<TokenStream2> {

for item in item_trait.items.iter_mut() {
if let syn::TraitItem::Fn(item_method) = item {
item_method.attrs.clear();
item_method
.attrs
.retain(|attr| !attr.path().is_ident("ink"));

// Turn &[u8] into Cow<[u8]>
for input in item_method.sig.inputs.iter_mut() {
Expand Down
39 changes: 38 additions & 1 deletion crates/pink/pink-extension/macro/src/driver_system.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
use quote::quote;
use syn::{spanned::Spanned, FnArg, Result};
use syn::{parse_quote, spanned::Spanned, FnArg, Result};

pub(crate) enum InterfaceType {
System,
Expand All @@ -25,6 +25,8 @@ fn patch_or_err(
) -> Result<TokenStream2> {
use heck::{ToLowerCamelCase, ToSnakeCase};
let the_trait: syn::ItemTrait = syn::parse2(input)?;
let trait_for_doc = generate_trait_for_doc(the_trait.clone());
let the_trait = patch_origin_system_doc(the_trait);
let trait_ident = &the_trait.ident;
let trait_name = the_trait.ident.to_string();
let trait_impl_mod = Ident::new(
Expand Down Expand Up @@ -133,6 +135,9 @@ fn patch_or_err(
#config
#the_trait

#[cfg(doc)]
#trait_for_doc

pub use #trait_impl_mod::#impl_type;
mod #trait_impl_mod {
use super::*;
Expand Down Expand Up @@ -223,6 +228,38 @@ fn patch_or_err(
})
}

fn patch_origin_system_doc(mut trait_item: syn::ItemTrait) -> syn::ItemTrait {
let additonal_doc = format!(
"**The doc is messed up by the ink macro. See [`{}ForDoc`] for a clean version**\n\n",
trait_item.ident
);
trait_item
.attrs
.insert(0, parse_quote!(#[doc = #additonal_doc]));
trait_item
}

fn generate_trait_for_doc(mut trait_item: syn::ItemTrait) -> syn::ItemTrait {
let additonal_doc = format!(
"**This is the clean version doc of [`{}`]**\n\n",
trait_item.ident
);
trait_item.attrs.retain(|attr| attr.path().is_ident("doc"));
trait_item
.attrs
.insert(0, parse_quote!(#[doc = #additonal_doc]));
trait_item.ident = syn::Ident::new(
&format!("{}ForDoc", trait_item.ident),
trait_item.ident.span(),
);
for item in trait_item.items.iter_mut() {
if let syn::TraitItem::Fn(method) = item {
method.attrs.retain(|attr| !attr.path().is_ident("ink"));
}
}
trait_item
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
55 changes: 53 additions & 2 deletions crates/pink/pink-extension/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn chain_extension(_: TokenStream, input: TokenStream) -> TokenStream {
output.into()
}

/// Mark an ink trait as pink's system contract
/// Mark an ink trait as pink's system contract. Internal use only.
#[proc_macro_attribute]
pub fn system(arg: TokenStream, input: TokenStream) -> TokenStream {
let config = parse_macro_input!(arg as TokenStream2);
Expand All @@ -36,7 +36,58 @@ pub fn system(arg: TokenStream, input: TokenStream) -> TokenStream {
module.into()
}

/// Mark an ink trait as pink's driver contract
/// This procedural macro marks an ink! trait as a 'driver contract' for the Pink system.
///
/// # What is the driver system?
///
/// The driver system is a straightforward concept. In the Pink system, there is a registry mapping driver names
/// to driver contract addresses. The System contract provides two methods to manage this registry:
/// `System::set_driver(driver_name, contract_address)` and `System::get_driver(driver_name)`.
///
/// # How does this macro work?
///
/// When this attribute is used, it modifies the given trait to be utilized as a driver contract
/// within the Pink system. This is achieved by adding a new type, TraitNameRef, which implements
/// the marked trait and provides a static method `instance()` to retrieve an instance of the driver.
///
/// # Example
///
/// Below, the `SidevmOperation` trait is annotated with `#[pink::driver]`. This marks it
/// as a driver contract, enabling it to manage SideVM deployments.
///
/// ```ignore
/// #[pink::driver]
/// #[ink::trait_definition]
/// pub trait SidevmOperation {
/// #[ink(message)]
/// fn deploy(&self, code_hash: Hash) -> Result<(), DriverError>;
///
/// #[ink(message)]
/// fn can_deploy(&self, contract_id: AccountId) -> bool;
/// }
/// ```
///
/// Once a trait has been defined as a driver using this macro, it can be set as a driver
/// by invoking the `System::set_driver(driver_name, contract_address)` method.
///
/// # Usage
///
/// The actual driver can then be retrieved and its methods, defined by the trait, can be used.
/// For instance, to start a SideVM, one would get the driver instance and call its `deploy` method:
///
/// ```ignore
/// pub fn start_sidevm(code_hash: Hash) -> Result<(), system::DriverError> {
/// let driver =
/// SidevmOperationRef::instance().ok_or(system::Error::DriverNotFound)?;
/// driver.deploy(code_hash)
/// }
/// ```
///
/// Here, `SidevmOperationRef::instance()` retrieves an instance of the driver contract for "SidevmOperation",
/// and then the `deploy` method of the driver is invoked to deploy a SideVM instance.
/// Internally, `SidevmOperationRef::instance()` retrieves the driver contract by invoking `System::get_driver("SidevmOperation")`.
///
/// Note: The name of the driver contract instance (e.g., "SidevmOperation") is generated by the macro.
#[proc_macro_attribute]
pub fn driver(arg: TokenStream, input: TokenStream) -> TokenStream {
let config = parse_macro_input!(arg as TokenStream2);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
---
source: crates/pink/pink-extension/macro/src/driver_system.rs
assertion_line: 250
assertion_line: 286
expression: "rustfmt_snippet::rustfmt_token_stream(&stream).unwrap()"
---
#[doc = "**The doc is messed up by the ink macro. See [`SystemForDoc`] for a clean version**\n\n"]
#[ink::trait_definition(namespace = "pink_system")]
pub trait System {
#[ink(message)]
Expand All @@ -12,6 +13,13 @@ pub trait System {
#[ink(message)]
fn deploy_sidevm_to(&self, code_hash: Hash, contract_id: AccountId) -> Result<()>;
}
#[cfg(doc)]
#[doc = "**This is the clean version doc of [`System`]**\n\n"]
pub trait SystemForDoc {
fn get_driver(&self, name: String) -> Option<AccountId>;
fn set_driver(&self, name: String, driver: AccountId);
fn deploy_sidevm_to(&self, code_hash: Hash, contract_id: AccountId) -> Result<()>;
}
pub use _pink_system_impl::SystemRef;
mod _pink_system_impl {
use super::*;
Expand Down
Loading

0 comments on commit bd467da

Please sign in to comment.