当前位置: 首页 > news >正文

golang验证Etherscan上的智能合约

文章目录

  • golang验证Etherscan上的智能合约
    • 为什么要验证智能合约
    • 如何使用golang去验证合约
    • 获取EtherscanAPI密钥
    • Verify Source Code接口
    • Check Source Code Verification Status接口
    • 演示示例及注意事项
    • 网络问题无法调用Etherscan接口(最重要的步骤)

golang验证Etherscan上的智能合约

在阅读此文章前,您需要掌握一定的基础知识,如golang与以太坊交互,此篇文章是对其的补充,提供利用代码自动验证智能合约,减少不太必要的人工操作,如果由于Etherscan接口的更新,导致代码不适用,请随时与我联系。

为什么要验证智能合约

出于多种原因,您可能希望在公共区块浏览器上开源(验证)您的智能合约。

在Etherscan或其他类似的区块链浏览器上验证智能合约具有以下几个重要的用途:

  1. 透明度和信任:通过验证智能合约,你向社区展示了你的合约代码是公开的、可审查的。这增加了用户和其他开发者对你项目的信任,因为他们可以查看代码,确认合约行为的逻辑和功能。
  2. 安全性审查:验证后的智能合约会吸引更多人的关注,特别是智能合约专家和安全研究人员。他们可以帮助发现潜在的安全漏洞或问题,并提供改进建议。这有助于提升你的合约的安全性和可靠性。
  3. 抵抗黑客攻击:通过让更多人审查你的合约代码,可以提前发现和修复可能存在的漏洞,从而降低黑客攻击的风险。黑客往往会寻找未经审查或有漏洞的智能合约来进行攻击,而经过验证的合约能够减少这种风险。
  4. 开发者社区增长:开源并验证的智能合约能够鼓励更多开发者参与到你的项目中来。他们可以基于你的代码进行二次开发、添加新功能或者将你的合约作为基础构建新的应用程序,从而推动生态系统的发展和扩展。

总结来说,通过在Etherscan上验证智能合约,你不仅增加了透明度和安全性,还能吸引更多开发者和用户参与到你的区块链项目中来,推动项目的发展和采纳。

如何使用golang去验证合约

如果你是通过在线工具如Remix或OpenZeppelin的合约向导部署了你的合约,请考虑使用合约验证页面进行验证。Verify & Publish Contract Source Code | Etherscan

如果你是通过开发工具如Hardhat、Foundry、Truffle等部署了你的合约,请考虑使用插件来自动化验证过程。Contract Verification Plugins | Etherscan

如果你是一名使用golang去开发Web3应用的开发者或学习者,我们可以查看Etherscan提供的api接口,然后根据需要,自己造轮子。Contracts | Etherscan

这里我们找到验证合约所必要的两个api接口,Verify Source Code和Check Source Code Verification Status,意如其名,一个是将合约源代码提交给类似 Etherscan 的浏览器进行验证,一个是返回合同验证请求的成功或错误状态。

只要这两个接口都返回成功,我们的智能合约就已经在Etherscan上进行了验证。

获取EtherscanAPI密钥

注册登录->仪表盘->API-KEYs->Add->copy,具体请看链接Getting an API key | Etherscan。

Verify Source Code接口

将合约源代码提交给类似 Etherscan 的浏览器进行验证。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

根据官方提供的api接口详情,我们可以造出以下的代码,但是略有不同,上面表单中没有提供OptimizationUsed这个参数(0没有,1有),但是我在使用postman测试的时候,得到必须添加这个参数的结果,此外,这个接口必须使用POST请求,尽管它更像是GET请求,没有Body,只有Params。

package utilsimport ("encoding/json""fmt""io""math/big""net/http""net/url""reflect"
)type VerifyRequest struct {ApiKey               string   `json:"apiKey"`                          // API密钥ChainId              *big.Int `json:"chainId"`                         // 链IDCodeFormat           string   `json:"codeformat"`                      // 代码格式SourceCode           string   `json:"sourceCode"`                      // 合约源代码ConstructorArguments string   `json:"constructorArguements,omitempty"` // 构造函数参数ContractAddress      string   `json:"contractaddress"`                 // 合约地址ContractName         string   `json:"contractname"`                    // 合约名称CompilerVersion      string   `json:"compilerversion"`                 // 编译器版本OptimizationUsed     int      `json:"OptimizationUsed"`                // 是否使用了优化
}type VerifyResponse struct {Status  string `json:"status"`  // 状态Message string `json:"message"` // 详细信息Result  string `json:"result"`  // 具体结果
}func Verify(apiKey string, chainId *big.Int, codeFormat, sourceCode, constructorArgs, contractAddress, contractName, compilerVersion string, optimizationUsed int) error {// 构造请求数据requestData := VerifyRequest{ApiKey:               apiKey,ChainId:              chainId,CodeFormat:           codeFormat,SourceCode:           sourceCode,ConstructorArguments: constructorArgs,ContractAddress:      contractAddress,ContractName:         contractName,CompilerVersion:      compilerVersion,OptimizationUsed:     optimizationUsed,}// 创建一个 Client 实例client := &http.Client{}// 准备查询参数params := url.Values{}// 使用反射获取requestData结构体中的字段和值val := reflect.ValueOf(requestData)// 如果是指针类型,则获取其指向的值if val.Kind() == reflect.Ptr {val = val.Elem()}for i := 0; i < val.NumField(); i++ {field := val.Type().Field(i)value := val.Field(i).Interface()// 获取标签的值tag := field.Tag.Get("json")if tag == "" {// 如果没有标签,默认使用字段名tag = field.Name}// 将字段名和值添加到查询参数中params.Set(tag, fmt.Sprint(value))}// 构建POST请求的URLapiURL := "https://api.etherscan.io/api?module=contract&action=verifysourcecode&" + params.Encode()// 创建POST请求req, err := http.NewRequest("POST", apiURL, nil)if err != nil {return fmt.Errorf("创建POST请求失败:%v", err)}// 发送POST请求到Etherscan APIresp, err := client.Do(req)if err != nil {return fmt.Errorf("POST请求失败:%v", err)}defer resp.Body.Close()// 读取响应体body, err := io.ReadAll(resp.Body)if err != nil {return fmt.Errorf("读取响应体失败:%v", err)}// 解析JSON响应var verifyResponse VerifyResponseerr = json.Unmarshal(body, &verifyResponse)if err != nil {return fmt.Errorf("解析JSON响应失败:%v", err)}// 检查验证提交状态if verifyResponse.Status != "1" {return fmt.Errorf("验证提交失败:%s,%s\n", verifyResponse.Message, verifyResponse.Result)}fmt.Printf("验证提交成功:%s,%s\n", verifyResponse.Message, verifyResponse.Result)return nil
}

其实在这里,也可以把verifyResponse.Result返回出去,因为接下来的检查验证会用到它。总之根据自己所需,可以随意更改函数形式,代码的灵活性和趣味性不尽也如此了吧。

参数列表:

参数类型描述举例
apiKeystringEtherscan的Api密钥,注册账户免费获取**********************************
chainId*big.Int提交验证的,例如主网1big.NewInt(int64(11155111))
codeFormatstring单个文件,使用solidity-single-file、使用JSON文件solidity-standard-json-inputsolidity-single-file
sourceCodestringSolidity 源代码// SPDX-License-Identifier……
constructorArgsstring可选,如果合约使用构造函数参数,则包括nil
contractAddressstring您的合约部署地址0x****************************************
contractNamestring合同的名称,例如contracts/Verified.sol:VerifiedVerified
compilerVersionstring使用的编译器版本,例如v0.8.26+commit.8a97fa7av0.8.26+commit.8a97fa7a
optimizationUsedint是否使用了优化,否0,是10

补充:

获取solc编译器版本:打开cmd,输入

solc --version

在这里插入图片描述

Check Source Code Verification Status接口

返回合同验证请求的成功或错误状态。

在这里插入图片描述

在这里插入图片描述

这个接口相对于上一个,就好写很多,只是简单的一个GET请求,我们很容易地写出以下代码。

package utilsimport ("encoding/json""fmt""io""net/http"
)type CheckVerificationStatusRequest struct {ApiKey string `json:"apiKey"` // API密钥Guid   string `json:"guid"`   // 从验证请求收到的唯一值
}type CheckVerificationStatusResponse struct {Status  string `json:"status"`  // 状态Message string `json:"message"` // 详细信息Result  string `json:"result"`  // 具体结果
}func CheckVerificationStatus(apiKey, guid string) error {requestData := CheckVerificationStatusRequest{ApiKey: apiKey,Guid:   guid,}// 创建一个 Client 实例client := &http.Client{}// 构建GET请求的URLapiURL := "https://api.etherscan.io/api?module=contract&action=checkverifystatus&guid=" + requestData.Guid + "&apikey=" + requestData.ApiKey// 创建GET请求req, err := http.NewRequest("GET", apiURL, nil)if err != nil {return fmt.Errorf("创建GET请求失败:%v", err)}// 发送GET请求到Etherscan APIresp, err := client.Do(req)if err != nil {return fmt.Errorf("GET请求失败:%v", err)}defer resp.Body.Close()// 读取响应体body, err := io.ReadAll(resp.Body)if err != nil {return fmt.Errorf("读取响应体失败:%v", err)}// 解析JSON响应var checkVerificationStatusResponse CheckVerificationStatusResponseerr = json.Unmarshal(body, &checkVerificationStatusResponse)if err != nil {return fmt.Errorf("解析JSON响应失败:%v", err)}// 检查验证状态if checkVerificationStatusResponse.Status != "1" {return fmt.Errorf("验证失败:%s,%s\n", checkVerificationStatusResponse.Message, checkVerificationStatusResponse.Result)}fmt.Printf("验证成功:%s,%s\n", checkVerificationStatusResponse.Message, checkVerificationStatusResponse.Result)return nil
}

通过这个函数,我们可以查询我们提交的验证是否已经通过了。

参数列表:

参数类型描述举例
apiKeystringEtherscan的Api密钥,注册账户免费获取**********************************
guidstring从验证请求收到的唯一值guidpdresyk3uidtwtcn5qxp3gqyp4ifsughl9hr8xdt3t2iw7acug

演示示例及注意事项

然后我用我在上一篇博客,也就是文章最开始的链接中的这个样例合约(已经部署在Sepolia上,但未进行验证),进行演示。

下面是调用Verify()函数的过程,(注意,因为网络问题,所以我对这个函数进行了小小的修改,所以叫VerifyZh()函数,后面会进行说明的),然后我们得到返回的guid标识。

在这里插入图片描述

接着,下面是调用CheckVerificationStatus()函数的过程,(注意,因为网络问题,所以我对这个函数进行了小小的修改,所以叫CheckVerificationStatusZh()函数,后面会进行说明的),然后我们看到我们的验证已经完成了!

在这里插入图片描述

当然也有可能失败,因为验证是需要排队的,等待一段时间,再次查询就好了。

在这里插入图片描述

然后打开Etherscan,查看我们的合约,可以看到它的Contract上多了一个√,我们点击后,就可以看到我们合约的源代码以及其他信息了。

在这里插入图片描述

在这里插入图片描述

注意

无法验证合约,有很多原因,请根据报错信息自行摸索,或者在下方留言。

此外Etherscan很聪明,如果别人已经验证过一个合约,然后你部署了跟他一模一样的字节码,就可能导致你部署的合约不用验证,就已经验证了。

网络问题无法调用Etherscan接口(最重要的步骤)

打开魔法软件面板,点击设置,查看代理端口。

在这里插入图片描述

或者,打开windows设置,点击网络和Internet->代理->手动设置代理服务器->编辑,查看端口。

在这里插入图片描述

然后将之前的代码中的如下代码

	// 创建一个 Client 实例client := &http.Client{}

替换为(注意端口号!!!)

	// 创建一个自定义的 Transport 实例transport := &http.Transport{Proxy: func(req *http.Request) (*url.URL, error) {return url.Parse("http://127.0.0.1:7897") // 设置代理(注意端口号!!!)},}// 创建一个自定义的 Client 实例client := &http.Client{Transport: transport, // 设置 Transport}

就可以了,我的加了Zh的函数就是修改了这段代码。

上述方法适用于大部分因网络问题,无法调用第三方api接口的问题。

这篇文章到这里就结束了,希望对您有所帮助,欢迎点赞、评论加收藏,您的支持是对我最大的帮助!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Docker-部署Sringboot项目保姆级教程(附项目源码)
  • RTOS系统 -- ARM Cortex-M4 RPMSG之通道初始化函数
  • k8s NetworkPolicy
  • [深度学习]卷积理解
  • 这几个开放式耳机值得买?六点选购建议你要注意了
  • 【机器学习】线性判别分析(LDA):从理论到实践
  • LangChain框架详解
  • 9月Sui Builder House新加坡站开启报名
  • 白骑士的C语言教学高级篇 3.4 C语言中的算法
  • 使用Java和WebSocket设计大型聊天系统的理论探讨
  • 【python】IPython的使用技巧
  • eclipse安装lombok
  • 萝卜快跑的狠活
  • FFmpeg——视频拼接总结
  • 昇思25天学习打卡营第17天|文本解码原理--以MindNLP为例
  • AHK 中 = 和 == 等比较运算符的用法
  • chrome扩展demo1-小时钟
  • Iterator 和 for...of 循环
  • JavaScript类型识别
  • js学习笔记
  • Selenium实战教程系列(二)---元素定位
  • vue自定义指令实现v-tap插件
  • WinRAR存在严重的安全漏洞影响5亿用户
  • 百度地图API标注+时间轴组件
  • ------- 计算机网络基础
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 正则学习笔记
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • ​【数据结构与算法】冒泡排序:简单易懂的排序算法解析
  • #宝哥教你#查看jquery绑定的事件函数
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (003)SlickEdit Unity的补全
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (第27天)Oracle 数据泵转换分区表
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • .NET Framework与.NET Framework SDK有什么不同?
  • .Net Remoting常用部署结构
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .NET/C# 项目如何优雅地设置条件编译符号?
  • .pyc文件是什么?
  • @Query中countQuery的介绍
  • @拔赤:Web前端开发十日谈
  • [ 攻防演练演示篇 ] 利用通达OA 文件上传漏洞上传webshell获取主机权限
  • [ 云计算 | Azure 实践 ] 在 Azure 门户中创建 VM 虚拟机并进行验证
  • [④ADRV902x]: Digital Filter Configuration(发射端)
  • [C#]C#学习笔记-CIL和动态程序集
  • [C#]将opencvsharp的Mat对象转成onnxruntime的inputtensor的3种方法
  • [IE编程] IE8的SDK 下载
  • [ISCTF 2023]——Web、Misc较全详细Writeup、Re、Crypto部分Writeup