传送门: 柏链项目学院


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

前期内容回顾

之前我们的介绍的是如何通过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. }

Go语言打造以太坊智能合约测试框架(level2)的更多相关文章

  1. Go语言打造以太坊智能合约测试框架(level1)

    传送门: 柏链项目学院 Go语言打造以太坊智能合约测试框架 前言 这是什么? 这是一个基于go语言编写的,自动化测试以太坊智能合约的开发框架,使用此框架,可以自动化的部署合约,自动测试合约内的功能函数 ...

  2. Go语言打造以太坊智能合约测试框架(level3)

    传送门: 柏链项目学院 第三课 智能合约自动化测试 之前课程回顾 我们之前介绍了go语言调用exec处理命令行,介绍了toml配置文件的处理,以及awk处理文本文件获得ABI信息.我们的代码算是完成了 ...

  3. 以太坊智能合约Hello World示例程序

    简介 以太坊(Ethereum)是一提供个智能合约(smart contract)功能的公共区块链(BlockChain)平台. 本文介绍了一个简单的以太坊智能合约的开发过程. 开发环境 在以太坊上开 ...

  4. 以太坊智能合约 Solidity 的常用数据类型介绍

    目录 目录 1.数组 1.1.对数组的增删改查操作. 2.String.Bytes.Mapping的使用 3.Enums 和 Structs 的简单应用 4.Ether 单位和 Time 单位 5.A ...

  5. 如何通过以太坊智能合约来进行众筹(ICO)

    前面我们有两遍文章写了如何发行代币,今天我们讲一下如何使用代币来公开募资,即编写一个募资合约. 写在前面 本文所讲的代币是使用以太坊智能合约创建,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还 ...

  6. 以太坊智能合约介绍,Solidity介绍

    以太坊智能合约介绍,Solidity介绍 一个简单的智能合约 先从一个非常基础的例子开始,不用担心你现在还一点都不了解,我们将逐步了解到更多的细节. Storage contract SimpleSt ...

  7. 深入以太坊智能合约 ABI

    开发 DApp 时要调用在区块链上的以太坊智能合约,就需要智能合约的 ABI.本文希望更多了解 ABI,如为什么需要 ABI?如何解读 Ethereum 的智能合约 ABI?以及如何取得合约的 ABI ...

  8. rpc接口调用以太坊智能合约

    rpc接口调用以太坊智能合约 传送门: 柏链项目学院   在以太坊摸爬滚打有些日子了,也遇到了各种各样的问题.这几天主要研究了一下如何通过rpc接口编译.部署和调用合约.也遇到了一些困难和问题,下面将 ...

  9. 使用web3.js监听以太坊智能合约event

    传送门: 柏链项目学院 使用web3.js监听以太坊智能合约event   当我们在前端页面调用合约时发现有些数据不会立即返回,这时还需要再调用更新数据的函数.那么这样的方法使用起来非常不便,监听ev ...

随机推荐

  1. SQL 存储过程中事务回滚

    在事务语句最前面加上 set xact_abort on GO SET QUOTED_IDENTIFIER OFF GO ALTER PROCEDURE [dbo].[test] @a int, @b ...

  2. SQLServer存储过程自制数据字典

    相信很多小伙伴都对[数据字典]很头疼. 小编刚入职的时候,老大丢一个项目过来,就一个设计文档,数据字典木有,字段说明木有, 全部都需要靠“联系上下文”来猜.所以小伙伴门一定要养成说明字段的习惯哦. 说 ...

  3. 数字信号处理专题(3)——FFT运算初探

    一.前言 FFT运算是目前最常用的信号频谱分析算法.在本科学习数字信号处理这门课时一直在想:学这些东西有啥用?公式推来推去的,有实用价值么?到了研究生后期才知道,广义上的数字信号处理无处不在:手机等各 ...

  4. LeetCode算法题-Minimum Distance Between BST Nodes(Java实现-四种解法)

    这是悦乐书的第314次更新,第335篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第183题(顺位题号是783).给定具有根节点值的二叉搜索树(BST),返回树中任何两个 ...

  5. 关于bootstrap报错

    在使用bootstrap报错.报错的位置如下 if("undefined"==typeof jQuery)throw new Error("Bootstrap's Jav ...

  6. Reading task(Introduction to Algorithms. 2nd)

    Introduction to Algorithms 2nd ed. Cambridge, MA: MIT Press, 2001. ISBN: 9780262032933. Introduction ...

  7. Ubuntu16 FTP的安装,基本配置与权限控制

    1.ftp与sftp 大致了解下: ftp是一个文件传输协议,linux环境需要它才能支持文件的传输与查看,它的默认端口是21. sftp是加密/解密的文件传输协议,因为它每次传输都有加密解密的步骤, ...

  8. python的进程与线程(三)

    线程的锁 1.几个概念 讲起线程的锁,先要了解几个概念:什么是并行?什么是并发?什么是同步?什么是异步?          并发:是指系统具有处理多个任务(动作)的能力          并行:是指系 ...

  9. java中的伪泛型---泛型擦除(不需要手工强转类型,却可以调用强转类型的方法)

    Java集合如Map.Set.List等所有集合只能存放引用类型数据,它们都是存放引用类型数据的容器,不能存放如int.long.float.double等基础类型的数据. 使用反射可以破解泛型T类型 ...

  10. ArticleRemoveDelDialog【基于AlertDialog的回收删除对话框】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 回收删除对话框,继承AlertDialog. 仿照钉钉的长按弹出的移除置顶对话框. 效果图 代码分析 继承AlertDialog: ...