common/compiler: fix parsing of solc output with solidity v.0.8.0 (#22092)

Solidity 0.8.0 changes the way that output is marshalled. This patch allows to parse both
the legacy format used previously and the new format.

See also https://docs.soliditylang.org/en/breaking/080-breaking-changes.html#interface-changes
This commit is contained in:
Marius van der Wijden 2021-01-05 14:48:22 +01:00 committed by GitHub
parent 4714ce9430
commit 9ba306d47e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -44,6 +44,20 @@ type solcOutput struct {
Version string Version string
} }
// solidity v.0.8 changes the way ABI, Devdoc and Userdoc are serialized
type solcOutputV8 struct {
Contracts map[string]struct {
BinRuntime string `json:"bin-runtime"`
SrcMapRuntime string `json:"srcmap-runtime"`
Bin, SrcMap, Metadata string
Abi interface{}
Devdoc interface{}
Userdoc interface{}
Hashes map[string]string
}
Version string
}
func (s *Solidity) makeArgs() []string { func (s *Solidity) makeArgs() []string {
p := []string{ p := []string{
"--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc", "--combined-json", "bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc",
@ -125,7 +139,6 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes()) return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
} }
return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " ")) return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " "))
} }
@ -141,7 +154,8 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) { func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
var output solcOutput var output solcOutput
if err := json.Unmarshal(combinedJSON, &output); err != nil { if err := json.Unmarshal(combinedJSON, &output); err != nil {
return nil, err // Try to parse the output with the new solidity v.0.8.0 rules
return parseCombinedJSONV8(combinedJSON, source, languageVersion, compilerVersion, compilerOptions)
} }
// Compilation succeeded, assemble and return the contracts. // Compilation succeeded, assemble and return the contracts.
contracts := make(map[string]*Contract) contracts := make(map[string]*Contract)
@ -176,3 +190,35 @@ func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion strin
} }
return contracts, nil return contracts, nil
} }
// parseCombinedJSONV8 parses the direct output of solc --combined-output
// and parses it using the rules from solidity v.0.8.0 and later.
func parseCombinedJSONV8(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
var output solcOutputV8
if err := json.Unmarshal(combinedJSON, &output); err != nil {
return nil, err
}
// Compilation succeeded, assemble and return the contracts.
contracts := make(map[string]*Contract)
for name, info := range output.Contracts {
contracts[name] = &Contract{
Code: "0x" + info.Bin,
RuntimeCode: "0x" + info.BinRuntime,
Hashes: info.Hashes,
Info: ContractInfo{
Source: source,
Language: "Solidity",
LanguageVersion: languageVersion,
CompilerVersion: compilerVersion,
CompilerOptions: compilerOptions,
SrcMap: info.SrcMap,
SrcMapRuntime: info.SrcMapRuntime,
AbiDefinition: info.Abi,
UserDoc: info.Userdoc,
DeveloperDoc: info.Devdoc,
Metadata: info.Metadata,
},
}
}
return contracts, nil
}