Solidity

使用 solc 編譯時無法獲取 abi 和字節碼

  • February 5, 2022

我是solidity 新手,正在學習使用solidity 編譯器版本0.4.25 的教程。在本教程中,solc.compile 在 compile.js 文件中使用,然後提取 abi 和字節碼並使用以下程式碼生成 json 文件:

const output = solc.compile(contractSource, 1);

for (let contract in output.contracts){
   fileSystem.outputJSONSync(
       path.resolve(exportPath,"Interface.json"),
       output.contracts[contract].interface
   );

   fileSystem.outputJSONSync(
       path.resolve(exportPath,"ByteCode.json"),
       output.contracts[contract].bytecode
   );
}

我正在嘗試使用solidity編譯器版本0.5.3來編譯契約,並且能夠通過將程式碼更改為從編譯器獲取輸出:

var input = {
   language: 'Solidity',
   sources: {
       'Voting.sol': {
           content: votingSource
       }
   },
   settings: {
       outputSelection: {
           '*': {
               '*': [ '*' ]
           }
       }
   }
}

const output = JSON.parse(solc.compile(JSON.stringify(input)),1);

但是,我無法使用以下方法找到 abi 和字節碼:

output.contracts[contract].interface
output.contracts[contract].bytecode

我認為這是因為輸出結構與使用 0.4.25 版本編譯的輸出不同,並且使用 0.5.3 版本編譯的結構中沒有介面。我想知道我用什麼來代替使用較新的編譯器版本獲得相同的 json 文件輸出,以及如何通過我遇到的錯誤,我將在下面展示。

我在終端中執行 compile.js 並收到以下錯誤

TypeError:無法在 Object.writeFileSync (…\node_modules\fs-extra\ node_modules\jsonfile\index.js:115:13) 在 Object.outputJsonSync (…\node_modules\fs-extra\lib\json\output-json-sync.js:15:12) 在 Object. (…\smartContract\compile.js:35:20) 在 Module._compile (internal/modules/cjs/loader.js:722:30) 在 Object.Module._extensions..js (internal/modules/cjs/ loader.js:733:10) 在 Module.load (internal/modules/cjs/loader.js:620:32) 在 tryModuleLoad (internal/modules/cjs/loader.js:560:12) 在 Function.Module._load (internal/modules/cjs/loader.js:552:3) 在 Function.Module.runMain (internal/modules/cjs/loader.js:775:12)

這是我的程式碼。投票.sol

pragma solidity ^0.5.3;

contract Voting {

   address chairPersonAddress;

   struct Candidate {
       address candidateAddress;
       uint votes;
   }

   struct Vote{
       uint votedCandidateIndex;
       bool alreadyVoted;
   }

   modifier onlyChairPerson(){
       require(msg.sender == chairPersonAddress);
       _;
   }

   mapping(address => Vote) public voterAddressToTheirVote;

   Candidate[] public candidates;

   constructor(address _chairPersonAddress) public {
       chairPersonAddress = _chairPersonAddress;
   }

   function nominateCandidate(address _candidateAddress) onlyChairPerson public {
       Candidate memory newCandidate = Candidate({
           candidateAddress: _candidateAddress,
           votes: 0
       });

       candidates.push(newCandidate);
   }

   function vote(uint _candidateIndex) public {
       Vote memory existingVote = voterAddressToTheirVote[msg.sender];
       //If voter vote for the first candidate in the list - the index is always 0
       if(_candidateIndex == 0){
           require(existingVote.alreadyVoted == false, "You already voted for the first candidate");
           _addNewVote(_candidateIndex);
       }
       else{
           require(existingVote.votedCandidateIndex != _candidateIndex && existingVote.alreadyVoted == false, "You already voted for this candidate");
           _addNewVote(_candidateIndex);
       }
   }

   function _addNewVote(uint _candidateIndex) private {
       Vote memory newVote = Vote({
           votedCandidateIndex: _candidateIndex,
           alreadyVoted: true
       });

       voterAddressToTheirVote[msg.sender] = newVote;

       candidates[_candidateIndex].votes++;
   }

   function numberOfCandidates() public view returns(uint){
       return candidates.length;
   }
}

編譯.js

const path = require("path");
const solc = require("solc");
const fileSystem = require("fs-extra");

//Preparing for bin folder
const exportPath = path.resolve(__dirname, "bin");
fileSystem.removeSync(exportPath);

//Get contract path
const votingContract = path.resolve(__dirname, "contracts", "Voting.sol");

//Read the contract from voting path
const votingSource = fileSystem.readFileSync(votingContract, "utf8");

var input = {
   language: 'Solidity',
   sources: {
       'Voting.sol': {
           content: votingSource
       }
   },
   settings: {
       outputSelection: {
           '*': {
               '*': [ '*' ]
           }
       }
   }
}

try{
   const output = JSON.parse(solc.compile(JSON.stringify(input)),1);

   for (let contract in output.contracts){
       fileSystem.outputJSONSync(
           path.resolve(exportPath,"VotingABI.json"),
           output.contracts[contract].interface
       );

       fileSystem.outputJSONSync(
           path.resolve(exportPath,"VotingBytecode.json"),
           output.contracts[contract].bytecode
       ); 
   }  

}catch(error){
   console.log(error);
}

用這個替換你的 for 循環

   for (let contract in output.contracts["Voting.sol"]) {
   fileSystem.outputJSONSync(
     path.resolve(exportPath, "VotingABI.json"),
     output.contracts["Voting.sol"][contract].abi
   );

   fileSystem.outputJSONSync(
     path.resolve(exportPath, "VotingBytecode.json"),
     output.contracts["Voting.sol"][contract].evm.bytecode.object
   );
 }

有關 solcjs 的參考用法,請查看https://www.npmjs.com/package/solc

我強烈推薦使用 Truffle 來編譯和部署這樣的合約,因為它既簡單又很棒。

免責聲明 - 我為 Consensys 工作

引用自:https://ethereum.stackexchange.com/questions/66723