Skip to content

Commit 4cf2b41

Browse files
Shadowfiendfjl
authored andcommitted
cmd/abigen: support for reading solc output from stdin (#16683)
Allow the --abi flag to be given - to indicate that it should read the ABI information from standard input. It expects to read the solc output with the --combined-json flag providing bin, abi, userdoc, devdoc, and metadata, and works very similarly to the internal invocation of solc, except it allows external invocation of solc. This facilitates integration with more complex solc invocations, such as invocations that require path remapping or --allow-paths tweaks. Simple usage example: solc --combined-json bin,abi,userdoc,devdoc,metadata *.sol | abigen --abi -
1 parent 0029a86 commit 4cf2b41

File tree

2 files changed

+50
-10
lines changed

2 files changed

+50
-10
lines changed

cmd/abigen/main.go

+26-6
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929
)
3030

3131
var (
32-
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind")
32+
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind, - for STDIN")
3333
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
3434
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
3535

@@ -75,16 +75,27 @@ func main() {
7575
bins []string
7676
types []string
7777
)
78-
if *solFlag != "" {
78+
if *solFlag != "" || *abiFlag == "-" {
7979
// Generate the list of types to exclude from binding
8080
exclude := make(map[string]bool)
8181
for _, kind := range strings.Split(*excFlag, ",") {
8282
exclude[strings.ToLower(kind)] = true
8383
}
84-
contracts, err := compiler.CompileSolidity(*solcFlag, *solFlag)
85-
if err != nil {
86-
fmt.Printf("Failed to build Solidity contract: %v\n", err)
87-
os.Exit(-1)
84+
85+
var contracts map[string]*compiler.Contract
86+
var err error
87+
if *solFlag != "" {
88+
contracts, err = compiler.CompileSolidity(*solcFlag, *solFlag)
89+
if err != nil {
90+
fmt.Printf("Failed to build Solidity contract: %v\n", err)
91+
os.Exit(-1)
92+
}
93+
} else {
94+
contracts, err = contractsFromStdin()
95+
if err != nil {
96+
fmt.Printf("Failed to read input ABIs from STDIN: %v\n", err)
97+
os.Exit(-1)
98+
}
8899
}
89100
// Gather all non-excluded contract for binding
90101
for name, contract := range contracts {
@@ -138,3 +149,12 @@ func main() {
138149
os.Exit(-1)
139150
}
140151
}
152+
153+
func contractsFromStdin() (map[string]*compiler.Contract, error) {
154+
bytes, err := ioutil.ReadAll(os.Stdin)
155+
if err != nil {
156+
return nil, err
157+
}
158+
159+
return compiler.ParseCombinedJSON(bytes, "", "", "", "")
160+
}

common/compiler/solidity.go

+24-4
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,17 @@ import (
3131

3232
var versionRegexp = regexp.MustCompile(`([0-9]+)\.([0-9]+)\.([0-9]+)`)
3333

34+
// Contract contains information about a compiled contract, alongside its code.
3435
type Contract struct {
3536
Code string `json:"code"`
3637
Info ContractInfo `json:"info"`
3738
}
3839

40+
// ContractInfo contains information about a compiled contract, including access
41+
// to the ABI definition, user and developer docs, and metadata.
42+
//
43+
// Depending on the source, language version, compiler version, and compiler
44+
// options will provide information about how the contract was compiled.
3945
type ContractInfo struct {
4046
Source string `json:"source"`
4147
Language string `json:"language"`
@@ -142,8 +148,22 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
142148
if err := cmd.Run(); err != nil {
143149
return nil, fmt.Errorf("solc: %v\n%s", err, stderr.Bytes())
144150
}
151+
152+
return ParseCombinedJSON(stdout.Bytes(), source, s.Version, s.Version, strings.Join(s.makeArgs(), " "))
153+
}
154+
155+
// ParseCombinedJSON takes the direct output of a solc --combined-output run and
156+
// parses it into a map of string contract name to Contract structs. The
157+
// provided source, language and compiler version, and compiler options are all
158+
// passed through into the Contract structs.
159+
//
160+
// The solc output is expected to contain ABI, user docs, and dev docs.
161+
//
162+
// Returns an error if the JSON is malformed or missing data, or if the JSON
163+
// embedded within the JSON is malformed.
164+
func ParseCombinedJSON(combinedJSON []byte, source string, languageVersion string, compilerVersion string, compilerOptions string) (map[string]*Contract, error) {
145165
var output solcOutput
146-
if err := json.Unmarshal(stdout.Bytes(), &output); err != nil {
166+
if err := json.Unmarshal(combinedJSON, &output); err != nil {
147167
return nil, err
148168
}
149169

@@ -168,9 +188,9 @@ func (s *Solidity) run(cmd *exec.Cmd, source string) (map[string]*Contract, erro
168188
Info: ContractInfo{
169189
Source: source,
170190
Language: "Solidity",
171-
LanguageVersion: s.Version,
172-
CompilerVersion: s.Version,
173-
CompilerOptions: strings.Join(s.makeArgs(), " "),
191+
LanguageVersion: languageVersion,
192+
CompilerVersion: compilerVersion,
193+
CompilerOptions: compilerOptions,
174194
AbiDefinition: abi,
175195
UserDoc: userdoc,
176196
DeveloperDoc: devdoc,

0 commit comments

Comments
 (0)