经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 其他 » 区块链 » 查看文章
Go语言打造以太坊智能合约测试框架(level2)
来源:cnblogs  作者:通证派大本营  时间:2019/4/10 8:34:45  对本文有异议


传送门: 柏链项目学院



第二课 智能合约自动化编译

前期内容回顾

之前我们的介绍的是如何通过solc编译智能合约,并且调用智能合约,本节我们继续实践,将智能合约的代码自动化编译以及abi文件生成搞定。

我们需要掌握什么技能呢?

  • go语言调用命令行
  • toml配置文件处理
  • awk工具的使用

go调用命令行

go调用命令行,我们使用exec包

  • LookPath 可以判断一个可执行程序是否存在
  • Command 创建一个命令行
  • cmd.Run() 运行命令行,也可以使用Start()模式,可以去接收管道信息来得到程序返回结果
  • 如果是一个shell脚本,那么可以用/bin/bash来启动

toml配置文件处理

TOML的全称是Tom's Obvious, Minimal Language,因为它的作者是GitHub联合创始人Tom Preston-Werner。TOML 的目标是成为一个极简的配置文件格式。TOML 被设计成可以无歧义地被映射为哈希表,从而被多种语言解析。

toml学习教程
在使用的时候,记得要安装toml第三方包。

  1. go get -u github.com/BurntSushi/toml

之后可以根据我们的需要,来编写配置文件,配置文件的目的仍然是为了让程序运行更灵活,而不应该成为我们的负担!

awk工具使用

awk其实是一个语言,unix平台上处理文本的一种语言,其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。该语言的能力十分强大,可以支持字符串处理,打印等操作,工程中对于文本处理要求比较高的环节多会使用awk进行操作。

awk功能举例:

  1. factory.txt 是一个工厂内目前产品库存情况,如果数量低于75,需要重新下订单,如何处理?
  1. yekaideMacBook-Pro:awk yk$ cat factory.txt
  2. ProdA 70
  3. ProdB 85
  4. ProdC 74

示例如下:

  1. awk '{if ($2 < 75) printf("%s reorder\n",$0);if ($2 >= 75) print $0}' factory.txt
  1. 查看本系统中shell是bash的用户名,并打印
  1. cat /etc/passwd |grep bash|awk -F ":" '{print $1}'
  1. awk处理合约的go文件,将abi信息截取处理存储到文本当中
  1. awk '/const.+ABI = .+/{print substr($4,2,length($4)-2) }' pdbank.go > pdbank.abi

编写自动编译功能

main.go

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. func Usage() {
  7. fmt.Printf("%s 1 -- compiler code\n", os.Args[0])
  8. fmt.Printf("%s 2 -- build test code\n", os.Args[0])
  9. }
  10. func main() {
  11. if len(os.Args) < 2 {
  12. Usage()
  13. os.Exit(0)
  14. }
  15. if os.Args[1] == "1" {
  16. CompilerRun()
  17. } else if os.Args[1] == "1" {
  18. //build test code
  19. } else {
  20. Usage()
  21. os.Exit(0)
  22. }
  23. }

接下来开始做填空题,也就是如何编译,我们先来实现。先编写扫描目录的代码,获取指定目录的sol文件,然后自动化的形成编译命令,送到命令行执行。

扫描指定目录的sol文件

  1. func CompilerRun() error {
  2. infos, err := ioutil.ReadDir("sol")
  3. if err != nil {
  4. fmt.Println("failed to readdir ", err)
  5. return err
  6. }
  7. for _, v := range infos {
  8. //后4位位.sol
  9. strNameRune := []rune(v.Name())
  10. strfix := string(strNameRune[len(strNameRune)-4:])
  11. if strfix == ".sol" && !v.IsDir() {
  12. fmt.Println(v.IsDir(), v.Name(), v.Size(), "ok")
  13. err = CompilerOnece("sol", v.Name(), "contracts")
  14. if err != nil {
  15. fmt.Println("call ompilerOnece err", err)
  16. break
  17. }
  18. }
  19. }
  20. return err
  21. }

编译函数

  1. //编译一个智能合约
  2. func CompilerOnece(solPath, solName, targetPath string) error {
  3. //xxx.sol - > xxx.go
  4. goName := strings.Replace(solName, ".sol", ".go", -1)
  5. cmd := exec.Command("abigen", "-sol", solPath+"/"+solName, "-pkg", targetPath, "-out", targetPath+"/"+goName)
  6. return cmd.Run()
  7. }

构建abi函数,我们需要先用awk实现一个shell脚本,用来处理go文件的abi信息。

  1. func BuildAbi(goCodeName string) error {
  2. abiName := strings.Replace(goCodeName, ".go", ".abi", -1)
  3. cmd := exec.Command("/bin/bash", "abi.sh", goCodeName, abiName)
  4. err := cmd.Run()
  5. fmt.Println("run BuildAbi ok!!", err)
  6. return nil
  7. }

abi.sh

  1. filename=$1
  2. targetfile=$2
  3. awk '/const.+ABI = .+/{print substr($4,2,length($4)-2) }' $filename > $targetfile

统一调用处理

  1. func ParseRun() {
  2. solfiles, err := ParseDir("sol")
  3. fmt.Println(solfiles, err)
  4. for _, solfile := range solfiles {
  5. fmt.Println(solfile)
  6. codeName, err := Compiler(solfile, "sol", "contracts")
  7. if err != nil {
  8. fmt.Println("failed to complie code", err)
  9. return
  10. }
  11. err = BuildAbi(codeName)
  12. if err != nil {
  13. fmt.Println("failed to build abi", err)
  14. return
  15. }
  16. }
  17. }

这样我们的基础工作完成了,但是代码不够完美,我们需要将部分写死的变量用配置文件来设置,所以再加入toml处理配置文件的部分。

添加config.tomls

  1. [version]
  2. auth = "yekai"
  3. company = "pdj"
  4. buildday = "2019-01-01"
  5. ver = "1.0.0" # 版本
  6. [common]
  7. solidityPath = "sol"
  8. goPath = "contracts"
  9. abiSH = "./abi.sh"

添加config.go

  1. package main
  2. import (
  3. "log"
  4. "github.com/BurntSushi/toml"
  5. )
  6. type ServerConfig struct {
  7. Version VersionInfo
  8. Common CommonInfo
  9. }
  10. type VersionInfo struct {
  11. Auth string
  12. Company string
  13. BuildDay string
  14. Ver string
  15. }
  16. type CommonInfo struct {
  17. SolidityPath string //智能合约原路径
  18. GoPath string //输出go代码路径
  19. AbiSH string //处理abi的shell脚本路径
  20. }
  21. var ServConf ServerConfig
  22. func init() {
  23. getConfig()
  24. }
  25. func getConfig() {
  26. var servConf ServerConfig
  27. _, err := toml.DecodeFile("config.toml", &servConf)
  28. if err != nil {
  29. log.Panic("faild to decodefile ", err)
  30. }
  31. ServConf = servConf
  32. //fmt.Println(servConf)
  33. }

接下来替换原来的代码部分

  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os/exec"
  6. "strings"
  7. )
  8. //编译一个智能合约
  9. func CompilerOnece(solPath, solName, targetPath string) error {
  10. //xxx.sol - > xxx.go
  11. goName := strings.Replace(solName, ".sol", ".go", -1)
  12. cmd := exec.Command("abigen", "-sol", solPath+"/"+solName, "-pkg", targetPath, "-out", targetPath+"/"+goName)
  13. return cmd.Run()
  14. }
  15. //构造abi
  16. func BuildAbi(codePath string) error {
  17. //"contracts/pdbank.go"
  18. //xxx.sol - > xxx.abi
  19. abiName := strings.Replace(codePath, ".sol", ".abi", -1)
  20. goName := strings.Replace(codePath, ".sol", ".go", -1)
  21. cmd := exec.Command(ServConf.Common.AbiSH, goName, abiName)
  22. return cmd.Run()
  23. }
  24. //扫描目录,获得全部的文件
  25. func CompilerRun() error {
  26. infos, err := ioutil.ReadDir(ServConf.Common.SolidityPath)
  27. if err != nil {
  28. fmt.Println("failed to readdir ", err)
  29. return err
  30. }
  31. for _, v := range infos {
  32. //后4位位.sol
  33. strNameRune := []rune(v.Name())
  34. strfix := string(strNameRune[len(strNameRune)-4:])
  35. if strfix == ".sol" && !v.IsDir() {
  36. fmt.Println(v.IsDir(), v.Name(), v.Size(), "ok")
  37. err = CompilerOnece(ServConf.Common.SolidityPath, v.Name(), ServConf.Common.GoPath)
  38. if err != nil {
  39. fmt.Println("call ompilerOnece err", err)
  40. break
  41. }
  42. //创建abi
  43. err = BuildAbi(ServConf.Common.GoPath + "/" + v.Name())
  44. if err != nil {
  45. fmt.Println("call BuildAbi err", err)
  46. break
  47. }
  48. }
  49. }
  50. return err
  51. }



原文链接:http://www.cnblogs.com/tokenpai/p/10679996.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号