zoukankan      html  css  js  c++  java
  • Solidity中的ABI文件以及Bin文件详解

    Solidity中的ABI文件以及Bin文件

    1、什么是ABI文件?

    ABI全名:Application Binary Interface,应用二进制接口文件。智能合约的接口描述,描述了字段名称、字段类型、方法名称、参数名称、参数类型、方法返回值类型等。

    当合约被编译后,对应的abi文件也就确定了。

    2、部署合约步骤

    • 编写智能合约代码(以太坊官方推荐的是Solidity语言)
    • 编译合约,将Solidity编写的代码编译成EVM可识别的bytecode,同时生成abi文件。
    • 部署合约,将合约部署到区块链上,生成合约地址,将合约内容(也就是上一步的bytecode)作为输入,部署合约是一个交易的过程,会生成交易hash。
    • 执行合约,获取合约地址,然后传入参数调用合约中的方法,获取执行结果。

    从以上的步骤中可以看出,部署合约时EVM虚拟机需要的是Solidity合约的二进制代码也就是bytecode(Bin文件)。ABI文件与合约部署到区块链没有关系,但是如果想要调用已经在区块链上的合约方法就需要ABI文件。

    ABI文件中是描述合约内容的json字符串。

    3、怎么获取ABI文件?

    3.1、编写一个简单的智能合约代码

    // SPDX-License-Identifier: GPL-3.0
    //合约的编译版本声明 
    pragma solidity >=0.7.0 <0.9.0;
    //合约名称Storage
    contract Storage {
    	//定义一个uint类型长度为256位的变量number
        uint256 number;
    	//store方法将参数num赋值给number
        function store(uint256 num) public {
            number = num;
        }
        //retrieve返回当前的number值
        function retrieve() public view returns (uint256){
            return number;
        }
    }
    

    合约第一行表示源代码是在gplversion3.0下授权的。在默认发布源代码的设置中,机器可读的许可证说明符,非常重要。

    3.2、获取ABI文件的方式

    (1)使用remix编译

    可以通过Remix获取该合约代码的ABI文件内容以及bytecode内容。
    可以看另一篇 Remix中合约编译后的ABI以及bytecode位置

    (2)使用solcjs编译合约代码

    solcjs是用于编译solidity文件的node.js库和命令行工具,它不使用solc命令行编译器,而是纯粹使用JavaScript进行编译,因此它的安装比solc简单得多。solc是真实的solidity编译器,用C++编写。

    • 安装nodejs,安装的过程自行百度

    • 使用 npm 可以便捷地安装Solidity编译器solcjs

    npm install -g solc
    

    加-g代表全局安装,任意位置都可以使用solc。

    • 将合约代码保存在文件中,例如:

    image-20210515194540240

    image-20210515194612125

    • 在刚才的目录下,输入cmd回车,进入控制台

    image-20210515194753846

    image-20210515194851251

    • 使用如下命令编译
    solcjs --abi --bin Storage.sol
    

    image-20210515195224074

    生成abi文件以及bin文件,其中abi文件的内容就是合约的接口描述,bin文件中内容就是EVM虚拟机可识别的合约的bytecode。

    打开abi文件:

    image-20210515195544892

    打开bin文件:

    image-20210515195618022

    solcjs 其他命令:

    image-20210515200524815

    -V:显示solc的版本

    --version:与-v相同

    --optimize:启用字节码优化器

    --bin:生成十六进制的合约二进制文件

    --abi:生成合约的接口描述文件

    --standard-json:打开标准的json格式的输入/输出

    --output-dir,-o:合约输出的目录

    (3)使用solc库通过js代码编译

    • 通过npm初始化一个项目
    npm init
    
    • 使用npm安装solc
    npm install solc
    
    • 创建index.js
    //引入solc
    var solc = require("solc");
    //引入fs
    let fs = require("fs");
    //使用node提供的fs读取合约文件
    var sourceCode = fs.readFileSync("Storage.sol").toString();
    
    //预先定义好编译源json对象
    var jsonContractSource = JSON.stringify({
        language: 'Solidity',
        sources: {
          'Storage.sol': {  // 指明编译的文件名
            content: sourceCode, // solidity 源代码
          },
        },
        settings: { // 自定义编译输出的格式。以下选择输出全部结果。
            outputSelection: {
    			'*': {
    				'*': [ '*' ]
    			}
    		}
        },
      });
    //编译得到结果,使用JSON解析
    var compileCode = JSON.parse(solc.compile(jsonContractSource));
    //取出abi对象
    var abi = compileCode.contracts["Storage.sol"]["Storage"].abi;
    //取出bytecode
    var bytecode = compileCode.contracts["Storage.sol"]["Storage"].evm.bytecode.object;
    
    //将abi以及bytecode数据输出到文件,也可以结合web3直接通过js代码部署
    fs.writeFile('Storage.abi', JSON.stringify(abi), function(err){
        if(err)
          console.error(err);
        console.log("contract compiled sucessfully.");
    });
    fs.writeFile('Storage.bin', JSON.stringify(bytecode), function(err){
        if(err)
          console.error(err);
        console.log("contract compiled sucessfully.");
    });
    
    • 使用node执行index.js
    node index.js
    

    image-20210515204311484

    即可得到abi文件以及bytecode。

    image-20210515204157345

    4、ABI文件内容详解

    (1)ABI文件中各参数

    • name: 函数名称
    • type:方法类型,包括function, constructor, fallback(缺省方法)可以缺省,默认为function
    • constant:布尔值,如果为true指明方法不会修改合约字段的状态变量
    • payable:布尔值,标明方法是否可以接收ether
    • stateMutability:状态类型,包括pure (不读取区块链状态),view (和constant类型,只能查看,不会修改合约字段),nonpayable(和payable含义一样),payable(和payable含义一样)。其实保留payable和constant是为了向后兼容
    • inputs:数组,描述参数的名称和类型
      • name:参数名称
      • type:参数类型
    • outputs:和inputs一样,如果没有返回值,缺省是一个空数组

    以上述合约代码为例,得到的ABI文件如下:

    [
    	{
    		"inputs": [],
    		"name": "retrieve",
    		"outputs": [
    			{
    				"internalType": "uint256",
    				"name": "",
    				"type": "uint256"
    			}
    		],
    		"stateMutability": "view",
    		"type": "function"
    	},
    	{
    		"inputs": [
    			{
    				"internalType": "uint256",
    				"name": "num",
    				"type": "uint256"
    			}
    		],
    		"name": "store",
    		"outputs": [],
    		"stateMutability": "nonpayable",
    		"type": "function"
    	}
    ]
    

    json的第一部分,描述的是retrieve方法。

    {		
    		"inputs": [],#输入的参数为空
    		"name": "retrieve", #方法名为retrieve
    		"outputs": [ #输出的参数
    			#1个参数
        		{
    				"internalType": "uint256",#内部参数类型uint256
    				"name": "", #参数名,匿名,所以为空
    				"type": "uint256" #参数类型uint256
    			}
    		],
    		"stateMutability": "view", #状态类型view,表示该方法只查看合约内部状态,不会修改合约内部状态
    		"type": "function" #方法类型
    	},
    

    json的第二部分,描述合约内的store方法

    {
    		"inputs": [ #输入参数
    			{
    				"internalType": "uint256", #参数内部类型 uint256
    				"name": "num", #参数名num
    				"type": "uint256" #参数类型,uint256
    			}
    		],
    		"name": "store", #方法名store
    		"outputs": [], #输出参数为空
    		"stateMutability": "nonpayable", #方法状态类型,不支持接受ether
    		"type": "function" #方法类型
    	}
    

    5、ABI文件的用处

    (1)通过ABI文件内容创建区块链上已部署合约的实例,方便调用合约方法。

    let Web3 = require("web3");
    let web3 = new Web3("http://localhost:8545");
    //将合约的代码的abi文件内容复制粘贴给这个变量
    let abi = JSON.parse('[{"inputs":[],"name":"retrieve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"}],"name":"store","outputs":[],"stateMutability":"nonpayable","type":"function"}]');
    //将已经部署的合约地址粘贴,如果没有,需要先部署合约
    let contractAddr = "0xA5330ede5f68050Fa83dcb417E7CbA8F1DF875Ed";
    //根据abi和合约地址创建合约实例
    let contract = new web3.eth.Contract(abi,contractAddr);
    
    //通过合约实例contract调用方法,参数from代表通过哪个账户向合约发起交易,修改合约的内容,from使用自己的账户
    var num = 23;
    contract.methods.store(num).send({from:"",gas: '5000000'}).then((res,err)=>{
        if(err){
            console.log("Error:"+JSON.stringify(err));
        }else{
            console.log(JSON.stringify(res));
        }
    });
    //调用retrieve方法,查询合约
    contract.methods.retrieve().call().then((res,err)=>{
        if(err){
    		console.log("Error:"+JSON.stringify(err));
    	}else{
    		console.log(JSON.stringify(res));
    	}
    });
    
  • 相关阅读:
    ASP.NET 学习日志
    igoogle 小工具
    nios ann 语音识别
    ASP 3.5 读书笔记
    C# delegate and event 续
    paper
    网站白痴的 ASP.NET website 学习日志
    盒子模型
    将对象序列化成json
    不错的Oracle 存储过程例子
  • 原文地址:https://www.cnblogs.com/YpfBolg/p/14772679.html
Copyright © 2011-2022 走看看