前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅谈佛萨奇2.0波场链/币安链/马蹄链智能合约系统开发技术详细及源码部署

浅谈佛萨奇2.0波场链/币安链/马蹄链智能合约系统开发技术详细及源码部署

原创
作者头像
VX_I357O98O7I8
发布2022-12-15 15:23:49
4980
发布2022-12-15 15:23:49
举报
文章被收录于专栏:商业模式策划

8.2. solidity合约内调用合约

ChainMaker evm虚拟机支持solidity合约动态调用solidity合约,solidity合约动态调用solidity合约,以及solidity合约动态调用其他类型合约。

8.2.1. 静态调用

静态调用,是指在调用之前,调用者必须知道被调用者合约的接口。即,必须将被调用者的接口和调用者合约一同编译。在实际执行使,调用者不能调用接口以外的方法。

静态调用示例

合约callee.sol为被调用者合约,实现了一个简单的加法功能。

代码语言:javascript
复制
// SPDX-License-Identifier: GPL-3.0

pragma solidity > 0.5.21;

//被调用者合约
contract Callee {
    function Adder(uint256 x, uint256 y) public returns(uint256) {
        return x + y;
    }
}

合约caller.sol为调用者合约,可以调用callee.sol合约的方法。

代码语言:javascript
复制
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.5.21;

//被调用合约Callee的接口
abstract contract ICallee {
		//Callee.Adder的方法签名
    function Adder(uint256 x, uint256 y) public virtual returns(uint256);
}

//调用者合约
contract Caller {
    function crossCall(address addr, uint256 x, uint256 y) public returns(uint256) {
        ICallee callee = ICallee(addr); //将被调用合约的地址转化为ICalle接口
        return callee.Adder(x, y);      //根据接口和方法签名调用
    }
}

如示例所示,调用者合约Caller所在文件内,声明了一个被调用者合约Callee的接口ICallee,接口内有Callee合约的方法签名。调用者合约获得被调用合约的地址后,即可根据实现声明的接口,调用该地址的方法了。注意,在调用者合约调用被调用者之前,必须确保被调用者合约已经部署完成。

8.2.2. 动态调用

所谓动态调用,是指调用者合约不需要提前知道被调用合约的接口,只需要在调用时,告诉调用者被调合约的方法签名即可。调用者合约不需要事前绑定被调者的接口,可以在调用时,指定任意被调用合约及其方法,更加灵活。

动态调用示例

合约dynamic_call.sol。部署Caller合约后,可以调用任意solidity合约及其方法,不限定接口。

代码语言:javascript
复制
// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.0;

contract Caller {
    string[10] x;
    string[8] params;

    function cross_call(address callee, string calldata method, string calldata key, int256 value) public {
			//注意,method必须为方法签名格式,且方法签名的参数间不能有空格,例如"save(string,int256)"
	    callee.call((abi.encodeWithSignature(method, key, value));
    }
}

如示例所示,调用者合约Caller可以调用任意合约的任意方法,只需要将被调用合约的地址、方法签名和参数传给调用者合约即可。

注意,被调合约的方法必须是方法签名样式,且方法签名的参数间不能有空格,如示例中注释所示,否则无法编译为准确的ABI类型的calldata,evm将无法识别。

8.2.3. 异构调用

异构调用是指,solidity合约调用其他虚拟机类型的合约,比如wasm、docker-go等,只要在ChainMaker支持范围内,都可以异构调用。

solidity执行跨合约调用时,会将参数编码为ABI格式的calldata。但,对其他虚拟机合约来说,它们的参数并不需要ABI编码,也没有ABI文件,所以无法解析从调用者solidity合约那里传递来的参数。针对这种情况,ChainMaker单独实现了一套异构调用逻辑。

​ 1 作为调用者的solidity合约需要在合约内声明一个string数组类型的状态变量,用做异构调用的参数缓冲区

​ 2 在异构调用之前,需要将带传递的参数按顺序写入参数缓冲区;

​ 3 参数缓冲区的第一个元素(下标为0)必须是**”CrossVMCall”**字符串,用于让ChainMaker evm识别这是跨虚拟机的异构合约调用;

​ 4 参数缓冲区的第二个元素必须是待调用的方法名(此方法名不需要方法签名格式);

​ 5 从第三个参数开始,每两个元素一组,标识一个待传递参数,前一个元素为参数的类型或key(视被调合约而定),后一个元素为参数的值。

关于进一步理解异构调用的内容,可以参考接下来的异构调用示例。

异构调用示例

合约cross_vm_call.sol。部署CrossCall合约后,可以通过cross_call方法调用其他虚拟机类型的合约。。

代码语言:javascript
复制
// SPDX-License-Identifier: GPL-3.0

pragma solidity >= 0.8.0;

contract CrossCall {
    string[10] x;
    string[8] params;  //参数缓冲区

		//address类型的参数callee为被调用合约地址
    function cross_call(address callee, string calldata method, string calldata time, string calldata name, string calldata hash) public {
        
	//CrossVMCall is reserved key word
        params[0] = "CrossVMCall";//CrossVMCall为固定值,第一个参数必须是此值
        params[1] = method;       //方法名,例如"save"
        params[2] = "time";       //参数1的类型或key
        params[3] = time;         //参数1的value
        params[4] = "file_name";  //参数2的类型或key
        params[5] = name;         //参数2的value
        params[6] = "file_hash";  //参数3的类型或key
        params[7] = hash;         //参数2的value

	      callee.call("");//跨虚拟机调用callee合约,callee.call的参数为空,evm虚拟机会从参数缓冲区读取对应的参数
    }
}

如示例所示,solidity跨虚拟机异构调用时,必须提供被调合约的地址,而不能是方法名,因为合约调用方法call是solidity语法中,地址类型的成员方法,使用合约名则无法识别。

8.3. 其他虚拟机跨合约调用

相比于solidity,ChainMaker的其他虚拟机类型合约,都不支持合约创建合约,只支持合约调用合约。但同构异构都支持,且相比solidity也更加简单,只需要调用该类型合约所提供的跨合约调用接口即可。

调用示例

合约go_cross_call_evm.go 为go语言合约跨虚拟机调用soldity合约示例。

代码语言:javascript
复制
/*
SPDX-License-Identifier: Apache-2.0
*/

package main

//export init_contract
func initContract() {}

//export upgrade
func upgrade() {}

//export crossCallEvmContract
func crossCallEvmContract() {
	ctx := NewSimContext()

	// 获取参数
	name, _ := ctx.ArgString("name")
	method, _ := ctx.ArgString("method")
	calldata, _ := ctx.Arg("calldata")
	params := make(map[string][]byte, 1)
	params["data"] = calldata

	//执行跨虚拟机低啊用
	if result, resultCode := ctx.CallContract(name, method, params); resultCode != SUCCESS {
		// 返回结果
		ctx.ErrorResult("failed to cross call evm contract: " + name)
	} else {
		// 返回结果
		ctx.SuccessResultByte(result)
		// 记录日志
		ctx.Log("cross call evm contract result:" + string(result))
	}
}

func main() {

}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 8.2. solidity合约内调用合约
    • 8.2.1. 静态调用
      • 8.2.2. 动态调用
        • 8.2.3. 异构调用
        • 8.3. 其他虚拟机跨合约调用
        相关产品与服务
        云数据库 SQL Server
        腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档