Skip to content

Commit 8dcea0a

Browse files
authored
Merge pull request #2977 from karalabe/initial-mobile-suport
mobile: initial wrappers for mobile support
2 parents d89ea3e + dfe79cc commit 8dcea0a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3278
-112
lines changed

.travis.yml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,36 @@ matrix:
5353
- CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
5454
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
5555

56-
# This builder does the OSX Azure uploads
56+
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
5757
- os: osx
5858
go: 1.7
5959
env:
6060
- azure-osx
61+
- mobile
62+
cache:
63+
directories:
64+
- $HOME/.android.platforms
65+
- $HOME/.cocoapods
6166
script:
6267
- go run build/ci.go install
6368
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
6469

70+
# Build the iOS framework and upload it to CocoaPods and Azure
71+
- gem install cocoapods --pre
72+
- go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
73+
74+
# Build the Android archive and upload it to Maven Central and Azure
75+
- brew update
76+
- brew install android-sdk maven
77+
- export ANDROID_HOME=/usr/local/opt/android-sdk
78+
79+
- mkdir -p $ANDROID_HOME/platforms
80+
- mv -f $HOME/.android.platforms $ANDROID_HOME/platforms
81+
- echo "y" | android update sdk --no-ui --filter platform
82+
83+
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
84+
- mv -f $ANDROID_HOME/platforms $HOME/.android.platforms
85+
6586
install:
6687
- go get golang.org/x/tools/cmd/cover
6788
script:

accounts/abi/bind/bind.go

Lines changed: 162 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,20 @@ import (
3232
"golang.org/x/tools/imports"
3333
)
3434

35+
// Lang is a target programming language selector to generate bindings for.
36+
type Lang int
37+
38+
const (
39+
LangGo Lang = iota
40+
LangJava
41+
LangObjC
42+
)
43+
3544
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
3645
// to be used as is in client code, but rather as an intermediate struct which
3746
// enforces compile time type safety and naming convention opposed to having to
3847
// manually maintain hard coded strings that break on runtime.
39-
func Bind(types []string, abis []string, bytecodes []string, pkg string) (string, error) {
48+
func Bind(types []string, abis []string, bytecodes []string, pkg string, lang Lang) (string, error) {
4049
// Process each individual contract requested binding
4150
contracts := make(map[string]*tmplContract)
4251

@@ -62,7 +71,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
6271
for _, original := range evmABI.Methods {
6372
// Normalize the method for capital cases and non-anonymous inputs/outputs
6473
normalized := original
65-
normalized.Name = capitalise(original.Name)
74+
normalized.Name = methodNormalizer[lang](original.Name)
6675

6776
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
6877
copy(normalized.Inputs, original.Inputs)
@@ -78,7 +87,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
7887
normalized.Outputs[j].Name = capitalise(output.Name)
7988
}
8089
}
81-
// Append the methos to the call or transact lists
90+
// Append the methods to the call or transact lists
8291
if original.Const {
8392
calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original)}
8493
} else {
@@ -87,7 +96,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
8796
}
8897
contracts[types[i]] = &tmplContract{
8998
Type: capitalise(types[i]),
90-
InputABI: strippedABI,
99+
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
91100
InputBin: strings.TrimSpace(bytecodes[i]),
92101
Constructor: evmABI.Constructor,
93102
Calls: calls,
@@ -102,24 +111,38 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
102111
buffer := new(bytes.Buffer)
103112

104113
funcs := map[string]interface{}{
105-
"bindtype": bindType,
114+
"bindtype": bindType[lang],
115+
"namedtype": namedType[lang],
116+
"capitalise": capitalise,
117+
"decapitalise": decapitalise,
106118
}
107-
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource))
119+
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang]))
108120
if err := tmpl.Execute(buffer, data); err != nil {
109121
return "", err
110122
}
111-
// Pass the code through goimports to clean it up and double check
112-
code, err := imports.Process("", buffer.Bytes(), nil)
113-
if err != nil {
114-
return "", fmt.Errorf("%v\n%s", err, buffer)
123+
// For Go bindings pass the code through goimports to clean it up and double check
124+
if lang == LangGo {
125+
code, err := imports.Process("", buffer.Bytes(), nil)
126+
if err != nil {
127+
return "", fmt.Errorf("%v\n%s", err, buffer)
128+
}
129+
return string(code), nil
115130
}
116-
return string(code), nil
131+
// For all others just return as is for now
132+
return string(buffer.Bytes()), nil
117133
}
118134

119-
// bindType converts a Solidity type to a Go one. Since there is no clear mapping
135+
// bindType is a set of type binders that convert Solidity types to some supported
136+
// programming language.
137+
var bindType = map[Lang]func(kind abi.Type) string{
138+
LangGo: bindTypeGo,
139+
LangJava: bindTypeJava,
140+
}
141+
142+
// bindTypeGo converts a Solidity type to a Go one. Since there is no clear mapping
120143
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
121144
// mapped will use an upscaled type (e.g. *big.Int).
122-
func bindType(kind abi.Type) string {
145+
func bindTypeGo(kind abi.Type) string {
123146
stringKind := kind.String()
124147

125148
switch {
@@ -160,11 +183,137 @@ func bindType(kind abi.Type) string {
160183
}
161184
}
162185

186+
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
187+
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
188+
// mapped will use an upscaled type (e.g. BigDecimal).
189+
func bindTypeJava(kind abi.Type) string {
190+
stringKind := kind.String()
191+
192+
switch {
193+
case strings.HasPrefix(stringKind, "address"):
194+
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
195+
if len(parts) != 2 {
196+
return stringKind
197+
}
198+
if parts[1] == "" {
199+
return fmt.Sprintf("Address")
200+
}
201+
return fmt.Sprintf("Addresses")
202+
203+
case strings.HasPrefix(stringKind, "bytes"):
204+
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
205+
if len(parts) != 3 {
206+
return stringKind
207+
}
208+
if parts[2] != "" {
209+
return "byte[][]"
210+
}
211+
return "byte[]"
212+
213+
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
214+
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
215+
if len(parts) != 4 {
216+
return stringKind
217+
}
218+
switch parts[2] {
219+
case "8", "16", "32", "64":
220+
if parts[1] == "" {
221+
if parts[3] == "" {
222+
return fmt.Sprintf("int%s", parts[2])
223+
}
224+
return fmt.Sprintf("int%s[]", parts[2])
225+
}
226+
}
227+
if parts[3] == "" {
228+
return fmt.Sprintf("BigInt")
229+
}
230+
return fmt.Sprintf("BigInts")
231+
232+
case strings.HasPrefix(stringKind, "bool"):
233+
parts := regexp.MustCompile("bool(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
234+
if len(parts) != 2 {
235+
return stringKind
236+
}
237+
if parts[1] == "" {
238+
return fmt.Sprintf("bool")
239+
}
240+
return fmt.Sprintf("bool[]")
241+
242+
case strings.HasPrefix(stringKind, "string"):
243+
parts := regexp.MustCompile("string(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
244+
if len(parts) != 2 {
245+
return stringKind
246+
}
247+
if parts[1] == "" {
248+
return fmt.Sprintf("String")
249+
}
250+
return fmt.Sprintf("String[]")
251+
252+
default:
253+
return stringKind
254+
}
255+
}
256+
257+
// namedType is a set of functions that transform language specific types to
258+
// named versions that my be used inside method names.
259+
var namedType = map[Lang]func(string, abi.Type) string{
260+
LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") },
261+
LangJava: namedTypeJava,
262+
}
263+
264+
// namedTypeJava converts some primitive data types to named variants that can
265+
// be used as parts of method names.
266+
func namedTypeJava(javaKind string, solKind abi.Type) string {
267+
switch javaKind {
268+
case "byte[]":
269+
return "Binary"
270+
case "byte[][]":
271+
return "Binaries"
272+
case "string":
273+
return "String"
274+
case "string[]":
275+
return "Strings"
276+
case "bool":
277+
return "Bool"
278+
case "bool[]":
279+
return "Bools"
280+
case "BigInt":
281+
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(solKind.String())
282+
if len(parts) != 4 {
283+
return javaKind
284+
}
285+
switch parts[2] {
286+
case "8", "16", "32", "64":
287+
if parts[3] == "" {
288+
return capitalise(fmt.Sprintf("%sint%s", parts[1], parts[2]))
289+
}
290+
return capitalise(fmt.Sprintf("%sint%ss", parts[1], parts[2]))
291+
292+
default:
293+
return javaKind
294+
}
295+
default:
296+
return javaKind
297+
}
298+
}
299+
300+
// methodNormalizer is a name transformer that modifies Solidity method names to
301+
// conform to target language naming concentions.
302+
var methodNormalizer = map[Lang]func(string) string{
303+
LangGo: capitalise,
304+
LangJava: decapitalise,
305+
}
306+
163307
// capitalise makes the first character of a string upper case.
164308
func capitalise(input string) string {
165309
return strings.ToUpper(input[:1]) + input[1:]
166310
}
167311

312+
// decapitalise makes the first character of a string lower case.
313+
func decapitalise(input string) string {
314+
return strings.ToLower(input[:1]) + input[1:]
315+
}
316+
168317
// structured checks whether a method has enough information to return a proper
169318
// Go struct ot if flat returns are needed.
170319
func structured(method abi.Method) bool {

accounts/abi/bind/bind_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ func TestBindings(t *testing.T) {
398398
// Generate the test suite for all the contracts
399399
for i, tt := range bindTests {
400400
// Generate the binding and create a Go source file in the workspace
401-
bind, err := Bind([]string{tt.name}, []string{tt.abi}, []string{tt.bytecode}, "bindtest")
401+
bind, err := Bind([]string{tt.name}, []string{tt.abi}, []string{tt.bytecode}, "bindtest", LangGo)
402402
if err != nil {
403403
t.Fatalf("test %d: failed to generate binding: %v", i, err)
404404
}

0 commit comments

Comments
 (0)