发明内容
本说明书一个或多个实施例描述了一种编译和执行智能合约的方法和装置,用以提升智能合约的部署效率和执行性能。
根据第一方面,提供了一种执行智能合约的方法,通过虚拟机执行,该方法包括:
获取智能合约对应的合约模块,所述合约模块包括代码区段和导入区段,所述导入区段中包括第一外部函数的函数声明信息;
解析所述代码区段中的字节码,得到对所述第一外部函数的调用指令代码;
根据所述第一外部函数的函数声明信息,从虚拟机中包含的采用相同语言实现的函数库中,确定用于实现所述第一外部函数的函数代码,并获取所述函数代码对应的可执行的第一代码段;
将所述调用指令代码链接到所述第一代码段,得到链接代码;
执行所述链接代码,以执行所述智能合约中的所述第一外部函数。
在一个实施例中,在获取智能合约对应的合约模块之前,方法还包括:接收第一交易,所述第一交易的目标地址字段指向所述智能合约的合约地址,以请求调用所述智能合约。
根据一个实施例,所述字节码模块为WASM模块。
在一个实施例中,方法还包括,根据所述第一外部函数的函数声明信息,确定所述第一外部函数为所述函数库中提供的函数。
在一种实施方式中,所述虚拟机和所述函数代码采用C语言或C++语言实现。
根据一种实施方式,获取所述函数代码对应的可执行的第一代码段包括:将所述函数代码编译为所述第一代码段,所述第一代码段是适用于所述虚拟机所在平台的原生代码。
根据另一种实施方式,获取所述函数代码对应的可执行的第一代码段包括:从内存中获取已加载、通过编译所述函数代码而生成的所述第一代码段,所述第一代码段是适用于所述虚拟机所在平台的原生代码。
在一个实施例,通过以下方式将所述调用指令代码链接到所述第一代码段:将执行所述调用指令代码的地址指向存储所述第一代码段的内存地址。
根据第二方面,提供了一种执行智能合约的装置,部署在虚拟机中,该装置包括:
模块获取单元,配置为获取智能合约对应的合约模块,所述合约模块包括代码区段和导入区段,所述导入区段中包括第一外部函数的函数声明信息;
解析单元,配置为解析所述代码区段中的字节码,得到对所述第一外部函数的调用指令代码;
代码获取单元,配置为根据所述第一外部函数的函数声明信息,从虚拟机中包含的采用相同语言实现的函数库中,确定用于实现所述第一外部函数的函数代码,并获取所述函数代码对应的可执行的第一代码段;
链接单元,配置为将所述调用指令代码链接到所述第一代码段,得到链接代码;
执行单元,配置为执行所述链接代码,以执行所述智能合约中的所述第一外部函数。
根据第三方面,提供了一种计算机可读存储介质,其上存储有计算机程序,当所述计算机程序在计算机中执行时,令计算机执行第一方面的方法。
根据第四方面,提供了一种计算设备,包括存储器和处理器,其特征在于,所述存储器中存储有可执行代码,所述处理器执行所述可执行代码时,实现第一方面的方法。
根据本说明书一个实施例提供的方法和装置,在对智能合约进行编译而该智能合约依赖于外部函数时,在生成的合约模块中仅包含外部函数的声明信息,而不包含该外部函数的实现代码。在执行该智能合约时,由虚拟机从本地的函数库中确定出用于实现上述外部函数的函数代码,进而获取到对应的可执行代码段,并将该代码段与合约代码相链接,从而执行该外部函数。通过以上方式,合约模块中不包含外部函数的实现代码,体积非常小,便于合约的传输和部署。此外,较小的模块体积还大大减轻了虚拟机加载合约模块、解析字节码的负担,使得合约执行效率更高。如此,提升智能合约的执行性能和区块链平台的可用性。
具体实施方式
下面结合附图,对本说明书提供的方案进行描述。
图1是在区块链网络中部署智能合约的过程示意图。如图1所示,区块链网络中包含若干节点,各个节点之间可以进行通信。用户可以借由外部账户通过上述节点发起交易,交易既可以是普通的转账交易,也可以用于创建智能合约或调用智能合约。假定在网络中某个节点处,合约开发者Bob想要发布一段智能合约,那么可以采用如图所示的发布过程。
首先,Bob可以以高级语言的形式编写智能合约。然后,通过编译器将高级语言编译为字节码(bytecode)文件,生成合约模块。
字节码是一种介于高级语言和机器码之间的中间码格式,包括一序列opcode代码(操作码)/数据对组成的二进制字符编码。字节码并不是可以直接执行的机器码,需要对应的虚拟机进行解析才能执行。
接着,Bob可以以交易的形式,发布该合约。具体的,Bob可以发起一笔交易,交易内容中发起方from字段即为Bob(更具体为Bob的地址),接收方to字段设为空值;并且,该交易内容中还包括Data字段,其中包含将上述智能合约编译为字节码之后的代码。
在Bob把这样一条交易发布到区块链网络之后,区块链网络中的各个节点均可以获取到上述智能合约的字节码,于是,上述智能合约就部署到了区块链网络的各个节点中。如常规交易类似的,记账节点会对该交易进行验证、打包等操作,将其记录在区块中,并通过共识机制,添加到区块链上。在这个过程中,还会根据一定算法,例如基于发布者地址进行哈希等,为上述智能合约赋予一个合约地址,例如0x6f…。如此,一个智能合约对应一个合约地址,与用户的外部账户地址在形式上没有区别。以上智能合约经过打包上链之后,区块链网络中的任意用户均可以调用该智能合约。
在有用户调用上述智能合约时,节点中的虚拟机就会执行合约逻辑对应的操作,并通过共识机制实现网络上合约状态的改变。具体的,虚拟机会加载并运行之前部署的智能合约的字节码,更具体而言,虚拟机中的解释器对字节码代表的指令流进行解释和执行,从而执行智能合约,改变合约中参数的状态。
通过以上过程可以看到,在智能合约发布的时候,部署到各个节点的是智能合约经过编译后的字节码。在从合约源代码编译为字节码过程中,在源代码中引入对外部接口的依赖时,常常会出现编译代码膨胀的情况。
图2示出智能合约的编译过程示意图。如前所述,智能合约可以采用高级语言编写,因此,开发者在编写智能合约时,可以根据需要在其中定义一些函数,或称为合约接口,也可以在合约中引入对其他接口的依赖,也就是调用一些外部函数,其中外部函数是指合约中自定义的函数之外的函数,通常由外部函数库提供,例如智能合约开发工具或开发平台会提供有系统函数库和/或三方函数库,或者其他第三方机构也可以提供有第三方函数库,等等。
在图2的示例中,高级语言C语言编写的智能合约包含有如下源代码:
int openat(…){
…
size=_myvm_strlen(…);
…
}
以上源代码段中定义了一个合约函数或合约接口“openat”,在该合约函数中,又调用了合约开发平台为C语言提供的系统库libc中的库函数“_myvm_strlen”,该函数用于求取字符串长度,相对于合约来说即为合约的外部函数。
在对上述源代码进行编译时,对于常规语句,编译器直接将语句本身编译为字节码。然而,在出现外部函数的调用时,编译器则会查询相应的函数库,从中获取到该外部函数的实现代码,将该实现代码纳入到合约中,然后编译为字节码。
例如,通过查询系统库libc,可以查找到库函数“_myvm_strlen”的实现代码“size_t strlen(const char*s)……”,如图2中箭头所指向。然后,将这段实现代码纳入到合约中,编译为字节码。
因此,在编译产生的合约模块中的代码区段中,除了包含合约自身语句编译生成的字节码,还包括对外部函数的实现代码进行编译生成的字节码。例如,在图2中对合约编译生成的wasm模块中,代码区段中不仅包含实现合约函数“openat”的字节码,还包括实现外部函数“_myvm_strlen”的字节码。
通过以上过程可以看到,如果合约源代码中引入对外部接口的依赖,或者说调用了外部函数,那么该外部函数的实现代码也被编译纳入到合约模块中,由此,源代码中一行对外部函数的调用语句会转化为该外部函数的整个实现代码,导致生成的字节码模块极具膨胀。以C/C++编写的智能合约为例,如果源代码为2k大小,生成的字节码代码通常至少有20k,代码体积膨胀20倍以上。
编译过程中代码的膨胀将会使得,生成的合约字节码体积较大,增加合约的传输成本和部署效率。进一步地,在合约执行时,较大的字节码模块也会增加加载、解析字节码过程中的性能开销,给虚拟机执行模型在性能上带来较大的挑战。
考虑到以上问题,在本说明书的一个实施例中,提出在虚拟机中提供共享函数库,其中包含各个函数的具体实现。与此相应地,在对智能合约源代码进行编译,而该智能合约依赖于外部函数时,可以只引入该外部函数的函数声明信息,而不必将函数的实现代码集成到合约中。在执行该智能合约时,虚拟机可以从其本地的共享函数库获取到函数的实现代码,从而执行该外部函数。如此,外部函数的具体实现代码不再包含在编译生成的合约模块中,大大缩减模块体积,提升合约传输和部署的效率,也提升合约执行性能。
下面描述以上构思的具体实现。
图3示出根据一个实施例的编译智能合约的方法流程图。通过图3的方法,将智能合约编译为十六进制的字节码,并生成该智能合约对应的合约模块或合约文件,其中包含编译的字节码。
图3的方法可以适用于多种语言的智能合约和多种字节码格式。例如,在一个实施例中,智能合约可以采用Solidity语言编写,并编译为字节码,生成.bin格式的合约模块。在另一个实施例中,智能合约采用C/C++,Java,Kotlin,TypeScript,Rust等高级语言编写,并编译为WASM字节码,生成相应的.WASM格式的合约模块。
WASM即WebAssembly,是由W3C社区组开发的开放标准,是一种新的平台无关的中间字节码格式。WASM是一种低级的类汇编语言,具有紧凑的二进制格式,可以在Web上高效运行,因此,近来作为区块链中智能合约的编译目标。
图4示出根据一个实施例的编译智能合约的示意图,该示意图示出了将C语言编写的智能合约编译为WASM字节码的示例过程。下面结合图4,以WASM字节码为例描述图3的方法流程,但是可以理解,该编译过程的构思可以推广适用于其他语言和其他字节码格式。
如图3所示,首先在步骤31,读取智能合约的源代码中的语句。对于常规的合约语句,按照常规的编译规则将其编译为字节码。例如,图4中的示例中,智能合约的源代码片段与图2所示相同,均为C语言编写的代码段。对于合约语句“int openat(…)”,按照常规方式对其进行编译。
特别地,如果读取的当前语句中涉及对外部接口的依赖,或者说,当前语句包括对外部函数的调用,则需要进行特殊处理。简单起见,将这样的语句称为第一语句,第一语句中调用的外部函数称为第一外部函数。
例如,图4中的语句“size=_myvm_strlen(…)”调用了外部函数“_myvm_strlen”,则对该语句进行特殊处理。
语句的特殊处理包括步骤32,根据与第一外部函数对应的函数库,判断该第一外部函数是否为预定类型函数,所述预定类型函数为在虚拟机中实现的函数,或者说,预定类型函数即前述的虚拟机提供的共享函数库中的函数,其实现代码已经包含在虚拟机中。
如果第一外部函数不是预定类型函数,那么仍然按照常规方式,将第一外部函数的实现代码纳入到合约代码中进行编译处理;如果第一外部函数是预定类型函数,则可以对该第一外部函数的调用进行特殊编译。因此,需要首先对第一外部函数进行判断。
可以通过多种方式判断第一外部函数是否为预定类型函数。
首先确定出第一外部函数对应的函数库。合约中所调用的外部函数可以来自系统函数库或第三方函数库。例如,在图4的例子中,myvm-libc库为针对C语言提供的系统函数库,libc++库为针对C++语言提供的系统函数库,mychainlib为区块链开发平台提供的三方函数库。在一个例子中,合约源代码中会声明所使用的函数库,例如通过“include”语句声明函数库。在一些例子中,第一外部函数的函数名中也会含有对应函数库的信息,例如图4中第一外部函数“_myvm_strlen”的前缀“myvm”即指示了函数库信息。通过以上信息,可以确定出第一外部函数对应的函数库。例如,可以确定出第一外部函数“_myvm_strlen”对应的函数库为myvm-libc库。
然后,基于上述函数库确定第一外部函数是否为预定类型函数。
在一个实施例中,提供该第一外部函数的函数库预先对其中的函数进行标注,例如,对于实现代码包含在虚拟机中的函数,为其添加一个特殊标记。该特殊标记可以采用各种形式,例如,“extern”,“CodeNull”等等。
在这样的情况下,可以通过函数名在函数库中查询第一外部函数,当函数库中针对第一外部函数标注有用于指示预定类型函数的标记时,则确定第一外部函数为预定类型函数。
例如,根据图4的例子,在myvm-libc库中,在一些函数前添加了标记“extern”,用于指示该函数的实现代码已经包含在虚拟机中,也就是用该标记指示出前述的预定类型函数。相应的,对于有“extern”标记的函数,myvm-libc库中仅记录这些函数的函数声明信息,例如函数名,参数类型,返回类型,等等,但是不包含这些函数的实现代码。
对于第一外部函数“_myvm_strlen”,可以用其函数名在myvm-libc库中进行查询,得到库中的记录“extern_myvm_strlen”,即,函数库针对第一外部函数标注了特定标记“extern”,因此,可以确定该第一外部函数是预定类型函数。
在另一实施例中,函数库中并不对预定类型函数进行特殊标记,但是可以通过以下方式进行区分:对于常规类型函数,函数库中会记录该函数的声明信息,以及实现代码;而对于上述预定类型函数,函数库中仅记录该函数的声明信息,不记录其实现代码。
在这样的情况下,为了对第一外部函数进行判断,编译器可以通过函数名在函数库中查询第一外部函数;如果函数库中针对该第一外部函数仅记录有函数声明而不包含函数的实现代码,则确定第一外部函数为预定类型函数。
在又一实施例中,可以预先确定某些函数库为专用于定义预定类型函数的函数库,其中包含的函数均为预定类型函数。例如,假定开发平台已经预先将系统库myvm-libc中所有函数的实现代码都集成到虚拟机中,那么就可以将该函数库标记为专用于定义预定类型函数的函数库,并通知编译器。如此,当编译器确定出第一外部函数对应的函数库为上述的专用函数库时,就可以确定该第一外部函数为预定类型函数。
如前所述,在确定第一外部函数为预定类型函数的情况下,需要对调用第一外部函数的第一语句进行特殊编译。
具体的,在步骤33,针对前述第一语句,生成对第一外部函数的调用指令。例如,针对第一语句,生成call指令,将该第一外部函数作为call的对象。
在一个实施例中,在生成调用指令之前,编译器首先对函数调用是否合法进行检查。具体的,编译器可以从之前确定出的函数库中查询获得第一外部函数的声明信息,声明信息除了包括函数名之外,还包括参数类型、参数个数、返回类型等中的至少一项。于是,编译器可以核查第一语句中对第一外部函数的调用是否与声明信息相匹配。例如,检查第一语句中调用第一外部函数时,提供的参数个数与函数声明中的是否一致,检查参数的类型与函数声明中的是否匹配,检查合约中对返回值的定义类型与函数声明中的返回类型是否一致,等等。在第一语句中的调用信息与函数声明相匹配的情况下,才生成对第一外部函数的调用指令。
对于以上生成的调用指令,按照编译规则将其转化为字节码。
并且,在步骤34,将上述调用指令对应的字节码包含在有待形成的合约模块的代码区段中,并将第一外部函数的函数信息包含在合约模块的导入区段中。
如本领域技术人员所知,智能合约通过编译,可以生成对应的合约模块,或合约文件。合约模块中包含合约编译后的字节码,可选的还可以包括其他合约相关信息。不同语言格式的合约模块可以具有不同的模块形式。
例如,以WASM格式的合约模块为例,生成的合约模块中包括多个区段,其中必选区块包括代码区块,其中记录合约源代码编译后的WASM字节码。此外,WASM文件还可选的包含导入区段和导出区段。导入区段(import section)定义本模块从其它模块中导入的函数、表、内存、全局变量等,而导出区段(export section)定义本模块中导出的函数、表、内存、全局变量等。
基于此,在步骤34中,可以在代码区块中包含上述调用指令对应的字节码,在导入区块中包含上述第一外部函数的函数声明信息。
参看图4,其中示例性示出了WASM模块。可以看到,对于第一外部函数“_myvm_strlen”,将其函数声明信息包含在WASM模块的导入区段中,如“import_myvm_strlen(…)”所示。相应的,在模块的代码区段中,关于第一外部函数,与图2中包括该函数的全部实现代码的字节码不同的,图4中仅包括该函数的调用指令所对应的字节码,因此是非常简短的一小段字节码。
通过以上过程可以看到,根据本说明书的一个实施例,在对智能合约进行编译而该智能合约依赖于外部函数时,不再将外部函数的实现代码纳入到合约中进行编译,而是将其转化为一条对该外部函数的调用指令,并将函数的声明信息添加到合约模块的导入区段中。
由于仅包含函数声明而不包含函数实现代码,因此,智能合约在编译时,代码体积不会出现明显膨胀,如此使得生成的合约模块体积较小,非常有利于合约的传输和部署,明显提升合约部署效率。
需要理解,编译过程中不再需要将函数的实现代码包含在合约模块中的前提是,用于执行智能合约的虚拟机可以从其本地获取这些实现代码,如此才能执行相应的函数功能,进而执行智能合约。
下面描述虚拟机获取函数的实现代码,以及执行智能合约的过程。
可以理解,虚拟机也可以认为是在操作系统上运行的程序,该程序用于模拟某种执行环境。因此,在一个实施例中,可以在已有的虚拟机程序中,添加用于实现各种函数的函数库,该函数库采用与虚拟机相同的语言实现。例如,虚拟机和函数库均可以采用C语言实现,或者均采用C++语言实现。如此,虚拟机就包含了采用相同语言实现的函数库,该函数库包括用于执行各个函数的函数代码。
如此,在虚拟机执行智能合约时,如果该智能合约调用了外部函数,且没有包含该外部函数的实现代码,那么虚拟机就从本地包含的函数库中获取函数的实现代码,并将该代码实现体与合约模块的对应部分“链接”在一起,由此执行智能合约。通过这样的方式,虚拟机以近乎原生代码的性能执行上述外部函数,使得合约执行效率进一步得到提升。
图5示出根据一个实施例的执行智能合约的方法流程图。该方法通过区块链网络中任意节点中的虚拟机执行,其中区块链网络可以是公有链、私有链、联盟链,在此不做限制。
可以理解,智能合约的执行一般是通过接收到调用该智能合约的交易而触发。因此,在图5的步骤开始之前,假定预先已经按照图3的方式对智能合约进行编译,并将编译生成的合约模块部署到区块链网络的各个节点中。然后,当某个节点处的某个账户(例如Alice)想要调用已经创建和部署的上述智能合约时,他可以发起一个调用该合约的交易,将该交易的目标地址字段(to字段)指向要调用的智能合约的合约地址,并在该交易的data字段中包含要调用的合约中的函数。相应地,各个节点中的虚拟机接收到上述交易后,均可以通过to字段确定出要调用的智能合约,并开始执行图5的方法流程。
如图5所示,在步骤51,获取智能合约对应的合约模块。可以理解,该智能合约是上述交易中所调用的智能合约,其合约模块已经预先部署到各个节点中。相应的,在步骤51,可以将该合约模块加载到内存中。并且,上述合约模块是根据图3的方式对智能合约进行编译而生成的,该合约模块包括代码区段和导入区段,其中代码区块中记录对智能合约的源代码进行编译所生成的字节码,导入区段中记录从外部导入的函数信息。在一个实施例中,上述合约模块是WASM模块。假定导入区段中包括第一外部函数的函数声明信息。
在步骤52,解析合约模块中代码区段的字节码,得到对上述第一外部函数的调用指令代码。需要理解的是,通过图3的编译过程,合约模块的字节码中仅包含第一外部函数的调用信息,而不包含具体用于实现第一外部函数的代码。因此,相应地,在该步骤52中,对合约模块中的字节码进行解析,仅可以得到对第一外部函数的调用指令代码,而无法得到第一外部函数的实现代码。
于是,根据导入区段中包含的第一外部函数的函数声明信息,尝试从虚拟机本地获取第一外部函数的实现代码。如前所述,在一个实施例中,在虚拟机中包含采用相同语言实现的函数库,该函数库中包括各个函数的实现代码。因此,在一个实施例中,可以首先根据第一外部函数的函数声明信息,确定第一外部函数是否为虚拟机包含的函数库中提供的函数。例如可以利用函数声明信息在操作系统函数库中进行查询。
一旦确定第一外部函数为虚拟机函数库中提供的函数,在步骤53,可以从上述虚拟机具有的函数库中,确定用于实现所述第一外部函数的函数代码,并获取所述函数代码对应的可执行的第一代码段。
在一个实施例中,对于确定出的用于实现第一外部函数的函数代码,对其进行编译,编译成为适用于虚拟机所在平台的可执行代码段,即第一代码段。因此,在该实施例中,通过即时编译得到原生代码段作为第一代码段。
在另一实施例中,在启动虚拟机时,即同时对虚拟机函数库中的所有函数代码进行加载,并将其编译为适用于平台的可执行代码。或者,对于较为常用的外部函数的函数代码,可以预先对其进行加载和编译,转化为可执行代码。在以上情况中,在内存中已经存储有至少部分函数对应的可执行代码段。在第一外部函数对应的函数代码已经预先加载和编译的情况下,在步骤53,可以直接从内存中读取适用于虚拟机所在平台执行的第一代码段。
然后,在步骤54,将解析字节码得到的调用指令代码链接到上述第一代码段,形成链接代码。具体的,在一个实施例中,将执行上述调用指令的地址指向存储所述第一代码段的内存地址,从而实现代码链接。在另一实施例中,也可以将第一代码段插入到合约字节码解析后的可执行代码中,从而实现代码链接。
于是,在步骤55,可以通过执行上述链接后代码,实现第一外部函数的功能,从而执行上述智能合约。
图6示出在一个例子中执行智能合约的示意图。可以看到,图6中示例性示出的WASM合约模块正是图4中编译生成的合约模块,其中在导入区段中包含外部函数“myvm_strlen(…)”的函数声明信息,在代码区段中包含针对该外部函数的调用指令对应的字节码。
通过图5的方法,可以从导入区段中获取到外部函数的声明信息,从代码区段中解析出对该外部函数的调用指令代码。然后,虚拟机从其自身的的函数库中获得该外部函数的实现代码,将其与解析后的合约代码链接。图6示例性示出了3种操作系统,针对每种操作系统分别提供其对应的虚拟机和函数库。虚拟机基于函数库获取到外部函数的适用于该平台的可执行代码,从而执行该外部函数,进而执行智能合约。
通过以上过程可以看到,由于合约模块中不包含外部函数的实现代码,体积非常小,除了便于合约的传输和部署之外,还大大减轻了虚拟机加载合约模块、解析字节码的负担,使得合约执行效率更高。更进一步地,对于合约中调用的外部函数,由虚拟机包含的函数库来提供其实现代码,以近乎原生代码的实现方式执行上述外部函数,从而进一步提升了合约执行效率。在实际的区块链平台中,合约的执行性能及吞吐率是平台系统的核心,因此通过以上方式,从多个角度改进合约的执行性能和吞吐量,极大提升了平台的效率和可用性。
根据另一方面的实施例,提供了一种编译智能合约的装置,部署在编译器中。图7示出根据一个实施例的编译装置的示意性框图。如图7所示,该编译装置700包括:
语句读取单元71,配置为读取智能合约的源代码中的第一语句,其中该第一语句包括对第一外部函数的调用;
确定单元72,配置为根据与所述第一外部函数对应的函数库,确定所述第一外部函数为预定类型函数,所述预定类型函数为在执行所述智能合约的虚拟机中实现的函数;
指令生成单元73,配置为针对所述第一语句,生成对所述第一外部函数的调用指令,并将该调用指令转换为对应的字节码;
记录单元74,配置为将所述调用指令对应的字节码包含在有待形成的合约模块的代码区段中,并将所述第一外部函数的函数声明信息包含在所述合约模块的导入区段中。
在一个实施例中,所述函数库为系统函数库或第三方函数库。
根据一个实施例,确定单元72配置为:
通过函数名在所述函数库中查询所述第一外部函数;
当所述函数库中针对所述第一外部函数标记有用于指示所述预定类型函数的预定标记时,确定所述第一外部函数为所述预定类型函数。
根据另一实施例,确定单元72配置为:
通过函数名在所述函数库中查询所述第一外部函数;
当所述函数库中针对所述第一外部函数仅记录有函数声明而不包含函数的实现代码时,确定所述第一外部函数为所述预定类型函数。
根据又一实施例,确定单元72配置为:
当确定所述函数库为专用于定义所述预定类型函数的函数库时,确定所述第一外部函数为预定类型函数。
根据一种实施方式,指令生成单元73配置为:
从所述函数库查询获得所述第一外部函数的函数声明信息,所述函数声明信息包括参数类型、参数个数、返回类型中的至少一项;
核查所述第一语句中对所述第一外部函数的调用是否与所述函数声明信息相匹配;
在匹配的情况下,生成对所述第一外部函数的调用指令。
在一个实施例中,上述字节码模块为WASM模块。
根据另一方面的实施例,提供了一种执行智能合约的装置,部署在区块链网络任意节点的虚拟机中,该任意节点可以体现为任何具有计算、处理能力的设备、平台或设备集群,该虚拟机可以是与智能合约格式相适应的虚拟机,例如Solidity虚拟机,WASM虚拟机等。图8示出根据一个实施例的合约执行装置的示意性框图。如图8所示,该合约执行装置800包括:
模块获取单元81,配置为获取智能合约对应的合约模块,所述合约模块包括代码区段和导入区段,所述导入区段中包括第一外部函数的函数声明信息;
解析单元82,配置为解析所述代码区段中的字节码,得到对所述第一外部函数的调用指令代码;
代码获取单元83,配置为根据所述第一外部函数的函数声明信息,从虚拟机中包含的采用相同语言实现的函数库中,确定用于实现所述第一外部函数的函数代码,并获取所述函数代码对应的可执行的第一代码段;
链接单元84,配置为将所述调用指令代码链接到所述第一代码段,得到链接代码;
执行单元85,配置为执行所述链接代码,以执行所述智能合约中的所述第一外部函数。
根据一个实施例,上述装置800还包括接收单元(未示出),配置为:
接收第一交易,所述第一交易的目标地址字段指向所述智能合约的合约地址,以请求调用所述智能合约。
在一个实施例中,所述字节码模块为WASM模块。
根据一个实施例,上述装置800还包括确定单元(未示出),配置为根据所述第一外部函数的函数声明信息,确定所述第一外部函数为所述函数库中提供的函数。
在一个实施例中,所述虚拟机和所述函数代码采用C语言或C++语言实现。
根据一种实施方式,所述代码获取单元83配置为:将所述函数代码编译为所述第一代码段,所述第一代码段是适用于所述虚拟机所在平台的原生代码。
根据另一种实施方式,所述代码获取单元83配置为:从内存中获取已加载、通过编译所述函数代码而生成的所述第一代码段,所述第一代码段是适用于所述虚拟机所在平台的原生代码。
在一个实施例中,所述链接单元84配置为,将执行所述调用指令代码的地址指向存储所述第一代码段的内存地址。
根据另一方面的实施例,还提供一种计算机可读存储介质,其上存储有计算机程序,当所述计算机程序在计算机中执行时,令计算机执行结合图3和图5所描述的方法。
根据再一方面的实施例,还提供一种计算设备,包括存储器和处理器,所述存储器中存储有可执行代码,所述处理器执行所述可执行代码时,实现结合图3和图5所述的方法。
本领域技术人员应该可以意识到,在上述一个或多个示例中,本发明所描述的功能可以用硬件、软件、固件或它们的任意组合来实现。当使用软件实现时,可以将这些功能存储在计算机可读介质中或者作为计算机可读介质上的一个或多个指令或代码进行传输。
以上所述的具体实施方式,对本发明的目的、技术方案和有益效果进行了进一步详细说明,所应理解的是,以上所述仅为本发明的具体实施方式而已,并不用于限定本发明的保护范围,凡在本发明的技术方案的基础之上,所做的任何修改、等同替换、改进等,均应包括在本发明的保护范围之内。