Merge pull request #2977 from karalabe/initial-mobile-suport
mobile: initial wrappers for mobile support
This commit is contained in:
commit
8dcea0ac07
23
.travis.yml
23
.travis.yml
@ -53,15 +53,36 @@ matrix:
|
|||||||
- CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
|
- CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
|
||||||
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
|
|
||||||
# This builder does the OSX Azure uploads
|
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.7
|
go: 1.7
|
||||||
env:
|
env:
|
||||||
- azure-osx
|
- azure-osx
|
||||||
|
- mobile
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.android.platforms
|
||||||
|
- $HOME/.cocoapods
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
|
||||||
|
|
||||||
|
# Build the iOS framework and upload it to CocoaPods and Azure
|
||||||
|
- gem install cocoapods --pre
|
||||||
|
- go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
|
||||||
|
|
||||||
|
# Build the Android archive and upload it to Maven Central and Azure
|
||||||
|
- brew update
|
||||||
|
- brew install android-sdk maven
|
||||||
|
- export ANDROID_HOME=/usr/local/opt/android-sdk
|
||||||
|
|
||||||
|
- mkdir -p $ANDROID_HOME/platforms
|
||||||
|
- mv -f $HOME/.android.platforms $ANDROID_HOME/platforms
|
||||||
|
- echo "y" | android update sdk --no-ui --filter platform
|
||||||
|
|
||||||
|
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
|
||||||
|
- mv -f $ANDROID_HOME/platforms $HOME/.android.platforms
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- go get golang.org/x/tools/cmd/cover
|
- go get golang.org/x/tools/cmd/cover
|
||||||
script:
|
script:
|
||||||
|
@ -32,11 +32,20 @@ import (
|
|||||||
"golang.org/x/tools/imports"
|
"golang.org/x/tools/imports"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Lang is a target programming language selector to generate bindings for.
|
||||||
|
type Lang int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LangGo Lang = iota
|
||||||
|
LangJava
|
||||||
|
LangObjC
|
||||||
|
)
|
||||||
|
|
||||||
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
|
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
|
||||||
// to be used as is in client code, but rather as an intermediate struct which
|
// to be used as is in client code, but rather as an intermediate struct which
|
||||||
// enforces compile time type safety and naming convention opposed to having to
|
// enforces compile time type safety and naming convention opposed to having to
|
||||||
// manually maintain hard coded strings that break on runtime.
|
// manually maintain hard coded strings that break on runtime.
|
||||||
func Bind(types []string, abis []string, bytecodes []string, pkg string) (string, error) {
|
func Bind(types []string, abis []string, bytecodes []string, pkg string, lang Lang) (string, error) {
|
||||||
// Process each individual contract requested binding
|
// Process each individual contract requested binding
|
||||||
contracts := make(map[string]*tmplContract)
|
contracts := make(map[string]*tmplContract)
|
||||||
|
|
||||||
@ -62,7 +71,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
|
|||||||
for _, original := range evmABI.Methods {
|
for _, original := range evmABI.Methods {
|
||||||
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
||||||
normalized := original
|
normalized := original
|
||||||
normalized.Name = capitalise(original.Name)
|
normalized.Name = methodNormalizer[lang](original.Name)
|
||||||
|
|
||||||
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
||||||
copy(normalized.Inputs, original.Inputs)
|
copy(normalized.Inputs, original.Inputs)
|
||||||
@ -78,7 +87,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
|
|||||||
normalized.Outputs[j].Name = capitalise(output.Name)
|
normalized.Outputs[j].Name = capitalise(output.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Append the methos to the call or transact lists
|
// Append the methods to the call or transact lists
|
||||||
if original.Const {
|
if original.Const {
|
||||||
calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original)}
|
calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original)}
|
||||||
} else {
|
} else {
|
||||||
@ -87,7 +96,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
|
|||||||
}
|
}
|
||||||
contracts[types[i]] = &tmplContract{
|
contracts[types[i]] = &tmplContract{
|
||||||
Type: capitalise(types[i]),
|
Type: capitalise(types[i]),
|
||||||
InputABI: strippedABI,
|
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
|
||||||
InputBin: strings.TrimSpace(bytecodes[i]),
|
InputBin: strings.TrimSpace(bytecodes[i]),
|
||||||
Constructor: evmABI.Constructor,
|
Constructor: evmABI.Constructor,
|
||||||
Calls: calls,
|
Calls: calls,
|
||||||
@ -102,24 +111,38 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
|
|||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
|
|
||||||
funcs := map[string]interface{}{
|
funcs := map[string]interface{}{
|
||||||
"bindtype": bindType,
|
"bindtype": bindType[lang],
|
||||||
|
"namedtype": namedType[lang],
|
||||||
|
"capitalise": capitalise,
|
||||||
|
"decapitalise": decapitalise,
|
||||||
}
|
}
|
||||||
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource))
|
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang]))
|
||||||
if err := tmpl.Execute(buffer, data); err != nil {
|
if err := tmpl.Execute(buffer, data); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// Pass the code through goimports to clean it up and double check
|
// For Go bindings pass the code through goimports to clean it up and double check
|
||||||
|
if lang == LangGo {
|
||||||
code, err := imports.Process("", buffer.Bytes(), nil)
|
code, err := imports.Process("", buffer.Bytes(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("%v\n%s", err, buffer)
|
return "", fmt.Errorf("%v\n%s", err, buffer)
|
||||||
}
|
}
|
||||||
return string(code), nil
|
return string(code), nil
|
||||||
}
|
}
|
||||||
|
// For all others just return as is for now
|
||||||
|
return string(buffer.Bytes()), nil
|
||||||
|
}
|
||||||
|
|
||||||
// bindType converts a Solidity type to a Go one. Since there is no clear mapping
|
// bindType is a set of type binders that convert Solidity types to some supported
|
||||||
|
// programming language.
|
||||||
|
var bindType = map[Lang]func(kind abi.Type) string{
|
||||||
|
LangGo: bindTypeGo,
|
||||||
|
LangJava: bindTypeJava,
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindTypeGo converts a Solidity type to a Go one. Since there is no clear mapping
|
||||||
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
|
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
|
||||||
// mapped will use an upscaled type (e.g. *big.Int).
|
// mapped will use an upscaled type (e.g. *big.Int).
|
||||||
func bindType(kind abi.Type) string {
|
func bindTypeGo(kind abi.Type) string {
|
||||||
stringKind := kind.String()
|
stringKind := kind.String()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@ -160,11 +183,137 @@ func bindType(kind abi.Type) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
|
||||||
|
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
|
||||||
|
// mapped will use an upscaled type (e.g. BigDecimal).
|
||||||
|
func bindTypeJava(kind abi.Type) string {
|
||||||
|
stringKind := kind.String()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(stringKind, "address"):
|
||||||
|
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
if parts[1] == "" {
|
||||||
|
return fmt.Sprintf("Address")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Addresses")
|
||||||
|
|
||||||
|
case strings.HasPrefix(stringKind, "bytes"):
|
||||||
|
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
if parts[2] != "" {
|
||||||
|
return "byte[][]"
|
||||||
|
}
|
||||||
|
return "byte[]"
|
||||||
|
|
||||||
|
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
||||||
|
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
switch parts[2] {
|
||||||
|
case "8", "16", "32", "64":
|
||||||
|
if parts[1] == "" {
|
||||||
|
if parts[3] == "" {
|
||||||
|
return fmt.Sprintf("int%s", parts[2])
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("int%s[]", parts[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parts[3] == "" {
|
||||||
|
return fmt.Sprintf("BigInt")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("BigInts")
|
||||||
|
|
||||||
|
case strings.HasPrefix(stringKind, "bool"):
|
||||||
|
parts := regexp.MustCompile("bool(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
if parts[1] == "" {
|
||||||
|
return fmt.Sprintf("bool")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("bool[]")
|
||||||
|
|
||||||
|
case strings.HasPrefix(stringKind, "string"):
|
||||||
|
parts := regexp.MustCompile("string(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
if parts[1] == "" {
|
||||||
|
return fmt.Sprintf("String")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("String[]")
|
||||||
|
|
||||||
|
default:
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// namedType is a set of functions that transform language specific types to
|
||||||
|
// named versions that my be used inside method names.
|
||||||
|
var namedType = map[Lang]func(string, abi.Type) string{
|
||||||
|
LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") },
|
||||||
|
LangJava: namedTypeJava,
|
||||||
|
}
|
||||||
|
|
||||||
|
// namedTypeJava converts some primitive data types to named variants that can
|
||||||
|
// be used as parts of method names.
|
||||||
|
func namedTypeJava(javaKind string, solKind abi.Type) string {
|
||||||
|
switch javaKind {
|
||||||
|
case "byte[]":
|
||||||
|
return "Binary"
|
||||||
|
case "byte[][]":
|
||||||
|
return "Binaries"
|
||||||
|
case "string":
|
||||||
|
return "String"
|
||||||
|
case "string[]":
|
||||||
|
return "Strings"
|
||||||
|
case "bool":
|
||||||
|
return "Bool"
|
||||||
|
case "bool[]":
|
||||||
|
return "Bools"
|
||||||
|
case "BigInt":
|
||||||
|
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(solKind.String())
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return javaKind
|
||||||
|
}
|
||||||
|
switch parts[2] {
|
||||||
|
case "8", "16", "32", "64":
|
||||||
|
if parts[3] == "" {
|
||||||
|
return capitalise(fmt.Sprintf("%sint%s", parts[1], parts[2]))
|
||||||
|
}
|
||||||
|
return capitalise(fmt.Sprintf("%sint%ss", parts[1], parts[2]))
|
||||||
|
|
||||||
|
default:
|
||||||
|
return javaKind
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return javaKind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// methodNormalizer is a name transformer that modifies Solidity method names to
|
||||||
|
// conform to target language naming concentions.
|
||||||
|
var methodNormalizer = map[Lang]func(string) string{
|
||||||
|
LangGo: capitalise,
|
||||||
|
LangJava: decapitalise,
|
||||||
|
}
|
||||||
|
|
||||||
// capitalise makes the first character of a string upper case.
|
// capitalise makes the first character of a string upper case.
|
||||||
func capitalise(input string) string {
|
func capitalise(input string) string {
|
||||||
return strings.ToUpper(input[:1]) + input[1:]
|
return strings.ToUpper(input[:1]) + input[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decapitalise makes the first character of a string lower case.
|
||||||
|
func decapitalise(input string) string {
|
||||||
|
return strings.ToLower(input[:1]) + input[1:]
|
||||||
|
}
|
||||||
|
|
||||||
// structured checks whether a method has enough information to return a proper
|
// structured checks whether a method has enough information to return a proper
|
||||||
// Go struct ot if flat returns are needed.
|
// Go struct ot if flat returns are needed.
|
||||||
func structured(method abi.Method) bool {
|
func structured(method abi.Method) bool {
|
||||||
|
@ -398,7 +398,7 @@ func TestBindings(t *testing.T) {
|
|||||||
// Generate the test suite for all the contracts
|
// Generate the test suite for all the contracts
|
||||||
for i, tt := range bindTests {
|
for i, tt := range bindTests {
|
||||||
// Generate the binding and create a Go source file in the workspace
|
// Generate the binding and create a Go source file in the workspace
|
||||||
bind, err := Bind([]string{tt.name}, []string{tt.abi}, []string{tt.bytecode}, "bindtest")
|
bind, err := Bind([]string{tt.name}, []string{tt.abi}, []string{tt.bytecode}, "bindtest", LangGo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
||||||
}
|
}
|
||||||
|
@ -42,9 +42,16 @@ type tmplMethod struct {
|
|||||||
Structured bool // Whether the returns should be accumulated into a contract
|
Structured bool // Whether the returns should be accumulated into a contract
|
||||||
}
|
}
|
||||||
|
|
||||||
// tmplSource is the Go source template use to generate the contract binding
|
// tmplSource is language to template mapping containing all the supported
|
||||||
|
// programming languages the package can generate to.
|
||||||
|
var tmplSource = map[Lang]string{
|
||||||
|
LangGo: tmplSourceGo,
|
||||||
|
LangJava: tmplSourceJava,
|
||||||
|
}
|
||||||
|
|
||||||
|
// tmplSourceGo is the Go source template use to generate the contract binding
|
||||||
// based on.
|
// based on.
|
||||||
const tmplSource = `
|
const tmplSourceGo = `
|
||||||
// This file is an automatically generated Go binding. Do not modify as any
|
// This file is an automatically generated Go binding. Do not modify as any
|
||||||
// change will likely be lost upon the next re-generation!
|
// change will likely be lost upon the next re-generation!
|
||||||
|
|
||||||
@ -52,7 +59,7 @@ package {{.Package}}
|
|||||||
|
|
||||||
{{range $contract := .Contracts}}
|
{{range $contract := .Contracts}}
|
||||||
// {{.Type}}ABI is the input ABI used to generate the binding from.
|
// {{.Type}}ABI is the input ABI used to generate the binding from.
|
||||||
const {{.Type}}ABI = ` + "`" + `{{.InputABI}}` + "`" + `
|
const {{.Type}}ABI = "{{.InputABI}}"
|
||||||
|
|
||||||
{{if .InputBin}}
|
{{if .InputBin}}
|
||||||
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
|
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
|
||||||
@ -258,3 +265,105 @@ package {{.Package}}
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// tmplSourceJava is the Java source template use to generate the contract binding
|
||||||
|
// based on.
|
||||||
|
const tmplSourceJava = `
|
||||||
|
// This file is an automatically generated Java binding. Do not modify as any
|
||||||
|
// change will likely be lost upon the next re-generation!
|
||||||
|
|
||||||
|
package {{.Package}};
|
||||||
|
|
||||||
|
import org.ethereum.geth.*;
|
||||||
|
import org.ethereum.geth.internal.*;
|
||||||
|
|
||||||
|
{{range $contract := .Contracts}}
|
||||||
|
public class {{.Type}} {
|
||||||
|
// ABI is the input ABI used to generate the binding from.
|
||||||
|
public final static String ABI = "{{.InputABI}}";
|
||||||
|
|
||||||
|
{{if .InputBin}}
|
||||||
|
// BYTECODE is the compiled bytecode used for deploying new contracts.
|
||||||
|
public final static byte[] BYTECODE = "{{.InputBin}}".getBytes();
|
||||||
|
|
||||||
|
// deploy deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
|
||||||
|
public static {{.Type}} deploy(TransactOpts auth, EthereumClient client{{range .Constructor.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
|
||||||
|
Interfaces args = Geth.newInterfaces({{(len .Constructor.Inputs)}});
|
||||||
|
{{range $index, $element := .Constructor.Inputs}}
|
||||||
|
args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
|
||||||
|
{{end}}
|
||||||
|
return new {{.Type}}(Geth.deployContract(auth, ABI, BYTECODE, client, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal constructor used by contract deployment.
|
||||||
|
private {{.Type}}(BoundContract deployment) {
|
||||||
|
this.Address = deployment.getAddress();
|
||||||
|
this.Deployer = deployment.getDeployer();
|
||||||
|
this.Contract = deployment;
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
// Ethereum address where this contract is located at.
|
||||||
|
public final Address Address;
|
||||||
|
|
||||||
|
// Ethereum transaction in which this contract was deployed (if known!).
|
||||||
|
public final Transaction Deployer;
|
||||||
|
|
||||||
|
// Contract instance bound to a blockchain address.
|
||||||
|
private final BoundContract Contract;
|
||||||
|
|
||||||
|
// Creates a new instance of {{.Type}}, bound to a specific deployed contract.
|
||||||
|
public {{.Type}}(Address address, EthereumClient client) throws Exception {
|
||||||
|
this(Geth.bindContract(address, ABI, client));
|
||||||
|
}
|
||||||
|
|
||||||
|
{{range .Calls}}
|
||||||
|
{{if gt (len .Normalized.Outputs) 1}}
|
||||||
|
// {{capitalise .Normalized.Name}}Results is the output of a call to {{.Normalized.Name}}.
|
||||||
|
public class {{capitalise .Normalized.Name}}Results {
|
||||||
|
{{range $index, $item := .Normalized.Outputs}}public {{bindtype .Type}} {{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}};
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||||
|
//
|
||||||
|
// Solidity: {{.Original.String}}
|
||||||
|
public {{if gt (len .Normalized.Outputs) 1}}{{capitalise .Normalized.Name}}Results{{else}}{{range .Normalized.Outputs}}{{bindtype .Type}}{{end}}{{end}} {{.Normalized.Name}}(CallOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
|
||||||
|
Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}});
|
||||||
|
{{range $index, $item := .Normalized.Inputs}}args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
Interfaces results = Geth.newInterfaces({{(len .Normalized.Outputs)}});
|
||||||
|
{{range $index, $item := .Normalized.Outputs}}Interface result{{$index}} = Geth.newInterface(); result{{$index}}.setDefault{{namedtype (bindtype .Type) .Type}}(); results.set({{$index}}, result{{$index}});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
if (opts == null) {
|
||||||
|
opts = Geth.newCallOpts();
|
||||||
|
}
|
||||||
|
this.Contract.call(opts, results, "{{.Original.Name}}", args);
|
||||||
|
{{if gt (len .Normalized.Outputs) 1}}
|
||||||
|
{{capitalise .Normalized.Name}}Results result = new {{capitalise .Normalized.Name}}Results();
|
||||||
|
{{range $index, $item := .Normalized.Outputs}}result.{{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}} = results.get({{$index}}).get{{namedtype (bindtype .Type) .Type}}();
|
||||||
|
{{end}}
|
||||||
|
return result;
|
||||||
|
{{else}}{{range .Normalized.Outputs}}return results.get(0).get{{namedtype (bindtype .Type) .Type}}();{{end}}
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{range .Transacts}}
|
||||||
|
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||||
|
//
|
||||||
|
// Solidity: {{.Original.String}}
|
||||||
|
public Transaction {{.Normalized.Name}}(TransactOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
|
||||||
|
Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}});
|
||||||
|
{{range $index, $item := .Normalized.Inputs}}args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
return this.Contract.transact(opts, "{{.Original.Name}}" , args);
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
@ -46,12 +46,20 @@ import (
|
|||||||
const (
|
const (
|
||||||
keyHeaderKDF = "scrypt"
|
keyHeaderKDF = "scrypt"
|
||||||
|
|
||||||
// n,r,p = 2^18, 8, 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
|
// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
|
||||||
|
// memory and taking approximately 1s CPU time on a modern processor.
|
||||||
StandardScryptN = 1 << 18
|
StandardScryptN = 1 << 18
|
||||||
|
|
||||||
|
// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
|
||||||
|
// memory and taking approximately 1s CPU time on a modern processor.
|
||||||
StandardScryptP = 1
|
StandardScryptP = 1
|
||||||
|
|
||||||
// n,r,p = 2^12, 8, 6 uses 4MB memory and approx 100ms CPU time on a modern CPU.
|
// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
|
||||||
|
// memory and taking approximately 100ms CPU time on a modern processor.
|
||||||
LightScryptN = 1 << 12
|
LightScryptN = 1 << 12
|
||||||
|
|
||||||
|
// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
|
||||||
|
// memory and taking approximately 100ms CPU time on a modern processor.
|
||||||
LightScryptP = 6
|
LightScryptP = 6
|
||||||
|
|
||||||
scryptR = 8
|
scryptR = 8
|
||||||
|
224
build/ci.go
224
build/ci.go
@ -29,6 +29,8 @@ Available commands are:
|
|||||||
importkeys -- imports signing keys from env
|
importkeys -- imports signing keys from env
|
||||||
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
||||||
nsis -- creates a Windows NSIS installer
|
nsis -- creates a Windows NSIS installer
|
||||||
|
aar [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an Android archive
|
||||||
|
xcode [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an iOS XCode framework
|
||||||
xgo [ options ] -- cross builds according to options
|
xgo [ options ] -- cross builds according to options
|
||||||
|
|
||||||
For all commands, -n prevents execution of external programs (dry run mode).
|
For all commands, -n prevents execution of external programs (dry run mode).
|
||||||
@ -37,6 +39,7 @@ For all commands, -n prevents execution of external programs (dry run mode).
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"flag"
|
"flag"
|
||||||
@ -48,6 +51,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -125,6 +129,10 @@ func main() {
|
|||||||
doDebianSource(os.Args[2:])
|
doDebianSource(os.Args[2:])
|
||||||
case "nsis":
|
case "nsis":
|
||||||
doWindowsInstaller(os.Args[2:])
|
doWindowsInstaller(os.Args[2:])
|
||||||
|
case "aar":
|
||||||
|
doAndroidArchive(os.Args[2:])
|
||||||
|
case "xcode":
|
||||||
|
doXCodeFramework(os.Args[2:])
|
||||||
case "xgo":
|
case "xgo":
|
||||||
doXgo(os.Args[2:])
|
doXgo(os.Args[2:])
|
||||||
default:
|
default:
|
||||||
@ -331,14 +339,24 @@ func archiveBasename(arch string, env build.Environment) string {
|
|||||||
if arch == "arm" {
|
if arch == "arm" {
|
||||||
platform += os.Getenv("GOARM")
|
platform += os.Getenv("GOARM")
|
||||||
}
|
}
|
||||||
archive := platform + "-" + build.VERSION()
|
if arch == "android" {
|
||||||
|
platform = "android-all"
|
||||||
|
}
|
||||||
|
if arch == "ios" {
|
||||||
|
platform = "ios-all"
|
||||||
|
}
|
||||||
|
return platform + "-" + archiveVersion(env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func archiveVersion(env build.Environment) string {
|
||||||
|
version := build.VERSION()
|
||||||
if isUnstableBuild(env) {
|
if isUnstableBuild(env) {
|
||||||
archive += "-unstable"
|
version += "-unstable"
|
||||||
}
|
}
|
||||||
if env.Commit != "" {
|
if env.Commit != "" {
|
||||||
archive += "-" + env.Commit[:8]
|
version += "-" + env.Commit[:8]
|
||||||
}
|
}
|
||||||
return archive
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
func archiveUpload(archive string, blobstore string, signer string) error {
|
func archiveUpload(archive string, blobstore string, signer string) error {
|
||||||
@ -632,6 +650,204 @@ func doWindowsInstaller(cmdline []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Android archives
|
||||||
|
|
||||||
|
func doAndroidArchive(cmdline []string) {
|
||||||
|
var (
|
||||||
|
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. ANDROID_SIGNING_KEY)`)
|
||||||
|
deploy = flag.String("deploy", "", `Destination to deploy the archive (usually "https://oss.sonatype.org")`)
|
||||||
|
upload = flag.String("upload", "", `Destination to upload the archive (usually "gethstore/builds")`)
|
||||||
|
)
|
||||||
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
env := build.Env()
|
||||||
|
|
||||||
|
// Build the Android archive and Maven resources
|
||||||
|
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
||||||
|
build.MustRun(gomobileTool("init"))
|
||||||
|
build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile"))
|
||||||
|
|
||||||
|
meta := newMavenMetadata(env)
|
||||||
|
build.Render("build/mvn.pom", meta.Package+".pom", 0755, meta)
|
||||||
|
|
||||||
|
// Skip Maven deploy and Azure upload for PR builds
|
||||||
|
maybeSkipArchive(env)
|
||||||
|
|
||||||
|
// Sign and upload all the artifacts to Maven Central
|
||||||
|
os.Rename("geth.aar", meta.Package+".aar")
|
||||||
|
if *signer != "" && *deploy != "" {
|
||||||
|
// Import the signing key into the local GPG instance
|
||||||
|
if b64key := os.Getenv(*signer); b64key != "" {
|
||||||
|
key, err := base64.StdEncoding.DecodeString(b64key)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("invalid base64 %s", *signer)
|
||||||
|
}
|
||||||
|
gpg := exec.Command("gpg", "--import")
|
||||||
|
gpg.Stdin = bytes.NewReader(key)
|
||||||
|
build.MustRun(gpg)
|
||||||
|
}
|
||||||
|
// Upload the artifacts to Sonatype and/or Maven Central
|
||||||
|
repo := *deploy + "/service/local/staging/deploy/maven2"
|
||||||
|
if meta.Develop {
|
||||||
|
repo = *deploy + "/content/repositories/snapshots"
|
||||||
|
}
|
||||||
|
build.MustRunCommand("mvn", "gpg:sign-and-deploy-file",
|
||||||
|
"-settings=build/mvn.settings", "-Durl="+repo, "-DrepositoryId=ossrh",
|
||||||
|
"-DpomFile="+meta.Package+".pom", "-Dfile="+meta.Package+".aar")
|
||||||
|
}
|
||||||
|
// Sign and upload the archive to Azure
|
||||||
|
archive := "geth-" + archiveBasename("android", env) + ".aar"
|
||||||
|
os.Rename(meta.Package+".aar", archive)
|
||||||
|
|
||||||
|
if err := archiveUpload(archive, *upload, *signer); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gomobileTool(subcmd string, args ...string) *exec.Cmd {
|
||||||
|
cmd := exec.Command(filepath.Join(GOBIN, "gomobile"), subcmd)
|
||||||
|
cmd.Args = append(cmd.Args, args...)
|
||||||
|
cmd.Env = []string{
|
||||||
|
"GOPATH=" + build.GOPATH(),
|
||||||
|
}
|
||||||
|
for _, e := range os.Environ() {
|
||||||
|
if strings.HasPrefix(e, "GOPATH=") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmd.Env = append(cmd.Env, e)
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type mavenMetadata struct {
|
||||||
|
Version string
|
||||||
|
Package string
|
||||||
|
Develop bool
|
||||||
|
Contributors []mavenContributor
|
||||||
|
}
|
||||||
|
|
||||||
|
type mavenContributor struct {
|
||||||
|
Name string
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMavenMetadata(env build.Environment) mavenMetadata {
|
||||||
|
// Collect the list of authors from the repo root
|
||||||
|
contribs := []mavenContributor{}
|
||||||
|
if authors, err := os.Open("AUTHORS"); err == nil {
|
||||||
|
defer authors.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(authors)
|
||||||
|
for scanner.Scan() {
|
||||||
|
// Skip any whitespace from the authors list
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
if line == "" || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Split the author and insert as a contributor
|
||||||
|
re := regexp.MustCompile("([^<]+) <(.+>)")
|
||||||
|
parts := re.FindStringSubmatch(line)
|
||||||
|
if len(parts) == 3 {
|
||||||
|
contribs = append(contribs, mavenContributor{Name: parts[1], Email: parts[2]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Render the version and package strings
|
||||||
|
version := build.VERSION()
|
||||||
|
if isUnstableBuild(env) {
|
||||||
|
version += "-SNAPSHOT"
|
||||||
|
}
|
||||||
|
return mavenMetadata{
|
||||||
|
Version: version,
|
||||||
|
Package: "geth-" + version,
|
||||||
|
Develop: isUnstableBuild(env),
|
||||||
|
Contributors: contribs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XCode frameworks
|
||||||
|
|
||||||
|
func doXCodeFramework(cmdline []string) {
|
||||||
|
var (
|
||||||
|
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. IOS_SIGNING_KEY)`)
|
||||||
|
deploy = flag.String("deploy", "", `Destination to deploy the archive (usually "trunk")`)
|
||||||
|
upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`)
|
||||||
|
)
|
||||||
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
env := build.Env()
|
||||||
|
|
||||||
|
// Build the iOS XCode framework
|
||||||
|
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
||||||
|
build.MustRun(gomobileTool("init"))
|
||||||
|
|
||||||
|
archive := "geth-" + archiveBasename("ios", env)
|
||||||
|
if err := os.Mkdir(archive, os.ModePerm); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "--prefix", "GE", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||||
|
bind.Dir, _ = filepath.Abs(archive)
|
||||||
|
build.MustRun(bind)
|
||||||
|
build.MustRunCommand("tar", "-zcvf", archive+".tar.gz", archive)
|
||||||
|
|
||||||
|
// Skip CocoaPods deploy and Azure upload for PR builds
|
||||||
|
maybeSkipArchive(env)
|
||||||
|
|
||||||
|
// Sign and upload the framework to Azure
|
||||||
|
if err := archiveUpload(archive+".tar.gz", *upload, *signer); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// Prepare and upload a PodSpec to CocoaPods
|
||||||
|
if *deploy != "" {
|
||||||
|
meta := newPodMetadata(env)
|
||||||
|
build.Render("build/pod.podspec", meta.Name+".podspec", 0755, meta)
|
||||||
|
build.MustRunCommand("pod", *deploy, "push", meta.Name+".podspec", "--allow-warnings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type podMetadata struct {
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
Commit string
|
||||||
|
Contributors []podContributor
|
||||||
|
}
|
||||||
|
|
||||||
|
type podContributor struct {
|
||||||
|
Name string
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPodMetadata(env build.Environment) podMetadata {
|
||||||
|
// Collect the list of authors from the repo root
|
||||||
|
contribs := []podContributor{}
|
||||||
|
if authors, err := os.Open("AUTHORS"); err == nil {
|
||||||
|
defer authors.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(authors)
|
||||||
|
for scanner.Scan() {
|
||||||
|
// Skip any whitespace from the authors list
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
if line == "" || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Split the author and insert as a contributor
|
||||||
|
re := regexp.MustCompile("([^<]+) <(.+>)")
|
||||||
|
parts := re.FindStringSubmatch(line)
|
||||||
|
if len(parts) == 3 {
|
||||||
|
contribs = append(contribs, podContributor{Name: parts[1], Email: parts[2]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name := "Geth"
|
||||||
|
if isUnstableBuild(env) {
|
||||||
|
name += "Develop"
|
||||||
|
}
|
||||||
|
return podMetadata{
|
||||||
|
Name: name,
|
||||||
|
Version: archiveVersion(env),
|
||||||
|
Commit: env.Commit,
|
||||||
|
Contributors: contribs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cross compilation
|
// Cross compilation
|
||||||
|
|
||||||
func doXgo(cmdline []string) {
|
func doXgo(cmdline []string) {
|
||||||
|
57
build/mvn.pom
Normal file
57
build/mvn.pom
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.ethereum</groupId>
|
||||||
|
<artifactId>geth</artifactId>
|
||||||
|
<version>{{.Version}}</version>
|
||||||
|
<packaging>aar</packaging>
|
||||||
|
|
||||||
|
<name>Android Ethereum Client</name>
|
||||||
|
<description>Android port of the go-ethereum libraries and node</description>
|
||||||
|
<url>https://github.com/ethereum/go-ethereum</url>
|
||||||
|
<inceptionYear>2015</inceptionYear>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>GNU Lesser General Public License, Version 3.0</name>
|
||||||
|
<url>https://www.gnu.org/licenses/lgpl-3.0.en.html</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<organization>
|
||||||
|
<name>Ethereum</name>
|
||||||
|
<url>https://ethereum.org</url>
|
||||||
|
</organization>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>karalabe</id>
|
||||||
|
<name>Péter Szilágyi</name>
|
||||||
|
<email>peterke@gmail.com</email>
|
||||||
|
<url>https://github.com/karalabe</url>
|
||||||
|
<properties>
|
||||||
|
<picUrl>https://www.gravatar.com/avatar/2ecbf0f5b4b79eebf8c193e5d324357f?s=256</picUrl>
|
||||||
|
</properties>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<contributors>{{range .Contributors}}
|
||||||
|
<contributor>
|
||||||
|
<name>{{.Name}}</name>
|
||||||
|
<email>{{.Email}}</email>
|
||||||
|
</contributor>{{end}}
|
||||||
|
</contributors>
|
||||||
|
|
||||||
|
<issueManagement>
|
||||||
|
<system>GitHub Issues</system>
|
||||||
|
<url>https://github.com/ethereum/go-ethereum/issues/</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<url>https://github.com/ethereum/go-ethereum</url>
|
||||||
|
</scm>
|
||||||
|
</project>
|
24
build/mvn.settings
Normal file
24
build/mvn.settings
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
|
||||||
|
http://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||||
|
<servers>
|
||||||
|
<server>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<username>${env.ANDROID_SONATYPE_USERNAME}</username>
|
||||||
|
<password>${env.ANDROID_SONATYPE_PASSWORD}</password>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<gpg.executable>gpg</gpg.executable>
|
||||||
|
<gpg.passphrase></gpg.passphrase>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</settings>
|
22
build/pod.podspec
Normal file
22
build/pod.podspec
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Pod::Spec.new do |spec|
|
||||||
|
spec.name = '{{.Name}}'
|
||||||
|
spec.version = '{{.Version}}'
|
||||||
|
spec.license = { :type => 'GNU Lesser General Public License, Version 3.0' }
|
||||||
|
spec.homepage = 'https://github.com/ethereum/go-ethereum'
|
||||||
|
spec.authors = { {{range .Contributors}}
|
||||||
|
'{{.Name}}' => '{{.Email}}',{{end}}
|
||||||
|
}
|
||||||
|
spec.summary = 'iOS Ethereum Client'
|
||||||
|
spec.source = { :git => 'https://github.com/ethereum/go-ethereum.git', :commit => '{{.Commit}}' }
|
||||||
|
|
||||||
|
spec.platform = :ios
|
||||||
|
spec.ios.deployment_target = '9.0'
|
||||||
|
spec.ios.vendored_frameworks = 'Frameworks/Geth.framework'
|
||||||
|
|
||||||
|
spec.prepare_command = <<-CMD
|
||||||
|
curl https://gethstore.blob.core.windows.net/builds/geth-ios-all-{{.Version}}.tar.gz | tar -xvz
|
||||||
|
mkdir Frameworks
|
||||||
|
mv geth-ios-all-{{.Version}}/Geth.framework Frameworks
|
||||||
|
rm -rf geth-ios-all-{{.Version}}
|
||||||
|
CMD
|
||||||
|
end
|
@ -31,14 +31,15 @@ import (
|
|||||||
var (
|
var (
|
||||||
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind")
|
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind")
|
||||||
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
|
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
|
||||||
typFlag = flag.String("type", "", "Go struct name for the binding (default = package name)")
|
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
|
||||||
|
|
||||||
solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind")
|
solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind")
|
||||||
solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested")
|
solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested")
|
||||||
excFlag = flag.String("exc", "", "Comma separated types to exclude from binding")
|
excFlag = flag.String("exc", "", "Comma separated types to exclude from binding")
|
||||||
|
|
||||||
pkgFlag = flag.String("pkg", "", "Go package name to generate the binding into")
|
pkgFlag = flag.String("pkg", "", "Package name to generate the binding into")
|
||||||
outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)")
|
outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)")
|
||||||
|
langFlag = flag.String("lang", "go", "Destination language for the bindings (go, java, objc)")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -53,7 +54,19 @@ func main() {
|
|||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
if *pkgFlag == "" {
|
if *pkgFlag == "" {
|
||||||
fmt.Printf("No destination Go package specified (--pkg)\n")
|
fmt.Printf("No destination package specified (--pkg)\n")
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
var lang bind.Lang
|
||||||
|
switch *langFlag {
|
||||||
|
case "go":
|
||||||
|
lang = bind.LangGo
|
||||||
|
case "java":
|
||||||
|
lang = bind.LangJava
|
||||||
|
case "objc":
|
||||||
|
lang = bind.LangObjC
|
||||||
|
default:
|
||||||
|
fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", *langFlag)
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
// If the entire solidity code was specified, build and bind based on that
|
// If the entire solidity code was specified, build and bind based on that
|
||||||
@ -108,7 +121,7 @@ func main() {
|
|||||||
types = append(types, kind)
|
types = append(types, kind)
|
||||||
}
|
}
|
||||||
// Generate the contract binding
|
// Generate the contract binding
|
||||||
code, err := bind.Bind(types, abis, bins, *pkgFlag)
|
code, err := bind.Bind(types, abis, bins, *pkgFlag, lang)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to generate ABI binding: %v\n", err)
|
fmt.Printf("Failed to generate ABI binding: %v\n", err)
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package utils
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/p2p/discover"
|
|
||||||
|
|
||||||
// FrontierBootNodes are the enode URLs of the P2P bootstrap nodes running on
|
|
||||||
// the Frontier network.
|
|
||||||
var FrontierBootNodes = []*discover.Node{
|
|
||||||
// ETH/DEV Go Bootnodes
|
|
||||||
discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE
|
|
||||||
discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR
|
|
||||||
discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG
|
|
||||||
|
|
||||||
// ETH/DEV Cpp Bootnodes
|
|
||||||
discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestNetBootNodes are the enode URLs of the P2P bootstrap nodes running on the
|
|
||||||
// Morden test network.
|
|
||||||
var TestNetBootNodes = []*discover.Node{
|
|
||||||
// ETH/DEV Go Bootnodes
|
|
||||||
discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"),
|
|
||||||
discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"),
|
|
||||||
|
|
||||||
// ETH/DEV Cpp Bootnodes
|
|
||||||
}
|
|
@ -46,6 +46,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
@ -487,9 +488,9 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
|||||||
// Return pre-configured nodes if none were manually requested
|
// Return pre-configured nodes if none were manually requested
|
||||||
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
return TestNetBootNodes
|
return params.TestnetBootnodes
|
||||||
}
|
}
|
||||||
return FrontierBootNodes
|
return params.MainnetBootnodes
|
||||||
}
|
}
|
||||||
// Otherwise parse and use the CLI bootstrap nodes
|
// Otherwise parse and use the CLI bootstrap nodes
|
||||||
bootnodes := []*discover.Node{}
|
bootnodes := []*discover.Node{}
|
||||||
@ -505,13 +506,36 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
|||||||
return bootnodes
|
return bootnodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line
|
||||||
|
// flags, reverting to pre-configured ones if none have been specified.
|
||||||
|
func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node {
|
||||||
|
// Return pre-configured nodes if none were manually requested
|
||||||
|
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||||
|
return params.DiscoveryV5Bootnodes
|
||||||
|
}
|
||||||
|
// Otherwise parse and use the CLI bootstrap nodes
|
||||||
|
bootnodes := []*discv5.Node{}
|
||||||
|
|
||||||
|
for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") {
|
||||||
|
node, err := discv5.ParseNode(url)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bootnodes = append(bootnodes, node)
|
||||||
|
}
|
||||||
|
return bootnodes
|
||||||
|
}
|
||||||
|
|
||||||
// MakeListenAddress creates a TCP listening address string from set command
|
// MakeListenAddress creates a TCP listening address string from set command
|
||||||
// line flags.
|
// line flags.
|
||||||
func MakeListenAddress(ctx *cli.Context) string {
|
func MakeListenAddress(ctx *cli.Context) string {
|
||||||
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
|
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeListenAddressV5(ctx *cli.Context) string {
|
// MakeDiscoveryV5Address creates a UDP listening address string from set command
|
||||||
|
// line flags for the V5 discovery protocol.
|
||||||
|
func MakeDiscoveryV5Address(ctx *cli.Context) string {
|
||||||
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1)
|
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,9 +671,10 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node {
|
|||||||
UserIdent: makeNodeUserIdent(ctx),
|
UserIdent: makeNodeUserIdent(ctx),
|
||||||
NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name),
|
NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name),
|
||||||
DiscoveryV5: ctx.GlobalBool(DiscoveryV5Flag.Name) || ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0,
|
DiscoveryV5: ctx.GlobalBool(DiscoveryV5Flag.Name) || ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0,
|
||||||
|
DiscoveryV5Addr: MakeDiscoveryV5Address(ctx),
|
||||||
BootstrapNodes: MakeBootstrapNodes(ctx),
|
BootstrapNodes: MakeBootstrapNodes(ctx),
|
||||||
|
BootstrapNodesV5: MakeBootstrapNodesV5(ctx),
|
||||||
ListenAddr: MakeListenAddress(ctx),
|
ListenAddr: MakeListenAddress(ctx),
|
||||||
ListenAddrV5: MakeListenAddressV5(ctx),
|
|
||||||
NAT: MakeNAT(ctx),
|
NAT: MakeNAT(ctx),
|
||||||
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
||||||
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
|
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
|
||||||
|
@ -35,7 +35,10 @@ const (
|
|||||||
var hashJsonLengthErr = errors.New("common: unmarshalJSON failed: hash must be exactly 32 bytes")
|
var hashJsonLengthErr = errors.New("common: unmarshalJSON failed: hash must be exactly 32 bytes")
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
||||||
Hash [HashLength]byte
|
Hash [HashLength]byte
|
||||||
|
|
||||||
|
// Address represents the 20 byte address of an Ethereum account.
|
||||||
Address [AddressLength]byte
|
Address [AddressLength]byte
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ func (n *BlockNonce) UnmarshalJSON(input []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header represents Ethereum block headers.
|
// Header represents a block header in the Ethereum blockchain.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
ParentHash common.Hash // Hash to the previous block
|
ParentHash common.Hash // Hash to the previous block
|
||||||
UncleHash common.Hash // Uncles of this block
|
UncleHash common.Hash // Uncles of this block
|
||||||
@ -214,7 +214,7 @@ type Body struct {
|
|||||||
Uncles []*Header
|
Uncles []*Header
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block represents a block in the Ethereum blockchain.
|
// Block represents an entire block in the Ethereum blockchain.
|
||||||
type Block struct {
|
type Block struct {
|
||||||
header *Header
|
header *Header
|
||||||
uncles []*Header
|
uncles []*Header
|
||||||
|
@ -56,7 +56,7 @@ func GOPATH() string {
|
|||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
log.Fatal("GOPATH is not set")
|
log.Fatal("GOPATH is not set")
|
||||||
}
|
}
|
||||||
// Ensure that our internal vendor folder in on GOPATH
|
// Ensure that our internal vendor folder is on GOPATH
|
||||||
vendor, _ := filepath.Abs(filepath.Join("build", "_vendor"))
|
vendor, _ := filepath.Abs(filepath.Join("build", "_vendor"))
|
||||||
for _, dir := range path {
|
for _, dir := range path {
|
||||||
if dir == vendor {
|
if dir == vendor {
|
||||||
|
181
mobile/accounts.go
Normal file
181
mobile/accounts.go
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the accounts package to support client side key
|
||||||
|
// management on mobile platforms.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
|
||||||
|
// memory and taking approximately 1s CPU time on a modern processor.
|
||||||
|
StandardScryptN = int(accounts.StandardScryptN)
|
||||||
|
|
||||||
|
// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
|
||||||
|
// memory and taking approximately 1s CPU time on a modern processor.
|
||||||
|
StandardScryptP = int(accounts.StandardScryptP)
|
||||||
|
|
||||||
|
// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
|
||||||
|
// memory and taking approximately 100ms CPU time on a modern processor.
|
||||||
|
LightScryptN = int(accounts.LightScryptN)
|
||||||
|
|
||||||
|
// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
|
||||||
|
// memory and taking approximately 100ms CPU time on a modern processor.
|
||||||
|
LightScryptP = int(accounts.LightScryptP)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Account represents a stored key.
|
||||||
|
type Account struct{ account accounts.Account }
|
||||||
|
|
||||||
|
// Accounts represents a slice of accounts.
|
||||||
|
type Accounts struct{ accounts []accounts.Account }
|
||||||
|
|
||||||
|
// Size returns the number of accounts in the slice.
|
||||||
|
func (a *Accounts) Size() int {
|
||||||
|
return len(a.accounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the account at the given index from the slice.
|
||||||
|
func (a *Accounts) Get(index int) (*Account, error) {
|
||||||
|
if index < 0 || index >= len(a.accounts) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Account{a.accounts[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the account at the given index in the slice.
|
||||||
|
func (a *Accounts) Set(index int, account *Account) error {
|
||||||
|
if index < 0 || index >= len(a.accounts) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
a.accounts[index] = account.account
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAddress retrieves the address associated with the account.
|
||||||
|
func (a *Account) GetAddress() *Address {
|
||||||
|
return &Address{a.account.Address}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFile retrieves the path of the file containing the account key.
|
||||||
|
func (a *Account) GetFile() string {
|
||||||
|
return a.account.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountManager manages a key storage directory on disk.
|
||||||
|
type AccountManager struct{ manager *accounts.Manager }
|
||||||
|
|
||||||
|
// NewAccountManager creates a manager for the given directory.
|
||||||
|
func NewAccountManager(keydir string, scryptN, scryptP int) *AccountManager {
|
||||||
|
return &AccountManager{manager: accounts.NewManager(keydir, scryptN, scryptP)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasAddress reports whether a key with the given address is present.
|
||||||
|
func (am *AccountManager) HasAddress(addr *Address) bool {
|
||||||
|
return am.manager.HasAddress(addr.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccounts returns all key files present in the directory.
|
||||||
|
func (am *AccountManager) GetAccounts() *Accounts {
|
||||||
|
return &Accounts{am.manager.Accounts()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAccount deletes the key matched by account if the passphrase is correct.
|
||||||
|
// If a contains no filename, the address must match a unique key.
|
||||||
|
func (am *AccountManager) DeleteAccount(a *Account, passphrase string) error {
|
||||||
|
return am.manager.DeleteAccount(accounts.Account{
|
||||||
|
Address: a.account.Address,
|
||||||
|
File: a.account.File,
|
||||||
|
}, passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs hash with an unlocked private key matching the given address.
|
||||||
|
func (am *AccountManager) Sign(addr *Address, hash []byte) ([]byte, error) {
|
||||||
|
return am.manager.Sign(addr.address, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignWithPassphrase signs hash if the private key matching the given address can be
|
||||||
|
// decrypted with the given passphrase.
|
||||||
|
func (am *AccountManager) SignWithPassphrase(addr *Address, passphrase string, hash []byte) ([]byte, error) {
|
||||||
|
return am.manager.SignWithPassphrase(addr.address, passphrase, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock unlocks the given account indefinitely.
|
||||||
|
func (am *AccountManager) Unlock(a *Account, passphrase string) error {
|
||||||
|
return am.manager.TimedUnlock(a.account, passphrase, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock removes the private key with the given address from memory.
|
||||||
|
func (am *AccountManager) Lock(addr *Address) error {
|
||||||
|
return am.manager.Lock(addr.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimedUnlock unlocks the given account with the passphrase. The account
|
||||||
|
// stays unlocked for the duration of timeout. A timeout of 0 unlocks the account
|
||||||
|
// until the program exits. The account must match a unique key file.
|
||||||
|
//
|
||||||
|
// If the account address is already unlocked for a duration, TimedUnlock extends or
|
||||||
|
// shortens the active unlock timeout. If the address was previously unlocked
|
||||||
|
// indefinitely the timeout is not altered.
|
||||||
|
func (am *AccountManager) TimedUnlock(a *Account, passphrase string, timeout int64) error {
|
||||||
|
return am.manager.TimedUnlock(a.account, passphrase, time.Duration(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAccount generates a new key and stores it into the key directory,
|
||||||
|
// encrypting it with the passphrase.
|
||||||
|
func (am *AccountManager) NewAccount(passphrase string) (*Account, error) {
|
||||||
|
account, err := am.manager.NewAccount(passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Account{account}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportKey exports as a JSON key, encrypted with newPassphrase.
|
||||||
|
func (am *AccountManager) ExportKey(a *Account, passphrase, newPassphrase string) ([]byte, error) {
|
||||||
|
return am.manager.Export(a.account, passphrase, newPassphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportKey stores the given encrypted JSON key into the key directory.
|
||||||
|
func (am *AccountManager) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (*Account, error) {
|
||||||
|
account, err := am.manager.Import(keyJSON, passphrase, newPassphrase)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Account{account}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update changes the passphrase of an existing account.
|
||||||
|
func (am *AccountManager) Update(a *Account, passphrase, newPassphrase string) error {
|
||||||
|
return am.manager.Update(a.account, passphrase, newPassphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores
|
||||||
|
// a key file in the key directory. The key file is encrypted with the same passphrase.
|
||||||
|
func (am *AccountManager) ImportPreSaleKey(keyJSON []byte, passphrase string) (*Account, error) {
|
||||||
|
account, err := am.manager.ImportPreSaleKey(keyJSON, passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Account{account}, nil
|
||||||
|
}
|
203
mobile/android_test.go
Normal file
203
mobile/android_test.go
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the accounts package to support client side key
|
||||||
|
// management on mobile platforms.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/internal/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
// androidTestClass is a Java class to do some lightweight tests against the Android
|
||||||
|
// bindings. The goal is not to test each individual functionality, rather just to
|
||||||
|
// catch breaking API and/or implementation changes.
|
||||||
|
const androidTestClass = `
|
||||||
|
package go;
|
||||||
|
|
||||||
|
import android.test.InstrumentationTestCase;
|
||||||
|
import android.test.MoreAsserts;
|
||||||
|
|
||||||
|
import org.ethereum.geth.*;
|
||||||
|
|
||||||
|
public class AndroidTest extends InstrumentationTestCase {
|
||||||
|
public AndroidTest() {}
|
||||||
|
|
||||||
|
public void testAccountManagement() {
|
||||||
|
try {
|
||||||
|
AccountManager am = new AccountManager(getInstrumentation().getContext().getFilesDir() + "/keystore", Geth.LightScryptN, Geth.LightScryptP);
|
||||||
|
|
||||||
|
Account newAcc = am.newAccount("Creation password");
|
||||||
|
byte[] jsonAcc = am.exportKey(newAcc, "Creation password", "Export password");
|
||||||
|
|
||||||
|
am.deleteAccount(newAcc, "Creation password");
|
||||||
|
Account impAcc = am.importKey(jsonAcc, "Export password", "Import password");
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInprocNode() {
|
||||||
|
Context ctx = new Context();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Start up a new inprocess node
|
||||||
|
Node node = new Node(getInstrumentation().getContext().getFilesDir() + "/.ethereum", new NodeConfig());
|
||||||
|
node.start();
|
||||||
|
|
||||||
|
// Retrieve some data via function calls (we don't really care about the results)
|
||||||
|
NodeInfo info = node.getNodeInfo();
|
||||||
|
info.getName();
|
||||||
|
info.getListenerAddress();
|
||||||
|
info.getProtocols();
|
||||||
|
|
||||||
|
// Retrieve some data via the APIs (we don't really care about the results)
|
||||||
|
EthereumClient ec = node.getEthereumClient();
|
||||||
|
ec.getBlockByNumber(ctx, -1).getNumber();
|
||||||
|
|
||||||
|
NewHeadHandler handler = new NewHeadHandler() {
|
||||||
|
@Override public void onError(String error) {}
|
||||||
|
@Override public void onNewHead(final Header header) {}
|
||||||
|
};
|
||||||
|
ec.subscribeNewHead(ctx, handler, 16);
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// TestAndroid runs the Android java test class specified above.
|
||||||
|
//
|
||||||
|
// This requires the gradle command in PATH and the Android SDK whose path is available
|
||||||
|
// through ANDROID_HOME environment variable. To successfully run the tests, an Android
|
||||||
|
// device must also be available with debugging enabled.
|
||||||
|
//
|
||||||
|
// This method has been adapted from golang.org/x/mobile/bind/java/seq_test.go/runTest
|
||||||
|
func TestAndroid(t *testing.T) {
|
||||||
|
// Skip tests on Windows altogether
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skip("cannot test Android bindings on Windows, skipping")
|
||||||
|
}
|
||||||
|
// Make sure all the Android tools are installed
|
||||||
|
if _, err := exec.Command("which", "gradle").CombinedOutput(); err != nil {
|
||||||
|
t.Skip("command gradle not found, skipping")
|
||||||
|
}
|
||||||
|
if sdk := os.Getenv("ANDROID_HOME"); sdk == "" {
|
||||||
|
t.Skip("ANDROID_HOME environment var not set, skipping")
|
||||||
|
}
|
||||||
|
if _, err := exec.Command("which", "gomobile").CombinedOutput(); err != nil {
|
||||||
|
t.Log("gomobile missing, installing it...")
|
||||||
|
if _, err := exec.Command("go", "install", "golang.org/x/mobile/cmd/gomobile").CombinedOutput(); err != nil {
|
||||||
|
t.Fatalf("install failed: %v", err)
|
||||||
|
}
|
||||||
|
t.Log("initializing gomobile...")
|
||||||
|
start := time.Now()
|
||||||
|
if _, err := exec.Command("gomobile", "init").CombinedOutput(); err != nil {
|
||||||
|
t.Fatalf("initialization failed: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("initialization took %v", time.Since(start))
|
||||||
|
}
|
||||||
|
// Create and switch to a temporary workspace
|
||||||
|
workspace, err := ioutil.TempDir("", "geth-android-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create temporary workspace: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(workspace)
|
||||||
|
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get current working directory: %v", err)
|
||||||
|
}
|
||||||
|
if err := os.Chdir(workspace); err != nil {
|
||||||
|
t.Fatalf("failed to switch to temporary workspace: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Chdir(pwd)
|
||||||
|
|
||||||
|
// Create the skeleton of the Android project
|
||||||
|
for _, dir := range []string{"src/main", "src/androidTest/java/org/ethereum/gethtest", "libs"} {
|
||||||
|
err = os.MkdirAll(dir, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Generate the mobile bindings for Geth and add the tester class
|
||||||
|
gobind := exec.Command("gomobile", "bind", "-javapkg", "org.ethereum", "github.com/ethereum/go-ethereum/mobile")
|
||||||
|
if output, err := gobind.CombinedOutput(); err != nil {
|
||||||
|
t.Logf("%s", output)
|
||||||
|
t.Fatalf("failed to run gomobile bind: %v", err)
|
||||||
|
}
|
||||||
|
build.CopyFile(filepath.Join("libs", "geth.aar"), "geth.aar", os.ModePerm)
|
||||||
|
|
||||||
|
if err = ioutil.WriteFile(filepath.Join("src", "androidTest", "java", "org", "ethereum", "gethtest", "AndroidTest.java"), []byte(androidTestClass), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("failed to write Android test class: %v", err)
|
||||||
|
}
|
||||||
|
// Finish creating the project and run the tests via gradle
|
||||||
|
if err = ioutil.WriteFile(filepath.Join("src", "main", "AndroidManifest.xml"), []byte(androidManifest), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("failed to write Android manifest: %v", err)
|
||||||
|
}
|
||||||
|
if err = ioutil.WriteFile("build.gradle", []byte(gradleConfig), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("failed to write gradle build file: %v", err)
|
||||||
|
}
|
||||||
|
if output, err := exec.Command("gradle", "connectedAndroidTest").CombinedOutput(); err != nil {
|
||||||
|
t.Logf("%s", output)
|
||||||
|
t.Errorf("failed to run gradle test: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const androidManifest = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.ethereum.gethtest"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
</manifest>`
|
||||||
|
|
||||||
|
const gradleConfig = `buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:1.5.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allprojects {
|
||||||
|
repositories { jcenter() }
|
||||||
|
}
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
android {
|
||||||
|
compileSdkVersion 'android-19'
|
||||||
|
buildToolsVersion '21.1.2'
|
||||||
|
defaultConfig { minSdkVersion 15 }
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
flatDir { dirs 'libs' }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
compile 'com.android.support:appcompat-v7:19.0.0'
|
||||||
|
compile(name: "geth", ext: "aar")
|
||||||
|
}
|
||||||
|
`
|
95
mobile/big.go
Normal file
95
mobile/big.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the math/big package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A BigInt represents a signed multi-precision integer.
|
||||||
|
type BigInt struct {
|
||||||
|
bigint *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBigInt allocates and returns a new BigInt set to x.
|
||||||
|
func NewBigInt(x int64) *BigInt {
|
||||||
|
return &BigInt{big.NewInt(x)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes returns the absolute value of x as a big-endian byte slice.
|
||||||
|
func (bi *BigInt) GetBytes() []byte {
|
||||||
|
return bi.bigint.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the value of x as a formatted decimal string.
|
||||||
|
func (bi *BigInt) String() string {
|
||||||
|
return bi.bigint.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt64 returns the int64 representation of x. If x cannot be represented in
|
||||||
|
// an int64, the result is undefined.
|
||||||
|
func (bi *BigInt) GetInt64() int64 {
|
||||||
|
return bi.bigint.Int64()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBytes interprets buf as the bytes of a big-endian unsigned integer and sets
|
||||||
|
// the big int to that value.
|
||||||
|
func (bi *BigInt) SetBytes(buf []byte) {
|
||||||
|
bi.bigint.SetBytes(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetInt64 sets the big int to x.
|
||||||
|
func (bi *BigInt) SetInt64(x int64) {
|
||||||
|
bi.bigint.SetInt64(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString sets the big int to x.
|
||||||
|
//
|
||||||
|
// The string prefix determines the actual conversion base. A prefix of "0x" or
|
||||||
|
// "0X" selects base 16; the "0" prefix selects base 8, and a "0b" or "0B" prefix
|
||||||
|
// selects base 2. Otherwise the selected base is 10.
|
||||||
|
func (bi *BigInt) SetString(x string, base int) {
|
||||||
|
bi.bigint.SetString(x, base)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BigInts represents a slice of big ints.
|
||||||
|
type BigInts struct{ bigints []*big.Int }
|
||||||
|
|
||||||
|
// Size returns the number of big ints in the slice.
|
||||||
|
func (bi *BigInts) Size() int {
|
||||||
|
return len(bi.bigints)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the bigint at the given index from the slice.
|
||||||
|
func (bi *BigInts) Get(index int) (*BigInt, error) {
|
||||||
|
if index < 0 || index >= len(bi.bigints) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &BigInt{bi.bigints[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the big int at the given index in the slice.
|
||||||
|
func (bi *BigInts) Set(index int, bigint *BigInt) error {
|
||||||
|
if index < 0 || index >= len(bi.bigints) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
bi.bigints[index] = bigint.bigint
|
||||||
|
return nil
|
||||||
|
}
|
26
mobile/big_go1.7.go
Normal file
26
mobile/big_go1.7.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains the wrappers from the math/big package that require Go 1.7 and above.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
// GetString returns the value of x as a formatted string in some number base.
|
||||||
|
func (bi *BigInt) GetString(base int) string {
|
||||||
|
return bi.bigint.Text(base)
|
||||||
|
}
|
202
mobile/bind.go
Normal file
202
mobile/bind.go
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the bind package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Signer is an interaface defining the callback when a contract requires a
|
||||||
|
// method to sign the transaction before submission.
|
||||||
|
type Signer interface {
|
||||||
|
Sign(*Address, *Transaction) (*Transaction, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type signer struct {
|
||||||
|
sign bind.SignerFn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *signer) Sign(addr *Address, tx *Transaction) (*Transaction, error) {
|
||||||
|
sig, err := s.sign(types.HomesteadSigner{}, addr.address, tx.tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Transaction{sig}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallOpts is the collection of options to fine tune a contract call request.
|
||||||
|
type CallOpts struct {
|
||||||
|
opts bind.CallOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCallOpts creates a new option set for contract calls.
|
||||||
|
func NewCallOpts() *CallOpts {
|
||||||
|
return new(CallOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *CallOpts) IsPending() bool { return opts.opts.Pending }
|
||||||
|
func (opts *CallOpts) GetGasLimit() int64 { return 0 /* TODO(karalabe) */ }
|
||||||
|
|
||||||
|
// GetContext cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876)
|
||||||
|
// Even then it's awkward to unpack the subtleties of a Go context out to Java.
|
||||||
|
// func (opts *CallOpts) GetContext() *Context { return &Context{opts.opts.Context} }
|
||||||
|
|
||||||
|
func (opts *CallOpts) SetPending(pending bool) { opts.opts.Pending = pending }
|
||||||
|
func (opts *CallOpts) SetGasLimit(limit int64) { /* TODO(karalabe) */ }
|
||||||
|
func (opts *CallOpts) SetContext(context *Context) { opts.opts.Context = context.context }
|
||||||
|
|
||||||
|
// TransactOpts is the collection of authorization data required to create a
|
||||||
|
// valid Ethereum transaction.
|
||||||
|
type TransactOpts struct {
|
||||||
|
opts bind.TransactOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *TransactOpts) GetFrom() *Address { return &Address{opts.opts.From} }
|
||||||
|
func (opts *TransactOpts) GetNonce() int64 { return opts.opts.Nonce.Int64() }
|
||||||
|
func (opts *TransactOpts) GetValue() *BigInt { return &BigInt{opts.opts.Value} }
|
||||||
|
func (opts *TransactOpts) GetGasPrice() *BigInt { return &BigInt{opts.opts.GasPrice} }
|
||||||
|
func (opts *TransactOpts) GetGasLimit() int64 { return opts.opts.GasLimit.Int64() }
|
||||||
|
|
||||||
|
// GetSigner cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876)
|
||||||
|
// func (opts *TransactOpts) GetSigner() Signer { return &signer{opts.opts.Signer} }
|
||||||
|
|
||||||
|
// GetContext cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876)
|
||||||
|
// Even then it's awkward to unpack the subtleties of a Go context out to Java.
|
||||||
|
//func (opts *TransactOpts) GetContext() *Context { return &Context{opts.opts.Context} }
|
||||||
|
|
||||||
|
func (opts *TransactOpts) SetFrom(from *Address) { opts.opts.From = from.address }
|
||||||
|
func (opts *TransactOpts) SetNonce(nonce int64) { opts.opts.Nonce = big.NewInt(nonce) }
|
||||||
|
func (opts *TransactOpts) SetSigner(s Signer) {
|
||||||
|
opts.opts.Signer = func(signer types.Signer, addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||||
|
sig, err := s.Sign(&Address{addr}, &Transaction{tx})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return sig.tx, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (opts *TransactOpts) SetValue(value *BigInt) { opts.opts.Value = value.bigint }
|
||||||
|
func (opts *TransactOpts) SetGasPrice(price *BigInt) { opts.opts.GasPrice = price.bigint }
|
||||||
|
func (opts *TransactOpts) SetGasLimit(limit int64) { opts.opts.GasLimit = big.NewInt(limit) }
|
||||||
|
func (opts *TransactOpts) SetContext(context *Context) { opts.opts.Context = context.context }
|
||||||
|
|
||||||
|
// BoundContract is the base wrapper object that reflects a contract on the
|
||||||
|
// Ethereum network. It contains a collection of methods that are used by the
|
||||||
|
// higher level contract bindings to operate.
|
||||||
|
type BoundContract struct {
|
||||||
|
contract *bind.BoundContract
|
||||||
|
address common.Address
|
||||||
|
deployer *types.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeployContract deploys a contract onto the Ethereum blockchain and binds the
|
||||||
|
// deployment address with a wrapper.
|
||||||
|
func DeployContract(opts *TransactOpts, abiJSON string, bytecode []byte, client *EthereumClient, args *Interfaces) (*BoundContract, error) {
|
||||||
|
// Convert all the deployment parameters to Go types
|
||||||
|
params := make([]interface{}, len(args.objects))
|
||||||
|
for i, obj := range args.objects {
|
||||||
|
params[i] = obj
|
||||||
|
}
|
||||||
|
// Deploy the contract to the network
|
||||||
|
parsed, err := abi.JSON(strings.NewReader(abiJSON))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, bytecode, client.client, params...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BoundContract{
|
||||||
|
contract: bound,
|
||||||
|
address: addr,
|
||||||
|
deployer: tx,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindContract creates a low level contract interface through which calls and
|
||||||
|
// transactions may be made through.
|
||||||
|
func BindContract(address *Address, abiJSON string, client *EthereumClient) (*BoundContract, error) {
|
||||||
|
parsed, err := abi.JSON(strings.NewReader(abiJSON))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BoundContract{
|
||||||
|
contract: bind.NewBoundContract(address.address, parsed, client.client, client.client),
|
||||||
|
address: address.address,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *BoundContract) GetAddress() *Address { return &Address{c.address} }
|
||||||
|
func (c *BoundContract) GetDeployer() *Transaction {
|
||||||
|
if c.deployer == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Transaction{c.deployer}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call invokes the (constant) contract method with params as input values and
|
||||||
|
// sets the output to result.
|
||||||
|
func (c *BoundContract) Call(opts *CallOpts, out *Interfaces, method string, args *Interfaces) error {
|
||||||
|
// Convert all the input and output parameters to Go types
|
||||||
|
params := make([]interface{}, len(args.objects))
|
||||||
|
for i, obj := range args.objects {
|
||||||
|
params[i] = obj
|
||||||
|
}
|
||||||
|
results := make([]interface{}, len(out.objects))
|
||||||
|
for i, obj := range out.objects {
|
||||||
|
results[i] = obj
|
||||||
|
}
|
||||||
|
// Execute the call to the contract and wrap any results
|
||||||
|
if err := c.contract.Call(&opts.opts, &results, method, params...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, res := range results {
|
||||||
|
out.objects[i] = res
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transact invokes the (paid) contract method with params as input values.
|
||||||
|
func (c *BoundContract) Transact(opts *TransactOpts, method string, args *Interfaces) (*Transaction, error) {
|
||||||
|
params := make([]interface{}, len(args.objects))
|
||||||
|
for i, obj := range args.objects {
|
||||||
|
params[i] = obj
|
||||||
|
}
|
||||||
|
tx, err := c.contract.Transact(&opts.opts, method, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Transaction{tx}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||||
|
// its default method if one is available.
|
||||||
|
func (c *BoundContract) Transfer(opts *TransactOpts) (*Transaction, error) {
|
||||||
|
tx, err := c.contract.Transfer(&opts.opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Transaction{tx}, nil
|
||||||
|
}
|
187
mobile/common.go
Normal file
187
mobile/common.go
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the common package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
||||||
|
type Hash struct {
|
||||||
|
hash common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHashFromBytes converts a slice of bytes to a hash value.
|
||||||
|
func NewHashFromBytes(hash []byte) (*Hash, error) {
|
||||||
|
h := new(Hash)
|
||||||
|
if err := h.SetBytes(hash); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHashFromHex converts a hex string to a hash value.
|
||||||
|
func NewHashFromHex(hash string) (*Hash, error) {
|
||||||
|
h := new(Hash)
|
||||||
|
if err := h.SetHex(hash); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBytes sets the specified slice of bytes as the hash value.
|
||||||
|
func (h *Hash) SetBytes(hash []byte) error {
|
||||||
|
if length := len(hash); length != common.HashLength {
|
||||||
|
return fmt.Errorf("invalid hash length: %v != %v", length, common.HashLength)
|
||||||
|
}
|
||||||
|
copy(h.hash[:], hash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes retrieves the byte representation of the hash.
|
||||||
|
func (h *Hash) GetBytes() []byte {
|
||||||
|
return h.hash[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHex sets the specified hex string as the hash value.
|
||||||
|
func (h *Hash) SetHex(hash string) error {
|
||||||
|
hash = strings.ToLower(hash)
|
||||||
|
if len(hash) >= 2 && hash[:2] == "0x" {
|
||||||
|
hash = hash[2:]
|
||||||
|
}
|
||||||
|
if length := len(hash); length != 2*common.HashLength {
|
||||||
|
return fmt.Errorf("invalid hash hex length: %v != %v", length, 2*common.HashLength)
|
||||||
|
}
|
||||||
|
bin, err := hex.DecodeString(hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
copy(h.hash[:], bin)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHex retrieves the hex string representation of the hash.
|
||||||
|
func (h *Hash) GetHex() string {
|
||||||
|
return h.hash.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hashes represents a slice of hashes.
|
||||||
|
type Hashes struct{ hashes []common.Hash }
|
||||||
|
|
||||||
|
// Size returns the number of hashes in the slice.
|
||||||
|
func (h *Hashes) Size() int {
|
||||||
|
return len(h.hashes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the hash at the given index from the slice.
|
||||||
|
func (h *Hashes) Get(index int) (*Hash, error) {
|
||||||
|
if index < 0 || index >= len(h.hashes) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Hash{h.hashes[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address represents the 20 byte address of an Ethereum account.
|
||||||
|
type Address struct {
|
||||||
|
address common.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAddressFromBytes converts a slice of bytes to a hash value.
|
||||||
|
func NewAddressFromBytes(address []byte) (*Address, error) {
|
||||||
|
a := new(Address)
|
||||||
|
if err := a.SetBytes(address); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAddressFromHex converts a hex string to a address value.
|
||||||
|
func NewAddressFromHex(address string) (*Address, error) {
|
||||||
|
a := new(Address)
|
||||||
|
if err := a.SetHex(address); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBytes sets the specified slice of bytes as the address value.
|
||||||
|
func (a *Address) SetBytes(address []byte) error {
|
||||||
|
if length := len(address); length != common.AddressLength {
|
||||||
|
return fmt.Errorf("invalid address length: %v != %v", length, common.AddressLength)
|
||||||
|
}
|
||||||
|
copy(a.address[:], address)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes retrieves the byte representation of the address.
|
||||||
|
func (a *Address) GetBytes() []byte {
|
||||||
|
return a.address[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHex sets the specified hex string as the address value.
|
||||||
|
func (a *Address) SetHex(address string) error {
|
||||||
|
address = strings.ToLower(address)
|
||||||
|
if len(address) >= 2 && address[:2] == "0x" {
|
||||||
|
address = address[2:]
|
||||||
|
}
|
||||||
|
if length := len(address); length != 2*common.AddressLength {
|
||||||
|
return fmt.Errorf("invalid address hex length: %v != %v", length, 2*common.AddressLength)
|
||||||
|
}
|
||||||
|
bin, err := hex.DecodeString(address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
copy(a.address[:], bin)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHex retrieves the hex string representation of the address.
|
||||||
|
func (a *Address) GetHex() string {
|
||||||
|
return a.address.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addresses represents a slice of addresses.
|
||||||
|
type Addresses struct{ addresses []common.Address }
|
||||||
|
|
||||||
|
// Size returns the number of addresses in the slice.
|
||||||
|
func (a *Addresses) Size() int {
|
||||||
|
return len(a.addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the address at the given index from the slice.
|
||||||
|
func (a *Addresses) Get(index int) (*Address, error) {
|
||||||
|
if index < 0 || index >= len(a.addresses) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Address{a.addresses[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the address at the given index in the slice.
|
||||||
|
func (a *Addresses) Set(index int, address *Address) error {
|
||||||
|
if index < 0 || index >= len(a.addresses) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
a.addresses[index] = address.address
|
||||||
|
return nil
|
||||||
|
}
|
81
mobile/context.go
Normal file
81
mobile/context.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the golang.org/x/net/context package to support
|
||||||
|
// client side context management on mobile platforms.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Context carries a deadline, a cancelation signal, and other values across API
|
||||||
|
// boundaries.
|
||||||
|
type Context struct {
|
||||||
|
context context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContext returns a non-nil, empty Context. It is never canceled, has no
|
||||||
|
// values, and has no deadline. It is typically used by the main function,
|
||||||
|
// initialization, and tests, and as the top-level Context for incoming requests.
|
||||||
|
func NewContext() *Context {
|
||||||
|
return &Context{
|
||||||
|
context: context.Background(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCancel returns a copy of the original context with cancellation mechanism
|
||||||
|
// included.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func (c *Context) WithCancel() *Context {
|
||||||
|
child, cancel := context.WithCancel(c.context)
|
||||||
|
return &Context{
|
||||||
|
context: child,
|
||||||
|
cancel: cancel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDeadline returns a copy of the original context with the deadline adjusted
|
||||||
|
// to be no later than the specified time.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func (c *Context) WithDeadline(sec int64, nsec int64) *Context {
|
||||||
|
child, cancel := context.WithDeadline(c.context, time.Unix(sec, nsec))
|
||||||
|
return &Context{
|
||||||
|
context: child,
|
||||||
|
cancel: cancel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout returns a copy of the original context with the deadline adjusted
|
||||||
|
// to be no later than now + the duration specified.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func (c *Context) WithTimeout(nsec int64) *Context {
|
||||||
|
child, cancel := context.WithTimeout(c.context, time.Duration(nsec))
|
||||||
|
return &Context{
|
||||||
|
context: child,
|
||||||
|
cancel: cancel,
|
||||||
|
}
|
||||||
|
}
|
104
mobile/discover.go
Normal file
104
mobile/discover.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the accounts package to support client side enode
|
||||||
|
// management on mobile platforms.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enode represents a host on the network.
|
||||||
|
type Enode struct {
|
||||||
|
node *discv5.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEnode parses a node designator.
|
||||||
|
//
|
||||||
|
// There are two basic forms of node designators
|
||||||
|
// - incomplete nodes, which only have the public key (node ID)
|
||||||
|
// - complete nodes, which contain the public key and IP/Port information
|
||||||
|
//
|
||||||
|
// For incomplete nodes, the designator must look like one of these
|
||||||
|
//
|
||||||
|
// enode://<hex node id>
|
||||||
|
// <hex node id>
|
||||||
|
//
|
||||||
|
// For complete nodes, the node ID is encoded in the username portion
|
||||||
|
// of the URL, separated from the host by an @ sign. The hostname can
|
||||||
|
// only be given as an IP address, DNS domain names are not allowed.
|
||||||
|
// The port in the host name section is the TCP listening port. If the
|
||||||
|
// TCP and UDP (discovery) ports differ, the UDP port is specified as
|
||||||
|
// query parameter "discport".
|
||||||
|
//
|
||||||
|
// In the following example, the node URL describes
|
||||||
|
// a node with IP address 10.3.58.6, TCP listening port 30303
|
||||||
|
// and UDP discovery port 30301.
|
||||||
|
//
|
||||||
|
// enode://<hex node id>@10.3.58.6:30303?discport=30301
|
||||||
|
func NewEnode(rawurl string) (*Enode, error) {
|
||||||
|
node, err := discv5.ParseNode(rawurl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Enode{node}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enodes represents a slice of accounts.
|
||||||
|
type Enodes struct{ nodes []*discv5.Node }
|
||||||
|
|
||||||
|
// NewEnodes creates a slice of uninitialized enodes.
|
||||||
|
func NewEnodes(size int) *Enodes {
|
||||||
|
return &Enodes{
|
||||||
|
nodes: make([]*discv5.Node, size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEnodesEmpty creates an empty slice of Enode values.
|
||||||
|
func NewEnodesEmpty() *Enodes {
|
||||||
|
return NewEnodes(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the number of enodes in the slice.
|
||||||
|
func (e *Enodes) Size() int {
|
||||||
|
return len(e.nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the enode at the given index from the slice.
|
||||||
|
func (e *Enodes) Get(index int) (*Enode, error) {
|
||||||
|
if index < 0 || index >= len(e.nodes) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Enode{e.nodes[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the enode at the given index in the slice.
|
||||||
|
func (e *Enodes) Set(index int, enode *Enode) error {
|
||||||
|
if index < 0 || index >= len(e.nodes) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
e.nodes[index] = enode.node
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append adds a new enode element to the end of the slice.
|
||||||
|
func (e *Enodes) Append(enode *Enode) {
|
||||||
|
e.nodes = append(e.nodes, enode.node)
|
||||||
|
}
|
57
mobile/doc.go
Normal file
57
mobile/doc.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Package geth contains the simplified mobile APIs to go-ethereum.
|
||||||
|
//
|
||||||
|
// The scope of this package is *not* to allow writing a custom Ethereun client
|
||||||
|
// with pieces plucked from go-ethereum, rather to allow writing native dapps on
|
||||||
|
// mobile platforms. Keep this in mind when using or extending this package!
|
||||||
|
//
|
||||||
|
// API limitations
|
||||||
|
//
|
||||||
|
// Since gomobile cannot bridge arbitrary types between Go and Android/iOS, the
|
||||||
|
// exposed APIs need to be manually wrapped into simplified types, with custom
|
||||||
|
// constructors and getters/setters to ensure that they can be meaninfully used
|
||||||
|
// from Java/ObjC too.
|
||||||
|
//
|
||||||
|
// With this in mind, please try to limit the scope of this package and only add
|
||||||
|
// essentials without which mobile support cannot work, especially since manually
|
||||||
|
// syncing the code will be unwieldy otherwise. In the long term we might consider
|
||||||
|
// writing custom library generators, but those are out of scope now.
|
||||||
|
//
|
||||||
|
// Content wise each file in this package corresponds to an entire Go package
|
||||||
|
// from the go-ethereum repository. Please adhere to this scoping to prevent this
|
||||||
|
// package getting unmaintainable.
|
||||||
|
//
|
||||||
|
// Wrapping guidelines:
|
||||||
|
//
|
||||||
|
// Every type that is to be exposed should be wrapped into its own plain struct,
|
||||||
|
// which internally contains a single field: the original go-ethereum version.
|
||||||
|
// This is needed because gomobile cannot expose named types for now.
|
||||||
|
//
|
||||||
|
// Whenever a method argument or a return type is a custom struct, the pointer
|
||||||
|
// variant should always be used as value types crossing over between language
|
||||||
|
// boundaries might have strange behaviors.
|
||||||
|
//
|
||||||
|
// Slices of types should be converted into a single multiplicative type wrapping
|
||||||
|
// a go slice with the methods `Size`, `Get` and `Set`. Further slice operations
|
||||||
|
// should not be provided to limit the remote code complexity. Arrays should be
|
||||||
|
// avoided as much as possible since they complicate bounds checking.
|
||||||
|
//
|
||||||
|
// Note, a panic *cannot* cross over language boundaries, instead will result in
|
||||||
|
// an undebuggable SEGFAULT in the process. For error handling only ever use error
|
||||||
|
// returns, which may be the only or the second return.
|
||||||
|
package geth
|
305
mobile/ethclient.go
Normal file
305
mobile/ethclient.go
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains a wrapper for the Ethereum client.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EthereumClient provides access to the Ethereum APIs.
|
||||||
|
type EthereumClient struct {
|
||||||
|
client *ethclient.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEthereumClient connects a client to the given URL.
|
||||||
|
func NewEthereumClient(rawurl string) (*EthereumClient, error) {
|
||||||
|
client, err := ethclient.Dial(rawurl)
|
||||||
|
return &EthereumClient{client}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockByHash returns the given full block.
|
||||||
|
func (ec *EthereumClient) GetBlockByHash(ctx *Context, hash *Hash) (*Block, error) {
|
||||||
|
block, err := ec.client.BlockByHash(ctx.context, hash.hash)
|
||||||
|
return &Block{block}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockByNumber returns a block from the current canonical chain. If number is <0, the
|
||||||
|
// latest known block is returned.
|
||||||
|
func (ec *EthereumClient) GetBlockByNumber(ctx *Context, number int64) (*Block, error) {
|
||||||
|
if number < 0 {
|
||||||
|
block, err := ec.client.BlockByNumber(ctx.context, nil)
|
||||||
|
return &Block{block}, err
|
||||||
|
}
|
||||||
|
block, err := ec.client.BlockByNumber(ctx.context, big.NewInt(number))
|
||||||
|
return &Block{block}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeaderByHash returns the block header with the given hash.
|
||||||
|
func (ec *EthereumClient) GetHeaderByHash(ctx *Context, hash *Hash) (*Header, error) {
|
||||||
|
header, err := ec.client.HeaderByHash(ctx.context, hash.hash)
|
||||||
|
return &Header{header}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeaderByNumber returns a block header from the current canonical chain. If number is <0,
|
||||||
|
// the latest known header is returned.
|
||||||
|
func (ec *EthereumClient) GetHeaderByNumber(ctx *Context, number int64) (*Header, error) {
|
||||||
|
if number < 0 {
|
||||||
|
header, err := ec.client.HeaderByNumber(ctx.context, nil)
|
||||||
|
return &Header{header}, err
|
||||||
|
}
|
||||||
|
header, err := ec.client.HeaderByNumber(ctx.context, big.NewInt(number))
|
||||||
|
return &Header{header}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionByHash returns the transaction with the given hash.
|
||||||
|
func (ec *EthereumClient) GetTransactionByHash(ctx *Context, hash *Hash) (*Transaction, error) {
|
||||||
|
tx, err := ec.client.TransactionByHash(ctx.context, hash.hash)
|
||||||
|
return &Transaction{tx}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionCount returns the total number of transactions in the given block.
|
||||||
|
func (ec *EthereumClient) GetTransactionCount(ctx *Context, hash *Hash) (int, error) {
|
||||||
|
count, err := ec.client.TransactionCount(ctx.context, hash.hash)
|
||||||
|
return int(count), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionInBlock returns a single transaction at index in the given block.
|
||||||
|
func (ec *EthereumClient) GetTransactionInBlock(ctx *Context, hash *Hash, index int) (*Transaction, error) {
|
||||||
|
tx, err := ec.client.TransactionInBlock(ctx.context, hash.hash, uint(index))
|
||||||
|
return &Transaction{tx}, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransactionReceipt returns the receipt of a transaction by transaction hash.
|
||||||
|
// Note that the receipt is not available for pending transactions.
|
||||||
|
func (ec *EthereumClient) GetTransactionReceipt(ctx *Context, hash *Hash) (*Receipt, error) {
|
||||||
|
receipt, err := ec.client.TransactionReceipt(ctx.context, hash.hash)
|
||||||
|
return &Receipt{receipt}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyncProgress retrieves the current progress of the sync algorithm. If there's
|
||||||
|
// no sync currently running, it returns nil.
|
||||||
|
func (ec *EthereumClient) SyncProgress(ctx *Context) (*SyncProgress, error) {
|
||||||
|
progress, err := ec.client.SyncProgress(ctx.context)
|
||||||
|
if progress == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &SyncProgress{*progress}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHeadHandler is a client-side subscription callback to invoke on events and
|
||||||
|
// subscription failure.
|
||||||
|
type NewHeadHandler interface {
|
||||||
|
OnNewHead(header *Header)
|
||||||
|
OnError(failure string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeNewHead subscribes to notifications about the current blockchain head
|
||||||
|
// on the given channel.
|
||||||
|
func (ec *EthereumClient) SubscribeNewHead(ctx *Context, handler NewHeadHandler, buffer int) (*Subscription, error) {
|
||||||
|
// Subscribe to the event internally
|
||||||
|
ch := make(chan *types.Header, buffer)
|
||||||
|
sub, err := ec.client.SubscribeNewHead(ctx.context, ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Start up a dispatcher to feed into the callback
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case header := <-ch:
|
||||||
|
handler.OnNewHead(&Header{header})
|
||||||
|
|
||||||
|
case err := <-sub.Err():
|
||||||
|
handler.OnError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return &Subscription{sub}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// State Access
|
||||||
|
|
||||||
|
// GetBalanceAt returns the wei balance of the given account.
|
||||||
|
// The block number can be <0, in which case the balance is taken from the latest known block.
|
||||||
|
func (ec *EthereumClient) GetBalanceAt(ctx *Context, account *Address, number int64) (*BigInt, error) {
|
||||||
|
if number < 0 {
|
||||||
|
balance, err := ec.client.BalanceAt(ctx.context, account.address, nil)
|
||||||
|
return &BigInt{balance}, err
|
||||||
|
}
|
||||||
|
balance, err := ec.client.BalanceAt(ctx.context, account.address, big.NewInt(number))
|
||||||
|
return &BigInt{balance}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStorageAt returns the value of key in the contract storage of the given account.
|
||||||
|
// The block number can be <0, in which case the value is taken from the latest known block.
|
||||||
|
func (ec *EthereumClient) GetStorageAt(ctx *Context, account *Address, key *Hash, number int64) ([]byte, error) {
|
||||||
|
if number < 0 {
|
||||||
|
return ec.client.StorageAt(ctx.context, account.address, key.hash, nil)
|
||||||
|
}
|
||||||
|
return ec.client.StorageAt(ctx.context, account.address, key.hash, big.NewInt(number))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCodeAt returns the contract code of the given account.
|
||||||
|
// The block number can be <0, in which case the code is taken from the latest known block.
|
||||||
|
func (ec *EthereumClient) GetCodeAt(ctx *Context, account *Address, number int64) ([]byte, error) {
|
||||||
|
if number < 0 {
|
||||||
|
return ec.client.CodeAt(ctx.context, account.address, nil)
|
||||||
|
}
|
||||||
|
return ec.client.CodeAt(ctx.context, account.address, big.NewInt(number))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNonceAt returns the account nonce of the given account.
|
||||||
|
// The block number can be <0, in which case the nonce is taken from the latest known block.
|
||||||
|
func (ec *EthereumClient) GetNonceAt(ctx *Context, account *Address, number int64) (int64, error) {
|
||||||
|
if number < 0 {
|
||||||
|
nonce, err := ec.client.NonceAt(ctx.context, account.address, nil)
|
||||||
|
return int64(nonce), err
|
||||||
|
}
|
||||||
|
nonce, err := ec.client.NonceAt(ctx.context, account.address, big.NewInt(number))
|
||||||
|
return int64(nonce), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filters
|
||||||
|
|
||||||
|
// FilterLogs executes a filter query.
|
||||||
|
func (ec *EthereumClient) FilterLogs(ctx *Context, query *FilterQuery) (*Logs, error) {
|
||||||
|
logs, err := ec.client.FilterLogs(ctx.context, query.query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Temp hack due to vm.Logs being []*vm.Log
|
||||||
|
res := make(vm.Logs, len(logs))
|
||||||
|
for i, log := range logs {
|
||||||
|
res[i] = &log
|
||||||
|
}
|
||||||
|
return &Logs{res}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterLogsHandler is a client-side subscription callback to invoke on events and
|
||||||
|
// subscription failure.
|
||||||
|
type FilterLogsHandler interface {
|
||||||
|
OnFilterLogs(log *Log)
|
||||||
|
OnError(failure string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeFilterLogs subscribes to the results of a streaming filter query.
|
||||||
|
func (ec *EthereumClient) SubscribeFilterLogs(ctx *Context, query *FilterQuery, handler FilterLogsHandler, buffer int) (*Subscription, error) {
|
||||||
|
// Subscribe to the event internally
|
||||||
|
ch := make(chan vm.Log, buffer)
|
||||||
|
sub, err := ec.client.SubscribeFilterLogs(ctx.context, query.query, ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Start up a dispatcher to feed into the callback
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case log := <-ch:
|
||||||
|
handler.OnFilterLogs(&Log{&log})
|
||||||
|
|
||||||
|
case err := <-sub.Err():
|
||||||
|
handler.OnError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return &Subscription{sub}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pending State
|
||||||
|
|
||||||
|
// GetPendingBalanceAt returns the wei balance of the given account in the pending state.
|
||||||
|
func (ec *EthereumClient) GetPendingBalanceAt(ctx *Context, account *Address) (*BigInt, error) {
|
||||||
|
balance, err := ec.client.PendingBalanceAt(ctx.context, account.address)
|
||||||
|
return &BigInt{balance}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingStorageAt returns the value of key in the contract storage of the given account in the pending state.
|
||||||
|
func (ec *EthereumClient) GetPendingStorageAt(ctx *Context, account *Address, key *Hash) ([]byte, error) {
|
||||||
|
return ec.client.PendingStorageAt(ctx.context, account.address, key.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingCodeAt returns the contract code of the given account in the pending state.
|
||||||
|
func (ec *EthereumClient) GetPendingCodeAt(ctx *Context, account *Address) ([]byte, error) {
|
||||||
|
return ec.client.PendingCodeAt(ctx.context, account.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingNonceAt returns the account nonce of the given account in the pending state.
|
||||||
|
// This is the nonce that should be used for the next transaction.
|
||||||
|
func (ec *EthereumClient) GetPendingNonceAt(ctx *Context, account *Address) (int64, error) {
|
||||||
|
nonce, err := ec.client.PendingNonceAt(ctx.context, account.address)
|
||||||
|
return int64(nonce), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingTransactionCount returns the total number of transactions in the pending state.
|
||||||
|
func (ec *EthereumClient) GetPendingTransactionCount(ctx *Context) (int, error) {
|
||||||
|
count, err := ec.client.PendingTransactionCount(ctx.context)
|
||||||
|
return int(count), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contract Calling
|
||||||
|
|
||||||
|
// CallContract executes a message call transaction, which is directly executed in the VM
|
||||||
|
// of the node, but never mined into the blockchain.
|
||||||
|
//
|
||||||
|
// blockNumber selects the block height at which the call runs. It can be <0, in which
|
||||||
|
// case the code is taken from the latest known block. Note that state from very old
|
||||||
|
// blocks might not be available.
|
||||||
|
func (ec *EthereumClient) CallContract(ctx *Context, msg *CallMsg, number int64) ([]byte, error) {
|
||||||
|
if number < 0 {
|
||||||
|
return ec.client.CallContract(ctx.context, msg.msg, nil)
|
||||||
|
}
|
||||||
|
return ec.client.CallContract(ctx.context, msg.msg, big.NewInt(number))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PendingCallContract executes a message call transaction using the EVM.
|
||||||
|
// The state seen by the contract call is the pending state.
|
||||||
|
func (ec *EthereumClient) PendingCallContract(ctx *Context, msg *CallMsg) ([]byte, error) {
|
||||||
|
return ec.client.PendingCallContract(ctx.context, msg.msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
||||||
|
// execution of a transaction.
|
||||||
|
func (ec *EthereumClient) SuggestGasPrice(ctx *Context) (*BigInt, error) {
|
||||||
|
price, err := ec.client.SuggestGasPrice(ctx.context)
|
||||||
|
return &BigInt{price}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EstimateGas tries to estimate the gas needed to execute a specific transaction based on
|
||||||
|
// the current pending state of the backend blockchain. There is no guarantee that this is
|
||||||
|
// the true gas limit requirement as other transactions may be added or removed by miners,
|
||||||
|
// but it should provide a basis for setting a reasonable default.
|
||||||
|
func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (*BigInt, error) {
|
||||||
|
price, err := ec.client.EstimateGas(ctx.context, msg.msg)
|
||||||
|
return &BigInt{price}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendTransaction injects a signed transaction into the pending pool for execution.
|
||||||
|
//
|
||||||
|
// If the transaction was a contract creation use the TransactionReceipt method to get the
|
||||||
|
// contract address after the transaction has been mined.
|
||||||
|
func (ec *EthereumClient) SendTransaction(ctx *Context, tx *Transaction) error {
|
||||||
|
return ec.client.SendTransaction(ctx.context, tx.tx)
|
||||||
|
}
|
125
mobile/ethereum.go
Normal file
125
mobile/ethereum.go
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the go-ethereum root package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Subscription represents an event subscription where events are
|
||||||
|
// delivered on a data channel.
|
||||||
|
type Subscription struct {
|
||||||
|
sub ethereum.Subscription
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsubscribe cancels the sending of events to the data channel
|
||||||
|
// and closes the error channel.
|
||||||
|
func (s *Subscription) Unsubscribe() {
|
||||||
|
s.sub.Unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallMsg contains parameters for contract calls.
|
||||||
|
type CallMsg struct {
|
||||||
|
msg ethereum.CallMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCallMsg creates an empty contract call parameter list.
|
||||||
|
func NewCallMsg() *CallMsg {
|
||||||
|
return new(CallMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *CallMsg) GetFrom() *Address { return &Address{msg.msg.From} }
|
||||||
|
func (msg *CallMsg) GetGas() int64 { return msg.msg.Gas.Int64() }
|
||||||
|
func (msg *CallMsg) GetGasPrice() *BigInt { return &BigInt{msg.msg.GasPrice} }
|
||||||
|
func (msg *CallMsg) GetValue() *BigInt { return &BigInt{msg.msg.Value} }
|
||||||
|
func (msg *CallMsg) GetData() []byte { return msg.msg.Data }
|
||||||
|
func (msg *CallMsg) GetTo() *Address {
|
||||||
|
if to := msg.msg.To; to != nil {
|
||||||
|
return &Address{*msg.msg.To}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (msg *CallMsg) SetFrom(address *Address) { msg.msg.From = address.address }
|
||||||
|
func (msg *CallMsg) SetGas(gas int64) { msg.msg.Gas = big.NewInt(gas) }
|
||||||
|
func (msg *CallMsg) SetGasPrice(price *BigInt) { msg.msg.GasPrice = price.bigint }
|
||||||
|
func (msg *CallMsg) SetValue(value *BigInt) { msg.msg.Value = value.bigint }
|
||||||
|
func (msg *CallMsg) SetData(data []byte) { msg.msg.Data = data }
|
||||||
|
func (msg *CallMsg) SetTo(address *Address) {
|
||||||
|
if address == nil {
|
||||||
|
msg.msg.To = nil
|
||||||
|
}
|
||||||
|
msg.msg.To = &address.address
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyncProgress gives progress indications when the node is synchronising with
|
||||||
|
// the Ethereum network.
|
||||||
|
type SyncProgress struct {
|
||||||
|
progress ethereum.SyncProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SyncProgress) GetStartingBlock() int64 { return int64(p.progress.StartingBlock) }
|
||||||
|
func (p *SyncProgress) GetCurrentBlock() int64 { return int64(p.progress.CurrentBlock) }
|
||||||
|
func (p *SyncProgress) GetHighestBlock() int64 { return int64(p.progress.HighestBlock) }
|
||||||
|
func (p *SyncProgress) GetPulledStates() int64 { return int64(p.progress.PulledStates) }
|
||||||
|
func (p *SyncProgress) GetKnownStates() int64 { return int64(p.progress.KnownStates) }
|
||||||
|
|
||||||
|
// Topics is a set of topic lists to filter events with.
|
||||||
|
type Topics struct{ topics [][]common.Hash }
|
||||||
|
|
||||||
|
// Size returns the number of topic lists inside the set
|
||||||
|
func (t *Topics) Size() int {
|
||||||
|
return len(t.topics)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the topic list at the given index from the slice.
|
||||||
|
func (t *Topics) Get(index int) (*Hashes, error) {
|
||||||
|
if index < 0 || index >= len(t.topics) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Hashes{t.topics[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the topic list at the given index in the slice.
|
||||||
|
func (t *Topics) Set(index int, topics *Hashes) error {
|
||||||
|
if index < 0 || index >= len(t.topics) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
t.topics[index] = topics.hashes
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FilterQuery contains options for contact log filtering.
|
||||||
|
type FilterQuery struct {
|
||||||
|
query ethereum.FilterQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFilterQuery creates an empty filter query for contact log filtering.
|
||||||
|
func NewFilterQuery() *FilterQuery {
|
||||||
|
return new(FilterQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fq *FilterQuery) GetFromBlock() *BigInt { return &BigInt{fq.query.FromBlock} }
|
||||||
|
func (fq *FilterQuery) GetToBlock() *BigInt { return &BigInt{fq.query.ToBlock} }
|
||||||
|
func (fq *FilterQuery) GetAddresses() *Addresses { return &Addresses{fq.query.Addresses} }
|
||||||
|
func (fq *FilterQuery) GetTopics() *Topics { return &Topics{fq.query.Topics} }
|
200
mobile/geth.go
Normal file
200
mobile/geth.go
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the node package to support client side node
|
||||||
|
// management on mobile platforms.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
"github.com/ethereum/go-ethereum/les"
|
||||||
|
"github.com/ethereum/go-ethereum/light"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/whisper/whisperv2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeConfig represents the collection of configuration values to fine tune the Geth
|
||||||
|
// node embedded into a mobile process. The available values are a subset of the
|
||||||
|
// entire API provided by go-ethereum to reduce the maintenance surface and dev
|
||||||
|
// complexity.
|
||||||
|
type NodeConfig struct {
|
||||||
|
// Bootstrap nodes used to establish connectivity with the rest of the network.
|
||||||
|
BootstrapNodes *Enodes
|
||||||
|
|
||||||
|
// MaxPeers is the maximum number of peers that can be connected. If this is
|
||||||
|
// set to zero, then only the configured static and trusted peers can connect.
|
||||||
|
MaxPeers int
|
||||||
|
|
||||||
|
// EthereumEnabled specifies whether the node should run the Ethereum protocol.
|
||||||
|
EthereumEnabled bool
|
||||||
|
|
||||||
|
// EthereumNetworkID is the network identifier used by the Ethereum protocol to
|
||||||
|
// decide if remote peers should be accepted or not.
|
||||||
|
EthereumNetworkID int
|
||||||
|
|
||||||
|
// EthereumChainConfig is the default parameters of the blockchain to use. If no
|
||||||
|
// configuration is specified, it defaults to the main network.
|
||||||
|
EthereumChainConfig *ChainConfig
|
||||||
|
|
||||||
|
// EthereumGenesis is the genesis JSON to use to seed the blockchain with. An
|
||||||
|
// empty genesis state is equivalent to using the mainnet's state.
|
||||||
|
EthereumGenesis string
|
||||||
|
|
||||||
|
// EthereumTestnetNonces specifies whether to use account nonces from the testnet
|
||||||
|
// range (2^20) or from the mainnet one (0).
|
||||||
|
EthereumTestnetNonces bool
|
||||||
|
|
||||||
|
// EthereumDatabaseCache is the system memory in MB to allocate for database caching.
|
||||||
|
// A minimum of 16MB is always reserved.
|
||||||
|
EthereumDatabaseCache int
|
||||||
|
|
||||||
|
// WhisperEnabled specifies whether the node should run the Whisper protocol.
|
||||||
|
WhisperEnabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultNodeConfig contains the default node configuration values to use if all
|
||||||
|
// or some fields are missing from the user's specified list.
|
||||||
|
var defaultNodeConfig = &NodeConfig{
|
||||||
|
BootstrapNodes: FoundationBootnodes(),
|
||||||
|
MaxPeers: 25,
|
||||||
|
EthereumEnabled: true,
|
||||||
|
EthereumNetworkID: 1,
|
||||||
|
EthereumChainConfig: MainnetChainConfig(),
|
||||||
|
EthereumDatabaseCache: 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNodeConfig creates a new node option set, initialized to the default values.
|
||||||
|
func NewNodeConfig() *NodeConfig {
|
||||||
|
config := *defaultNodeConfig
|
||||||
|
return &config
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node represents a Geth Ethereum node instance.
|
||||||
|
type Node struct {
|
||||||
|
node *node.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNode creates and configures a new Geth node.
|
||||||
|
func NewNode(datadir string, config *NodeConfig) (*Node, error) {
|
||||||
|
// If no or partial configurations were specified, use defaults
|
||||||
|
if config == nil {
|
||||||
|
config = NewNodeConfig()
|
||||||
|
}
|
||||||
|
if config.MaxPeers == 0 {
|
||||||
|
config.MaxPeers = defaultNodeConfig.MaxPeers
|
||||||
|
}
|
||||||
|
if config.BootstrapNodes == nil || config.BootstrapNodes.Size() == 0 {
|
||||||
|
config.BootstrapNodes = defaultNodeConfig.BootstrapNodes
|
||||||
|
}
|
||||||
|
// Create the empty networking stack
|
||||||
|
nodeConf := &node.Config{
|
||||||
|
Name: clientIdentifier,
|
||||||
|
DataDir: datadir,
|
||||||
|
KeyStoreDir: filepath.Join(datadir, "keystore"), // Mobile should never use internal keystores!
|
||||||
|
NoDiscovery: true,
|
||||||
|
DiscoveryV5: true,
|
||||||
|
DiscoveryV5Addr: ":0",
|
||||||
|
BootstrapNodesV5: config.BootstrapNodes.nodes,
|
||||||
|
ListenAddr: ":0",
|
||||||
|
NAT: nat.Any(),
|
||||||
|
MaxPeers: config.MaxPeers,
|
||||||
|
}
|
||||||
|
stack, err := node.New(nodeConf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Register the Ethereum protocol if requested
|
||||||
|
if config.EthereumEnabled {
|
||||||
|
ethConf := ð.Config{
|
||||||
|
ChainConfig: ¶ms.ChainConfig{
|
||||||
|
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
|
||||||
|
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
|
||||||
|
DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
|
||||||
|
EIP150Block: big.NewInt(config.EthereumChainConfig.EIP150Block),
|
||||||
|
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
|
||||||
|
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
|
||||||
|
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
|
||||||
|
},
|
||||||
|
Genesis: config.EthereumGenesis,
|
||||||
|
LightMode: true,
|
||||||
|
DatabaseCache: config.EthereumDatabaseCache,
|
||||||
|
NetworkId: config.EthereumNetworkID,
|
||||||
|
GasPrice: new(big.Int).Mul(big.NewInt(20), common.Shannon),
|
||||||
|
GpoMinGasPrice: new(big.Int).Mul(big.NewInt(20), common.Shannon),
|
||||||
|
GpoMaxGasPrice: new(big.Int).Mul(big.NewInt(500), common.Shannon),
|
||||||
|
GpoFullBlockRatio: 80,
|
||||||
|
GpobaseStepDown: 10,
|
||||||
|
GpobaseStepUp: 100,
|
||||||
|
GpobaseCorrectionFactor: 110,
|
||||||
|
}
|
||||||
|
if config.EthereumTestnetNonces {
|
||||||
|
state.StartingNonce = 1048576 // (2**20)
|
||||||
|
light.StartingNonce = 1048576 // (2**20)
|
||||||
|
}
|
||||||
|
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
|
return les.New(ctx, ethConf)
|
||||||
|
}); err != nil {
|
||||||
|
return nil, fmt.Errorf("ethereum init: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Register the Whisper protocol if requested
|
||||||
|
if config.WhisperEnabled {
|
||||||
|
if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisperv2.New(), nil }); err != nil {
|
||||||
|
return nil, fmt.Errorf("whisper init: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Node{stack}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start creates a live P2P node and starts running it.
|
||||||
|
func (n *Node) Start() error {
|
||||||
|
return n.node.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop terminates a running node along with all it's services. In the node was
|
||||||
|
// not started, an error is returned.
|
||||||
|
func (n *Node) Stop() error {
|
||||||
|
return n.node.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEthereumClient retrieves a client to access the Ethereum subsystem.
|
||||||
|
func (n *Node) GetEthereumClient() (*EthereumClient, error) {
|
||||||
|
rpc, err := n.node.Attach()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &EthereumClient{ethclient.NewClient(rpc)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodeInfo gathers and returns a collection of metadata known about the host.
|
||||||
|
func (n *Node) GetNodeInfo() *NodeInfo {
|
||||||
|
return &NodeInfo{n.node.Server().NodeInfo()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPeersInfo returns an array of metadata objects describing connected peers.
|
||||||
|
func (n *Node) GetPeersInfo() *PeerInfos {
|
||||||
|
return &PeerInfos{n.node.Server().PeersInfo()}
|
||||||
|
}
|
22
mobile/geth_android.go
Normal file
22
mobile/geth_android.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// +build android
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
// clientIdentifier is a hard coded identifier to report into the network.
|
||||||
|
var clientIdentifier = "GethDroid"
|
22
mobile/geth_ios.go
Normal file
22
mobile/geth_ios.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// +build ios
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
// clientIdentifier is a hard coded identifier to report into the network.
|
||||||
|
var clientIdentifier = "iGeth"
|
22
mobile/geth_other.go
Normal file
22
mobile/geth_other.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// +build !android,!ios
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
// clientIdentifier is a hard coded identifier to report into the network.
|
||||||
|
var clientIdentifier = "GethMobile"
|
35
mobile/init.go
Normal file
35
mobile/init.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains initialization code for the mbile library.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Initialize the logger
|
||||||
|
glog.SetV(logger.Info)
|
||||||
|
glog.SetToStderr(true)
|
||||||
|
|
||||||
|
// Initialize the goroutine count
|
||||||
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
}
|
148
mobile/interface.go
Normal file
148
mobile/interface.go
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains perverted wrappers to allow crossing over empty interfaces.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface represents a wrapped version of Go's interface{}, with the capacity
|
||||||
|
// to store arbitrary data types.
|
||||||
|
//
|
||||||
|
// Since it's impossible to get the arbitrary-ness converted between Go and mobile
|
||||||
|
// platforms, we're using explicit getters and setters for the conversions. There
|
||||||
|
// is of course no point in enumerating everything, just enough to support the
|
||||||
|
// contract bindins requiring client side generated code.
|
||||||
|
type Interface struct {
|
||||||
|
object interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInterface creates a new empty interface that can be used to pass around
|
||||||
|
// generic types.
|
||||||
|
func NewInterface() *Interface {
|
||||||
|
return new(Interface)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Interface) SetBool(b bool) { i.object = &b }
|
||||||
|
func (i *Interface) SetBools(bs []bool) { i.object = &bs }
|
||||||
|
func (i *Interface) SetString(str string) { i.object = &str }
|
||||||
|
func (i *Interface) SetStrings(strs *Strings) { i.object = &strs.strs }
|
||||||
|
func (i *Interface) SetBinary(binary []byte) { i.object = &binary }
|
||||||
|
func (i *Interface) SetBinaries(binaries [][]byte) { i.object = &binaries }
|
||||||
|
func (i *Interface) SetAddress(address *Address) { i.object = &address.address }
|
||||||
|
func (i *Interface) SetAddresses(addrs *Addresses) { i.object = &addrs.addresses }
|
||||||
|
func (i *Interface) SetHash(hash *Hash) { i.object = &hash.hash }
|
||||||
|
func (i *Interface) SetHashes(hashes *Hashes) { i.object = &hashes.hashes }
|
||||||
|
func (i *Interface) SetInt8(n int8) { i.object = &n }
|
||||||
|
func (i *Interface) SetInt16(n int16) { i.object = &n }
|
||||||
|
func (i *Interface) SetInt32(n int32) { i.object = &n }
|
||||||
|
func (i *Interface) SetInt64(n int64) { i.object = &n }
|
||||||
|
func (i *Interface) SetUint8(bigint *BigInt) { n := uint8(bigint.bigint.Uint64()); i.object = &n }
|
||||||
|
func (i *Interface) SetUint16(bigint *BigInt) { n := uint16(bigint.bigint.Uint64()); i.object = &n }
|
||||||
|
func (i *Interface) SetUint32(bigint *BigInt) { n := uint32(bigint.bigint.Uint64()); i.object = &n }
|
||||||
|
func (i *Interface) SetUint64(bigint *BigInt) { n := uint64(bigint.bigint.Uint64()); i.object = &n }
|
||||||
|
func (i *Interface) SetBigInt(bigint *BigInt) { i.object = &bigint.bigint }
|
||||||
|
func (i *Interface) SetBigInts(bigints *BigInts) { i.object = &bigints.bigints }
|
||||||
|
|
||||||
|
func (i *Interface) SetDefaultBool() { i.object = new(bool) }
|
||||||
|
func (i *Interface) SetDefaultBools() { i.object = new([]bool) }
|
||||||
|
func (i *Interface) SetDefaultString() { i.object = new(string) }
|
||||||
|
func (i *Interface) SetDefaultStrings() { i.object = new([]string) }
|
||||||
|
func (i *Interface) SetDefaultBinary() { i.object = new([]byte) }
|
||||||
|
func (i *Interface) SetDefaultBinaries() { i.object = new([][]byte) }
|
||||||
|
func (i *Interface) SetDefaultAddress() { i.object = new(common.Address) }
|
||||||
|
func (i *Interface) SetDefaultAddresses() { i.object = new([]common.Address) }
|
||||||
|
func (i *Interface) SetDefaultHash() { i.object = new(common.Hash) }
|
||||||
|
func (i *Interface) SetDefaultHashes() { i.object = new([]common.Hash) }
|
||||||
|
func (i *Interface) SetDefaultInt8() { i.object = new(int8) }
|
||||||
|
func (i *Interface) SetDefaultInt16() { i.object = new(int16) }
|
||||||
|
func (i *Interface) SetDefaultInt32() { i.object = new(int32) }
|
||||||
|
func (i *Interface) SetDefaultInt64() { i.object = new(int64) }
|
||||||
|
func (i *Interface) SetDefaultUint8() { i.object = new(uint8) }
|
||||||
|
func (i *Interface) SetDefaultUint16() { i.object = new(uint16) }
|
||||||
|
func (i *Interface) SetDefaultUint32() { i.object = new(uint32) }
|
||||||
|
func (i *Interface) SetDefaultUint64() { i.object = new(uint64) }
|
||||||
|
func (i *Interface) SetDefaultBigInt() { i.object = new(*big.Int) }
|
||||||
|
func (i *Interface) SetDefaultBigInts() { i.object = new([]*big.Int) }
|
||||||
|
|
||||||
|
func (i *Interface) GetBool() bool { return *i.object.(*bool) }
|
||||||
|
func (i *Interface) GetBools() []bool { return *i.object.(*[]bool) }
|
||||||
|
func (i *Interface) GetString() string { return *i.object.(*string) }
|
||||||
|
func (i *Interface) GetStrings() *Strings { return &Strings{*i.object.(*[]string)} }
|
||||||
|
func (i *Interface) GetBinary() []byte { return *i.object.(*[]byte) }
|
||||||
|
func (i *Interface) GetBinaries() [][]byte { return *i.object.(*[][]byte) }
|
||||||
|
func (i *Interface) GetAddress() *Address { return &Address{*i.object.(*common.Address)} }
|
||||||
|
func (i *Interface) GetAddresses() *Addresses { return &Addresses{*i.object.(*[]common.Address)} }
|
||||||
|
func (i *Interface) GetHash() *Hash { return &Hash{*i.object.(*common.Hash)} }
|
||||||
|
func (i *Interface) GetHashes() *Hashes { return &Hashes{*i.object.(*[]common.Hash)} }
|
||||||
|
func (i *Interface) GetInt8() int8 { return *i.object.(*int8) }
|
||||||
|
func (i *Interface) GetInt16() int16 { return *i.object.(*int16) }
|
||||||
|
func (i *Interface) GetInt32() int32 { return *i.object.(*int32) }
|
||||||
|
func (i *Interface) GetInt64() int64 { return *i.object.(*int64) }
|
||||||
|
func (i *Interface) GetUint8() *BigInt {
|
||||||
|
return &BigInt{new(big.Int).SetUint64(uint64(*i.object.(*uint8)))}
|
||||||
|
}
|
||||||
|
func (i *Interface) GetUint16() *BigInt {
|
||||||
|
return &BigInt{new(big.Int).SetUint64(uint64(*i.object.(*uint16)))}
|
||||||
|
}
|
||||||
|
func (i *Interface) GetUint32() *BigInt {
|
||||||
|
return &BigInt{new(big.Int).SetUint64(uint64(*i.object.(*uint32)))}
|
||||||
|
}
|
||||||
|
func (i *Interface) GetUint64() *BigInt {
|
||||||
|
return &BigInt{new(big.Int).SetUint64(*i.object.(*uint64))}
|
||||||
|
}
|
||||||
|
func (i *Interface) GetBigInt() *BigInt { return &BigInt{*i.object.(**big.Int)} }
|
||||||
|
func (i *Interface) GetBigInts() *BigInts { return &BigInts{*i.object.(*[]*big.Int)} }
|
||||||
|
|
||||||
|
// Interfaces is a slices of wrapped generic objects.
|
||||||
|
type Interfaces struct {
|
||||||
|
objects []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInterfaces creates a slice of uninitialized interfaces.
|
||||||
|
func NewInterfaces(size int) *Interfaces {
|
||||||
|
return &Interfaces{
|
||||||
|
objects: make([]interface{}, size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the number of interfaces in the slice.
|
||||||
|
func (i *Interfaces) Size() int {
|
||||||
|
return len(i.objects)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the bigint at the given index from the slice.
|
||||||
|
func (i *Interfaces) Get(index int) (*Interface, error) {
|
||||||
|
if index < 0 || index >= len(i.objects) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Interface{i.objects[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the big int at the given index in the slice.
|
||||||
|
func (i *Interfaces) Set(index int, object *Interface) error {
|
||||||
|
if index < 0 || index >= len(i.objects) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
i.objects[index] = object.object
|
||||||
|
return nil
|
||||||
|
}
|
74
mobile/p2p.go
Normal file
74
mobile/p2p.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received pi copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains wrappers for the p2p package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeInfo represents pi short summary of the information known about the host.
|
||||||
|
type NodeInfo struct {
|
||||||
|
info *p2p.NodeInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ni *NodeInfo) GetID() string { return ni.info.ID }
|
||||||
|
func (ni *NodeInfo) GetName() string { return ni.info.Name }
|
||||||
|
func (ni *NodeInfo) GetEnode() string { return ni.info.Enode }
|
||||||
|
func (ni *NodeInfo) GetIP() string { return ni.info.IP }
|
||||||
|
func (ni *NodeInfo) GetDiscoveryPort() int { return ni.info.Ports.Discovery }
|
||||||
|
func (ni *NodeInfo) GetListenerPort() int { return ni.info.Ports.Listener }
|
||||||
|
func (ni *NodeInfo) GetListenerAddress() string { return ni.info.ListenAddr }
|
||||||
|
func (ni *NodeInfo) GetProtocols() *Strings {
|
||||||
|
protos := []string{}
|
||||||
|
for proto, _ := range ni.info.Protocols {
|
||||||
|
protos = append(protos, proto)
|
||||||
|
}
|
||||||
|
return &Strings{protos}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerInfo represents pi short summary of the information known about pi connected peer.
|
||||||
|
type PeerInfo struct {
|
||||||
|
info *p2p.PeerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pi *PeerInfo) GetID() string { return pi.info.ID }
|
||||||
|
func (pi *PeerInfo) GetName() string { return pi.info.Name }
|
||||||
|
func (pi *PeerInfo) GetCaps() *Strings { return &Strings{pi.info.Caps} }
|
||||||
|
func (pi *PeerInfo) GetLocalAddress() string { return pi.info.Network.LocalAddress }
|
||||||
|
func (pi *PeerInfo) GetRemoteAddress() string { return pi.info.Network.RemoteAddress }
|
||||||
|
|
||||||
|
// PeerInfos represents a slice of infos about remote peers.
|
||||||
|
type PeerInfos struct {
|
||||||
|
infos []*p2p.PeerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the number of peer info entries in the slice.
|
||||||
|
func (pi *PeerInfos) Size() int {
|
||||||
|
return len(pi.infos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the peer info at the given index from the slice.
|
||||||
|
func (pi *PeerInfos) Get(index int) (*PeerInfo, error) {
|
||||||
|
if index < 0 || index >= len(pi.infos) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &PeerInfo{pi.infos[index]}, nil
|
||||||
|
}
|
89
mobile/params.go
Normal file
89
mobile/params.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the params package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MainnetChainConfig returns the chain configurations for the main Ethereum network.
|
||||||
|
func MainnetChainConfig() *ChainConfig {
|
||||||
|
return &ChainConfig{
|
||||||
|
HomesteadBlock: params.MainNetHomesteadBlock.Int64(),
|
||||||
|
DAOForkBlock: params.MainNetDAOForkBlock.Int64(),
|
||||||
|
DAOForkSupport: true,
|
||||||
|
EIP150Block: params.MainNetHomesteadGasRepriceBlock.Int64(),
|
||||||
|
EIP150Hash: Hash{params.MainNetHomesteadGasRepriceHash},
|
||||||
|
EIP155Block: params.MainNetSpuriousDragon.Int64(),
|
||||||
|
EIP158Block: params.MainNetSpuriousDragon.Int64(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MainnetGenesis returns the JSON spec to use for the main Ethereum network. It
|
||||||
|
// is actually empty since that defaults to the hard coded binary genesis block.
|
||||||
|
func MainnetGenesis() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestnetChainConfig returns the chain configurations for the Ethereum test network.
|
||||||
|
func TestnetChainConfig() *ChainConfig {
|
||||||
|
return &ChainConfig{
|
||||||
|
HomesteadBlock: params.TestNetHomesteadBlock.Int64(),
|
||||||
|
DAOForkBlock: 0,
|
||||||
|
DAOForkSupport: false,
|
||||||
|
EIP150Block: params.TestNetHomesteadGasRepriceBlock.Int64(),
|
||||||
|
EIP150Hash: Hash{params.TestNetHomesteadGasRepriceHash},
|
||||||
|
EIP155Block: params.TestNetSpuriousDragon.Int64(),
|
||||||
|
EIP158Block: params.TestNetSpuriousDragon.Int64(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestnetGenesis returns the JSON spec to use for the Ethereum test network.
|
||||||
|
func TestnetGenesis() string {
|
||||||
|
return core.TestNetGenesisBlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainConfig is the core config which determines the blockchain settings.
|
||||||
|
type ChainConfig struct {
|
||||||
|
HomesteadBlock int64 // Homestead switch block
|
||||||
|
DAOForkBlock int64 // TheDAO hard-fork switch block
|
||||||
|
DAOForkSupport bool // Whether the nodes supports or opposes the DAO hard-fork
|
||||||
|
EIP150Block int64 // Homestead gas reprice switch block
|
||||||
|
EIP150Hash Hash // Homestead gas reprice switch block hash
|
||||||
|
EIP155Block int64 // Replay protection switch block
|
||||||
|
EIP158Block int64 // Empty account pruning switch block
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewChainConfig creates a new chain configuration that transitions immediately
|
||||||
|
// to homestead and has no notion of the DAO fork (ideal for a private network).
|
||||||
|
func NewChainConfig() *ChainConfig {
|
||||||
|
return new(ChainConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FoundationBootnodes returns the enode URLs of the P2P bootstrap nodes operated
|
||||||
|
// by the foundation running the V5 discovery protocol.
|
||||||
|
func FoundationBootnodes() *Enodes {
|
||||||
|
nodes := &Enodes{nodes: make([]*discv5.Node, len(params.DiscoveryV5Bootnodes))}
|
||||||
|
for i, node := range params.DiscoveryV5Bootnodes {
|
||||||
|
nodes.nodes[i] = node
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
54
mobile/primitives.go
Normal file
54
mobile/primitives.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received s copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains various wrappers for primitive types.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Strings represents s slice of strs.
|
||||||
|
type Strings struct{ strs []string }
|
||||||
|
|
||||||
|
// Size returns the number of strs in the slice.
|
||||||
|
func (s *Strings) Size() int {
|
||||||
|
return len(s.strs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the string at the given index from the slice.
|
||||||
|
func (s *Strings) Get(index int) (string, error) {
|
||||||
|
if index < 0 || index >= len(s.strs) {
|
||||||
|
return "", errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return s.strs[index], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the string at the given index in the slice.
|
||||||
|
func (s *Strings) Set(index int, str string) error {
|
||||||
|
if index < 0 || index >= len(s.strs) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
s.strs[index] = str
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the Stringer interface.
|
||||||
|
func (s *Strings) String() string {
|
||||||
|
return fmt.Sprintf("%v", s.strs)
|
||||||
|
}
|
189
mobile/types.go
Normal file
189
mobile/types.go
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the core/types package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Nonce is a 64-bit hash which proves (combined with the mix-hash) that
|
||||||
|
// a sufficient amount of computation has been carried out on a block.
|
||||||
|
type Nonce struct {
|
||||||
|
nonce types.BlockNonce
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes retrieves the byte representation of the block nonce.
|
||||||
|
func (n *Nonce) GetBytes() []byte {
|
||||||
|
return n.nonce[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHex retrieves the hex string representation of the block nonce.
|
||||||
|
func (n *Nonce) GetHex() string {
|
||||||
|
return fmt.Sprintf("0x%x", n.nonce[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bloom represents a 256 bit bloom filter.
|
||||||
|
type Bloom struct {
|
||||||
|
bloom types.Bloom
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes retrieves the byte representation of the bloom filter.
|
||||||
|
func (b *Bloom) GetBytes() []byte {
|
||||||
|
return b.bloom[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHex retrieves the hex string representation of the bloom filter.
|
||||||
|
func (b *Bloom) GetHex() string {
|
||||||
|
return fmt.Sprintf("0x%x", b.bloom[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header represents a block header in the Ethereum blockchain.
|
||||||
|
type Header struct {
|
||||||
|
header *types.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Header) GetParentHash() *Hash { return &Hash{h.header.ParentHash} }
|
||||||
|
func (h *Header) GetUncleHash() *Hash { return &Hash{h.header.UncleHash} }
|
||||||
|
func (h *Header) GetCoinbase() *Address { return &Address{h.header.Coinbase} }
|
||||||
|
func (h *Header) GetRoot() *Hash { return &Hash{h.header.Root} }
|
||||||
|
func (h *Header) GetTxHash() *Hash { return &Hash{h.header.TxHash} }
|
||||||
|
func (h *Header) GetReceiptHash() *Hash { return &Hash{h.header.ReceiptHash} }
|
||||||
|
func (h *Header) GetBloom() *Bloom { return &Bloom{h.header.Bloom} }
|
||||||
|
func (h *Header) GetDifficulty() *BigInt { return &BigInt{h.header.Difficulty} }
|
||||||
|
func (h *Header) GetNumber() int64 { return h.header.Number.Int64() }
|
||||||
|
func (h *Header) GetGasLimit() int64 { return h.header.GasLimit.Int64() }
|
||||||
|
func (h *Header) GetGasUsed() int64 { return h.header.GasUsed.Int64() }
|
||||||
|
func (h *Header) GetTime() int64 { return h.header.Time.Int64() }
|
||||||
|
func (h *Header) GetExtra() []byte { return h.header.Extra }
|
||||||
|
func (h *Header) GetMixDigest() *Hash { return &Hash{h.header.MixDigest} }
|
||||||
|
func (h *Header) GetNonce() *Nonce { return &Nonce{h.header.Nonce} }
|
||||||
|
|
||||||
|
func (h *Header) GetHash() *Hash { return &Hash{h.header.Hash()} }
|
||||||
|
func (h *Header) GetHashNoNonce() *Hash { return &Hash{h.header.HashNoNonce()} }
|
||||||
|
|
||||||
|
// Headers represents a slice of headers.
|
||||||
|
type Headers struct{ headers []*types.Header }
|
||||||
|
|
||||||
|
// Size returns the number of headers in the slice.
|
||||||
|
func (h *Headers) Size() int {
|
||||||
|
return len(h.headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the header at the given index from the slice.
|
||||||
|
func (h *Headers) Get(index int) (*Header, error) {
|
||||||
|
if index < 0 || index >= len(h.headers) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Header{h.headers[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block represents an entire block in the Ethereum blockchain.
|
||||||
|
type Block struct {
|
||||||
|
block *types.Block
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Block) GetParentHash() *Hash { return &Hash{b.block.ParentHash()} }
|
||||||
|
func (b *Block) GetUncleHash() *Hash { return &Hash{b.block.UncleHash()} }
|
||||||
|
func (b *Block) GetCoinbase() *Address { return &Address{b.block.Coinbase()} }
|
||||||
|
func (b *Block) GetRoot() *Hash { return &Hash{b.block.Root()} }
|
||||||
|
func (b *Block) GetTxHash() *Hash { return &Hash{b.block.TxHash()} }
|
||||||
|
func (b *Block) GetReceiptHash() *Hash { return &Hash{b.block.ReceiptHash()} }
|
||||||
|
func (b *Block) GetBloom() *Bloom { return &Bloom{b.block.Bloom()} }
|
||||||
|
func (b *Block) GetDifficulty() *BigInt { return &BigInt{b.block.Difficulty()} }
|
||||||
|
func (b *Block) GetNumber() int64 { return b.block.Number().Int64() }
|
||||||
|
func (b *Block) GetGasLimit() int64 { return b.block.GasLimit().Int64() }
|
||||||
|
func (b *Block) GetGasUsed() int64 { return b.block.GasUsed().Int64() }
|
||||||
|
func (b *Block) GetTime() int64 { return b.block.Time().Int64() }
|
||||||
|
func (b *Block) GetExtra() []byte { return b.block.Extra() }
|
||||||
|
func (b *Block) GetMixDigest() *Hash { return &Hash{b.block.MixDigest()} }
|
||||||
|
func (b *Block) GetNonce() int64 { return int64(b.block.Nonce()) }
|
||||||
|
|
||||||
|
func (b *Block) GetHash() *Hash { return &Hash{b.block.Hash()} }
|
||||||
|
func (b *Block) GetHashNoNonce() *Hash { return &Hash{b.block.HashNoNonce()} }
|
||||||
|
|
||||||
|
func (b *Block) GetHeader() *Header { return &Header{b.block.Header()} }
|
||||||
|
func (b *Block) GetUncles() *Headers { return &Headers{b.block.Uncles()} }
|
||||||
|
func (b *Block) GetTransactions() *Transactions { return &Transactions{b.block.Transactions()} }
|
||||||
|
func (b *Block) GetTransaction(hash *Hash) *Transaction {
|
||||||
|
return &Transaction{b.block.Transaction(hash.hash)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction represents a single Ethereum transaction.
|
||||||
|
type Transaction struct {
|
||||||
|
tx *types.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *Transaction) GetData() []byte { return tx.tx.Data() }
|
||||||
|
func (tx *Transaction) GetGas() int64 { return tx.tx.Gas().Int64() }
|
||||||
|
func (tx *Transaction) GetGasPrice() *BigInt { return &BigInt{tx.tx.GasPrice()} }
|
||||||
|
func (tx *Transaction) GetValue() *BigInt { return &BigInt{tx.tx.Value()} }
|
||||||
|
func (tx *Transaction) GetNonce() int64 { return int64(tx.tx.Nonce()) }
|
||||||
|
|
||||||
|
func (tx *Transaction) GetHash() *Hash { return &Hash{tx.tx.Hash()} }
|
||||||
|
func (tx *Transaction) GetSigHash() *Hash { return &Hash{tx.tx.SigHash(types.HomesteadSigner{})} }
|
||||||
|
func (tx *Transaction) GetCost() *BigInt { return &BigInt{tx.tx.Cost()} }
|
||||||
|
|
||||||
|
func (tx *Transaction) GetFrom() (*Address, error) {
|
||||||
|
from, err := types.Sender(types.HomesteadSigner{}, tx.tx)
|
||||||
|
return &Address{from}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *Transaction) GetTo() *Address {
|
||||||
|
if to := tx.tx.To(); to != nil {
|
||||||
|
return &Address{*to}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *Transaction) WithSignature(sig []byte) (*Transaction, error) {
|
||||||
|
t, err := tx.tx.WithSignature(types.HomesteadSigner{}, sig)
|
||||||
|
return &Transaction{t}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transactions represents a slice of transactions.
|
||||||
|
type Transactions struct{ txs types.Transactions }
|
||||||
|
|
||||||
|
// Size returns the number of transactions in the slice.
|
||||||
|
func (t *Transactions) Size() int {
|
||||||
|
return len(t.txs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the transaction at the given index from the slice.
|
||||||
|
func (t *Transactions) Get(index int) (*Transaction, error) {
|
||||||
|
if index < 0 || index >= len(t.txs) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Transaction{t.txs[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receipt represents the results of a transaction.
|
||||||
|
type Receipt struct {
|
||||||
|
receipt *types.Receipt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Receipt) GetPostState() []byte { return r.receipt.PostState }
|
||||||
|
func (r *Receipt) GetCumulativeGasUsed() *BigInt { return &BigInt{r.receipt.CumulativeGasUsed} }
|
||||||
|
func (r *Receipt) GetBloom() *Bloom { return &Bloom{r.receipt.Bloom} }
|
||||||
|
func (r *Receipt) GetLogs() *Logs { return &Logs{r.receipt.Logs} }
|
||||||
|
func (r *Receipt) GetTxHash() *Hash { return &Hash{r.receipt.TxHash} }
|
||||||
|
func (r *Receipt) GetContractAddress() *Address { return &Address{r.receipt.ContractAddress} }
|
||||||
|
func (r *Receipt) GetGasUsed() *BigInt { return &BigInt{r.receipt.GasUsed} }
|
56
mobile/vm.go
Normal file
56
mobile/vm.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2016 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the core/types package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Log represents a contract log event. These events are generated by the LOG
|
||||||
|
// opcode and stored/indexed by the node.
|
||||||
|
type Log struct {
|
||||||
|
log *vm.Log
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Log) GetAddress() *Address { return &Address{l.log.Address} }
|
||||||
|
func (l *Log) GetTopics() *Hashes { return &Hashes{l.log.Topics} }
|
||||||
|
func (l *Log) GetData() []byte { return l.log.Data }
|
||||||
|
func (l *Log) GetBlockNumber() int64 { return int64(l.log.BlockNumber) }
|
||||||
|
func (l *Log) GetTxHash() *Hash { return &Hash{l.log.TxHash} }
|
||||||
|
func (l *Log) GetTxIndex() int { return int(l.log.TxIndex) }
|
||||||
|
func (l *Log) GetBlockHash() *Hash { return &Hash{l.log.BlockHash} }
|
||||||
|
func (l *Log) GetIndex() int { return int(l.log.Index) }
|
||||||
|
|
||||||
|
// Logs represents a slice of VM logs.
|
||||||
|
type Logs struct{ logs vm.Logs }
|
||||||
|
|
||||||
|
// Size returns the number of logs in the slice.
|
||||||
|
func (l *Logs) Size() int {
|
||||||
|
return len(l.logs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the log at the given index from the slice.
|
||||||
|
func (l *Logs) Get(index int) (*Log, error) {
|
||||||
|
if index < 0 || index >= len(l.logs) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Log{l.logs[index]}, nil
|
||||||
|
}
|
@ -32,6 +32,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -95,16 +96,23 @@ type Config struct {
|
|||||||
// or not. Disabling is usually useful for protocol debugging (manual topology).
|
// or not. Disabling is usually useful for protocol debugging (manual topology).
|
||||||
NoDiscovery bool
|
NoDiscovery bool
|
||||||
|
|
||||||
|
// DiscoveryV5 specifies whether the the new topic-discovery based V5 discovery
|
||||||
|
// protocol should be started or not.
|
||||||
DiscoveryV5 bool
|
DiscoveryV5 bool
|
||||||
|
|
||||||
// Bootstrap nodes used to establish connectivity with the rest of the network.
|
// Listener address for the V5 discovery protocol UDP traffic.
|
||||||
|
DiscoveryV5Addr string
|
||||||
|
|
||||||
|
// BootstrapNodes used to establish connectivity with the rest of the network.
|
||||||
BootstrapNodes []*discover.Node
|
BootstrapNodes []*discover.Node
|
||||||
|
|
||||||
|
// BootstrapNodesV5 used to establish connectivity with the rest of the network
|
||||||
|
// using the V5 discovery protocol.
|
||||||
|
BootstrapNodesV5 []*discv5.Node
|
||||||
|
|
||||||
// Network interface address on which the node should listen for inbound peers.
|
// Network interface address on which the node should listen for inbound peers.
|
||||||
ListenAddr string
|
ListenAddr string
|
||||||
|
|
||||||
ListenAddrV5 string
|
|
||||||
|
|
||||||
// If set to a non-nil value, the given NAT port mapper is used to make the
|
// If set to a non-nil value, the given NAT port mapper is used to make the
|
||||||
// listening port available to the Internet.
|
// listening port available to the Internet.
|
||||||
NAT nat.Interface
|
NAT nat.Interface
|
||||||
|
@ -158,12 +158,13 @@ func (n *Node) Start() error {
|
|||||||
Name: n.config.NodeName(),
|
Name: n.config.NodeName(),
|
||||||
Discovery: !n.config.NoDiscovery,
|
Discovery: !n.config.NoDiscovery,
|
||||||
DiscoveryV5: n.config.DiscoveryV5,
|
DiscoveryV5: n.config.DiscoveryV5,
|
||||||
|
DiscoveryV5Addr: n.config.DiscoveryV5Addr,
|
||||||
BootstrapNodes: n.config.BootstrapNodes,
|
BootstrapNodes: n.config.BootstrapNodes,
|
||||||
|
BootstrapNodesV5: n.config.BootstrapNodesV5,
|
||||||
StaticNodes: n.config.StaticNodes(),
|
StaticNodes: n.config.StaticNodes(),
|
||||||
TrustedNodes: n.config.TrusterNodes(),
|
TrustedNodes: n.config.TrusterNodes(),
|
||||||
NodeDatabase: n.config.NodeDB(),
|
NodeDatabase: n.config.NodeDB(),
|
||||||
ListenAddr: n.config.ListenAddr,
|
ListenAddr: n.config.ListenAddr,
|
||||||
ListenAddrV5: n.config.ListenAddrV5,
|
|
||||||
NAT: n.config.NAT,
|
NAT: n.config.NAT,
|
||||||
Dialer: n.config.Dialer,
|
Dialer: n.config.Dialer,
|
||||||
NoDial: n.config.NoDial,
|
NoDial: n.config.NoDial,
|
||||||
|
@ -35,7 +35,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const nodeIDBits = 512
|
const NodeIDBits = 512
|
||||||
|
|
||||||
// Node represents a host on the network.
|
// Node represents a host on the network.
|
||||||
// The fields of Node may not be modified.
|
// The fields of Node may not be modified.
|
||||||
@ -209,7 +209,7 @@ func MustParseNode(rawurl string) *Node {
|
|||||||
|
|
||||||
// NodeID is a unique identifier for each node.
|
// NodeID is a unique identifier for each node.
|
||||||
// The node identifier is a marshaled elliptic curve public key.
|
// The node identifier is a marshaled elliptic curve public key.
|
||||||
type NodeID [nodeIDBits / 8]byte
|
type NodeID [NodeIDBits / 8]byte
|
||||||
|
|
||||||
// NodeID prints as a long hexadecimal number.
|
// NodeID prints as a long hexadecimal number.
|
||||||
func (n NodeID) String() string {
|
func (n NodeID) String() string {
|
||||||
|
@ -60,14 +60,6 @@ func debugLog(s string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BootNodes are the enode URLs of the P2P bootstrap nodes for the experimental RLPx v5 "Topic Discovery" network
|
|
||||||
// warning: local bootnodes for testing!!!
|
|
||||||
var BootNodes = []*Node{
|
|
||||||
MustParseNode("enode://0cc5f5ffb5d9098c8b8c62325f3797f56509bff942704687b6530992ac706e2cb946b90a34f1f19548cd3c7baccbcaea354531e5983c7d1bc0dee16ce4b6440b@40.118.3.223:30305"),
|
|
||||||
MustParseNode("enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308"),
|
|
||||||
MustParseNode("enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Network manages the table and all protocol interaction.
|
// Network manages the table and all protocol interaction.
|
||||||
type Network struct {
|
type Network struct {
|
||||||
db *nodeDB // database of known nodes
|
db *nodeDB // database of known nodes
|
||||||
|
@ -73,16 +73,26 @@ type Config struct {
|
|||||||
// or not. Disabling is usually useful for protocol debugging (manual topology).
|
// or not. Disabling is usually useful for protocol debugging (manual topology).
|
||||||
Discovery bool
|
Discovery bool
|
||||||
|
|
||||||
|
// DiscoveryV5 specifies whether the the new topic-discovery based V5 discovery
|
||||||
|
// protocol should be started or not.
|
||||||
DiscoveryV5 bool
|
DiscoveryV5 bool
|
||||||
|
|
||||||
|
// Listener address for the V5 discovery protocol UDP traffic.
|
||||||
|
DiscoveryV5Addr string
|
||||||
|
|
||||||
// Name sets the node name of this server.
|
// Name sets the node name of this server.
|
||||||
// Use common.MakeName to create a name that follows existing conventions.
|
// Use common.MakeName to create a name that follows existing conventions.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Bootstrap nodes are used to establish connectivity
|
// BootstrapNodes are used to establish connectivity
|
||||||
// with the rest of the network.
|
// with the rest of the network.
|
||||||
BootstrapNodes []*discover.Node
|
BootstrapNodes []*discover.Node
|
||||||
|
|
||||||
|
// BootstrapNodesV5 are used to establish connectivity
|
||||||
|
// with the rest of the network using the V5 discovery
|
||||||
|
// protocol.
|
||||||
|
BootstrapNodesV5 []*discv5.Node
|
||||||
|
|
||||||
// Static nodes are used as pre-configured connections which are always
|
// Static nodes are used as pre-configured connections which are always
|
||||||
// maintained and re-connected on disconnects.
|
// maintained and re-connected on disconnects.
|
||||||
StaticNodes []*discover.Node
|
StaticNodes []*discover.Node
|
||||||
@ -108,8 +118,6 @@ type Config struct {
|
|||||||
// the server is started.
|
// the server is started.
|
||||||
ListenAddr string
|
ListenAddr string
|
||||||
|
|
||||||
ListenAddrV5 string
|
|
||||||
|
|
||||||
// If set to a non-nil value, the given NAT port mapper
|
// If set to a non-nil value, the given NAT port mapper
|
||||||
// is used to make the listening port available to the
|
// is used to make the listening port available to the
|
||||||
// Internet.
|
// Internet.
|
||||||
@ -359,11 +367,11 @@ func (srv *Server) Start() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if srv.DiscoveryV5 {
|
if srv.DiscoveryV5 {
|
||||||
ntab, err := discv5.ListenUDP(srv.PrivateKey, srv.ListenAddrV5, srv.NAT, "") //srv.NodeDatabase)
|
ntab, err := discv5.ListenUDP(srv.PrivateKey, srv.DiscoveryV5Addr, srv.NAT, "") //srv.NodeDatabase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ntab.SetFallbackNodes(discv5.BootNodes); err != nil {
|
if err := ntab.SetFallbackNodes(srv.BootstrapNodesV5); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
srv.DiscV5 = ntab
|
srv.DiscV5 = ntab
|
||||||
@ -748,7 +756,7 @@ type NodeInfo struct {
|
|||||||
Protocols map[string]interface{} `json:"protocols"`
|
Protocols map[string]interface{} `json:"protocols"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info gathers and returns a collection of metadata known about the host.
|
// NodeInfo gathers and returns a collection of metadata known about the host.
|
||||||
func (srv *Server) NodeInfo() *NodeInfo {
|
func (srv *Server) NodeInfo() *NodeInfo {
|
||||||
node := srv.Self()
|
node := srv.Self()
|
||||||
|
|
||||||
|
52
params/bootnodes.go
Normal file
52
params/bootnodes.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2015 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MainnetBootnodes are the enode URLs of the P2P bootstrap nodes running on
|
||||||
|
// the main Ethereum network.
|
||||||
|
var MainnetBootnodes = []*discover.Node{
|
||||||
|
// ETH/DEV Go Bootnodes
|
||||||
|
discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE
|
||||||
|
discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR
|
||||||
|
discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG
|
||||||
|
|
||||||
|
// ETH/DEV Cpp Bootnodes
|
||||||
|
discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the
|
||||||
|
// Morden test network.
|
||||||
|
var TestnetBootnodes = []*discover.Node{
|
||||||
|
// ETH/DEV Go Bootnodes
|
||||||
|
discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"),
|
||||||
|
discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"),
|
||||||
|
|
||||||
|
// ETH/DEV Cpp Bootnodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscoveryV5Bootnodes are the enode URLs of the P2P bootstrap nodes for the
|
||||||
|
// experimental RLPx v5 topic-discovery network.
|
||||||
|
var DiscoveryV5Bootnodes = []*discv5.Node{
|
||||||
|
discv5.MustParseNode("enode://0cc5f5ffb5d9098c8b8c62325f3797f56509bff942704687b6530992ac706e2cb946b90a34f1f19548cd3c7baccbcaea354531e5983c7d1bc0dee16ce4b6440b@40.118.3.223:30305"),
|
||||||
|
discv5.MustParseNode("enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308"),
|
||||||
|
discv5.MustParseNode("enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309"),
|
||||||
|
}
|
@ -22,6 +22,28 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MainnetChainConfig is the chain parameters to run a node on the main network.
|
||||||
|
var MainnetChainConfig = &ChainConfig{
|
||||||
|
HomesteadBlock: MainNetHomesteadBlock,
|
||||||
|
DAOForkBlock: MainNetDAOForkBlock,
|
||||||
|
DAOForkSupport: true,
|
||||||
|
EIP150Block: MainNetHomesteadGasRepriceBlock,
|
||||||
|
EIP150Hash: MainNetHomesteadGasRepriceHash,
|
||||||
|
EIP155Block: MainNetSpuriousDragon,
|
||||||
|
EIP158Block: MainNetSpuriousDragon,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestnetChainConfig is the chain parameters to run a node on the test network.
|
||||||
|
var TestnetChainConfig = &ChainConfig{
|
||||||
|
HomesteadBlock: TestNetHomesteadBlock,
|
||||||
|
DAOForkBlock: TestNetDAOForkBlock,
|
||||||
|
DAOForkSupport: false,
|
||||||
|
EIP150Block: TestNetHomesteadGasRepriceBlock,
|
||||||
|
EIP150Hash: TestNetHomesteadGasRepriceHash,
|
||||||
|
EIP155Block: TestNetSpuriousDragon,
|
||||||
|
EIP158Block: TestNetSpuriousDragon,
|
||||||
|
}
|
||||||
|
|
||||||
// ChainConfig is the core config which determines the blockchain settings.
|
// ChainConfig is the core config which determines the blockchain settings.
|
||||||
//
|
//
|
||||||
// ChainConfig is stored in the database on a per block basis. This means
|
// ChainConfig is stored in the database on a per block basis. This means
|
||||||
|
Loading…
Reference in New Issue
Block a user