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));
	}
});


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM