程序员

cosmwasm&wasmd —— 智能合约、合约计费规则、合约与世界状

作者:admin 2021-05-07 我要评论

一、前言 1.1 项目版本 1. cosmwasmorgin/main2. wasmdorigin/master 1.2 简单介绍 1. cosmwasm主要功能- cosmwasm-template提供编写智能合约以下简称合约的模板...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

一、前言

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主要功能如图所示

wasm智能合约生命周期

图中的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 合约计费规则

  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
    }
}
  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清单
在这里插入图片描述
当然以太坊gas消耗是可以优化的,具体见此处

  1. 执行智能合约时 gasUsed 无法提前预知, 这样存在一个风险,当用户的交易涉及一个恶意的智能合约,该合约执行将消耗无限的燃料, 这样会导致交易方的余额全部消耗(恶意的智能合约有可能是程序Bug,如合约执行陷入一个死循环)。为了避免合约中的错误引起不可预计的燃料消耗,用户需要在发送交易时设定允许消耗的燃料上限,即 gasLimit。 这样不管合约是否良好,最坏情况也只是消耗 gasLimit 量的燃料。

  2. 如果交易尚未执行完成,而gas已用完,那么交易回滚,用完的gas不会返还。

  3. 即使交易失败,也必须为已占用的计算资源支付手续费。

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://blog.csdn.net/qq_28080747/article/details/115343384

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • “鸿蒙设备开发”选“址” --&gt;

    “鸿蒙设备开发”选“址” --&gt;

  • Nextcloud是如何成为终极开源生产力套

    Nextcloud是如何成为终极开源生产力套

  • 手把手教你用Pycharm连接远程Python环

    手把手教你用Pycharm连接远程Python环

  • Windows 10X镜像生成工具发布:任意PC

    Windows 10X镜像生成工具发布:任意PC

腾讯云代理商
海外云服务器