PDX Utopia區(qū)塊鏈協(xié)議棧使用Solidity調(diào)用wasm智能合約

在這個(gè)瞬息萬(wàn)變的世界中,智能合約已成為所有平臺(tái)中強(qiáng)有力的服務(wù)夭委。Solidity是一種趨勢(shì),PDX Utopia區(qū)塊鏈協(xié)議棧使用Solidity調(diào)用wasm智能合約。

什么是Solidity辅髓?

Solidity是一種語(yǔ)法類似JavaScript的高級(jí)語(yǔ)言。它被設(shè)計(jì)成以編譯的方式生成以太坊虛擬機(jī)代碼少梁,這種語(yǔ)言的突出優(yōu)點(diǎn)是安全洛口。

Solidity語(yǔ)言是靜態(tài)類型語(yǔ)言,支持繼承猎莲、庫(kù)和復(fù)雜的用戶定義類型绍弟,可以使用Solidity語(yǔ)言創(chuàng)建區(qū)塊鏈上運(yùn)行的投票、眾籌著洼、錢包等各種類型的智能合約樟遣。

以太坊合約中的Solidity

合約是以太坊去中心化應(yīng)用程序的基本構(gòu)建模塊。所有變量和函數(shù)都是合約的一部分身笤,這是所有項(xiàng)目的起點(diǎn)豹悬。一個(gè)名為MyFirst的空合約看起來(lái)像這樣:

version pragma ^0.4.19;contract MyFirst{}

Solidity文件的布局

源文件可以包含任意數(shù)量的合約定義,包括指令和pragma指令液荸。

注釋

就像任何其他語(yǔ)言一樣瞻佛,Solidity可以使用單行和多行注釋。

// This is a single-line comment./*This is amulti-line comment*/

Solidity中的值類型

以下類型也稱為值類型,因?yàn)檫@些類型的變量將始終按值傳遞伤柄。

Solidity數(shù)據(jù)結(jié)構(gòu)

Solidity提供三種類型的數(shù)據(jù)結(jié)構(gòu):

使用Solidity調(diào)用wasm智能合約

定義 ABI

>在 `hello-wasm-abi/src/abi.rs` 中定義了 Contract 對(duì)象绊困,包含了 `hello-wasm` 樣例中的

>`put/get/getcounter` 三個(gè)方法的 `ABI` 描述适刀,注意秤朗,我們還不能直接用 `JSON` 來(lái)描述 `ABI`;

>必須使用 `pdxabi::Contract` 來(lái)定義聲明笔喉。

建議通過(guò)以下三步來(lái)生成 ABI :

1. 使用 `solidity` 編寫 `contract interface`;

2. 使用 `remix` 編譯 `contract interface` 得到對(duì)應(yīng)的 `ABI` 描述取视;

3. 參照 `ABI` 描述文件編寫 `pdxabi::Contract`;

部署 wasm 合約后可以使用合約地址和 contract interface 在 remix 里對(duì)合約進(jìn)行實(shí)例化常挚,方便測(cè)試作谭。

### Solidity Contract Interface

在 [Remix IDE](Remix - Ethereum IDE) 中編寫合約接口,并編譯

```solidity

pragma solidity ^0.5.3;

contract hello_wasm_abi {

function getcounter() public view returns(uint256);

function get(string memory key) public view returns(string memory);

function put(string memory key,string memory val) public payable;

}

```

### JSON ABI

編譯合約接口可以得到對(duì)應(yīng)的 `ABI JSON` 描述奄毡,提供合約地址和此 `JSON ABI` 文檔折欠,

`DAPP` 開(kāi)發(fā)者即可實(shí)例化 `hello_wasm_abi` 合約,并使用其中的三個(gè)函數(shù)

```json

[

{

"constant": false,

"inputs": [

{

"name": "key",

"type": "string"

},

{

"name": "val",

"type": "string"

}

],

"name": "put",

"outputs": [],

"payable": true,

"stateMutability": "payable",

"type": "function"

},

{

"constant": true,

"inputs": [

{

"name": "key",

"type": "string"

}

],

"name": "get",

"outputs": [

{

"name": "",

"type": "string"

}

],

"payable": false,

"stateMutability": "view",

"type": "function"

},

{

"constant": true,

"inputs": [],

"name": "getcounter",

"outputs": [

{

"name": "",

"type": "uint256"

}

],

"payable": false,

"stateMutability": "view",

"type": "function"

}

]

```

### pdxabi::Contract

根據(jù) `JSON ABI` 描述實(shí)例化 `pdxabi::Contract` 對(duì)象秧倾,用來(lái)對(duì)合約的 `input/output` 進(jìn)行序列化和反序列化

```rust

pub fn get_contract_abi() -> pdxabi::Contract {

let mut functions: HashMap<String, pdxabi::Function> = HashMap::new();

let fn_put = pdxabi::Function {

constant: false,

name: String::from("put"),

inputs: Vec::from(vec![

pdxabi::Param { name: String::from("key"), kind: pdxabi::param_type::ParamType::String },

pdxabi::Param { name: String::from("val"), kind: pdxabi::param_type::ParamType::String },

]),

outputs: Vec::default(),

};

let fn_get = pdxabi::Function {

constant: true,

name: String::from("get"),

inputs: Vec::from(vec![

pdxabi::Param { name: String::from("key"), kind: pdxabi::param_type::ParamType::String },

]),

outputs: Vec::from(vec![

pdxabi::Param { name: String::default(), kind: pdxabi::param_type::ParamType::String },

]),

};

let fn_getcounter = pdxabi::Function {

constant: true,

name: String::from("getcounter"),

inputs: Vec::default(),

outputs: Vec::from(vec![

pdxabi::Param { name: String::default(), kind: pdxabi::param_type::ParamType::Uint(256) },

]),

};

functions.insert(fn_put.clone().name, fn_put.clone());

functions.insert(fn_get.clone().name, fn_get.clone());

functions.insert(fn_getcounter.clone().name, fn_getcounter.clone());

pdxabi::Contract {

constructor: None,

functions: functions,

events: HashMap::default(),

fallback: false,

signers: HashMap::default(),

}

}

```

## 使用 `ABI`

>在 hello-wasm-abi 合約中

```rust

extern crate wasm_bindgen;

extern crate ewasm_api;

use wasm_bindgen::prelude::*;

use ewasm_api::types::*;

use ewasm_api::pdx::utils::*;

// 倒入處理 abi 的開(kāi)發(fā)庫(kù)

use ewasm_api::pdxabi;

// pdxabi::Contract 定義的對(duì)象放在 abi 模塊中

pub mod abi;

const COUNTER_KEY: Bytes32 = Bytes32 { bytes: [255; 32] };

fn inc_counter() {

let old_v = ewasm_api::storage_load(&COUNTER_KEY);

let old_i = bytes_to_uint(&old_v.bytes[..]);

let new_i = old_i + 1;

let val = u32_to_bytes32(new_i as u32);

let value = Bytes32 { bytes: val };

ewasm_api::storage_store(&COUNTER_KEY, &value);

}

fn get_counter() -> Vec<u8> {

let v = ewasm_api::storage_load(&COUNTER_KEY);

Vec::from(&v.bytes[..])

}

fn put_data(k: String, v: String) {

ewasm_api::pdx::storage_store(k.as_bytes(), v.as_bytes());

}

fn get_data(k: String) -> Vec<u8> {

ewasm_api::pdx::storage_load(k.as_bytes())

}

#[wasm_bindgen]

pub fn main() {

inc_counter();

let input = ewasm_api::calldata_acquire();

if !input.is_empty() {

// 獲取 pdxabi::Contract 對(duì)象怨酝,這個(gè)函數(shù)寫在 abi 模塊中

let mut contract = abi::get_contract_abi();

// 從 input 獲取方法簽名,按照 ABI 規(guī)范那先,input 的前 4 個(gè) byte 為方法簽名

let fn_sig = &Vec::from(&input[..4]);

// 根據(jù)方法簽名獲取 function 對(duì)象

let function = contract.function_by_sig(fn_sig).expect("error_fn_sig");

// 通過(guò)?RU-CENTER?來(lái)匹配相應(yīng)的 handler

match function.name.as_str() {

"getcounter" => { // function getcounter() public view returns(uint256);

// 調(diào)用 get_counter 得到返回值农猬,轉(zhuǎn)換成 uint

let rtn = ewasm_api::pdx::utils::bytes_to_uint(get_counter().as_slice());

// 此方法沒(méi)有輸入值,只有輸出售淡,通過(guò) function.encode_output 序列化輸出

let data = function.encode_output(&[pdxabi::Token::Uint(rtn.into())]).unwrap();

// 將結(jié)果返回給合約調(diào)用者

ewasm_api::finish_data(data.as_slice());

}

"get" => { // function get(string memory key) public view returns(string memory);

// 此方法有定義輸入 string key , 先用 function.decode_input 解析 input, 得到輸入列表

let tokens = function.decode_input(input.as_slice()).expect("error_put_input");

// 接口中 input 只定義了一個(gè)參數(shù)斤葱,所以 key = tokens[0]

let key = tokens.get(0).expect("error_put_key");

// 調(diào)用 get_data(key) 函數(shù),得到 val 的字節(jié)數(shù)組

let val = get_data(key.clone().to_string().unwrap());

// 接口描述輸出值為 string揖闸,所以要將 val 轉(zhuǎn)換為 string

let rtn = String::from_utf8(val).expect("error_get_val");

// 使用 function.encode_output 對(duì)返回值進(jìn)行序列化

let data = function.encode_output(&[pdxabi::Token::String(rtn)]).expect("error_get_output");

// 將結(jié)果返回給合約調(diào)用者

ewasm_api::finish_data(data.as_slice());

}

"put" => { // function put(string memory key,string memory val) public payable;

// 此方法有定義輸入 [string key,string val] , 先用 function.decode_input 解析 input, 得到輸入列表

let tokens = function.decode_input(input.as_slice()).expect("error_put_input");

// 接口中定義了兩個(gè)參數(shù)揍堕,分別對(duì)應(yīng) key = tokens[0] , val = tokens[1]

let key = tokens.get(0).expect("error_put_key");

let val = tokens.get(1).expect("error_put_val");

// 調(diào)用 put_data(key,val)

put_data(key.clone().to_string().unwrap(), val.clone().to_string().unwrap());

// 結(jié)束調(diào)用,此方法沒(méi)有返回值

ewasm_api::finish()

}

_ => ewasm_api::finish() // 如果方法匹配失敗汤纸,則直接返回不做任何處理

}

}

}

```

## 部署與使用

* 部署合約方式與 `hello-wasm` 樣例相同衩茸,可以參照 [README.md](PDXbaap/ewasm-rust-demo) 中關(guān)于`部署`的描述;

* 調(diào)用合約:部署成功后會(huì)得到 `Contract Address` ,如果使用 `web3` 系列 `SDK` 可以使用 `JSON ABI` + `Contract Address` 來(lái)實(shí)例化合約贮泞,并進(jìn)行調(diào)用楞慈,如果使用 `remix IDE` 進(jìn)行測(cè)試調(diào)用,可以使用 `Solidity Contract Interface` + `Contract Address` 來(lái)實(shí)例化合約并調(diào)用

關(guān)于 web3 提供的 SDK 和 remix IDE 的詳細(xì)資料請(qǐng)參閱 web3 基金會(huì)的相關(guān)資料

## Solidity 調(diào)用 Wasm 合約

用 `sol` 合約來(lái)調(diào)用 `wasm` 合約啃擦,與 `sol` 調(diào)用 `sol` 方式相同囊蓝,

假設(shè)已經(jīng)部署過(guò) `hello-wasm-abi` 這個(gè)合約,并得到合約地址 `0xda3ce11d916ffba4a1289cef66a7f142ec5a0f74`,

通過(guò) `hello-wasm-abi` 合約接口和地址令蛉,即可實(shí)例化這個(gè)合約聚霜,之后用法與 `sol` 調(diào)用 `sol` 一致,

例如:

```solidity

pragma solidity ^0.5.3;

// hello-wasm-abi 合約接口

contract hello_wasm_abi {

function getcounter() public view returns(uint256);

function get(string memory key) public view returns(string memory);

function put(string memory key,string memory val) public payable;

}

// 使用 hello-wasm-abi 合約的 solidity 合約

contract foobar {

function fetch(address addr,string memory key) public view returns(string memory) {

// 第一個(gè)參數(shù) addr 為 wasm 合約地址,通過(guò)接口和地址實(shí)例化合約對(duì)象

hello_wasm_abi hello = hello_wasm_abi(addr);

// 調(diào)用 wasm 合約方法

return hello.get(key);

}

function set(address addr,string memory key,string memory val) public payable {

hello_wasm_abi hello = hello_wasm_abi(addr);

hello.put(key,val);

}

}

```

部署 `foobar` 合約后蝎宇,使用 `hello-wasm-abi` 的合約地址 `0xda3ce11d916ffba4a1289cef66a7f142ec5a0f74` 作為第一個(gè)參數(shù)分別

調(diào)用 `fetch` 和 `set` 方法弟劲,完成對(duì) `hello-wasm-abi` 合約的 `get` 和 `put` 的調(diào)用。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末姥芥,一起剝皮案震驚了整個(gè)濱河市函卒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撇眯,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虱咧,死亡現(xiàn)場(chǎng)離奇詭異熊榛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)腕巡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門玄坦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人绘沉,你說(shuō)我怎么就攤上這事煎楣。” “怎么了车伞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵择懂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我另玖,道長(zhǎng)困曙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任谦去,我火速辦了婚禮慷丽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鳄哭。我一直安慰自己要糊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布妆丘。 她就那樣靜靜地躺著锄俄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪飘痛。 梳的紋絲不亂的頭發(fā)上珊膜,一...
    開(kāi)封第一講書(shū)人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音宣脉,去河邊找鬼车柠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的竹祷。 我是一名探鬼主播谈跛,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼塑陵!你這毒婦竟也來(lái)了感憾?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤令花,失蹤者是張志新(化名)和其女友劉穎阻桅,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體兼都,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嫂沉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扮碧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趟章。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖慎王,靈堂內(nèi)的尸體忽然破棺而出蚓土,到底是詐尸還是另有隱情,我是刑警寧澤赖淤,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布蜀漆,位于F島的核電站,受9級(jí)特大地震影響漫蛔,放射性物質(zhì)發(fā)生泄漏嗜愈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一莽龟、第九天 我趴在偏房一處隱蔽的房頂上張望蠕嫁。 院中可真熱鬧,春花似錦毯盈、人聲如沸剃毒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赘阀。三九已至,卻和暖如春脑奠,著一層夾襖步出監(jiān)牢的瞬間基公,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工宋欺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轰豆,地道東北人胰伍。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像酸休,于是被迫代替她去往敵國(guó)和親骂租。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容