一、前言
1.1 專案版本
1. cosmwasm:orgin/main
2. wasmd:origin/master
1.2 簡單介紹
1. cosmwasm主要功能:
- cosmwasm-template:提供撰寫智能合約(以下簡稱合約)的模板
- cosmwasm-examples:提供合約樣例
- cosmwasm-storage:存盤合約
- cosmwasm-vm:使用wasmer引擎執行給定的智能合約,還包含合約計費、存盤和快取wasm組件的功能
- go-cosmwasm:現已改名為wasmvm,呼叫cosmwasm-vm中的部署、實體化和執行合約的介面,使用它的優化和快取
2. wasmd主要功能:
- 基于cosmos-sdk寫的app,集群智能合約,匯入了wasmvm
先從簡單的說起
二、wasmd
wasmd主要功能如圖所示

圖中的irita網路是基于cosmos-sdk寫的區塊鏈網路,匯入了wasmd模塊,所以irita網路對于智能合約相關邏輯是與wasmd一致的,關于irita這里不做過多介紹,
0. 編譯:根據cosmwasm-template,參考cosmwasm-examples,使用rust撰寫合約,然后用cli命令編譯成wasm檔案,也可以用go來撰寫,
但是暫時沒有找到操作區塊鏈存盤、世界狀態的介面樣例,
1. 部署:將wasm原始位元組,經base64標準編碼后作為引數傳給wasmd,或者使用gzip演算法壓縮原始位元組后base64編碼,wasmd會將合約存盤并回傳
合約編號,若編譯好的Wasm位元組碼檔案比較大,則部署到鏈上需要的存盤空間會比較多,費用也會比較高,但是可以使用ontio-Wasm-build工具將 Wasm 位元組碼減小,
2. 初始化:也就是實體化,將合約編號作為引數傳給wasmd,wasmd會根據合約編號生成合約賬號,然后將合約賬號、合約位元組內容經base64編碼回傳,
可自行驗證本地編譯的代碼是否與上傳的代碼散列相匹配,
3. 執行:將合約賬號作為引數傳給wasmd,wasmd呼叫wasmvm提供的介面執行合約(其實初始化也會呼叫),回傳執行后的資料
4. 升降級:首先新合約按照步驟1執行,然后將舊合約賬號與新合約編號作為引數傳給wasmd,wasmd會重新建立合約賬號與合約的系結,也就是代理合約,
回傳新合約位元組內容,
三、cosmwasm
3.1 合約計費規則
-
cosmwasm定義了合約在加密驗簽的gas消耗,如代碼所示
定位代碼:cosmwasm/packages/vm/src/environment.rs -> GasConfig:
impl GasConfig {
// 底層加密驗簽消耗gas:1000(cosmos-sdk定義的)* 100(cosmwasm定義的)
const BASE_CRYPTO_COST: u64 = 100_000;
// secp256k1 演算法驗簽消耗gas的因子
const SECP256K1_VERIFY_FACTOR: (u64, u64) = (154, 154); // ~154 us in crypto benchmarks
// secp256k1 演算法恢復公鑰消耗gas的因子
const SECP256K1_RECOVER_PUBKEY_FACTOR: (u64, u64) = (162, 154); // 162 us / 154 us ~ 1.05
// ed25519 演算法驗簽消耗gas的因子
const ED25519_VERIFY_FACTOR: (u64, u64) = (63, 154); // 63 us / 154 us ~ 0.41
// ed25519 演算法批量驗簽消耗gas的因子
const ED255219_BATCH_VERIFY_FACTOR: (u64, u64) = (
GasConfig::ED25519_VERIFY_FACTOR.0,
GasConfig::ED25519_VERIFY_FACTOR.1 * 2,
); // 0.41 / 2. ~ 0.21
// ed25519 演算法單公鑰驗簽消耗gas的因子
const ED255219_BATCH_VERIFY_ONE_PUBKEY_FACTOR: (u64, u64) = (
GasConfig::ED25519_VERIFY_FACTOR.0,
GasConfig::ED25519_VERIFY_FACTOR.1 * 4,
); // 0.41 / 4. ~ 0.1
// 計算加密驗簽消耗的gas
fn calc_crypto_cost(factor: (u64, u64)) -> u64 {
(GasConfig::BASE_CRYPTO_COST * factor.0) / factor.1
}
}
-
cosmwasm對于存盤的讀、寫、修改、洗掉的gas的計費規則由gas_limit控制,如代碼所示,但是對加、乘演算法等操作沒有定義,
這里只展示部分代碼,定位代碼:cosmwasm/packages/vm/src/environment.rs -> Environment
pub fn new(api: A, gas_limit: u64, print_debug: bool) -> Self {
Environment {
api,
print_debug,
gas_config: GasConfig::default(),
data: Arc::new(RwLock::new(ContextData::new(gas_limit))),
}
}
// 其他函式與此函式類似,就不貼代碼了
// FnOnce匿名函式,可訪問外部變數S、Q
fn with_context_data_mut<C, R>(&self, callback: C) -> R
where
C: FnOnce(&mut ContextData<S, Q>) -> R,
{
// 根據new函式:self.data的值來自gasLimit
let mut guard = self.data.as_ref().write().unwrap();
let context_data = guard.borrow_mut();
callback(context_data)
}
以太坊對于gas的消耗就非常詳細,可參考下圖,具體見以太坊黃皮書第20頁,

并且以太坊對每個操作指令都有明文規定的Gas消耗量,可參考下圖,具體見Gas清單 ,

當然以太坊gas消耗是可以優化的,具體見此處,
-
執行智能合約時 gasUsed 無法提前預知, 這樣存在一個風險,當用戶的交易涉及一個惡意的智能合約,該合約執行將消耗無限的燃料, 這樣會導致交易方的余額全部消耗(惡意的智能合約有可能是程式Bug,如合約執行陷入一個死回圈),為了避免合約中的錯誤引起不可預計的燃料消耗,用戶需要在發送交易時設定允許消耗的燃料上限,即 gasLimit, 這樣不管合約是否良好,最壞情況也只是消耗 gasLimit 量的燃料,
-
如果交易尚未執行完成,而gas已用完,那么交易回滾,用完的gas不會返還,
-
即使交易失敗,也必須為已占用的計算資源支付手續費,
3.2 合約與世界狀態互動
先來看世界狀態的定義:所有節點從同一個創世狀態開始,依次運行達成共識的區塊內的交易,驅動各個節點的狀態按照相同操作序列(增加,洗掉,
修改)不斷變化,實作所有節點在執行完相同編號區塊內的交易后,狀態完全一致,把這個狀態稱之為世界狀態,

合約與世界狀態的互動實際上是合約呼叫底層區塊鏈的讀寫介面,各節點執行相同的合約從而使得資料達成一致,
只有在每個交易和區塊處理過后,并且每個節點達到相同狀態,智能合約才能正常運行,
來看合約對存盤的操作,如代碼(cosmwasm/packages/std/src/imports.rs)所示,此介面通過C/C++撰寫的動態庫操作存盤、驗簽,此介面將在vm中用到,見 cosmwasm/packages/vm/src/instance.rs -> Instance::from_module() 所示代碼
extern "C" {
// 增刪改介面
fn db_read(key: u32) -> u32;
fn db_write(key: u32, value: u32);
fn db_remove(key: u32);
// scan creates an iterator, which can be read by consecutive next() calls
// 迭代資料介面
#[cfg(feature = "iterator")]
fn db_scan(start_ptr: u32, end_ptr: u32, order: i32) -> u32;
#[cfg(feature = "iterator")]
fn db_next(iterator_id: u32) -> u32;
// 可視化賬號
fn canonicalize_address(source_ptr: u32, destination_ptr: u32) -> u32;
fn humanize_address(source_ptr: u32, destination_ptr: u32) -> u32;
// 演算法驗證
fn secp256k1_verify(message_hash_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32;
fn secp256k1_recover_pubkey(
message_hash_ptr: u32,
signature_ptr: u32,
recovery_param: u32,
) -> u64;
fn ed25519_verify(message_ptr: u32, signature_ptr: u32, public_key_ptr: u32) -> u32;
fn ed25519_batch_verify(messages_ptr: u32, signatures_ptr: u32, public_keys_ptr: u32) -> u32;
fn debug(source_ptr: u32);
// 查詢鏈上資料
/// Executes a query on the chain (import). Not to be confused with the
/// query export, which queries the state of the contract.
fn query_chain(request: u32) -> u32;
}
Fabric中智能合約與賬本中世界狀態進行互動的方法:利用PutState和GetState這兩個API來實作的,見下圖,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/273283.html
標籤:區塊鏈
上一篇:Visual Studio使用筆記:cmake工程 missing and no known rule to make it
下一篇:愷撒密碼加密與解密
