如何通过solc编译solidity编写的以太坊智能合约

solc:solidity的编译器

solidity编写的以太坊智能合约可通过命令行编译工具solc来进行编译,成为以太坊虚拟机中的代码。solc编译后最终部署到链上形成我们所见到的各种智能合约。

作为一个solidity命令行编译工具,我们来看看官网都怎么说solc。

solc的安装很简单:

npm install -g solc
//或者
npm install -g solc-cli
//或者
sudo apt-get install solc

安装完成后我们来看,solc --help,solc --help命令显示所有的solc命令选项。编译器可以生成各种输出,比如最终的二进制合约文件、语法树的汇编或者需要预计的要花费的gas等。solc --bin sourceFile.sol,可以编译后输出一个名为sourceFile.sol的智能合约文件。如果你想从solc获得更丰富的一些输出变量,你可以使用solc -o outputDirectory --bin --ast --asm sourceFile.sol

你在部署以太坊智能合约之前可以用solc --optimize --bin sourceFile.sol优化一下。默认情况下solc编译器会帮你优化200次。你也可以设置 --runs=1,这样就按照最小化的方式进行编译,如果你希望多次交易不太在乎成本,那你可以设置成你想要的次数:)。

命令行编译器会自动读取需要导入的文件,也可以通过使用prefix = path来指定路径,例如:

solc github.com/ethereum/dapp-bin/=/usr/local/lib/dapp-bin/ =/usr/local/lib/fallback file.sol

这样编译器就会从指定目录github.com/ethereum/dapp-bin/下的/usr/local/lib/dapp-bin/目录开始搜索,如果没有找到文件,它将查看/usr/local/lib/fallback。solc将只读取你指定的这两个路径的,因此像import "/etc/passwd";必须要通过/=重新映射才起作用。如果有多个匹配,则选择具有最长公共前缀的进行匹配。

出于安全上的考虑,编译器限制了它可以访问的一些目录。在命令行中指定的源文件的路径(及其子目录)和命令行指定的路径外其他所有内容都会被拒绝。--allow-paths /sample/path,/another/sample/path来切换。

如果智能合约使用了libraries,你会注意到字节码包含了__LibraryName______的子字符串。您可以使用solc作为链接器,这意味着它将在这些点为您插入库地址。

可以通过添加库--libraries "Math:0x12345678901234567890 Heap:0xabcdef0123456"到您的命令,以提供每个库的地址,或者使用文件中的说明字符串(每行一个库),并使用--libraries fileName运行solc。

如果用选项--link调用Solc,则所有输入文件都被解释为未链接的二进制文件(HEX编码),在上面给出的__LibraryName____格式中,将其链接到适当地址(如果从stdin读取输入,则将其写入stdout)。在这种情况下,除了库外,所有选项都被忽略(包括-o)。

如果用--standard-json调用SOLC,它就将标准的JSON输入(如下所述),并返回JSON输出。

solc编译器输入输出JSON描述

这些JSON格式通过编译器API使用,可以通过SOLC获得。内容都是可以修改的,一些对象是可选的(如前所述),其目的是向后兼容。

编译器的API需要一个JSON格式的输入,然后以JSON格式输出编译结果。

注意不允许注释。下面示例中的注释,是官网为了学习者更好的理解标注的。

  • 输入格式说明:
{
  // Required: Source code language, such as "Solidity", "serpent", "lll", "assembly", etc.
  language: "Solidity",
  // Required
  sources:
  {
    // The keys here are the "global" names of the source files,
    // imports can use other files via remappings (see below).
    "myFile.sol":
    {
      // Optional: keccak256 hash of the source file
      // It is used to verify the retrieved content if imported via URLs.
      "keccak256": "0x123...",
      // Required (unless "content" is used, see below): URL(s) to the source file.
      // URL(s) should be imported in this order and the result checked against the
      // keccak256 hash (if available). If the hash doesn't match or none of the
      // URL(s) result in success, an error should be raised.
      "urls":
      [
        "bzzr://56ab...",
        "ipfs://Qma...",
        "file:///tmp/path/to/file.sol"
      ]
    },
    "mortal":
    {
      // Optional: keccak256 hash of the source file
      "keccak256": "0x234...",
      // Required (unless "urls" is used): literal contents of the source file
      "content": "contract mortal is owned { function kill() { if (msg.sender == owner) selfdestruct(owner); } }"
    }
  },
  // Optional
  settings:
  {
    // Optional: Sorted list of remappings
    remappings: [ ":g/dir" ],
    // Optional: Optimizer settings
    optimizer: {
      // disabled by default
      enabled: true,
      // Optimize for how many times you intend to run the code.
      // Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage.
      runs: 200
    },
    evmVersion: "byzantium", // Version of the EVM to compile for. Affects type checking and code generation. Can be homestead, tangerineWhistle, spuriousDragon, byzantium or constantinople
    // Metadata settings (optional)
    metadata: {
      // Use only literal content and not URLs (false by default)
      useLiteralContent: true
    },
    // Addresses of the libraries. If not all libraries are given here, it can result in unlinked objects whose output data is different.
    libraries: {
      // The top level key is the the name of the source file where the library is used.
      // If remappings are used, this source file should match the global path after remappings were applied.
      // If this key is an empty string, that refers to a global level.
      "myFile.sol": {
        "MyLib": "0x123123..."
      }
    }
    // The following can be used to select desired outputs.
    // If this field is omitted, then the compiler loads and does type checking, but will not generate any outputs apart from errors.
    // The first level key is the file name and the second is the contract name, where empty contract name refers to the file itself,
    // while the star refers to all of the contracts.
    //
    // The available output types are as follows:
    //   abi - ABI
    //   ast - AST of all source files
    //   legacyAST - legacy AST of all source files
    //   devdoc - Developer documentation (natspec)
    //   userdoc - User documentation (natspec)
    //   metadata - Metadata
    //   ir - New assembly format before desugaring
    //   evm.assembly - New assembly format after desugaring
    //   evm.legacyAssembly - Old-style assembly format in JSON
    //   evm.bytecode.object - Bytecode object
    //   evm.bytecode.opcodes - Opcodes list
    //   evm.bytecode.sourceMap - Source mapping (useful for debugging)
    //   evm.bytecode.linkReferences - Link references (if unlinked object)
    //   evm.deployedBytecode* - Deployed bytecode (has the same options as evm.bytecode)
    //   evm.methodIdentifiers - The list of function hashes
    //   evm.gasEstimates - Function gas estimates
    //   ewasm.wast - eWASM S-expressions format (not supported atm)
    //   ewasm.wasm - eWASM binary format (not supported atm)
    //
    // Note that using a using `evm`, `evm.bytecode`, `ewasm`, etc. will select every
    // target part of that output. Additionally, `*` can be used as a wildcard to request everything.
    //
    outputSelection: {
      // Enable the metadata and bytecode outputs of every single contract.
      "*": {
        "*": [ "metadata", "evm.bytecode" ]
      },
      // Enable the abi and opcodes output of MyContract defined in file def.
      "def": {
        "MyContract": [ "abi", "evm.bytecode.opcodes" ]
      },
      // Enable the source map output of every single contract.
      "*": {
        "*": [ "evm.bytecode.sourceMap" ]
      },
      // Enable the legacy AST output of every single file.
      "*": {
        "": [ "legacyAST" ]
      }
    }
  }
}
  • 输出格式说明
{
  // Optional: not present if no errors/warnings were encountered
  errors: [
    {
      // Optional: Location within the source file.
      sourceLocation: {
        file: "sourceFile.sol",
        start: 0,
        end: 100
      ],
      // Mandatory: Error type, such as "TypeError", "InternalCompilerError", "Exception", etc.
      // See below for complete list of types.
      type: "TypeError",
      // Mandatory: Component where the error originated, such as "general", "ewasm", etc.
      component: "general",
      // Mandatory ("error" or "warning")
      severity: "error",
      // Mandatory
      message: "Invalid keyword"
      // Optional: the message formatted with source location
      formattedMessage: "sourceFile.sol:100: Invalid keyword"
    }
  ],
  // This contains the file-level outputs. In can be limited/filtered by the outputSelection settings.
  sources: {
    "sourceFile.sol": {
      // Identifier (used in source maps)
      id: 1,
      // The AST object
      ast: {},
      // The legacy AST object
      legacyAST: {}
    }
  },
  // This contains the contract-level outputs. It can be limited/filtered by the outputSelection settings.
  contracts: {
    "sourceFile.sol": {
      // If the language used has no contract names, this field should equal to an empty string.
      "ContractName": {
        // The Ethereum Contract ABI. If empty, it is represented as an empty array.
        // See https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
        abi: [],
        // See the Metadata Output documentation (serialised JSON string)
        metadata: "{...}",
        // User documentation (natspec)
        userdoc: {},
        // Developer documentation (natspec)
        devdoc: {},
        // Intermediate representation (string)
        ir: "",
        // EVM-related outputs
        evm: {
          // Assembly (string)
          assembly: "",
          // Old-style assembly (object)
          legacyAssembly: {},
          // Bytecode and related details.
          bytecode: {
            // The bytecode as a hex string.
            object: "00fe",
            // Opcodes list (string)
            opcodes: "",
            // The source mapping as a string. See the source mapping definition.
            sourceMap: "",
            // If given, this is an unlinked object.
            linkReferences: {
              "libraryFile.sol": {
                // Byte offsets into the bytecode. Linking replaces the 20 bytes located there.
                "Library1": [
                  { start: 0, length: 20 },
                  { start: 200, length: 20 }
                ]
              }
            }
          },
          // The same layout as above.
          deployedBytecode: { },
          // The list of function hashes
          methodIdentifiers: {
            "delegate(address)": "5c19a95c"
          },
          // Function gas estimates
          gasEstimates: {
            creation: {
              codeDepositCost: "420000",
              executionCost: "infinite",
              totalCost: "infinite"
            },
            external: {
              "delegate(address)": "25000"
            },
            internal: {
              "heavyLifting()": "infinite"
            }
          }
        },
        // eWASM related outputs
        ewasm: {
          // S-expressions format
          wast: "",
          // Binary format (hex string)
          wasm: ""
        }
      }
    }
  }
}
  • 错误类型说明:
  1. JSONError:JSON错误,JSON输入不符合要求的格式,例如输入不是JSON对象,不支持语言,等等。
  2. IOError:IO错误,IO和导入处理错误,如提供的源中的不可解析URL或hash不匹配。
  3. ParserError:语法f分析错误,源代码不符合语言规则。
  4. DocstringParsingError:文档解析错误,无法解析注释块中的NATSPEC标记。
  5. SytRealError:语法错误,如continuefor循环之外使用。
  6. DeclarationError:声明错误,无效、不可解析或冲突的标识符名称。例如未找到标识符
  7. TypeError:类型错误,如无效类型转换、无效赋值等。
  8. UnimplementedFeatureError:编译器不支持该特性,但希望在将来的版本中得到支持。
  9. InternalCompilerError:编译器中触发内部错误,这应该作为一个问题来反馈。
  10. Exception:例外,编译过程中未知的故障,这应该作为一个问题反馈。
  11. CompilerError:编译错误,编译器堆栈的使用无效,这应该作为一个问题来反馈。
  12. FatalError:致命错误,这应该作为一个问题来反馈。
  13. Warning:警告并没有停止编译,但如果可能的话,应该加以处理。

原文请访问:solc

如果你希望马上开始学习以太坊DApp开发,推荐访问一个在线教程:

  • 以太坊教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容