bind.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. // Copyright 2016 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. // Package bind generates Ethereum contract Go bindings.
  17. //
  18. // Detailed usage document and tutorial available on the go-ethereum Wiki page:
  19. // https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts
  20. package bind
  21. import (
  22. "bytes"
  23. "errors"
  24. "fmt"
  25. "go/format"
  26. "regexp"
  27. "strings"
  28. "text/template"
  29. "unicode"
  30. "github.com/ethereum/go-ethereum/accounts/abi"
  31. "github.com/ethereum/go-ethereum/log"
  32. )
  33. // Lang is a target programming language selector to generate bindings for.
  34. type Lang int
  35. const (
  36. LangGo Lang = iota
  37. LangJava
  38. LangObjC
  39. )
  40. // Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
  41. // to be used as is in client code, but rather as an intermediate struct which
  42. // enforces compile time type safety and naming convention opposed to having to
  43. // manually maintain hard coded strings that break on runtime.
  44. func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string) (string, error) {
  45. var (
  46. // contracts is the map of each individual contract requested binding
  47. contracts = make(map[string]*tmplContract)
  48. // structs is the map of all redeclared structs shared by passed contracts.
  49. structs = make(map[string]*tmplStruct)
  50. // isLib is the map used to flag each encountered library as such
  51. isLib = make(map[string]struct{})
  52. )
  53. for i := 0; i < len(types); i++ {
  54. // Parse the actual ABI to generate the binding for
  55. evmABI, err := abi.JSON(strings.NewReader(abis[i]))
  56. if err != nil {
  57. return "", err
  58. }
  59. // Strip any whitespace from the JSON ABI
  60. strippedABI := strings.Map(func(r rune) rune {
  61. if unicode.IsSpace(r) {
  62. return -1
  63. }
  64. return r
  65. }, abis[i])
  66. // Extract the call and transact methods; events, struct definitions; and sort them alphabetically
  67. var (
  68. calls = make(map[string]*tmplMethod)
  69. transacts = make(map[string]*tmplMethod)
  70. events = make(map[string]*tmplEvent)
  71. fallback *tmplMethod
  72. receive *tmplMethod
  73. // identifiers are used to detect duplicated identifiers of functions
  74. // and events. For all calls, transacts and events, abigen will generate
  75. // corresponding bindings. However we have to ensure there is no
  76. // identifier collisions in the bindings of these categories.
  77. callIdentifiers = make(map[string]bool)
  78. transactIdentifiers = make(map[string]bool)
  79. eventIdentifiers = make(map[string]bool)
  80. )
  81. for _, original := range evmABI.Methods {
  82. // Normalize the method for capital cases and non-anonymous inputs/outputs
  83. normalized := original
  84. normalizedName := methodNormalizer[lang](alias(aliases, original.Name))
  85. // Ensure there is no duplicated identifier
  86. var identifiers = callIdentifiers
  87. if !original.IsConstant() {
  88. identifiers = transactIdentifiers
  89. }
  90. if identifiers[normalizedName] {
  91. return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
  92. }
  93. identifiers[normalizedName] = true
  94. normalized.Name = normalizedName
  95. normalized.Inputs = make([]abi.Argument, len(original.Inputs))
  96. copy(normalized.Inputs, original.Inputs)
  97. for j, input := range normalized.Inputs {
  98. if input.Name == "" {
  99. normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j)
  100. }
  101. if hasStruct(input.Type) {
  102. bindStructType[lang](input.Type, structs)
  103. }
  104. }
  105. normalized.Outputs = make([]abi.Argument, len(original.Outputs))
  106. copy(normalized.Outputs, original.Outputs)
  107. for j, output := range normalized.Outputs {
  108. if output.Name != "" {
  109. normalized.Outputs[j].Name = capitalise(output.Name)
  110. }
  111. if hasStruct(output.Type) {
  112. bindStructType[lang](output.Type, structs)
  113. }
  114. }
  115. // Append the methods to the call or transact lists
  116. if original.IsConstant() {
  117. calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
  118. } else {
  119. transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original.Outputs)}
  120. }
  121. }
  122. for _, original := range evmABI.Events {
  123. // Skip anonymous events as they don't support explicit filtering
  124. if original.Anonymous {
  125. continue
  126. }
  127. // Normalize the event for capital cases and non-anonymous outputs
  128. normalized := original
  129. // Ensure there is no duplicated identifier
  130. normalizedName := methodNormalizer[lang](alias(aliases, original.Name))
  131. if eventIdentifiers[normalizedName] {
  132. return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
  133. }
  134. eventIdentifiers[normalizedName] = true
  135. normalized.Name = normalizedName
  136. normalized.Inputs = make([]abi.Argument, len(original.Inputs))
  137. copy(normalized.Inputs, original.Inputs)
  138. for j, input := range normalized.Inputs {
  139. if input.Name == "" {
  140. normalized.Inputs[j].Name = fmt.Sprintf("arg%d", j)
  141. }
  142. if hasStruct(input.Type) {
  143. bindStructType[lang](input.Type, structs)
  144. }
  145. }
  146. // Append the event to the accumulator list
  147. events[original.Name] = &tmplEvent{Original: original, Normalized: normalized}
  148. }
  149. // Add two special fallback functions if they exist
  150. if evmABI.HasFallback() {
  151. fallback = &tmplMethod{Original: evmABI.Fallback}
  152. }
  153. if evmABI.HasReceive() {
  154. receive = &tmplMethod{Original: evmABI.Receive}
  155. }
  156. // There is no easy way to pass arbitrary java objects to the Go side.
  157. if len(structs) > 0 && lang == LangJava {
  158. return "", errors.New("java binding for tuple arguments is not supported yet")
  159. }
  160. contracts[types[i]] = &tmplContract{
  161. Type: capitalise(types[i]),
  162. InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
  163. InputBin: strings.TrimPrefix(strings.TrimSpace(bytecodes[i]), "0x"),
  164. Constructor: evmABI.Constructor,
  165. Calls: calls,
  166. Transacts: transacts,
  167. Fallback: fallback,
  168. Receive: receive,
  169. Events: events,
  170. Libraries: make(map[string]string),
  171. }
  172. // Function 4-byte signatures are stored in the same sequence
  173. // as types, if available.
  174. if len(fsigs) > i {
  175. contracts[types[i]].FuncSigs = fsigs[i]
  176. }
  177. // Parse library references.
  178. for pattern, name := range libs {
  179. matched, err := regexp.Match("__\\$"+pattern+"\\$__", []byte(contracts[types[i]].InputBin))
  180. if err != nil {
  181. log.Error("Could not search for pattern", "pattern", pattern, "contract", contracts[types[i]], "err", err)
  182. }
  183. if matched {
  184. contracts[types[i]].Libraries[pattern] = name
  185. // keep track that this type is a library
  186. if _, ok := isLib[name]; !ok {
  187. isLib[name] = struct{}{}
  188. }
  189. }
  190. }
  191. }
  192. // Check if that type has already been identified as a library
  193. for i := 0; i < len(types); i++ {
  194. _, ok := isLib[types[i]]
  195. contracts[types[i]].Library = ok
  196. }
  197. // Generate the contract template data content and render it
  198. data := &tmplData{
  199. Package: pkg,
  200. Contracts: contracts,
  201. Libraries: libs,
  202. Structs: structs,
  203. }
  204. buffer := new(bytes.Buffer)
  205. funcs := map[string]interface{}{
  206. "bindtype": bindType[lang],
  207. "bindtopictype": bindTopicType[lang],
  208. "namedtype": namedType[lang],
  209. "capitalise": capitalise,
  210. "decapitalise": decapitalise,
  211. }
  212. tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang]))
  213. if err := tmpl.Execute(buffer, data); err != nil {
  214. return "", err
  215. }
  216. // For Go bindings pass the code through gofmt to clean it up
  217. if lang == LangGo {
  218. code, err := format.Source(buffer.Bytes())
  219. if err != nil {
  220. return "", fmt.Errorf("%v\n%s", err, buffer)
  221. }
  222. return string(code), nil
  223. }
  224. // For all others just return as is for now
  225. return buffer.String(), nil
  226. }
  227. // bindType is a set of type binders that convert Solidity types to some supported
  228. // programming language types.
  229. var bindType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
  230. LangGo: bindTypeGo,
  231. LangJava: bindTypeJava,
  232. }
  233. // bindBasicTypeGo converts basic solidity types(except array, slice and tuple) to Go ones.
  234. func bindBasicTypeGo(kind abi.Type) string {
  235. switch kind.T {
  236. case abi.AddressTy:
  237. return "common.Address"
  238. case abi.IntTy, abi.UintTy:
  239. parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(kind.String())
  240. switch parts[2] {
  241. case "8", "16", "32", "64":
  242. return fmt.Sprintf("%sint%s", parts[1], parts[2])
  243. }
  244. return "*big.Int"
  245. case abi.FixedBytesTy:
  246. return fmt.Sprintf("[%d]byte", kind.Size)
  247. case abi.BytesTy:
  248. return "[]byte"
  249. case abi.FunctionTy:
  250. return "[24]byte"
  251. default:
  252. // string, bool types
  253. return kind.String()
  254. }
  255. }
  256. // bindTypeGo converts solidity types to Go ones. Since there is no clear mapping
  257. // from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
  258. // mapped will use an upscaled type (e.g. BigDecimal).
  259. func bindTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
  260. switch kind.T {
  261. case abi.TupleTy:
  262. return structs[kind.TupleRawName+kind.String()].Name
  263. case abi.ArrayTy:
  264. return fmt.Sprintf("[%d]", kind.Size) + bindTypeGo(*kind.Elem, structs)
  265. case abi.SliceTy:
  266. return "[]" + bindTypeGo(*kind.Elem, structs)
  267. default:
  268. return bindBasicTypeGo(kind)
  269. }
  270. }
  271. // bindBasicTypeJava converts basic solidity types(except array, slice and tuple) to Java ones.
  272. func bindBasicTypeJava(kind abi.Type) string {
  273. switch kind.T {
  274. case abi.AddressTy:
  275. return "Address"
  276. case abi.IntTy, abi.UintTy:
  277. // Note that uint and int (without digits) are also matched,
  278. // these are size 256, and will translate to BigInt (the default).
  279. parts := regexp.MustCompile(`(u)?int([0-9]*)`).FindStringSubmatch(kind.String())
  280. if len(parts) != 3 {
  281. return kind.String()
  282. }
  283. // All unsigned integers should be translated to BigInt since gomobile doesn't
  284. // support them.
  285. if parts[1] == "u" {
  286. return "BigInt"
  287. }
  288. namedSize := map[string]string{
  289. "8": "byte",
  290. "16": "short",
  291. "32": "int",
  292. "64": "long",
  293. }[parts[2]]
  294. // default to BigInt
  295. if namedSize == "" {
  296. namedSize = "BigInt"
  297. }
  298. return namedSize
  299. case abi.FixedBytesTy, abi.BytesTy:
  300. return "byte[]"
  301. case abi.BoolTy:
  302. return "boolean"
  303. case abi.StringTy:
  304. return "String"
  305. case abi.FunctionTy:
  306. return "byte[24]"
  307. default:
  308. return kind.String()
  309. }
  310. }
  311. // pluralizeJavaType explicitly converts multidimensional types to predefined
  312. // types in go side.
  313. func pluralizeJavaType(typ string) string {
  314. switch typ {
  315. case "boolean":
  316. return "Bools"
  317. case "String":
  318. return "Strings"
  319. case "Address":
  320. return "Addresses"
  321. case "byte[]":
  322. return "Binaries"
  323. case "BigInt":
  324. return "BigInts"
  325. }
  326. return typ + "[]"
  327. }
  328. // bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
  329. // from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
  330. // mapped will use an upscaled type (e.g. BigDecimal).
  331. func bindTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
  332. switch kind.T {
  333. case abi.TupleTy:
  334. return structs[kind.TupleRawName+kind.String()].Name
  335. case abi.ArrayTy, abi.SliceTy:
  336. return pluralizeJavaType(bindTypeJava(*kind.Elem, structs))
  337. default:
  338. return bindBasicTypeJava(kind)
  339. }
  340. }
  341. // bindTopicType is a set of type binders that convert Solidity types to some
  342. // supported programming language topic types.
  343. var bindTopicType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
  344. LangGo: bindTopicTypeGo,
  345. LangJava: bindTopicTypeJava,
  346. }
  347. // bindTopicTypeGo converts a Solidity topic type to a Go one. It is almost the same
  348. // functionality as for simple types, but dynamic types get converted to hashes.
  349. func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
  350. bound := bindTypeGo(kind, structs)
  351. // todo(rjl493456442) according solidity documentation, indexed event
  352. // parameters that are not value types i.e. arrays and structs are not
  353. // stored directly but instead a keccak256-hash of an encoding is stored.
  354. //
  355. // We only convert stringS and bytes to hash, still need to deal with
  356. // array(both fixed-size and dynamic-size) and struct.
  357. if bound == "string" || bound == "[]byte" {
  358. bound = "common.Hash"
  359. }
  360. return bound
  361. }
  362. // bindTopicTypeJava converts a Solidity topic type to a Java one. It is almost the same
  363. // functionality as for simple types, but dynamic types get converted to hashes.
  364. func bindTopicTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
  365. bound := bindTypeJava(kind, structs)
  366. // todo(rjl493456442) according solidity documentation, indexed event
  367. // parameters that are not value types i.e. arrays and structs are not
  368. // stored directly but instead a keccak256-hash of an encoding is stored.
  369. //
  370. // We only convert strings and bytes to hash, still need to deal with
  371. // array(both fixed-size and dynamic-size) and struct.
  372. if bound == "String" || bound == "byte[]" {
  373. bound = "Hash"
  374. }
  375. return bound
  376. }
  377. // bindStructType is a set of type binders that convert Solidity tuple types to some supported
  378. // programming language struct definition.
  379. var bindStructType = map[Lang]func(kind abi.Type, structs map[string]*tmplStruct) string{
  380. LangGo: bindStructTypeGo,
  381. LangJava: bindStructTypeJava,
  382. }
  383. // bindStructTypeGo converts a Solidity tuple type to a Go one and records the mapping
  384. // in the given map.
  385. // Notably, this function will resolve and record nested struct recursively.
  386. func bindStructTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
  387. switch kind.T {
  388. case abi.TupleTy:
  389. // We compose a raw struct name and a canonical parameter expression
  390. // together here. The reason is before solidity v0.5.11, kind.TupleRawName
  391. // is empty, so we use canonical parameter expression to distinguish
  392. // different struct definition. From the consideration of backward
  393. // compatibility, we concat these two together so that if kind.TupleRawName
  394. // is not empty, it can have unique id.
  395. id := kind.TupleRawName + kind.String()
  396. if s, exist := structs[id]; exist {
  397. return s.Name
  398. }
  399. var fields []*tmplField
  400. for i, elem := range kind.TupleElems {
  401. field := bindStructTypeGo(*elem, structs)
  402. fields = append(fields, &tmplField{Type: field, Name: capitalise(kind.TupleRawNames[i]), SolKind: *elem})
  403. }
  404. name := kind.TupleRawName
  405. if name == "" {
  406. name = fmt.Sprintf("Struct%d", len(structs))
  407. }
  408. structs[id] = &tmplStruct{
  409. Name: name,
  410. Fields: fields,
  411. }
  412. return name
  413. case abi.ArrayTy:
  414. return fmt.Sprintf("[%d]", kind.Size) + bindStructTypeGo(*kind.Elem, structs)
  415. case abi.SliceTy:
  416. return "[]" + bindStructTypeGo(*kind.Elem, structs)
  417. default:
  418. return bindBasicTypeGo(kind)
  419. }
  420. }
  421. // bindStructTypeJava converts a Solidity tuple type to a Java one and records the mapping
  422. // in the given map.
  423. // Notably, this function will resolve and record nested struct recursively.
  424. func bindStructTypeJava(kind abi.Type, structs map[string]*tmplStruct) string {
  425. switch kind.T {
  426. case abi.TupleTy:
  427. // We compose a raw struct name and a canonical parameter expression
  428. // together here. The reason is before solidity v0.5.11, kind.TupleRawName
  429. // is empty, so we use canonical parameter expression to distinguish
  430. // different struct definition. From the consideration of backward
  431. // compatibility, we concat these two together so that if kind.TupleRawName
  432. // is not empty, it can have unique id.
  433. id := kind.TupleRawName + kind.String()
  434. if s, exist := structs[id]; exist {
  435. return s.Name
  436. }
  437. var fields []*tmplField
  438. for i, elem := range kind.TupleElems {
  439. field := bindStructTypeJava(*elem, structs)
  440. fields = append(fields, &tmplField{Type: field, Name: decapitalise(kind.TupleRawNames[i]), SolKind: *elem})
  441. }
  442. name := kind.TupleRawName
  443. if name == "" {
  444. name = fmt.Sprintf("Class%d", len(structs))
  445. }
  446. structs[id] = &tmplStruct{
  447. Name: name,
  448. Fields: fields,
  449. }
  450. return name
  451. case abi.ArrayTy, abi.SliceTy:
  452. return pluralizeJavaType(bindStructTypeJava(*kind.Elem, structs))
  453. default:
  454. return bindBasicTypeJava(kind)
  455. }
  456. }
  457. // namedType is a set of functions that transform language specific types to
  458. // named versions that may be used inside method names.
  459. var namedType = map[Lang]func(string, abi.Type) string{
  460. LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") },
  461. LangJava: namedTypeJava,
  462. }
  463. // namedTypeJava converts some primitive data types to named variants that can
  464. // be used as parts of method names.
  465. func namedTypeJava(javaKind string, solKind abi.Type) string {
  466. switch javaKind {
  467. case "byte[]":
  468. return "Binary"
  469. case "boolean":
  470. return "Bool"
  471. default:
  472. parts := regexp.MustCompile(`(u)?int([0-9]*)(\[[0-9]*\])?`).FindStringSubmatch(solKind.String())
  473. if len(parts) != 4 {
  474. return javaKind
  475. }
  476. switch parts[2] {
  477. case "8", "16", "32", "64":
  478. if parts[3] == "" {
  479. return capitalise(fmt.Sprintf("%sint%s", parts[1], parts[2]))
  480. }
  481. return capitalise(fmt.Sprintf("%sint%ss", parts[1], parts[2]))
  482. default:
  483. return javaKind
  484. }
  485. }
  486. }
  487. // alias returns an alias of the given string based on the aliasing rules
  488. // or returns itself if no rule is matched.
  489. func alias(aliases map[string]string, n string) string {
  490. if alias, exist := aliases[n]; exist {
  491. return alias
  492. }
  493. return n
  494. }
  495. // methodNormalizer is a name transformer that modifies Solidity method names to
  496. // conform to target language naming conventions.
  497. var methodNormalizer = map[Lang]func(string) string{
  498. LangGo: abi.ToCamelCase,
  499. LangJava: decapitalise,
  500. }
  501. // capitalise makes a camel-case string which starts with an upper case character.
  502. var capitalise = abi.ToCamelCase
  503. // decapitalise makes a camel-case string which starts with a lower case character.
  504. func decapitalise(input string) string {
  505. if len(input) == 0 {
  506. return input
  507. }
  508. goForm := abi.ToCamelCase(input)
  509. return strings.ToLower(goForm[:1]) + goForm[1:]
  510. }
  511. // structured checks whether a list of ABI data types has enough information to
  512. // operate through a proper Go struct or if flat returns are needed.
  513. func structured(args abi.Arguments) bool {
  514. if len(args) < 2 {
  515. return false
  516. }
  517. exists := make(map[string]bool)
  518. for _, out := range args {
  519. // If the name is anonymous, we can't organize into a struct
  520. if out.Name == "" {
  521. return false
  522. }
  523. // If the field name is empty when normalized or collides (var, Var, _var, _Var),
  524. // we can't organize into a struct
  525. field := capitalise(out.Name)
  526. if field == "" || exists[field] {
  527. return false
  528. }
  529. exists[field] = true
  530. }
  531. return true
  532. }
  533. // hasStruct returns an indicator whether the given type is struct, struct slice
  534. // or struct array.
  535. func hasStruct(t abi.Type) bool {
  536. switch t.T {
  537. case abi.SliceTy:
  538. return hasStruct(*t.Elem)
  539. case abi.ArrayTy:
  540. return hasStruct(*t.Elem)
  541. case abi.TupleTy:
  542. return true
  543. default:
  544. return false
  545. }
  546. }