rpc: migrated the RPC insterface to a new reflection based RPC layer
This commit is contained in:
		
				
					committed by
					
						 Jeffrey Wilcke
						Jeffrey Wilcke
					
				
			
			
				
	
			
			
			
						parent
						
							f2ab351e8d
						
					
				
				
					commit
					19b2640e89
				
			
							
								
								
									
										14
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
| 	"ImportPath": "github.com/ethereum/go-ethereum", | 	"ImportPath": "github.com/ethereum/go-ethereum", | ||||||
| 	"GoVersion": "go1.4", | 	"GoVersion": "go1.5.2", | ||||||
| 	"Packages": [ | 	"Packages": [ | ||||||
| 		"./..." | 		"./..." | ||||||
| 	], | 	], | ||||||
| @@ -40,10 +40,6 @@ | |||||||
| 			"ImportPath": "github.com/jackpal/go-nat-pmp", | 			"ImportPath": "github.com/jackpal/go-nat-pmp", | ||||||
| 			"Rev": "a45aa3d54aef73b504e15eb71bea0e5565b5e6e1" | 			"Rev": "a45aa3d54aef73b504e15eb71bea0e5565b5e6e1" | ||||||
| 		}, | 		}, | ||||||
| 		{ |  | ||||||
| 			"ImportPath": "github.com/kardianos/osext", |  | ||||||
| 			"Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a" |  | ||||||
| 		}, |  | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/mattn/go-isatty", | 			"ImportPath": "github.com/mattn/go-isatty", | ||||||
| 			"Rev": "7fcbc72f853b92b5720db4a6b8482be612daef24" | 			"Rev": "7fcbc72f853b92b5720db4a6b8482be612daef24" | ||||||
| @@ -73,10 +69,6 @@ | |||||||
| 			"ImportPath": "github.com/robertkrimen/otto", | 			"ImportPath": "github.com/robertkrimen/otto", | ||||||
| 			"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba" | 			"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba" | ||||||
| 		}, | 		}, | ||||||
| 		{ |  | ||||||
| 			"ImportPath": "github.com/rs/cors", |  | ||||||
| 			"Rev": "6e0c3cb65fc0fdb064c743d176a620e3ca446dfb" |  | ||||||
| 		}, |  | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/shiena/ansicolor", | 			"ImportPath": "github.com/shiena/ansicolor", | ||||||
| 			"Rev": "a5e2b567a4dd6cc74545b8a4f27c9d63b9e7735b" | 			"Rev": "a5e2b567a4dd6cc74545b8a4f27c9d63b9e7735b" | ||||||
| @@ -109,6 +101,10 @@ | |||||||
| 			"ImportPath": "golang.org/x/net/html", | 			"ImportPath": "golang.org/x/net/html", | ||||||
| 			"Rev": "e0403b4e005737430c05a57aac078479844f919c" | 			"Rev": "e0403b4e005737430c05a57aac078479844f919c" | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			"ImportPath": "golang.org/x/net/websocket", | ||||||
|  | 			"Rev": "e0403b4e005737430c05a57aac078479844f919c" | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "golang.org/x/text/encoding", | 			"ImportPath": "golang.org/x/text/encoding", | ||||||
| 			"Rev": "c93e7c9fff19fb9139b5ab04ce041833add0134e" | 			"Rev": "c93e7c9fff19fb9139b5ab04ce041833add0134e" | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,27 +0,0 @@ | |||||||
| Copyright (c) 2012 The Go Authors. All rights reserved. |  | ||||||
|  |  | ||||||
| Redistribution and use in source and binary forms, with or without |  | ||||||
| modification, are permitted provided that the following conditions are |  | ||||||
| met: |  | ||||||
|  |  | ||||||
|    * Redistributions of source code must retain the above copyright |  | ||||||
| notice, this list of conditions and the following disclaimer. |  | ||||||
|    * Redistributions in binary form must reproduce the above |  | ||||||
| copyright notice, this list of conditions and the following disclaimer |  | ||||||
| in the documentation and/or other materials provided with the |  | ||||||
| distribution. |  | ||||||
|    * Neither the name of Google Inc. nor the names of its |  | ||||||
| contributors may be used to endorse or promote products derived from |  | ||||||
| this software without specific prior written permission. |  | ||||||
|  |  | ||||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |  | ||||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |  | ||||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |  | ||||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |  | ||||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |  | ||||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |  | ||||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |  | ||||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |  | ||||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |  | ||||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |  | ||||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
							
								
								
									
										14
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,14 +0,0 @@ | |||||||
| ### Extensions to the "os" package. |  | ||||||
|  |  | ||||||
| ## Find the current Executable and ExecutableFolder. |  | ||||||
|  |  | ||||||
| There is sometimes utility in finding the current executable file |  | ||||||
| that is running. This can be used for upgrading the current executable |  | ||||||
| or finding resources located relative to the executable file. |  | ||||||
|  |  | ||||||
| Multi-platform and supports: |  | ||||||
|  * Linux |  | ||||||
|  * OS X |  | ||||||
|  * Windows |  | ||||||
|  * Plan 9 |  | ||||||
|  * BSDs. |  | ||||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,27 +0,0 @@ | |||||||
| // Copyright 2012 The Go Authors. All rights reserved. |  | ||||||
| // Use of this source code is governed by a BSD-style |  | ||||||
| // license that can be found in the LICENSE file. |  | ||||||
|  |  | ||||||
| // Extensions to the standard "os" package. |  | ||||||
| package osext |  | ||||||
|  |  | ||||||
| import "path/filepath" |  | ||||||
|  |  | ||||||
| // Executable returns an absolute path that can be used to |  | ||||||
| // re-invoke the current program. |  | ||||||
| // It may not be valid after the current program exits. |  | ||||||
| func Executable() (string, error) { |  | ||||||
| 	p, err := executable() |  | ||||||
| 	return filepath.Clean(p), err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Returns same path as Executable, returns just the folder |  | ||||||
| // path. Excludes the executable name. |  | ||||||
| func ExecutableFolder() (string, error) { |  | ||||||
| 	p, err := Executable() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	folder, _ := filepath.Split(p) |  | ||||||
| 	return folder, nil |  | ||||||
| } |  | ||||||
							
								
								
									
										20
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_plan9.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,20 +0,0 @@ | |||||||
| // Copyright 2012 The Go Authors. All rights reserved. |  | ||||||
| // Use of this source code is governed by a BSD-style |  | ||||||
| // license that can be found in the LICENSE file. |  | ||||||
|  |  | ||||||
| package osext |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"os" |  | ||||||
| 	"strconv" |  | ||||||
| 	"syscall" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func executable() (string, error) { |  | ||||||
| 	f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text") |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	defer f.Close() |  | ||||||
| 	return syscall.Fd2path(int(f.Fd())) |  | ||||||
| } |  | ||||||
							
								
								
									
										28
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_procfs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,28 +0,0 @@ | |||||||
| // Copyright 2012 The Go Authors. All rights reserved. |  | ||||||
| // Use of this source code is governed by a BSD-style |  | ||||||
| // license that can be found in the LICENSE file. |  | ||||||
|  |  | ||||||
| // +build linux netbsd openbsd solaris dragonfly |  | ||||||
|  |  | ||||||
| package osext |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"os" |  | ||||||
| 	"runtime" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func executable() (string, error) { |  | ||||||
| 	switch runtime.GOOS { |  | ||||||
| 	case "linux": |  | ||||||
| 		return os.Readlink("/proc/self/exe") |  | ||||||
| 	case "netbsd": |  | ||||||
| 		return os.Readlink("/proc/curproc/exe") |  | ||||||
| 	case "openbsd", "dragonfly": |  | ||||||
| 		return os.Readlink("/proc/curproc/file") |  | ||||||
| 	case "solaris": |  | ||||||
| 		return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid())) |  | ||||||
| 	} |  | ||||||
| 	return "", errors.New("ExecPath not implemented for " + runtime.GOOS) |  | ||||||
| } |  | ||||||
							
								
								
									
										79
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_sysctl.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,79 +0,0 @@ | |||||||
| // Copyright 2012 The Go Authors. All rights reserved. |  | ||||||
| // Use of this source code is governed by a BSD-style |  | ||||||
| // license that can be found in the LICENSE file. |  | ||||||
|  |  | ||||||
| // +build darwin freebsd |  | ||||||
|  |  | ||||||
| package osext |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"runtime" |  | ||||||
| 	"syscall" |  | ||||||
| 	"unsafe" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var initCwd, initCwdErr = os.Getwd() |  | ||||||
|  |  | ||||||
| func executable() (string, error) { |  | ||||||
| 	var mib [4]int32 |  | ||||||
| 	switch runtime.GOOS { |  | ||||||
| 	case "freebsd": |  | ||||||
| 		mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1} |  | ||||||
| 	case "darwin": |  | ||||||
| 		mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	n := uintptr(0) |  | ||||||
| 	// Get length. |  | ||||||
| 	_, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0) |  | ||||||
| 	if errNum != 0 { |  | ||||||
| 		return "", errNum |  | ||||||
| 	} |  | ||||||
| 	if n == 0 { // This shouldn't happen. |  | ||||||
| 		return "", nil |  | ||||||
| 	} |  | ||||||
| 	buf := make([]byte, n) |  | ||||||
| 	_, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0) |  | ||||||
| 	if errNum != 0 { |  | ||||||
| 		return "", errNum |  | ||||||
| 	} |  | ||||||
| 	if n == 0 { // This shouldn't happen. |  | ||||||
| 		return "", nil |  | ||||||
| 	} |  | ||||||
| 	for i, v := range buf { |  | ||||||
| 		if v == 0 { |  | ||||||
| 			buf = buf[:i] |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	var err error |  | ||||||
| 	execPath := string(buf) |  | ||||||
| 	// execPath will not be empty due to above checks. |  | ||||||
| 	// Try to get the absolute path if the execPath is not rooted. |  | ||||||
| 	if execPath[0] != '/' { |  | ||||||
| 		execPath, err = getAbs(execPath) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return execPath, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	// For darwin KERN_PROCARGS may return the path to a symlink rather than the |  | ||||||
| 	// actual executable. |  | ||||||
| 	if runtime.GOOS == "darwin" { |  | ||||||
| 		if execPath, err = filepath.EvalSymlinks(execPath); err != nil { |  | ||||||
| 			return execPath, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return execPath, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getAbs(execPath string) (string, error) { |  | ||||||
| 	if initCwdErr != nil { |  | ||||||
| 		return execPath, initCwdErr |  | ||||||
| 	} |  | ||||||
| 	// The execPath may begin with a "../" or a "./" so clean it first. |  | ||||||
| 	// Join the two paths, trailing and starting slashes undetermined, so use |  | ||||||
| 	// the generic Join function. |  | ||||||
| 	return filepath.Join(initCwd, filepath.Clean(execPath)), nil |  | ||||||
| } |  | ||||||
							
								
								
									
										79
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,79 +0,0 @@ | |||||||
| // Copyright 2012 The Go Authors. All rights reserved. |  | ||||||
| // Use of this source code is governed by a BSD-style |  | ||||||
| // license that can be found in the LICENSE file. |  | ||||||
|  |  | ||||||
| // +build darwin linux freebsd netbsd windows |  | ||||||
|  |  | ||||||
| package osext |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"os" |  | ||||||
| 	oexec "os/exec" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"runtime" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const execPath_EnvVar = "OSTEST_OUTPUT_EXECPATH" |  | ||||||
|  |  | ||||||
| func TestExecPath(t *testing.T) { |  | ||||||
| 	ep, err := Executable() |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatalf("ExecPath failed: %v", err) |  | ||||||
| 	} |  | ||||||
| 	// we want fn to be of the form "dir/prog" |  | ||||||
| 	dir := filepath.Dir(filepath.Dir(ep)) |  | ||||||
| 	fn, err := filepath.Rel(dir, ep) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatalf("filepath.Rel: %v", err) |  | ||||||
| 	} |  | ||||||
| 	cmd := &oexec.Cmd{} |  | ||||||
| 	// make child start with a relative program path |  | ||||||
| 	cmd.Dir = dir |  | ||||||
| 	cmd.Path = fn |  | ||||||
| 	// forge argv[0] for child, so that we can verify we could correctly |  | ||||||
| 	// get real path of the executable without influenced by argv[0]. |  | ||||||
| 	cmd.Args = []string{"-", "-test.run=XXXX"} |  | ||||||
| 	cmd.Env = []string{fmt.Sprintf("%s=1", execPath_EnvVar)} |  | ||||||
| 	out, err := cmd.CombinedOutput() |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatalf("exec(self) failed: %v", err) |  | ||||||
| 	} |  | ||||||
| 	outs := string(out) |  | ||||||
| 	if !filepath.IsAbs(outs) { |  | ||||||
| 		t.Fatalf("Child returned %q, want an absolute path", out) |  | ||||||
| 	} |  | ||||||
| 	if !sameFile(outs, ep) { |  | ||||||
| 		t.Fatalf("Child returned %q, not the same file as %q", out, ep) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func sameFile(fn1, fn2 string) bool { |  | ||||||
| 	fi1, err := os.Stat(fn1) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	fi2, err := os.Stat(fn2) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	return os.SameFile(fi1, fi2) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	if e := os.Getenv(execPath_EnvVar); e != "" { |  | ||||||
| 		// first chdir to another path |  | ||||||
| 		dir := "/" |  | ||||||
| 		if runtime.GOOS == "windows" { |  | ||||||
| 			dir = filepath.VolumeName(".") |  | ||||||
| 		} |  | ||||||
| 		os.Chdir(dir) |  | ||||||
| 		if ep, err := Executable(); err != nil { |  | ||||||
| 			fmt.Fprint(os.Stderr, "ERROR: ", err) |  | ||||||
| 		} else { |  | ||||||
| 			fmt.Fprint(os.Stderr, ep) |  | ||||||
| 		} |  | ||||||
| 		os.Exit(0) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										34
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								Godeps/_workspace/src/github.com/kardianos/osext/osext_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,34 +0,0 @@ | |||||||
| // Copyright 2012 The Go Authors. All rights reserved. |  | ||||||
| // Use of this source code is governed by a BSD-style |  | ||||||
| // license that can be found in the LICENSE file. |  | ||||||
|  |  | ||||||
| package osext |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"syscall" |  | ||||||
| 	"unicode/utf16" |  | ||||||
| 	"unsafe" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	kernel                = syscall.MustLoadDLL("kernel32.dll") |  | ||||||
| 	getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW") |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // GetModuleFileName() with hModule = NULL |  | ||||||
| func executable() (exePath string, err error) { |  | ||||||
| 	return getModuleFileName() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getModuleFileName() (string, error) { |  | ||||||
| 	var n uint32 |  | ||||||
| 	b := make([]uint16, syscall.MAX_PATH) |  | ||||||
| 	size := uint32(len(b)) |  | ||||||
|  |  | ||||||
| 	r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size)) |  | ||||||
| 	n = uint32(r0) |  | ||||||
| 	if n == 0 { |  | ||||||
| 		return "", e1 |  | ||||||
| 	} |  | ||||||
| 	return string(utf16.Decode(b[0:n])), nil |  | ||||||
| } |  | ||||||
							
								
								
									
										4
									
								
								Godeps/_workspace/src/github.com/rs/cors/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/_workspace/src/github.com/rs/cors/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +0,0 @@ | |||||||
| language: go |  | ||||||
| go: |  | ||||||
| - 1.3 |  | ||||||
| - 1.4 |  | ||||||
							
								
								
									
										19
									
								
								Godeps/_workspace/src/github.com/rs/cors/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								Godeps/_workspace/src/github.com/rs/cors/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,19 +0,0 @@ | |||||||
| Copyright (c) 2014 Olivier Poitrey <rs@dailymotion.com> |  | ||||||
|  |  | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
| of this software and associated documentation files (the "Software"), to deal |  | ||||||
| in the Software without restriction, including without limitation the rights |  | ||||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
| copies of the Software, and to permit persons to whom the Software is furnished |  | ||||||
| to do so, subject to the following conditions: |  | ||||||
|  |  | ||||||
| The above copyright notice and this permission notice shall be included in all |  | ||||||
| copies or substantial portions of the Software. |  | ||||||
|  |  | ||||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |  | ||||||
| THE SOFTWARE. |  | ||||||
							
								
								
									
										84
									
								
								Godeps/_workspace/src/github.com/rs/cors/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										84
									
								
								Godeps/_workspace/src/github.com/rs/cors/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,84 +0,0 @@ | |||||||
| # Go CORS handler [](https://godoc.org/github.com/rs/cors) [](https://raw.githubusercontent.com/rs/cors/master/LICENSE) [](https://travis-ci.org/rs/cors) |  | ||||||
|  |  | ||||||
| CORS is a `net/http` handler implementing [Cross Origin Resource Sharing W3 specification](http://www.w3.org/TR/cors/) in Golang. |  | ||||||
|  |  | ||||||
| ## Getting Started |  | ||||||
|  |  | ||||||
| After installing Go and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file. We'll call it `server.go`. |  | ||||||
|  |  | ||||||
| ```go |  | ||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
|     "net/http" |  | ||||||
|  |  | ||||||
|     "github.com/rs/cors" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
|     h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |  | ||||||
|         w.Header().Set("Content-Type", "application/json") |  | ||||||
|         w.Write([]byte("{\"hello\": \"world\"}")) |  | ||||||
|     }) |  | ||||||
|  |  | ||||||
|     // cors.Default() setup the middleware with default options being |  | ||||||
|     // all origins accepted with simple methods (GET, POST). See |  | ||||||
|     // documentation below for more options. |  | ||||||
|     handler = cors.Default().Handler(h) |  | ||||||
|     http.ListenAndServe(":8080", handler) |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Install `cors`: |  | ||||||
|  |  | ||||||
|     go get github.com/rs/cors |  | ||||||
|  |  | ||||||
| Then run your server: |  | ||||||
|  |  | ||||||
|     go run server.go |  | ||||||
|  |  | ||||||
| The server now runs on `localhost:8080`: |  | ||||||
|  |  | ||||||
|     $ curl -D - -H 'Origin: http://foo.com' http://localhost:8080/ |  | ||||||
|     HTTP/1.1 200 OK |  | ||||||
|     Access-Control-Allow-Origin: foo.com |  | ||||||
|     Content-Type: application/json |  | ||||||
|     Date: Sat, 25 Oct 2014 03:43:57 GMT |  | ||||||
|     Content-Length: 18 |  | ||||||
|  |  | ||||||
|     {"hello": "world"} |  | ||||||
|  |  | ||||||
| ### More Examples |  | ||||||
|  |  | ||||||
| * `net/http`: [examples/nethttp/server.go](https://github.com/rs/cors/blob/master/examples/nethttp/server.go) |  | ||||||
| * [Goji](https://goji.io): [examples/goji/server.go](https://github.com/rs/cors/blob/master/examples/goji/server.go) |  | ||||||
| * [Martini](http://martini.codegangsta.io): [examples/martini/server.go](https://github.com/rs/cors/blob/master/examples/martini/server.go) |  | ||||||
| * [Negroni](https://github.com/codegangsta/negroni): [examples/negroni/server.go](https://github.com/rs/cors/blob/master/examples/negroni/server.go) |  | ||||||
| * [Alice](https://github.com/justinas/alice): [examples/alice/server.go](https://github.com/rs/cors/blob/master/examples/alice/server.go) |  | ||||||
|  |  | ||||||
| ## Parameters |  | ||||||
|  |  | ||||||
| Parameters are passed to the middleware thru the `cors.New` method as follow: |  | ||||||
|  |  | ||||||
| ```go |  | ||||||
| c := cors.New(cors.Options{ |  | ||||||
|     AllowedOrigins: []string{"http://foo.com"}, |  | ||||||
|     AllowCredentials: true, |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| // Insert the middleware |  | ||||||
| handler = c.Handler(handler) |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| * **AllowedOrigins** `[]string`: A list of origins a cross-domain request can be executed from. If the special `*` value is present in the list, all origins will be allowed. The default value is `*`. |  | ||||||
| * **AllowedMethods** `[]string`: A list of methods the client is allowed to use with cross-domain requests. |  | ||||||
| * **AllowedHeaders** `[]string`: A list of non simple headers the client is allowed to use with cross-domain requests. Default value is simple methods (`GET` and `POST`) |  | ||||||
| * **ExposedHeaders** `[]string`: Indicates which headers are safe to expose to the API of a CORS API specification |  | ||||||
| * **AllowCredentials** `bool`: Indicates whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates. The default is `false`. |  | ||||||
| * **MaxAge** `int`: Indicates how long (in seconds) the results of a preflight request can be cached. The default is `0` which stands for no max age. |  | ||||||
|  |  | ||||||
| See [API documentation](http://godoc.org/github.com/rs/cors) for more info. |  | ||||||
|  |  | ||||||
| ## Licenses |  | ||||||
|  |  | ||||||
| All source code is licensed under the [MIT License](https://raw.github.com/rs/cors/master/LICENSE). |  | ||||||
							
								
								
									
										37
									
								
								Godeps/_workspace/src/github.com/rs/cors/bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								Godeps/_workspace/src/github.com/rs/cors/bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,37 +0,0 @@ | |||||||
| package cors |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
| 	"net/http/httptest" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func BenchmarkWithout(b *testing.B) { |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("GET", "http://example.com/foo", nil) |  | ||||||
|  |  | ||||||
| 	for i := 0; i < b.N; i++ { |  | ||||||
| 		testHandler.ServeHTTP(res, req) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func BenchmarkDefault(b *testing.B) { |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("GET", "http://example.com/foo", nil) |  | ||||||
| 	handler := Default() |  | ||||||
|  |  | ||||||
| 	for i := 0; i < b.N; i++ { |  | ||||||
| 		handler.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func BenchmarkPreflight(b *testing.B) { |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Access-Control-Request-Method", "GET") |  | ||||||
| 	handler := Default() |  | ||||||
|  |  | ||||||
| 	for i := 0; i < b.N; i++ { |  | ||||||
| 		handler.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										308
									
								
								Godeps/_workspace/src/github.com/rs/cors/cors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										308
									
								
								Godeps/_workspace/src/github.com/rs/cors/cors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,308 +0,0 @@ | |||||||
| /* |  | ||||||
| Package cors is net/http handler to handle CORS related requests |  | ||||||
| as defined by http://www.w3.org/TR/cors/ |  | ||||||
|  |  | ||||||
| You can configure it by passing an option struct to cors.New: |  | ||||||
|  |  | ||||||
|     c := cors.New(cors.Options{ |  | ||||||
|         AllowedOrigins: []string{"foo.com"}, |  | ||||||
|         AllowedMethods: []string{"GET", "POST", "DELETE"}, |  | ||||||
|         AllowCredentials: true, |  | ||||||
|     }) |  | ||||||
|  |  | ||||||
| Then insert the handler in the chain: |  | ||||||
|  |  | ||||||
|     handler = c.Handler(handler) |  | ||||||
|  |  | ||||||
| See Options documentation for more options. |  | ||||||
|  |  | ||||||
| The resulting handler is a standard net/http handler. |  | ||||||
| */ |  | ||||||
| package cors |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"log" |  | ||||||
| 	"net/http" |  | ||||||
| 	"os" |  | ||||||
| 	"strconv" |  | ||||||
| 	"strings" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Options is a configuration container to setup the CORS middleware. |  | ||||||
| type Options struct { |  | ||||||
| 	// AllowedOrigins is a list of origins a cross-domain request can be executed from. |  | ||||||
| 	// If the special "*" value is present in the list, all origins will be allowed. |  | ||||||
| 	// Default value is ["*"] |  | ||||||
| 	AllowedOrigins []string |  | ||||||
| 	// AllowedMethods is a list of methods the client is allowed to use with |  | ||||||
| 	// cross-domain requests. Default value is simple methods (GET and POST) |  | ||||||
| 	AllowedMethods []string |  | ||||||
| 	// AllowedHeaders is list of non simple headers the client is allowed to use with |  | ||||||
| 	// cross-domain requests. |  | ||||||
| 	// If the special "*" value is present in the list, all headers will be allowed. |  | ||||||
| 	// Default value is [] but "Origin" is always appended to the list. |  | ||||||
| 	AllowedHeaders []string |  | ||||||
| 	// ExposedHeaders indicates which headers are safe to expose to the API of a CORS |  | ||||||
| 	// API specification |  | ||||||
| 	ExposedHeaders []string |  | ||||||
| 	// AllowCredentials indicates whether the request can include user credentials like |  | ||||||
| 	// cookies, HTTP authentication or client side SSL certificates. |  | ||||||
| 	AllowCredentials bool |  | ||||||
| 	// MaxAge indicates how long (in seconds) the results of a preflight request |  | ||||||
| 	// can be cached |  | ||||||
| 	MaxAge int |  | ||||||
| 	// Debugging flag adds additional output to debug server side CORS issues |  | ||||||
| 	Debug bool |  | ||||||
| 	// log object to use when debugging |  | ||||||
| 	log *log.Logger |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Cors struct { |  | ||||||
| 	// The CORS Options |  | ||||||
| 	options Options |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // New creates a new Cors handler with the provided options. |  | ||||||
| func New(options Options) *Cors { |  | ||||||
| 	// Normalize options |  | ||||||
| 	// Note: for origins and methods matching, the spec requires a case-sensitive matching. |  | ||||||
| 	// As it may error prone, we chose to ignore the spec here. |  | ||||||
| 	normOptions := Options{ |  | ||||||
| 		AllowedOrigins: convert(options.AllowedOrigins, strings.ToLower), |  | ||||||
| 		AllowedMethods: convert(options.AllowedMethods, strings.ToUpper), |  | ||||||
| 		// Origin is always appended as some browsers will always request |  | ||||||
| 		// for this header at preflight |  | ||||||
| 		AllowedHeaders:   convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey), |  | ||||||
| 		ExposedHeaders:   convert(options.ExposedHeaders, http.CanonicalHeaderKey), |  | ||||||
| 		AllowCredentials: options.AllowCredentials, |  | ||||||
| 		MaxAge:           options.MaxAge, |  | ||||||
| 		Debug:            options.Debug, |  | ||||||
| 		log:              log.New(os.Stdout, "[cors] ", log.LstdFlags), |  | ||||||
| 	} |  | ||||||
| 	if len(normOptions.AllowedOrigins) == 0 { |  | ||||||
| 		// Default is all origins |  | ||||||
| 		normOptions.AllowedOrigins = []string{"*"} |  | ||||||
| 	} |  | ||||||
| 	if len(normOptions.AllowedHeaders) == 1 { |  | ||||||
| 		// Add some sensible defaults |  | ||||||
| 		normOptions.AllowedHeaders = []string{"Origin", "Accept", "Content-Type"} |  | ||||||
| 	} |  | ||||||
| 	if len(normOptions.AllowedMethods) == 0 { |  | ||||||
| 		// Default is simple methods |  | ||||||
| 		normOptions.AllowedMethods = []string{"GET", "POST"} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if normOptions.Debug { |  | ||||||
| 		normOptions.log.Printf("Options: %v", normOptions) |  | ||||||
| 	} |  | ||||||
| 	return &Cors{ |  | ||||||
| 		options: normOptions, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Default creates a new Cors handler with default options |  | ||||||
| func Default() *Cors { |  | ||||||
| 	return New(Options{}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Handler apply the CORS specification on the request, and add relevant CORS headers |  | ||||||
| // as necessary. |  | ||||||
| func (cors *Cors) Handler(h http.Handler) http.Handler { |  | ||||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		if r.Method == "OPTIONS" { |  | ||||||
| 			cors.logf("Handler: Preflight request") |  | ||||||
| 			cors.handlePreflight(w, r) |  | ||||||
| 			// Preflight requests are standalone and should stop the chain as some other |  | ||||||
| 			// middleware may not handle OPTIONS requests correctly. One typical example |  | ||||||
| 			// is authentication middleware ; OPTIONS requests won't carry authentication |  | ||||||
| 			// headers (see #1) |  | ||||||
| 		} else { |  | ||||||
| 			cors.logf("Handler: Actual request") |  | ||||||
| 			cors.handleActualRequest(w, r) |  | ||||||
| 			h.ServeHTTP(w, r) |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Martini compatible handler |  | ||||||
| func (cors *Cors) HandlerFunc(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	if r.Method == "OPTIONS" { |  | ||||||
| 		cors.logf("HandlerFunc: Preflight request") |  | ||||||
| 		cors.handlePreflight(w, r) |  | ||||||
| 	} else { |  | ||||||
| 		cors.logf("HandlerFunc: Actual request") |  | ||||||
| 		cors.handleActualRequest(w, r) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Negroni compatible interface |  | ||||||
| func (cors *Cors) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { |  | ||||||
| 	if r.Method == "OPTIONS" { |  | ||||||
| 		cors.logf("ServeHTTP: Preflight request") |  | ||||||
| 		cors.handlePreflight(w, r) |  | ||||||
| 		// Preflight requests are standalone and should stop the chain as some other |  | ||||||
| 		// middleware may not handle OPTIONS requests correctly. One typical example |  | ||||||
| 		// is authentication middleware ; OPTIONS requests won't carry authentication |  | ||||||
| 		// headers (see #1) |  | ||||||
| 	} else { |  | ||||||
| 		cors.logf("ServeHTTP: Actual request") |  | ||||||
| 		cors.handleActualRequest(w, r) |  | ||||||
| 		next(w, r) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // handlePreflight handles pre-flight CORS requests |  | ||||||
| func (cors *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	options := cors.options |  | ||||||
| 	headers := w.Header() |  | ||||||
| 	origin := r.Header.Get("Origin") |  | ||||||
|  |  | ||||||
| 	if r.Method != "OPTIONS" { |  | ||||||
| 		cors.logf("  Preflight aborted: %s!=OPTIONS", r.Method) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if origin == "" { |  | ||||||
| 		cors.logf("  Preflight aborted: empty origin") |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if !cors.isOriginAllowed(origin) { |  | ||||||
| 		cors.logf("  Preflight aborted: origin '%s' not allowed", origin) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	reqMethod := r.Header.Get("Access-Control-Request-Method") |  | ||||||
| 	if !cors.isMethodAllowed(reqMethod) { |  | ||||||
| 		cors.logf("  Preflight aborted: method '%s' not allowed", reqMethod) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers")) |  | ||||||
| 	if !cors.areHeadersAllowed(reqHeaders) { |  | ||||||
| 		cors.logf("  Preflight aborted: headers '%v' not allowed", reqHeaders) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	headers.Set("Access-Control-Allow-Origin", origin) |  | ||||||
| 	headers.Add("Vary", "Origin") |  | ||||||
| 	// Spec says: Since the list of methods can be unbounded, simply returning the method indicated |  | ||||||
| 	// by Access-Control-Request-Method (if supported) can be enough |  | ||||||
| 	headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod)) |  | ||||||
| 	if len(reqHeaders) > 0 { |  | ||||||
|  |  | ||||||
| 		// Spec says: Since the list of headers can be unbounded, simply returning supported headers |  | ||||||
| 		// from Access-Control-Request-Headers can be enough |  | ||||||
| 		headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", ")) |  | ||||||
| 	} |  | ||||||
| 	if options.AllowCredentials { |  | ||||||
| 		headers.Set("Access-Control-Allow-Credentials", "true") |  | ||||||
| 	} |  | ||||||
| 	if options.MaxAge > 0 { |  | ||||||
| 		headers.Set("Access-Control-Max-Age", strconv.Itoa(options.MaxAge)) |  | ||||||
| 	} |  | ||||||
| 	cors.logf("  Preflight response headers: %v", headers) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // handleActualRequest handles simple cross-origin requests, actual request or redirects |  | ||||||
| func (cors *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	options := cors.options |  | ||||||
| 	headers := w.Header() |  | ||||||
| 	origin := r.Header.Get("Origin") |  | ||||||
|  |  | ||||||
| 	if r.Method == "OPTIONS" { |  | ||||||
| 		cors.logf("  Actual request no headers added: method == %s", r.Method) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if origin == "" { |  | ||||||
| 		cors.logf("  Actual request no headers added: missing origin") |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if !cors.isOriginAllowed(origin) { |  | ||||||
| 		cors.logf("  Actual request no headers added: origin '%s' not allowed", origin) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Note that spec does define a way to specifically disallow a simple method like GET or |  | ||||||
| 	// POST. Access-Control-Allow-Methods is only used for pre-flight requests and the |  | ||||||
| 	// spec doesn't instruct to check the allowed methods for simple cross-origin requests. |  | ||||||
| 	// We think it's a nice feature to be able to have control on those methods though. |  | ||||||
| 	if !cors.isMethodAllowed(r.Method) { |  | ||||||
| 		if cors.options.Debug { |  | ||||||
| 			cors.logf("  Actual request no headers added: method '%s' not allowed", |  | ||||||
| 				r.Method) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	headers.Set("Access-Control-Allow-Origin", origin) |  | ||||||
| 	headers.Add("Vary", "Origin") |  | ||||||
| 	if len(options.ExposedHeaders) > 0 { |  | ||||||
| 		headers.Set("Access-Control-Expose-Headers", strings.Join(options.ExposedHeaders, ", ")) |  | ||||||
| 	} |  | ||||||
| 	if options.AllowCredentials { |  | ||||||
| 		headers.Set("Access-Control-Allow-Credentials", "true") |  | ||||||
| 	} |  | ||||||
| 	cors.logf("  Actual response added headers: %v", headers) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // convenience method. checks if debugging is turned on before printing |  | ||||||
| func (cors *Cors) logf(format string, a ...interface{}) { |  | ||||||
| 	if cors.options.Debug { |  | ||||||
| 		cors.options.log.Printf(format, a...) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // isOriginAllowed checks if a given origin is allowed to perform cross-domain requests |  | ||||||
| // on the endpoint |  | ||||||
| func (cors *Cors) isOriginAllowed(origin string) bool { |  | ||||||
| 	allowedOrigins := cors.options.AllowedOrigins |  | ||||||
| 	origin = strings.ToLower(origin) |  | ||||||
| 	for _, allowedOrigin := range allowedOrigins { |  | ||||||
| 		switch allowedOrigin { |  | ||||||
| 		case "*": |  | ||||||
| 			return true |  | ||||||
| 		case origin: |  | ||||||
| 			return true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // isMethodAllowed checks if a given method can be used as part of a cross-domain request |  | ||||||
| // on the endpoing |  | ||||||
| func (cors *Cors) isMethodAllowed(method string) bool { |  | ||||||
| 	allowedMethods := cors.options.AllowedMethods |  | ||||||
| 	if len(allowedMethods) == 0 { |  | ||||||
| 		// If no method allowed, always return false, even for preflight request |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	method = strings.ToUpper(method) |  | ||||||
| 	if method == "OPTIONS" { |  | ||||||
| 		// Always allow preflight requests |  | ||||||
| 		return true |  | ||||||
| 	} |  | ||||||
| 	for _, allowedMethod := range allowedMethods { |  | ||||||
| 		if allowedMethod == method { |  | ||||||
| 			return true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // areHeadersAllowed checks if a given list of headers are allowed to used within |  | ||||||
| // a cross-domain request. |  | ||||||
| func (cors *Cors) areHeadersAllowed(requestedHeaders []string) bool { |  | ||||||
| 	if len(requestedHeaders) == 0 { |  | ||||||
| 		return true |  | ||||||
| 	} |  | ||||||
| 	for _, header := range requestedHeaders { |  | ||||||
| 		found := false |  | ||||||
| 		for _, allowedHeader := range cors.options.AllowedHeaders { |  | ||||||
| 			if allowedHeader == "*" || allowedHeader == header { |  | ||||||
| 				found = true |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if !found { |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
							
								
								
									
										288
									
								
								Godeps/_workspace/src/github.com/rs/cors/cors_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										288
									
								
								Godeps/_workspace/src/github.com/rs/cors/cors_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,288 +0,0 @@ | |||||||
| package cors |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
| 	"net/http/httptest" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var testHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	w.Write([]byte("bar")) |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| func assertHeaders(t *testing.T, resHeaders http.Header, reqHeaders map[string]string) { |  | ||||||
| 	for name, value := range reqHeaders { |  | ||||||
| 		if resHeaders.Get(name) != value { |  | ||||||
| 			t.Errorf("Invalid header `%s', wanted `%s', got `%s'", name, value, resHeaders.Get(name)) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestNoConfig(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 	// Intentionally left blank. |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("GET", "http://example.com/foo", nil) |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "", |  | ||||||
| 		"Access-Control-Allow-Methods":     "", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestWildcardOrigin(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"*"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("GET", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "http://foobar.com", |  | ||||||
| 		"Access-Control-Allow-Methods":     "", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestAllowedOrigin(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("GET", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "http://foobar.com", |  | ||||||
| 		"Access-Control-Allow-Methods":     "", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestDisallowedOrigin(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("GET", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://barbaz.com") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "", |  | ||||||
| 		"Access-Control-Allow-Methods":     "", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestAllowedMethod(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 		AllowedMethods: []string{"PUT", "DELETE"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Method", "PUT") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "http://foobar.com", |  | ||||||
| 		"Access-Control-Allow-Methods":     "PUT", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestDisallowedMethod(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 		AllowedMethods: []string{"PUT", "DELETE"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Method", "PATCH") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "", |  | ||||||
| 		"Access-Control-Allow-Methods":     "", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestAllowedHeader(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 		AllowedHeaders: []string{"X-Header-1", "x-header-2"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Method", "GET") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Headers", "X-Header-2, X-HEADER-1") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "http://foobar.com", |  | ||||||
| 		"Access-Control-Allow-Methods":     "GET", |  | ||||||
| 		"Access-Control-Allow-Headers":     "X-Header-2, X-Header-1", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestAllowedWildcardHeader(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 		AllowedHeaders: []string{"*"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Method", "GET") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Headers", "X-Header-2, X-HEADER-1") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "http://foobar.com", |  | ||||||
| 		"Access-Control-Allow-Methods":     "GET", |  | ||||||
| 		"Access-Control-Allow-Headers":     "X-Header-2, X-Header-1", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestDisallowedHeader(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 		AllowedHeaders: []string{"X-Header-1", "x-header-2"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Method", "GET") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Headers", "X-Header-3, X-Header-1") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "", |  | ||||||
| 		"Access-Control-Allow-Methods":     "", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestOriginHeader(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Method", "GET") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Headers", "origin") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "http://foobar.com", |  | ||||||
| 		"Access-Control-Allow-Methods":     "GET", |  | ||||||
| 		"Access-Control-Allow-Headers":     "Origin", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestExposedHeader(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foobar.com"}, |  | ||||||
| 		ExposedHeaders: []string{"X-Header-1", "x-header-2"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("GET", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "http://foobar.com", |  | ||||||
| 		"Access-Control-Allow-Methods":     "", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "X-Header-1, X-Header-2", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestAllowedCredentials(t *testing.T) { |  | ||||||
| 	s := New(Options{ |  | ||||||
| 		AllowedOrigins:   []string{"http://foobar.com"}, |  | ||||||
| 		AllowCredentials: true, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	res := httptest.NewRecorder() |  | ||||||
| 	req, _ := http.NewRequest("OPTIONS", "http://example.com/foo", nil) |  | ||||||
| 	req.Header.Add("Origin", "http://foobar.com") |  | ||||||
| 	req.Header.Add("Access-Control-Request-Method", "GET") |  | ||||||
|  |  | ||||||
| 	s.Handler(testHandler).ServeHTTP(res, req) |  | ||||||
|  |  | ||||||
| 	assertHeaders(t, res.Header(), map[string]string{ |  | ||||||
| 		"Access-Control-Allow-Origin":      "http://foobar.com", |  | ||||||
| 		"Access-Control-Allow-Methods":     "GET", |  | ||||||
| 		"Access-Control-Allow-Headers":     "", |  | ||||||
| 		"Access-Control-Allow-Credentials": "true", |  | ||||||
| 		"Access-Control-Max-Age":           "", |  | ||||||
| 		"Access-Control-Expose-Headers":    "", |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
							
								
								
									
										24
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/alice/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/alice/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,24 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/justinas/alice" |  | ||||||
| 	"github.com/rs/cors" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	c := cors.New(cors.Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foo.com"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	mux := http.NewServeMux() |  | ||||||
|  |  | ||||||
| 	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		w.Write([]byte("{\"hello\": \"world\"}")) |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	chain := alice.New(c.Handler).Then(mux) |  | ||||||
| 	http.ListenAndServe(":8080", chain) |  | ||||||
| } |  | ||||||
							
								
								
									
										18
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/default/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/default/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,18 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/rs/cors" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		w.Write([]byte("{\"hello\": \"world\"}")) |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	// Use default options |  | ||||||
| 	handler := cors.Default().Handler(h) |  | ||||||
| 	http.ListenAndServe(":8080", handler) |  | ||||||
| } |  | ||||||
							
								
								
									
										22
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/goji/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/goji/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,22 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/rs/cors" |  | ||||||
| 	"github.com/zenazn/goji" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	c := cors.New(cors.Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foo.com"}, |  | ||||||
| 	}) |  | ||||||
| 	goji.Use(c.Handler) |  | ||||||
|  |  | ||||||
| 	goji.Get("/", func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		w.Write([]byte("{\"hello\": \"world\"}")) |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	goji.Serve() |  | ||||||
| } |  | ||||||
							
								
								
									
										23
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/martini/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/martini/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,23 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/go-martini/martini" |  | ||||||
| 	"github.com/martini-contrib/render" |  | ||||||
| 	"github.com/rs/cors" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	c := cors.New(cors.Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foo.com"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	m := martini.Classic() |  | ||||||
| 	m.Use(render.Renderer()) |  | ||||||
| 	m.Use(c.HandlerFunc) |  | ||||||
|  |  | ||||||
| 	m.Get("/", func(r render.Render) { |  | ||||||
| 		r.JSON(200, map[string]interface{}{"hello": "world"}) |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	m.Run() |  | ||||||
| } |  | ||||||
							
								
								
									
										26
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/negroni/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/negroni/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,26 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/codegangsta/negroni" |  | ||||||
| 	"github.com/rs/cors" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	c := cors.New(cors.Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foo.com"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	mux := http.NewServeMux() |  | ||||||
|  |  | ||||||
| 	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		w.Write([]byte("{\"hello\": \"world\"}")) |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	n := negroni.Classic() |  | ||||||
| 	n.Use(c) |  | ||||||
| 	n.UseHandler(mux) |  | ||||||
| 	n.Run(":3000") |  | ||||||
| } |  | ||||||
							
								
								
									
										20
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/nethttp/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/nethttp/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,20 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/rs/cors" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	c := cors.New(cors.Options{ |  | ||||||
| 		AllowedOrigins: []string{"http://foo.com"}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		w.Write([]byte("{\"hello\": \"world\"}")) |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	http.ListenAndServe(":8080", c.Handler(handler)) |  | ||||||
| } |  | ||||||
							
								
								
									
										22
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/openbar/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								Godeps/_workspace/src/github.com/rs/cors/examples/openbar/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,22 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/rs/cors" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	c := cors.New(cors.Options{ |  | ||||||
| 		AllowedOrigins:   []string{"*"}, |  | ||||||
| 		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE"}, |  | ||||||
| 		AllowCredentials: true, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		w.Write([]byte("{\"hello\": \"world\"}")) |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	http.ListenAndServe(":8080", c.Handler(h)) |  | ||||||
| } |  | ||||||
							
								
								
									
										27
									
								
								Godeps/_workspace/src/github.com/rs/cors/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								Godeps/_workspace/src/github.com/rs/cors/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,27 +0,0 @@ | |||||||
| package cors |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
| 	"strings" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type converter func(string) string |  | ||||||
|  |  | ||||||
| // convert converts a list of string using the passed converter function |  | ||||||
| func convert(s []string, c converter) []string { |  | ||||||
| 	out := []string{} |  | ||||||
| 	for _, i := range s { |  | ||||||
| 		out = append(out, c(i)) |  | ||||||
| 	} |  | ||||||
| 	return out |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func parseHeaderList(headerList string) (headers []string) { |  | ||||||
| 	for _, header := range strings.Split(headerList, ",") { |  | ||||||
| 		header = http.CanonicalHeaderKey(strings.TrimSpace(header)) |  | ||||||
| 		if header != "" { |  | ||||||
| 			headers = append(headers, header) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return headers |  | ||||||
| } |  | ||||||
							
								
								
									
										28
									
								
								Godeps/_workspace/src/github.com/rs/cors/utils_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								Godeps/_workspace/src/github.com/rs/cors/utils_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,28 +0,0 @@ | |||||||
| package cors |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"strings" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestConvert(t *testing.T) { |  | ||||||
| 	s := convert([]string{"A", "b", "C"}, strings.ToLower) |  | ||||||
| 	e := []string{"a", "b", "c"} |  | ||||||
| 	if s[0] != e[0] || s[1] != e[1] || s[2] != e[2] { |  | ||||||
| 		t.Errorf("%v != %v", s, e) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestParseHeaderList(t *testing.T) { |  | ||||||
| 	h := parseHeaderList("header, second-header, THIRD-HEADER") |  | ||||||
| 	e := []string{"Header", "Second-Header", "Third-Header"} |  | ||||||
| 	if h[0] != e[0] || h[1] != e[1] || h[2] != e[2] { |  | ||||||
| 		t.Errorf("%v != %v", h, e) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestParseHeaderListEmpty(t *testing.T) { |  | ||||||
| 	if len(parseHeaderList("")) != 0 { |  | ||||||
| 		t.Error("should be empty sclice") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										113
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | |||||||
|  | // Copyright 2009 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package websocket | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"crypto/tls" | ||||||
|  | 	"io" | ||||||
|  | 	"net" | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // DialError is an error that occurs while dialling a websocket server. | ||||||
|  | type DialError struct { | ||||||
|  | 	*Config | ||||||
|  | 	Err error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (e *DialError) Error() string { | ||||||
|  | 	return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewConfig creates a new WebSocket config for client connection. | ||||||
|  | func NewConfig(server, origin string) (config *Config, err error) { | ||||||
|  | 	config = new(Config) | ||||||
|  | 	config.Version = ProtocolVersionHybi13 | ||||||
|  | 	config.Location, err = url.ParseRequestURI(server) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	config.Origin, err = url.ParseRequestURI(origin) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	config.Header = http.Header(make(map[string][]string)) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewClient creates a new WebSocket client connection over rwc. | ||||||
|  | func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) { | ||||||
|  | 	br := bufio.NewReader(rwc) | ||||||
|  | 	bw := bufio.NewWriter(rwc) | ||||||
|  | 	err = hybiClientHandshake(config, br, bw) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	buf := bufio.NewReadWriter(br, bw) | ||||||
|  | 	ws = newHybiClientConn(config, buf, rwc) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Dial opens a new client connection to a WebSocket. | ||||||
|  | func Dial(url_, protocol, origin string) (ws *Conn, err error) { | ||||||
|  | 	config, err := NewConfig(url_, origin) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if protocol != "" { | ||||||
|  | 		config.Protocol = []string{protocol} | ||||||
|  | 	} | ||||||
|  | 	return DialConfig(config) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var portMap = map[string]string{ | ||||||
|  | 	"ws":  "80", | ||||||
|  | 	"wss": "443", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseAuthority(location *url.URL) string { | ||||||
|  | 	if _, ok := portMap[location.Scheme]; ok { | ||||||
|  | 		if _, _, err := net.SplitHostPort(location.Host); err != nil { | ||||||
|  | 			return net.JoinHostPort(location.Host, portMap[location.Scheme]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return location.Host | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DialConfig opens a new client connection to a WebSocket with a config. | ||||||
|  | func DialConfig(config *Config) (ws *Conn, err error) { | ||||||
|  | 	var client net.Conn | ||||||
|  | 	if config.Location == nil { | ||||||
|  | 		return nil, &DialError{config, ErrBadWebSocketLocation} | ||||||
|  | 	} | ||||||
|  | 	if config.Origin == nil { | ||||||
|  | 		return nil, &DialError{config, ErrBadWebSocketOrigin} | ||||||
|  | 	} | ||||||
|  | 	switch config.Location.Scheme { | ||||||
|  | 	case "ws": | ||||||
|  | 		client, err = net.Dial("tcp", parseAuthority(config.Location)) | ||||||
|  |  | ||||||
|  | 	case "wss": | ||||||
|  | 		client, err = tls.Dial("tcp", parseAuthority(config.Location), config.TlsConfig) | ||||||
|  |  | ||||||
|  | 	default: | ||||||
|  | 		err = ErrBadScheme | ||||||
|  | 	} | ||||||
|  | 	if err != nil { | ||||||
|  | 		goto Error | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ws, err = NewClient(config, client) | ||||||
|  | 	if err != nil { | ||||||
|  | 		client.Close() | ||||||
|  | 		goto Error | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  |  | ||||||
|  | Error: | ||||||
|  | 	return nil, &DialError{config, err} | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/exampledial_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/exampledial_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | // Copyright 2012 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package websocket_test | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/net/websocket" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // This example demonstrates a trivial client. | ||||||
|  | func ExampleDial() { | ||||||
|  | 	origin := "http://localhost/" | ||||||
|  | 	url := "ws://localhost:12345/ws" | ||||||
|  | 	ws, err := websocket.Dial(url, "", origin) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	if _, err := ws.Write([]byte("hello, world!\n")); err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	var msg = make([]byte, 512) | ||||||
|  | 	var n int | ||||||
|  | 	if n, err = ws.Read(msg); err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	fmt.Printf("Received: %s.\n", msg[:n]) | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/examplehandler_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/examplehandler_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | // Copyright 2012 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package websocket_test | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | 	"net/http" | ||||||
|  |  | ||||||
|  | 	"golang.org/x/net/websocket" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Echo the data received on the WebSocket. | ||||||
|  | func EchoServer(ws *websocket.Conn) { | ||||||
|  | 	io.Copy(ws, ws) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // This example demonstrates a trivial echo server. | ||||||
|  | func ExampleHandler() { | ||||||
|  | 	http.Handle("/echo", websocket.Handler(EchoServer)) | ||||||
|  | 	err := http.ListenAndServe(":12345", nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic("ListenAndServe: " + err.Error()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										564
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										564
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,564 @@ | |||||||
|  | // Copyright 2011 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package websocket | ||||||
|  |  | ||||||
|  | // This file implements a protocol of hybi draft. | ||||||
|  | // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/sha1" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"encoding/binary" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" | ||||||
|  |  | ||||||
|  | 	closeStatusNormal            = 1000 | ||||||
|  | 	closeStatusGoingAway         = 1001 | ||||||
|  | 	closeStatusProtocolError     = 1002 | ||||||
|  | 	closeStatusUnsupportedData   = 1003 | ||||||
|  | 	closeStatusFrameTooLarge     = 1004 | ||||||
|  | 	closeStatusNoStatusRcvd      = 1005 | ||||||
|  | 	closeStatusAbnormalClosure   = 1006 | ||||||
|  | 	closeStatusBadMessageData    = 1007 | ||||||
|  | 	closeStatusPolicyViolation   = 1008 | ||||||
|  | 	closeStatusTooBigData        = 1009 | ||||||
|  | 	closeStatusExtensionMismatch = 1010 | ||||||
|  |  | ||||||
|  | 	maxControlFramePayloadLength = 125 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	ErrBadMaskingKey         = &ProtocolError{"bad masking key"} | ||||||
|  | 	ErrBadPongMessage        = &ProtocolError{"bad pong message"} | ||||||
|  | 	ErrBadClosingStatus      = &ProtocolError{"bad closing status"} | ||||||
|  | 	ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"} | ||||||
|  | 	ErrNotImplemented        = &ProtocolError{"not implemented"} | ||||||
|  |  | ||||||
|  | 	handshakeHeader = map[string]bool{ | ||||||
|  | 		"Host":                   true, | ||||||
|  | 		"Upgrade":                true, | ||||||
|  | 		"Connection":             true, | ||||||
|  | 		"Sec-Websocket-Key":      true, | ||||||
|  | 		"Sec-Websocket-Origin":   true, | ||||||
|  | 		"Sec-Websocket-Version":  true, | ||||||
|  | 		"Sec-Websocket-Protocol": true, | ||||||
|  | 		"Sec-Websocket-Accept":   true, | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // A hybiFrameHeader is a frame header as defined in hybi draft. | ||||||
|  | type hybiFrameHeader struct { | ||||||
|  | 	Fin        bool | ||||||
|  | 	Rsv        [3]bool | ||||||
|  | 	OpCode     byte | ||||||
|  | 	Length     int64 | ||||||
|  | 	MaskingKey []byte | ||||||
|  |  | ||||||
|  | 	data *bytes.Buffer | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A hybiFrameReader is a reader for hybi frame. | ||||||
|  | type hybiFrameReader struct { | ||||||
|  | 	reader io.Reader | ||||||
|  |  | ||||||
|  | 	header hybiFrameHeader | ||||||
|  | 	pos    int64 | ||||||
|  | 	length int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) { | ||||||
|  | 	n, err = frame.reader.Read(msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	if frame.header.MaskingKey != nil { | ||||||
|  | 		for i := 0; i < n; i++ { | ||||||
|  | 			msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4] | ||||||
|  | 			frame.pos++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode } | ||||||
|  |  | ||||||
|  | func (frame *hybiFrameReader) HeaderReader() io.Reader { | ||||||
|  | 	if frame.header.data == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if frame.header.data.Len() == 0 { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return frame.header.data | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil } | ||||||
|  |  | ||||||
|  | func (frame *hybiFrameReader) Len() (n int) { return frame.length } | ||||||
|  |  | ||||||
|  | // A hybiFrameReaderFactory creates new frame reader based on its frame type. | ||||||
|  | type hybiFrameReaderFactory struct { | ||||||
|  | 	*bufio.Reader | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewFrameReader reads a frame header from the connection, and creates new reader for the frame. | ||||||
|  | // See Section 5.2 Base Framing protocol for detail. | ||||||
|  | // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2 | ||||||
|  | func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) { | ||||||
|  | 	hybiFrame := new(hybiFrameReader) | ||||||
|  | 	frame = hybiFrame | ||||||
|  | 	var header []byte | ||||||
|  | 	var b byte | ||||||
|  | 	// First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits) | ||||||
|  | 	b, err = buf.ReadByte() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	header = append(header, b) | ||||||
|  | 	hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0 | ||||||
|  | 	for i := 0; i < 3; i++ { | ||||||
|  | 		j := uint(6 - i) | ||||||
|  | 		hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0 | ||||||
|  | 	} | ||||||
|  | 	hybiFrame.header.OpCode = header[0] & 0x0f | ||||||
|  |  | ||||||
|  | 	// Second byte. Mask/Payload len(7bits) | ||||||
|  | 	b, err = buf.ReadByte() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	header = append(header, b) | ||||||
|  | 	mask := (b & 0x80) != 0 | ||||||
|  | 	b &= 0x7f | ||||||
|  | 	lengthFields := 0 | ||||||
|  | 	switch { | ||||||
|  | 	case b <= 125: // Payload length 7bits. | ||||||
|  | 		hybiFrame.header.Length = int64(b) | ||||||
|  | 	case b == 126: // Payload length 7+16bits | ||||||
|  | 		lengthFields = 2 | ||||||
|  | 	case b == 127: // Payload length 7+64bits | ||||||
|  | 		lengthFields = 8 | ||||||
|  | 	} | ||||||
|  | 	for i := 0; i < lengthFields; i++ { | ||||||
|  | 		b, err = buf.ReadByte() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		header = append(header, b) | ||||||
|  | 		hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b) | ||||||
|  | 	} | ||||||
|  | 	if mask { | ||||||
|  | 		// Masking key. 4 bytes. | ||||||
|  | 		for i := 0; i < 4; i++ { | ||||||
|  | 			b, err = buf.ReadByte() | ||||||
|  | 			if err != nil { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 			header = append(header, b) | ||||||
|  | 			hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length) | ||||||
|  | 	hybiFrame.header.data = bytes.NewBuffer(header) | ||||||
|  | 	hybiFrame.length = len(header) + int(hybiFrame.header.Length) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A HybiFrameWriter is a writer for hybi frame. | ||||||
|  | type hybiFrameWriter struct { | ||||||
|  | 	writer *bufio.Writer | ||||||
|  |  | ||||||
|  | 	header *hybiFrameHeader | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) { | ||||||
|  | 	var header []byte | ||||||
|  | 	var b byte | ||||||
|  | 	if frame.header.Fin { | ||||||
|  | 		b |= 0x80 | ||||||
|  | 	} | ||||||
|  | 	for i := 0; i < 3; i++ { | ||||||
|  | 		if frame.header.Rsv[i] { | ||||||
|  | 			j := uint(6 - i) | ||||||
|  | 			b |= 1 << j | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	b |= frame.header.OpCode | ||||||
|  | 	header = append(header, b) | ||||||
|  | 	if frame.header.MaskingKey != nil { | ||||||
|  | 		b = 0x80 | ||||||
|  | 	} else { | ||||||
|  | 		b = 0 | ||||||
|  | 	} | ||||||
|  | 	lengthFields := 0 | ||||||
|  | 	length := len(msg) | ||||||
|  | 	switch { | ||||||
|  | 	case length <= 125: | ||||||
|  | 		b |= byte(length) | ||||||
|  | 	case length < 65536: | ||||||
|  | 		b |= 126 | ||||||
|  | 		lengthFields = 2 | ||||||
|  | 	default: | ||||||
|  | 		b |= 127 | ||||||
|  | 		lengthFields = 8 | ||||||
|  | 	} | ||||||
|  | 	header = append(header, b) | ||||||
|  | 	for i := 0; i < lengthFields; i++ { | ||||||
|  | 		j := uint((lengthFields - i - 1) * 8) | ||||||
|  | 		b = byte((length >> j) & 0xff) | ||||||
|  | 		header = append(header, b) | ||||||
|  | 	} | ||||||
|  | 	if frame.header.MaskingKey != nil { | ||||||
|  | 		if len(frame.header.MaskingKey) != 4 { | ||||||
|  | 			return 0, ErrBadMaskingKey | ||||||
|  | 		} | ||||||
|  | 		header = append(header, frame.header.MaskingKey...) | ||||||
|  | 		frame.writer.Write(header) | ||||||
|  | 		data := make([]byte, length) | ||||||
|  | 		for i := range data { | ||||||
|  | 			data[i] = msg[i] ^ frame.header.MaskingKey[i%4] | ||||||
|  | 		} | ||||||
|  | 		frame.writer.Write(data) | ||||||
|  | 		err = frame.writer.Flush() | ||||||
|  | 		return length, err | ||||||
|  | 	} | ||||||
|  | 	frame.writer.Write(header) | ||||||
|  | 	frame.writer.Write(msg) | ||||||
|  | 	err = frame.writer.Flush() | ||||||
|  | 	return length, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (frame *hybiFrameWriter) Close() error { return nil } | ||||||
|  |  | ||||||
|  | type hybiFrameWriterFactory struct { | ||||||
|  | 	*bufio.Writer | ||||||
|  | 	needMaskingKey bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) { | ||||||
|  | 	frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType} | ||||||
|  | 	if buf.needMaskingKey { | ||||||
|  | 		frameHeader.MaskingKey, err = generateMaskingKey() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type hybiFrameHandler struct { | ||||||
|  | 	conn        *Conn | ||||||
|  | 	payloadType byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) { | ||||||
|  | 	if handler.conn.IsServerConn() { | ||||||
|  | 		// The client MUST mask all frames sent to the server. | ||||||
|  | 		if frame.(*hybiFrameReader).header.MaskingKey == nil { | ||||||
|  | 			handler.WriteClose(closeStatusProtocolError) | ||||||
|  | 			return nil, io.EOF | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// The server MUST NOT mask all frames. | ||||||
|  | 		if frame.(*hybiFrameReader).header.MaskingKey != nil { | ||||||
|  | 			handler.WriteClose(closeStatusProtocolError) | ||||||
|  | 			return nil, io.EOF | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if header := frame.HeaderReader(); header != nil { | ||||||
|  | 		io.Copy(ioutil.Discard, header) | ||||||
|  | 	} | ||||||
|  | 	switch frame.PayloadType() { | ||||||
|  | 	case ContinuationFrame: | ||||||
|  | 		frame.(*hybiFrameReader).header.OpCode = handler.payloadType | ||||||
|  | 	case TextFrame, BinaryFrame: | ||||||
|  | 		handler.payloadType = frame.PayloadType() | ||||||
|  | 	case CloseFrame: | ||||||
|  | 		return nil, io.EOF | ||||||
|  | 	case PingFrame: | ||||||
|  | 		pingMsg := make([]byte, maxControlFramePayloadLength) | ||||||
|  | 		n, err := io.ReadFull(frame, pingMsg) | ||||||
|  | 		if err != nil && err != io.ErrUnexpectedEOF { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		io.Copy(ioutil.Discard, frame) | ||||||
|  | 		n, err = handler.WritePong(pingMsg[:n]) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		return nil, nil | ||||||
|  | 	case PongFrame: | ||||||
|  | 		return nil, ErrNotImplemented | ||||||
|  | 	} | ||||||
|  | 	return frame, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (handler *hybiFrameHandler) WriteClose(status int) (err error) { | ||||||
|  | 	handler.conn.wio.Lock() | ||||||
|  | 	defer handler.conn.wio.Unlock() | ||||||
|  | 	w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	msg := make([]byte, 2) | ||||||
|  | 	binary.BigEndian.PutUint16(msg, uint16(status)) | ||||||
|  | 	_, err = w.Write(msg) | ||||||
|  | 	w.Close() | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) { | ||||||
|  | 	handler.conn.wio.Lock() | ||||||
|  | 	defer handler.conn.wio.Unlock() | ||||||
|  | 	w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	n, err = w.Write(msg) | ||||||
|  | 	w.Close() | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // newHybiConn creates a new WebSocket connection speaking hybi draft protocol. | ||||||
|  | func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { | ||||||
|  | 	if buf == nil { | ||||||
|  | 		br := bufio.NewReader(rwc) | ||||||
|  | 		bw := bufio.NewWriter(rwc) | ||||||
|  | 		buf = bufio.NewReadWriter(br, bw) | ||||||
|  | 	} | ||||||
|  | 	ws := &Conn{config: config, request: request, buf: buf, rwc: rwc, | ||||||
|  | 		frameReaderFactory: hybiFrameReaderFactory{buf.Reader}, | ||||||
|  | 		frameWriterFactory: hybiFrameWriterFactory{ | ||||||
|  | 			buf.Writer, request == nil}, | ||||||
|  | 		PayloadType:        TextFrame, | ||||||
|  | 		defaultCloseStatus: closeStatusNormal} | ||||||
|  | 	ws.frameHandler = &hybiFrameHandler{conn: ws} | ||||||
|  | 	return ws | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // generateMaskingKey generates a masking key for a frame. | ||||||
|  | func generateMaskingKey() (maskingKey []byte, err error) { | ||||||
|  | 	maskingKey = make([]byte, 4) | ||||||
|  | 	if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // generateNonce generates a nonce consisting of a randomly selected 16-byte | ||||||
|  | // value that has been base64-encoded. | ||||||
|  | func generateNonce() (nonce []byte) { | ||||||
|  | 	key := make([]byte, 16) | ||||||
|  | 	if _, err := io.ReadFull(rand.Reader, key); err != nil { | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  | 	nonce = make([]byte, 24) | ||||||
|  | 	base64.StdEncoding.Encode(nonce, key) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // getNonceAccept computes the base64-encoded SHA-1 of the concatenation of | ||||||
|  | // the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string. | ||||||
|  | func getNonceAccept(nonce []byte) (expected []byte, err error) { | ||||||
|  | 	h := sha1.New() | ||||||
|  | 	if _, err = h.Write(nonce); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if _, err = h.Write([]byte(websocketGUID)); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	expected = make([]byte, 28) | ||||||
|  | 	base64.StdEncoding.Encode(expected, h.Sum(nil)) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17 | ||||||
|  | func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) { | ||||||
|  | 	bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") | ||||||
|  |  | ||||||
|  | 	bw.WriteString("Host: " + config.Location.Host + "\r\n") | ||||||
|  | 	bw.WriteString("Upgrade: websocket\r\n") | ||||||
|  | 	bw.WriteString("Connection: Upgrade\r\n") | ||||||
|  | 	nonce := generateNonce() | ||||||
|  | 	if config.handshakeData != nil { | ||||||
|  | 		nonce = []byte(config.handshakeData["key"]) | ||||||
|  | 	} | ||||||
|  | 	bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n") | ||||||
|  | 	bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") | ||||||
|  |  | ||||||
|  | 	if config.Version != ProtocolVersionHybi13 { | ||||||
|  | 		return ErrBadProtocolVersion | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n") | ||||||
|  | 	if len(config.Protocol) > 0 { | ||||||
|  | 		bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n") | ||||||
|  | 	} | ||||||
|  | 	// TODO(ukai): send Sec-WebSocket-Extensions. | ||||||
|  | 	err = config.Header.WriteSubset(bw, handshakeHeader) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bw.WriteString("\r\n") | ||||||
|  | 	if err = bw.Flush(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	resp, err := http.ReadResponse(br, &http.Request{Method: "GET"}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if resp.StatusCode != 101 { | ||||||
|  | 		return ErrBadStatus | ||||||
|  | 	} | ||||||
|  | 	if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" || | ||||||
|  | 		strings.ToLower(resp.Header.Get("Connection")) != "upgrade" { | ||||||
|  | 		return ErrBadUpgrade | ||||||
|  | 	} | ||||||
|  | 	expectedAccept, err := getNonceAccept(nonce) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) { | ||||||
|  | 		return ErrChallengeResponse | ||||||
|  | 	} | ||||||
|  | 	if resp.Header.Get("Sec-WebSocket-Extensions") != "" { | ||||||
|  | 		return ErrUnsupportedExtensions | ||||||
|  | 	} | ||||||
|  | 	offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol") | ||||||
|  | 	if offeredProtocol != "" { | ||||||
|  | 		protocolMatched := false | ||||||
|  | 		for i := 0; i < len(config.Protocol); i++ { | ||||||
|  | 			if config.Protocol[i] == offeredProtocol { | ||||||
|  | 				protocolMatched = true | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if !protocolMatched { | ||||||
|  | 			return ErrBadWebSocketProtocol | ||||||
|  | 		} | ||||||
|  | 		config.Protocol = []string{offeredProtocol} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // newHybiClientConn creates a client WebSocket connection after handshake. | ||||||
|  | func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn { | ||||||
|  | 	return newHybiConn(config, buf, rwc, nil) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A HybiServerHandshaker performs a server handshake using hybi draft protocol. | ||||||
|  | type hybiServerHandshaker struct { | ||||||
|  | 	*Config | ||||||
|  | 	accept []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) { | ||||||
|  | 	c.Version = ProtocolVersionHybi13 | ||||||
|  | 	if req.Method != "GET" { | ||||||
|  | 		return http.StatusMethodNotAllowed, ErrBadRequestMethod | ||||||
|  | 	} | ||||||
|  | 	// HTTP version can be safely ignored. | ||||||
|  |  | ||||||
|  | 	if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" || | ||||||
|  | 		!strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") { | ||||||
|  | 		return http.StatusBadRequest, ErrNotWebSocket | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	key := req.Header.Get("Sec-Websocket-Key") | ||||||
|  | 	if key == "" { | ||||||
|  | 		return http.StatusBadRequest, ErrChallengeResponse | ||||||
|  | 	} | ||||||
|  | 	version := req.Header.Get("Sec-Websocket-Version") | ||||||
|  | 	switch version { | ||||||
|  | 	case "13": | ||||||
|  | 		c.Version = ProtocolVersionHybi13 | ||||||
|  | 	default: | ||||||
|  | 		return http.StatusBadRequest, ErrBadWebSocketVersion | ||||||
|  | 	} | ||||||
|  | 	var scheme string | ||||||
|  | 	if req.TLS != nil { | ||||||
|  | 		scheme = "wss" | ||||||
|  | 	} else { | ||||||
|  | 		scheme = "ws" | ||||||
|  | 	} | ||||||
|  | 	c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return http.StatusBadRequest, err | ||||||
|  | 	} | ||||||
|  | 	protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol")) | ||||||
|  | 	if protocol != "" { | ||||||
|  | 		protocols := strings.Split(protocol, ",") | ||||||
|  | 		for i := 0; i < len(protocols); i++ { | ||||||
|  | 			c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i])) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	c.accept, err = getNonceAccept([]byte(key)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return http.StatusInternalServerError, err | ||||||
|  | 	} | ||||||
|  | 	return http.StatusSwitchingProtocols, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Origin parses Origin header in "req". | ||||||
|  | // If origin is "null", returns (nil, nil). | ||||||
|  | func Origin(config *Config, req *http.Request) (*url.URL, error) { | ||||||
|  | 	var origin string | ||||||
|  | 	switch config.Version { | ||||||
|  | 	case ProtocolVersionHybi13: | ||||||
|  | 		origin = req.Header.Get("Origin") | ||||||
|  | 	} | ||||||
|  | 	if origin == "null" { | ||||||
|  | 		return nil, nil | ||||||
|  | 	} | ||||||
|  | 	return url.ParseRequestURI(origin) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) { | ||||||
|  | 	if len(c.Protocol) > 0 { | ||||||
|  | 		if len(c.Protocol) != 1 { | ||||||
|  | 			// You need choose a Protocol in Handshake func in Server. | ||||||
|  | 			return ErrBadWebSocketProtocol | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n") | ||||||
|  | 	buf.WriteString("Upgrade: websocket\r\n") | ||||||
|  | 	buf.WriteString("Connection: Upgrade\r\n") | ||||||
|  | 	buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n") | ||||||
|  | 	if len(c.Protocol) > 0 { | ||||||
|  | 		buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n") | ||||||
|  | 	} | ||||||
|  | 	// TODO(ukai): send Sec-WebSocket-Extensions. | ||||||
|  | 	if c.Header != nil { | ||||||
|  | 		err := c.Header.WriteSubset(buf, handshakeHeader) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	buf.WriteString("\r\n") | ||||||
|  | 	return buf.Flush() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { | ||||||
|  | 	return newHybiServerConn(c.Config, buf, rwc, request) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol. | ||||||
|  | func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { | ||||||
|  | 	return newHybiConn(config, buf, rwc, request) | ||||||
|  | } | ||||||
							
								
								
									
										590
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										590
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,590 @@ | |||||||
|  | // Copyright 2011 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package websocket | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
|  | 	"strings" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Test the getNonceAccept function with values in | ||||||
|  | // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 | ||||||
|  | func TestSecWebSocketAccept(t *testing.T) { | ||||||
|  | 	nonce := []byte("dGhlIHNhbXBsZSBub25jZQ==") | ||||||
|  | 	expected := []byte("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=") | ||||||
|  | 	accept, err := getNonceAccept(nonce) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("getNonceAccept: returned error %v", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if !bytes.Equal(expected, accept) { | ||||||
|  | 		t.Errorf("getNonceAccept: expected %q got %q", expected, accept) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiClientHandshake(t *testing.T) { | ||||||
|  | 	b := bytes.NewBuffer([]byte{}) | ||||||
|  | 	bw := bufio.NewWriter(b) | ||||||
|  | 	br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols | ||||||
|  | Upgrade: websocket | ||||||
|  | Connection: Upgrade | ||||||
|  | Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= | ||||||
|  | Sec-WebSocket-Protocol: chat | ||||||
|  |  | ||||||
|  | `)) | ||||||
|  | 	var err error | ||||||
|  | 	config := new(Config) | ||||||
|  | 	config.Location, err = url.ParseRequestURI("ws://server.example.com/chat") | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("location url", err) | ||||||
|  | 	} | ||||||
|  | 	config.Origin, err = url.ParseRequestURI("http://example.com") | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("origin url", err) | ||||||
|  | 	} | ||||||
|  | 	config.Protocol = append(config.Protocol, "chat") | ||||||
|  | 	config.Protocol = append(config.Protocol, "superchat") | ||||||
|  | 	config.Version = ProtocolVersionHybi13 | ||||||
|  |  | ||||||
|  | 	config.handshakeData = map[string]string{ | ||||||
|  | 		"key": "dGhlIHNhbXBsZSBub25jZQ==", | ||||||
|  | 	} | ||||||
|  | 	err = hybiClientHandshake(config, br, bw) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("handshake failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	req, err := http.ReadRequest(bufio.NewReader(b)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("read request: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if req.Method != "GET" { | ||||||
|  | 		t.Errorf("request method expected GET, but got %q", req.Method) | ||||||
|  | 	} | ||||||
|  | 	if req.URL.Path != "/chat" { | ||||||
|  | 		t.Errorf("request path expected /chat, but got %q", req.URL.Path) | ||||||
|  | 	} | ||||||
|  | 	if req.Proto != "HTTP/1.1" { | ||||||
|  | 		t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto) | ||||||
|  | 	} | ||||||
|  | 	if req.Host != "server.example.com" { | ||||||
|  | 		t.Errorf("request Host expected server.example.com, but got %v", req.Host) | ||||||
|  | 	} | ||||||
|  | 	var expectedHeader = map[string]string{ | ||||||
|  | 		"Connection":             "Upgrade", | ||||||
|  | 		"Upgrade":                "websocket", | ||||||
|  | 		"Sec-Websocket-Key":      config.handshakeData["key"], | ||||||
|  | 		"Origin":                 config.Origin.String(), | ||||||
|  | 		"Sec-Websocket-Protocol": "chat, superchat", | ||||||
|  | 		"Sec-Websocket-Version":  fmt.Sprintf("%d", ProtocolVersionHybi13), | ||||||
|  | 	} | ||||||
|  | 	for k, v := range expectedHeader { | ||||||
|  | 		if req.Header.Get(k) != v { | ||||||
|  | 			t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k))) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiClientHandshakeWithHeader(t *testing.T) { | ||||||
|  | 	b := bytes.NewBuffer([]byte{}) | ||||||
|  | 	bw := bufio.NewWriter(b) | ||||||
|  | 	br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols | ||||||
|  | Upgrade: websocket | ||||||
|  | Connection: Upgrade | ||||||
|  | Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= | ||||||
|  | Sec-WebSocket-Protocol: chat | ||||||
|  |  | ||||||
|  | `)) | ||||||
|  | 	var err error | ||||||
|  | 	config := new(Config) | ||||||
|  | 	config.Location, err = url.ParseRequestURI("ws://server.example.com/chat") | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("location url", err) | ||||||
|  | 	} | ||||||
|  | 	config.Origin, err = url.ParseRequestURI("http://example.com") | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("origin url", err) | ||||||
|  | 	} | ||||||
|  | 	config.Protocol = append(config.Protocol, "chat") | ||||||
|  | 	config.Protocol = append(config.Protocol, "superchat") | ||||||
|  | 	config.Version = ProtocolVersionHybi13 | ||||||
|  | 	config.Header = http.Header(make(map[string][]string)) | ||||||
|  | 	config.Header.Add("User-Agent", "test") | ||||||
|  |  | ||||||
|  | 	config.handshakeData = map[string]string{ | ||||||
|  | 		"key": "dGhlIHNhbXBsZSBub25jZQ==", | ||||||
|  | 	} | ||||||
|  | 	err = hybiClientHandshake(config, br, bw) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("handshake failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	req, err := http.ReadRequest(bufio.NewReader(b)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("read request: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if req.Method != "GET" { | ||||||
|  | 		t.Errorf("request method expected GET, but got %q", req.Method) | ||||||
|  | 	} | ||||||
|  | 	if req.URL.Path != "/chat" { | ||||||
|  | 		t.Errorf("request path expected /chat, but got %q", req.URL.Path) | ||||||
|  | 	} | ||||||
|  | 	if req.Proto != "HTTP/1.1" { | ||||||
|  | 		t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto) | ||||||
|  | 	} | ||||||
|  | 	if req.Host != "server.example.com" { | ||||||
|  | 		t.Errorf("request Host expected server.example.com, but got %v", req.Host) | ||||||
|  | 	} | ||||||
|  | 	var expectedHeader = map[string]string{ | ||||||
|  | 		"Connection":             "Upgrade", | ||||||
|  | 		"Upgrade":                "websocket", | ||||||
|  | 		"Sec-Websocket-Key":      config.handshakeData["key"], | ||||||
|  | 		"Origin":                 config.Origin.String(), | ||||||
|  | 		"Sec-Websocket-Protocol": "chat, superchat", | ||||||
|  | 		"Sec-Websocket-Version":  fmt.Sprintf("%d", ProtocolVersionHybi13), | ||||||
|  | 		"User-Agent":             "test", | ||||||
|  | 	} | ||||||
|  | 	for k, v := range expectedHeader { | ||||||
|  | 		if req.Header.Get(k) != v { | ||||||
|  | 			t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k))) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiServerHandshake(t *testing.T) { | ||||||
|  | 	config := new(Config) | ||||||
|  | 	handshaker := &hybiServerHandshaker{Config: config} | ||||||
|  | 	br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 | ||||||
|  | Host: server.example.com | ||||||
|  | Upgrade: websocket | ||||||
|  | Connection: Upgrade | ||||||
|  | Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== | ||||||
|  | Origin: http://example.com | ||||||
|  | Sec-WebSocket-Protocol: chat, superchat | ||||||
|  | Sec-WebSocket-Version: 13 | ||||||
|  |  | ||||||
|  | `)) | ||||||
|  | 	req, err := http.ReadRequest(br) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("request", err) | ||||||
|  | 	} | ||||||
|  | 	code, err := handshaker.ReadHandshake(br, req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("handshake failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if code != http.StatusSwitchingProtocols { | ||||||
|  | 		t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code) | ||||||
|  | 	} | ||||||
|  | 	expectedProtocols := []string{"chat", "superchat"} | ||||||
|  | 	if fmt.Sprintf("%v", config.Protocol) != fmt.Sprintf("%v", expectedProtocols) { | ||||||
|  | 		t.Errorf("protocol expected %q but got %q", expectedProtocols, config.Protocol) | ||||||
|  | 	} | ||||||
|  | 	b := bytes.NewBuffer([]byte{}) | ||||||
|  | 	bw := bufio.NewWriter(b) | ||||||
|  |  | ||||||
|  | 	config.Protocol = config.Protocol[:1] | ||||||
|  |  | ||||||
|  | 	err = handshaker.AcceptHandshake(bw) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("handshake response failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	expectedResponse := strings.Join([]string{ | ||||||
|  | 		"HTTP/1.1 101 Switching Protocols", | ||||||
|  | 		"Upgrade: websocket", | ||||||
|  | 		"Connection: Upgrade", | ||||||
|  | 		"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", | ||||||
|  | 		"Sec-WebSocket-Protocol: chat", | ||||||
|  | 		"", ""}, "\r\n") | ||||||
|  |  | ||||||
|  | 	if b.String() != expectedResponse { | ||||||
|  | 		t.Errorf("handshake expected %q but got %q", expectedResponse, b.String()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiServerHandshakeNoSubProtocol(t *testing.T) { | ||||||
|  | 	config := new(Config) | ||||||
|  | 	handshaker := &hybiServerHandshaker{Config: config} | ||||||
|  | 	br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 | ||||||
|  | Host: server.example.com | ||||||
|  | Upgrade: websocket | ||||||
|  | Connection: Upgrade | ||||||
|  | Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== | ||||||
|  | Origin: http://example.com | ||||||
|  | Sec-WebSocket-Version: 13 | ||||||
|  |  | ||||||
|  | `)) | ||||||
|  | 	req, err := http.ReadRequest(br) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("request", err) | ||||||
|  | 	} | ||||||
|  | 	code, err := handshaker.ReadHandshake(br, req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("handshake failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if code != http.StatusSwitchingProtocols { | ||||||
|  | 		t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code) | ||||||
|  | 	} | ||||||
|  | 	if len(config.Protocol) != 0 { | ||||||
|  | 		t.Errorf("len(config.Protocol) expected 0, but got %q", len(config.Protocol)) | ||||||
|  | 	} | ||||||
|  | 	b := bytes.NewBuffer([]byte{}) | ||||||
|  | 	bw := bufio.NewWriter(b) | ||||||
|  |  | ||||||
|  | 	err = handshaker.AcceptHandshake(bw) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("handshake response failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	expectedResponse := strings.Join([]string{ | ||||||
|  | 		"HTTP/1.1 101 Switching Protocols", | ||||||
|  | 		"Upgrade: websocket", | ||||||
|  | 		"Connection: Upgrade", | ||||||
|  | 		"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", | ||||||
|  | 		"", ""}, "\r\n") | ||||||
|  |  | ||||||
|  | 	if b.String() != expectedResponse { | ||||||
|  | 		t.Errorf("handshake expected %q but got %q", expectedResponse, b.String()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiServerHandshakeHybiBadVersion(t *testing.T) { | ||||||
|  | 	config := new(Config) | ||||||
|  | 	handshaker := &hybiServerHandshaker{Config: config} | ||||||
|  | 	br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 | ||||||
|  | Host: server.example.com | ||||||
|  | Upgrade: websocket | ||||||
|  | Connection: Upgrade | ||||||
|  | Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== | ||||||
|  | Sec-WebSocket-Origin: http://example.com | ||||||
|  | Sec-WebSocket-Protocol: chat, superchat | ||||||
|  | Sec-WebSocket-Version: 9 | ||||||
|  |  | ||||||
|  | `)) | ||||||
|  | 	req, err := http.ReadRequest(br) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("request", err) | ||||||
|  | 	} | ||||||
|  | 	code, err := handshaker.ReadHandshake(br, req) | ||||||
|  | 	if err != ErrBadWebSocketVersion { | ||||||
|  | 		t.Errorf("handshake expected err %q but got %q", ErrBadWebSocketVersion, err) | ||||||
|  | 	} | ||||||
|  | 	if code != http.StatusBadRequest { | ||||||
|  | 		t.Errorf("status expected %q but got %q", http.StatusBadRequest, code) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testHybiFrame(t *testing.T, testHeader, testPayload, testMaskedPayload []byte, frameHeader *hybiFrameHeader) { | ||||||
|  | 	b := bytes.NewBuffer([]byte{}) | ||||||
|  | 	frameWriterFactory := &hybiFrameWriterFactory{bufio.NewWriter(b), false} | ||||||
|  | 	w, _ := frameWriterFactory.NewFrameWriter(TextFrame) | ||||||
|  | 	w.(*hybiFrameWriter).header = frameHeader | ||||||
|  | 	_, err := w.Write(testPayload) | ||||||
|  | 	w.Close() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Write error %q", err) | ||||||
|  | 	} | ||||||
|  | 	var expectedFrame []byte | ||||||
|  | 	expectedFrame = append(expectedFrame, testHeader...) | ||||||
|  | 	expectedFrame = append(expectedFrame, testMaskedPayload...) | ||||||
|  | 	if !bytes.Equal(expectedFrame, b.Bytes()) { | ||||||
|  | 		t.Errorf("frame expected %q got %q", expectedFrame, b.Bytes()) | ||||||
|  | 	} | ||||||
|  | 	frameReaderFactory := &hybiFrameReaderFactory{bufio.NewReader(b)} | ||||||
|  | 	r, err := frameReaderFactory.NewFrameReader() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Read error %q", err) | ||||||
|  | 	} | ||||||
|  | 	if header := r.HeaderReader(); header == nil { | ||||||
|  | 		t.Errorf("no header") | ||||||
|  | 	} else { | ||||||
|  | 		actualHeader := make([]byte, r.Len()) | ||||||
|  | 		n, err := header.Read(actualHeader) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Read header error %q", err) | ||||||
|  | 		} else { | ||||||
|  | 			if n < len(testHeader) { | ||||||
|  | 				t.Errorf("header too short %q got %q", testHeader, actualHeader[:n]) | ||||||
|  | 			} | ||||||
|  | 			if !bytes.Equal(testHeader, actualHeader[:n]) { | ||||||
|  | 				t.Errorf("header expected %q got %q", testHeader, actualHeader[:n]) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if trailer := r.TrailerReader(); trailer != nil { | ||||||
|  | 		t.Errorf("unexpected trailer %q", trailer) | ||||||
|  | 	} | ||||||
|  | 	frame := r.(*hybiFrameReader) | ||||||
|  | 	if frameHeader.Fin != frame.header.Fin || | ||||||
|  | 		frameHeader.OpCode != frame.header.OpCode || | ||||||
|  | 		len(testPayload) != int(frame.header.Length) { | ||||||
|  | 		t.Errorf("mismatch %v (%d) vs %v", frameHeader, len(testPayload), frame) | ||||||
|  | 	} | ||||||
|  | 	payload := make([]byte, len(testPayload)) | ||||||
|  | 	_, err = r.Read(payload) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("read %v", err) | ||||||
|  | 	} | ||||||
|  | 	if !bytes.Equal(testPayload, payload) { | ||||||
|  | 		t.Errorf("payload %q vs %q", testPayload, payload) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiShortTextFrame(t *testing.T) { | ||||||
|  | 	frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame} | ||||||
|  | 	payload := []byte("hello") | ||||||
|  | 	testHybiFrame(t, []byte{0x81, 0x05}, payload, payload, frameHeader) | ||||||
|  |  | ||||||
|  | 	payload = make([]byte, 125) | ||||||
|  | 	testHybiFrame(t, []byte{0x81, 125}, payload, payload, frameHeader) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiShortMaskedTextFrame(t *testing.T) { | ||||||
|  | 	frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame, | ||||||
|  | 		MaskingKey: []byte{0xcc, 0x55, 0x80, 0x20}} | ||||||
|  | 	payload := []byte("hello") | ||||||
|  | 	maskedPayload := []byte{0xa4, 0x30, 0xec, 0x4c, 0xa3} | ||||||
|  | 	header := []byte{0x81, 0x85} | ||||||
|  | 	header = append(header, frameHeader.MaskingKey...) | ||||||
|  | 	testHybiFrame(t, header, payload, maskedPayload, frameHeader) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiShortBinaryFrame(t *testing.T) { | ||||||
|  | 	frameHeader := &hybiFrameHeader{Fin: true, OpCode: BinaryFrame} | ||||||
|  | 	payload := []byte("hello") | ||||||
|  | 	testHybiFrame(t, []byte{0x82, 0x05}, payload, payload, frameHeader) | ||||||
|  |  | ||||||
|  | 	payload = make([]byte, 125) | ||||||
|  | 	testHybiFrame(t, []byte{0x82, 125}, payload, payload, frameHeader) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiControlFrame(t *testing.T) { | ||||||
|  | 	frameHeader := &hybiFrameHeader{Fin: true, OpCode: PingFrame} | ||||||
|  | 	payload := []byte("hello") | ||||||
|  | 	testHybiFrame(t, []byte{0x89, 0x05}, payload, payload, frameHeader) | ||||||
|  |  | ||||||
|  | 	frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame} | ||||||
|  | 	testHybiFrame(t, []byte{0x8A, 0x05}, payload, payload, frameHeader) | ||||||
|  |  | ||||||
|  | 	frameHeader = &hybiFrameHeader{Fin: true, OpCode: CloseFrame} | ||||||
|  | 	payload = []byte{0x03, 0xe8} // 1000 | ||||||
|  | 	testHybiFrame(t, []byte{0x88, 0x02}, payload, payload, frameHeader) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiLongFrame(t *testing.T) { | ||||||
|  | 	frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame} | ||||||
|  | 	payload := make([]byte, 126) | ||||||
|  | 	testHybiFrame(t, []byte{0x81, 126, 0x00, 126}, payload, payload, frameHeader) | ||||||
|  |  | ||||||
|  | 	payload = make([]byte, 65535) | ||||||
|  | 	testHybiFrame(t, []byte{0x81, 126, 0xff, 0xff}, payload, payload, frameHeader) | ||||||
|  |  | ||||||
|  | 	payload = make([]byte, 65536) | ||||||
|  | 	testHybiFrame(t, []byte{0x81, 127, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, payload, payload, frameHeader) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiClientRead(t *testing.T) { | ||||||
|  | 	wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o', | ||||||
|  | 		0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping | ||||||
|  | 		0x81, 0x05, 'w', 'o', 'r', 'l', 'd'} | ||||||
|  | 	br := bufio.NewReader(bytes.NewBuffer(wireData)) | ||||||
|  | 	bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) | ||||||
|  | 	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil) | ||||||
|  |  | ||||||
|  | 	msg := make([]byte, 512) | ||||||
|  | 	n, err := conn.Read(msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("read 1st frame, error %q", err) | ||||||
|  | 	} | ||||||
|  | 	if n != 5 { | ||||||
|  | 		t.Errorf("read 1st frame, expect 5, got %d", n) | ||||||
|  | 	} | ||||||
|  | 	if !bytes.Equal(wireData[2:7], msg[:n]) { | ||||||
|  | 		t.Errorf("read 1st frame %v, got %v", wireData[2:7], msg[:n]) | ||||||
|  | 	} | ||||||
|  | 	n, err = conn.Read(msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("read 2nd frame, error %q", err) | ||||||
|  | 	} | ||||||
|  | 	if n != 5 { | ||||||
|  | 		t.Errorf("read 2nd frame, expect 5, got %d", n) | ||||||
|  | 	} | ||||||
|  | 	if !bytes.Equal(wireData[16:21], msg[:n]) { | ||||||
|  | 		t.Errorf("read 2nd frame %v, got %v", wireData[16:21], msg[:n]) | ||||||
|  | 	} | ||||||
|  | 	n, err = conn.Read(msg) | ||||||
|  | 	if err == nil { | ||||||
|  | 		t.Errorf("read not EOF") | ||||||
|  | 	} | ||||||
|  | 	if n != 0 { | ||||||
|  | 		t.Errorf("expect read 0, got %d", n) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiShortRead(t *testing.T) { | ||||||
|  | 	wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o', | ||||||
|  | 		0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping | ||||||
|  | 		0x81, 0x05, 'w', 'o', 'r', 'l', 'd'} | ||||||
|  | 	br := bufio.NewReader(bytes.NewBuffer(wireData)) | ||||||
|  | 	bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) | ||||||
|  | 	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil) | ||||||
|  |  | ||||||
|  | 	step := 0 | ||||||
|  | 	pos := 0 | ||||||
|  | 	expectedPos := []int{2, 5, 16, 19} | ||||||
|  | 	expectedLen := []int{3, 2, 3, 2} | ||||||
|  | 	for { | ||||||
|  | 		msg := make([]byte, 3) | ||||||
|  | 		n, err := conn.Read(msg) | ||||||
|  | 		if step >= len(expectedPos) { | ||||||
|  | 			if err == nil { | ||||||
|  | 				t.Errorf("read not EOF") | ||||||
|  | 			} | ||||||
|  | 			if n != 0 { | ||||||
|  | 				t.Errorf("expect read 0, got %d", n) | ||||||
|  | 			} | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		pos = expectedPos[step] | ||||||
|  | 		endPos := pos + expectedLen[step] | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("read from %d, got error %q", pos, err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if n != endPos-pos { | ||||||
|  | 			t.Errorf("read from %d, expect %d, got %d", pos, endPos-pos, n) | ||||||
|  | 		} | ||||||
|  | 		if !bytes.Equal(wireData[pos:endPos], msg[:n]) { | ||||||
|  | 			t.Errorf("read from %d, frame %v, got %v", pos, wireData[pos:endPos], msg[:n]) | ||||||
|  | 		} | ||||||
|  | 		step++ | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiServerRead(t *testing.T) { | ||||||
|  | 	wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20, | ||||||
|  | 		0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello | ||||||
|  | 		0x89, 0x85, 0xcc, 0x55, 0x80, 0x20, | ||||||
|  | 		0xa4, 0x30, 0xec, 0x4c, 0xa3, // ping: hello | ||||||
|  | 		0x81, 0x85, 0xed, 0x83, 0xb4, 0x24, | ||||||
|  | 		0x9a, 0xec, 0xc6, 0x48, 0x89, // world | ||||||
|  | 	} | ||||||
|  | 	br := bufio.NewReader(bytes.NewBuffer(wireData)) | ||||||
|  | 	bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) | ||||||
|  | 	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request)) | ||||||
|  |  | ||||||
|  | 	expected := [][]byte{[]byte("hello"), []byte("world")} | ||||||
|  |  | ||||||
|  | 	msg := make([]byte, 512) | ||||||
|  | 	n, err := conn.Read(msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("read 1st frame, error %q", err) | ||||||
|  | 	} | ||||||
|  | 	if n != 5 { | ||||||
|  | 		t.Errorf("read 1st frame, expect 5, got %d", n) | ||||||
|  | 	} | ||||||
|  | 	if !bytes.Equal(expected[0], msg[:n]) { | ||||||
|  | 		t.Errorf("read 1st frame %q, got %q", expected[0], msg[:n]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	n, err = conn.Read(msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("read 2nd frame, error %q", err) | ||||||
|  | 	} | ||||||
|  | 	if n != 5 { | ||||||
|  | 		t.Errorf("read 2nd frame, expect 5, got %d", n) | ||||||
|  | 	} | ||||||
|  | 	if !bytes.Equal(expected[1], msg[:n]) { | ||||||
|  | 		t.Errorf("read 2nd frame %q, got %q", expected[1], msg[:n]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	n, err = conn.Read(msg) | ||||||
|  | 	if err == nil { | ||||||
|  | 		t.Errorf("read not EOF") | ||||||
|  | 	} | ||||||
|  | 	if n != 0 { | ||||||
|  | 		t.Errorf("expect read 0, got %d", n) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiServerReadWithoutMasking(t *testing.T) { | ||||||
|  | 	wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o'} | ||||||
|  | 	br := bufio.NewReader(bytes.NewBuffer(wireData)) | ||||||
|  | 	bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) | ||||||
|  | 	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request)) | ||||||
|  | 	// server MUST close the connection upon receiving a non-masked frame. | ||||||
|  | 	msg := make([]byte, 512) | ||||||
|  | 	_, err := conn.Read(msg) | ||||||
|  | 	if err != io.EOF { | ||||||
|  | 		t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHybiClientReadWithMasking(t *testing.T) { | ||||||
|  | 	wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20, | ||||||
|  | 		0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello | ||||||
|  | 	} | ||||||
|  | 	br := bufio.NewReader(bytes.NewBuffer(wireData)) | ||||||
|  | 	bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) | ||||||
|  | 	conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil) | ||||||
|  |  | ||||||
|  | 	// client MUST close the connection upon receiving a masked frame. | ||||||
|  | 	msg := make([]byte, 512) | ||||||
|  | 	_, err := conn.Read(msg) | ||||||
|  | 	if err != io.EOF { | ||||||
|  | 		t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Test the hybiServerHandshaker supports firefox implementation and | ||||||
|  | // checks Connection request header include (but it's not necessary | ||||||
|  | // equal to) "upgrade" | ||||||
|  | func TestHybiServerFirefoxHandshake(t *testing.T) { | ||||||
|  | 	config := new(Config) | ||||||
|  | 	handshaker := &hybiServerHandshaker{Config: config} | ||||||
|  | 	br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 | ||||||
|  | Host: server.example.com | ||||||
|  | Upgrade: websocket | ||||||
|  | Connection: keep-alive, upgrade | ||||||
|  | Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== | ||||||
|  | Origin: http://example.com | ||||||
|  | Sec-WebSocket-Protocol: chat, superchat | ||||||
|  | Sec-WebSocket-Version: 13 | ||||||
|  |  | ||||||
|  | `)) | ||||||
|  | 	req, err := http.ReadRequest(br) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("request", err) | ||||||
|  | 	} | ||||||
|  | 	code, err := handshaker.ReadHandshake(br, req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("handshake failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if code != http.StatusSwitchingProtocols { | ||||||
|  | 		t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code) | ||||||
|  | 	} | ||||||
|  | 	b := bytes.NewBuffer([]byte{}) | ||||||
|  | 	bw := bufio.NewWriter(b) | ||||||
|  |  | ||||||
|  | 	config.Protocol = []string{"chat"} | ||||||
|  |  | ||||||
|  | 	err = handshaker.AcceptHandshake(bw) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("handshake response failed: %v", err) | ||||||
|  | 	} | ||||||
|  | 	expectedResponse := strings.Join([]string{ | ||||||
|  | 		"HTTP/1.1 101 Switching Protocols", | ||||||
|  | 		"Upgrade: websocket", | ||||||
|  | 		"Connection: Upgrade", | ||||||
|  | 		"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", | ||||||
|  | 		"Sec-WebSocket-Protocol: chat", | ||||||
|  | 		"", ""}, "\r\n") | ||||||
|  |  | ||||||
|  | 	if b.String() != expectedResponse { | ||||||
|  | 		t.Errorf("handshake expected %q but got %q", expectedResponse, b.String()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										114
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | |||||||
|  | // Copyright 2009 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package websocket | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"net/http" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) { | ||||||
|  | 	var hs serverHandshaker = &hybiServerHandshaker{Config: config} | ||||||
|  | 	code, err := hs.ReadHandshake(buf.Reader, req) | ||||||
|  | 	if err == ErrBadWebSocketVersion { | ||||||
|  | 		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) | ||||||
|  | 		fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion) | ||||||
|  | 		buf.WriteString("\r\n") | ||||||
|  | 		buf.WriteString(err.Error()) | ||||||
|  | 		buf.Flush() | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if err != nil { | ||||||
|  | 		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) | ||||||
|  | 		buf.WriteString("\r\n") | ||||||
|  | 		buf.WriteString(err.Error()) | ||||||
|  | 		buf.Flush() | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if handshake != nil { | ||||||
|  | 		err = handshake(config, req) | ||||||
|  | 		if err != nil { | ||||||
|  | 			code = http.StatusForbidden | ||||||
|  | 			fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) | ||||||
|  | 			buf.WriteString("\r\n") | ||||||
|  | 			buf.Flush() | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	err = hs.AcceptHandshake(buf.Writer) | ||||||
|  | 	if err != nil { | ||||||
|  | 		code = http.StatusBadRequest | ||||||
|  | 		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) | ||||||
|  | 		buf.WriteString("\r\n") | ||||||
|  | 		buf.Flush() | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	conn = hs.NewServerConn(buf, rwc, req) | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Server represents a server of a WebSocket. | ||||||
|  | type Server struct { | ||||||
|  | 	// Config is a WebSocket configuration for new WebSocket connection. | ||||||
|  | 	Config | ||||||
|  |  | ||||||
|  | 	// Handshake is an optional function in WebSocket handshake. | ||||||
|  | 	// For example, you can check, or don't check Origin header. | ||||||
|  | 	// Another example, you can select config.Protocol. | ||||||
|  | 	Handshake func(*Config, *http.Request) error | ||||||
|  |  | ||||||
|  | 	// Handler handles a WebSocket connection. | ||||||
|  | 	Handler | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServeHTTP implements the http.Handler interface for a WebSocket | ||||||
|  | func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||||||
|  | 	s.serveWebSocket(w, req) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) { | ||||||
|  | 	rwc, buf, err := w.(http.Hijacker).Hijack() | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic("Hijack failed: " + err.Error()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	// The server should abort the WebSocket connection if it finds | ||||||
|  | 	// the client did not send a handshake that matches with protocol | ||||||
|  | 	// specification. | ||||||
|  | 	defer rwc.Close() | ||||||
|  | 	conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if conn == nil { | ||||||
|  | 		panic("unexpected nil conn") | ||||||
|  | 	} | ||||||
|  | 	s.Handler(conn) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Handler is a simple interface to a WebSocket browser client. | ||||||
|  | // It checks if Origin header is valid URL by default. | ||||||
|  | // You might want to verify websocket.Conn.Config().Origin in the func. | ||||||
|  | // If you use Server instead of Handler, you could call websocket.Origin and | ||||||
|  | // check the origin in your Handshake func. So, if you want to accept | ||||||
|  | // non-browser client, which doesn't send Origin header, you could use Server | ||||||
|  | //. that doesn't check origin in its Handshake. | ||||||
|  | type Handler func(*Conn) | ||||||
|  |  | ||||||
|  | func checkOrigin(config *Config, req *http.Request) (err error) { | ||||||
|  | 	config.Origin, err = Origin(config, req) | ||||||
|  | 	if err == nil && config.Origin == nil { | ||||||
|  | 		return fmt.Errorf("null origin") | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ServeHTTP implements the http.Handler interface for a WebSocket | ||||||
|  | func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||||||
|  | 	s := Server{Handler: h, Handshake: checkOrigin} | ||||||
|  | 	s.serveWebSocket(w, req) | ||||||
|  | } | ||||||
							
								
								
									
										411
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										411
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,411 @@ | |||||||
|  | // Copyright 2009 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | // Package websocket implements a client and server for the WebSocket protocol | ||||||
|  | // as specified in RFC 6455. | ||||||
|  | package websocket | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"crypto/tls" | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
|  | 	"io" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"net" | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	ProtocolVersionHybi13    = 13 | ||||||
|  | 	ProtocolVersionHybi      = ProtocolVersionHybi13 | ||||||
|  | 	SupportedProtocolVersion = "13" | ||||||
|  |  | ||||||
|  | 	ContinuationFrame = 0 | ||||||
|  | 	TextFrame         = 1 | ||||||
|  | 	BinaryFrame       = 2 | ||||||
|  | 	CloseFrame        = 8 | ||||||
|  | 	PingFrame         = 9 | ||||||
|  | 	PongFrame         = 10 | ||||||
|  | 	UnknownFrame      = 255 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // ProtocolError represents WebSocket protocol errors. | ||||||
|  | type ProtocolError struct { | ||||||
|  | 	ErrorString string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (err *ProtocolError) Error() string { return err.ErrorString } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	ErrBadProtocolVersion   = &ProtocolError{"bad protocol version"} | ||||||
|  | 	ErrBadScheme            = &ProtocolError{"bad scheme"} | ||||||
|  | 	ErrBadStatus            = &ProtocolError{"bad status"} | ||||||
|  | 	ErrBadUpgrade           = &ProtocolError{"missing or bad upgrade"} | ||||||
|  | 	ErrBadWebSocketOrigin   = &ProtocolError{"missing or bad WebSocket-Origin"} | ||||||
|  | 	ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"} | ||||||
|  | 	ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"} | ||||||
|  | 	ErrBadWebSocketVersion  = &ProtocolError{"missing or bad WebSocket Version"} | ||||||
|  | 	ErrChallengeResponse    = &ProtocolError{"mismatch challenge/response"} | ||||||
|  | 	ErrBadFrame             = &ProtocolError{"bad frame"} | ||||||
|  | 	ErrBadFrameBoundary     = &ProtocolError{"not on frame boundary"} | ||||||
|  | 	ErrNotWebSocket         = &ProtocolError{"not websocket protocol"} | ||||||
|  | 	ErrBadRequestMethod     = &ProtocolError{"bad method"} | ||||||
|  | 	ErrNotSupported         = &ProtocolError{"not supported"} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Addr is an implementation of net.Addr for WebSocket. | ||||||
|  | type Addr struct { | ||||||
|  | 	*url.URL | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Network returns the network type for a WebSocket, "websocket". | ||||||
|  | func (addr *Addr) Network() string { return "websocket" } | ||||||
|  |  | ||||||
|  | // Config is a WebSocket configuration | ||||||
|  | type Config struct { | ||||||
|  | 	// A WebSocket server address. | ||||||
|  | 	Location *url.URL | ||||||
|  |  | ||||||
|  | 	// A Websocket client origin. | ||||||
|  | 	Origin *url.URL | ||||||
|  |  | ||||||
|  | 	// WebSocket subprotocols. | ||||||
|  | 	Protocol []string | ||||||
|  |  | ||||||
|  | 	// WebSocket protocol version. | ||||||
|  | 	Version int | ||||||
|  |  | ||||||
|  | 	// TLS config for secure WebSocket (wss). | ||||||
|  | 	TlsConfig *tls.Config | ||||||
|  |  | ||||||
|  | 	// Additional header fields to be sent in WebSocket opening handshake. | ||||||
|  | 	Header http.Header | ||||||
|  |  | ||||||
|  | 	handshakeData map[string]string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // serverHandshaker is an interface to handle WebSocket server side handshake. | ||||||
|  | type serverHandshaker interface { | ||||||
|  | 	// ReadHandshake reads handshake request message from client. | ||||||
|  | 	// Returns http response code and error if any. | ||||||
|  | 	ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) | ||||||
|  |  | ||||||
|  | 	// AcceptHandshake accepts the client handshake request and sends | ||||||
|  | 	// handshake response back to client. | ||||||
|  | 	AcceptHandshake(buf *bufio.Writer) (err error) | ||||||
|  |  | ||||||
|  | 	// NewServerConn creates a new WebSocket connection. | ||||||
|  | 	NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // frameReader is an interface to read a WebSocket frame. | ||||||
|  | type frameReader interface { | ||||||
|  | 	// Reader is to read payload of the frame. | ||||||
|  | 	io.Reader | ||||||
|  |  | ||||||
|  | 	// PayloadType returns payload type. | ||||||
|  | 	PayloadType() byte | ||||||
|  |  | ||||||
|  | 	// HeaderReader returns a reader to read header of the frame. | ||||||
|  | 	HeaderReader() io.Reader | ||||||
|  |  | ||||||
|  | 	// TrailerReader returns a reader to read trailer of the frame. | ||||||
|  | 	// If it returns nil, there is no trailer in the frame. | ||||||
|  | 	TrailerReader() io.Reader | ||||||
|  |  | ||||||
|  | 	// Len returns total length of the frame, including header and trailer. | ||||||
|  | 	Len() int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // frameReaderFactory is an interface to creates new frame reader. | ||||||
|  | type frameReaderFactory interface { | ||||||
|  | 	NewFrameReader() (r frameReader, err error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // frameWriter is an interface to write a WebSocket frame. | ||||||
|  | type frameWriter interface { | ||||||
|  | 	// Writer is to write payload of the frame. | ||||||
|  | 	io.WriteCloser | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // frameWriterFactory is an interface to create new frame writer. | ||||||
|  | type frameWriterFactory interface { | ||||||
|  | 	NewFrameWriter(payloadType byte) (w frameWriter, err error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type frameHandler interface { | ||||||
|  | 	HandleFrame(frame frameReader) (r frameReader, err error) | ||||||
|  | 	WriteClose(status int) (err error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Conn represents a WebSocket connection. | ||||||
|  | type Conn struct { | ||||||
|  | 	config  *Config | ||||||
|  | 	request *http.Request | ||||||
|  |  | ||||||
|  | 	buf *bufio.ReadWriter | ||||||
|  | 	rwc io.ReadWriteCloser | ||||||
|  |  | ||||||
|  | 	rio sync.Mutex | ||||||
|  | 	frameReaderFactory | ||||||
|  | 	frameReader | ||||||
|  |  | ||||||
|  | 	wio sync.Mutex | ||||||
|  | 	frameWriterFactory | ||||||
|  |  | ||||||
|  | 	frameHandler | ||||||
|  | 	PayloadType        byte | ||||||
|  | 	defaultCloseStatus int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Read implements the io.Reader interface: | ||||||
|  | // it reads data of a frame from the WebSocket connection. | ||||||
|  | // if msg is not large enough for the frame data, it fills the msg and next Read | ||||||
|  | // will read the rest of the frame data. | ||||||
|  | // it reads Text frame or Binary frame. | ||||||
|  | func (ws *Conn) Read(msg []byte) (n int, err error) { | ||||||
|  | 	ws.rio.Lock() | ||||||
|  | 	defer ws.rio.Unlock() | ||||||
|  | again: | ||||||
|  | 	if ws.frameReader == nil { | ||||||
|  | 		frame, err := ws.frameReaderFactory.NewFrameReader() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return 0, err | ||||||
|  | 		} | ||||||
|  | 		ws.frameReader, err = ws.frameHandler.HandleFrame(frame) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return 0, err | ||||||
|  | 		} | ||||||
|  | 		if ws.frameReader == nil { | ||||||
|  | 			goto again | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	n, err = ws.frameReader.Read(msg) | ||||||
|  | 	if err == io.EOF { | ||||||
|  | 		if trailer := ws.frameReader.TrailerReader(); trailer != nil { | ||||||
|  | 			io.Copy(ioutil.Discard, trailer) | ||||||
|  | 		} | ||||||
|  | 		ws.frameReader = nil | ||||||
|  | 		goto again | ||||||
|  | 	} | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Write implements the io.Writer interface: | ||||||
|  | // it writes data as a frame to the WebSocket connection. | ||||||
|  | func (ws *Conn) Write(msg []byte) (n int, err error) { | ||||||
|  | 	ws.wio.Lock() | ||||||
|  | 	defer ws.wio.Unlock() | ||||||
|  | 	w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, err | ||||||
|  | 	} | ||||||
|  | 	n, err = w.Write(msg) | ||||||
|  | 	w.Close() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return n, err | ||||||
|  | 	} | ||||||
|  | 	return n, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close implements the io.Closer interface. | ||||||
|  | func (ws *Conn) Close() error { | ||||||
|  | 	err := ws.frameHandler.WriteClose(ws.defaultCloseStatus) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return ws.rwc.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (ws *Conn) IsClientConn() bool { return ws.request == nil } | ||||||
|  | func (ws *Conn) IsServerConn() bool { return ws.request != nil } | ||||||
|  |  | ||||||
|  | // LocalAddr returns the WebSocket Origin for the connection for client, or | ||||||
|  | // the WebSocket location for server. | ||||||
|  | func (ws *Conn) LocalAddr() net.Addr { | ||||||
|  | 	if ws.IsClientConn() { | ||||||
|  | 		return &Addr{ws.config.Origin} | ||||||
|  | 	} | ||||||
|  | 	return &Addr{ws.config.Location} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RemoteAddr returns the WebSocket location for the connection for client, or | ||||||
|  | // the Websocket Origin for server. | ||||||
|  | func (ws *Conn) RemoteAddr() net.Addr { | ||||||
|  | 	if ws.IsClientConn() { | ||||||
|  | 		return &Addr{ws.config.Location} | ||||||
|  | 	} | ||||||
|  | 	return &Addr{ws.config.Origin} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn") | ||||||
|  |  | ||||||
|  | // SetDeadline sets the connection's network read & write deadlines. | ||||||
|  | func (ws *Conn) SetDeadline(t time.Time) error { | ||||||
|  | 	if conn, ok := ws.rwc.(net.Conn); ok { | ||||||
|  | 		return conn.SetDeadline(t) | ||||||
|  | 	} | ||||||
|  | 	return errSetDeadline | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetReadDeadline sets the connection's network read deadline. | ||||||
|  | func (ws *Conn) SetReadDeadline(t time.Time) error { | ||||||
|  | 	if conn, ok := ws.rwc.(net.Conn); ok { | ||||||
|  | 		return conn.SetReadDeadline(t) | ||||||
|  | 	} | ||||||
|  | 	return errSetDeadline | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetWriteDeadline sets the connection's network write deadline. | ||||||
|  | func (ws *Conn) SetWriteDeadline(t time.Time) error { | ||||||
|  | 	if conn, ok := ws.rwc.(net.Conn); ok { | ||||||
|  | 		return conn.SetWriteDeadline(t) | ||||||
|  | 	} | ||||||
|  | 	return errSetDeadline | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Config returns the WebSocket config. | ||||||
|  | func (ws *Conn) Config() *Config { return ws.config } | ||||||
|  |  | ||||||
|  | // Request returns the http request upgraded to the WebSocket. | ||||||
|  | // It is nil for client side. | ||||||
|  | func (ws *Conn) Request() *http.Request { return ws.request } | ||||||
|  |  | ||||||
|  | // Codec represents a symmetric pair of functions that implement a codec. | ||||||
|  | type Codec struct { | ||||||
|  | 	Marshal   func(v interface{}) (data []byte, payloadType byte, err error) | ||||||
|  | 	Unmarshal func(data []byte, payloadType byte, v interface{}) (err error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Send sends v marshaled by cd.Marshal as single frame to ws. | ||||||
|  | func (cd Codec) Send(ws *Conn, v interface{}) (err error) { | ||||||
|  | 	data, payloadType, err := cd.Marshal(v) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	ws.wio.Lock() | ||||||
|  | 	defer ws.wio.Unlock() | ||||||
|  | 	w, err := ws.frameWriterFactory.NewFrameWriter(payloadType) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	_, err = w.Write(data) | ||||||
|  | 	w.Close() | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores in v. | ||||||
|  | func (cd Codec) Receive(ws *Conn, v interface{}) (err error) { | ||||||
|  | 	ws.rio.Lock() | ||||||
|  | 	defer ws.rio.Unlock() | ||||||
|  | 	if ws.frameReader != nil { | ||||||
|  | 		_, err = io.Copy(ioutil.Discard, ws.frameReader) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		ws.frameReader = nil | ||||||
|  | 	} | ||||||
|  | again: | ||||||
|  | 	frame, err := ws.frameReaderFactory.NewFrameReader() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	frame, err = ws.frameHandler.HandleFrame(frame) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if frame == nil { | ||||||
|  | 		goto again | ||||||
|  | 	} | ||||||
|  | 	payloadType := frame.PayloadType() | ||||||
|  | 	data, err := ioutil.ReadAll(frame) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	return cd.Unmarshal(data, payloadType, v) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func marshal(v interface{}) (msg []byte, payloadType byte, err error) { | ||||||
|  | 	switch data := v.(type) { | ||||||
|  | 	case string: | ||||||
|  | 		return []byte(data), TextFrame, nil | ||||||
|  | 	case []byte: | ||||||
|  | 		return data, BinaryFrame, nil | ||||||
|  | 	} | ||||||
|  | 	return nil, UnknownFrame, ErrNotSupported | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) { | ||||||
|  | 	switch data := v.(type) { | ||||||
|  | 	case *string: | ||||||
|  | 		*data = string(msg) | ||||||
|  | 		return nil | ||||||
|  | 	case *[]byte: | ||||||
|  | 		*data = msg | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return ErrNotSupported | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Message is a codec to send/receive text/binary data in a frame on WebSocket connection. | ||||||
|  | To send/receive text frame, use string type. | ||||||
|  | To send/receive binary frame, use []byte type. | ||||||
|  |  | ||||||
|  | Trivial usage: | ||||||
|  |  | ||||||
|  | 	import "websocket" | ||||||
|  |  | ||||||
|  | 	// receive text frame | ||||||
|  | 	var message string | ||||||
|  | 	websocket.Message.Receive(ws, &message) | ||||||
|  |  | ||||||
|  | 	// send text frame | ||||||
|  | 	message = "hello" | ||||||
|  | 	websocket.Message.Send(ws, message) | ||||||
|  |  | ||||||
|  | 	// receive binary frame | ||||||
|  | 	var data []byte | ||||||
|  | 	websocket.Message.Receive(ws, &data) | ||||||
|  |  | ||||||
|  | 	// send binary frame | ||||||
|  | 	data = []byte{0, 1, 2} | ||||||
|  | 	websocket.Message.Send(ws, data) | ||||||
|  |  | ||||||
|  | */ | ||||||
|  | var Message = Codec{marshal, unmarshal} | ||||||
|  |  | ||||||
|  | func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) { | ||||||
|  | 	msg, err = json.Marshal(v) | ||||||
|  | 	return msg, TextFrame, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) { | ||||||
|  | 	return json.Unmarshal(msg, v) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | JSON is a codec to send/receive JSON data in a frame from a WebSocket connection. | ||||||
|  |  | ||||||
|  | Trivial usage: | ||||||
|  |  | ||||||
|  | 	import "websocket" | ||||||
|  |  | ||||||
|  | 	type T struct { | ||||||
|  | 		Msg string | ||||||
|  | 		Count int | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// receive JSON type T | ||||||
|  | 	var data T | ||||||
|  | 	websocket.JSON.Receive(ws, &data) | ||||||
|  |  | ||||||
|  | 	// send JSON type T | ||||||
|  | 	websocket.JSON.Send(ws, data) | ||||||
|  | */ | ||||||
|  | var JSON = Codec{jsonMarshal, jsonUnmarshal} | ||||||
							
								
								
									
										414
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,414 @@ | |||||||
|  | // Copyright 2009 The Go Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a BSD-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package websocket | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	"net" | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/http/httptest" | ||||||
|  | 	"net/url" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var serverAddr string | ||||||
|  | var once sync.Once | ||||||
|  |  | ||||||
|  | func echoServer(ws *Conn) { io.Copy(ws, ws) } | ||||||
|  |  | ||||||
|  | type Count struct { | ||||||
|  | 	S string | ||||||
|  | 	N int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func countServer(ws *Conn) { | ||||||
|  | 	for { | ||||||
|  | 		var count Count | ||||||
|  | 		err := JSON.Receive(ws, &count) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		count.N++ | ||||||
|  | 		count.S = strings.Repeat(count.S, count.N) | ||||||
|  | 		err = JSON.Send(ws, count) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func subProtocolHandshake(config *Config, req *http.Request) error { | ||||||
|  | 	for _, proto := range config.Protocol { | ||||||
|  | 		if proto == "chat" { | ||||||
|  | 			config.Protocol = []string{proto} | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return ErrBadWebSocketProtocol | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func subProtoServer(ws *Conn) { | ||||||
|  | 	for _, proto := range ws.Config().Protocol { | ||||||
|  | 		io.WriteString(ws, proto) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func startServer() { | ||||||
|  | 	http.Handle("/echo", Handler(echoServer)) | ||||||
|  | 	http.Handle("/count", Handler(countServer)) | ||||||
|  | 	subproto := Server{ | ||||||
|  | 		Handshake: subProtocolHandshake, | ||||||
|  | 		Handler:   Handler(subProtoServer), | ||||||
|  | 	} | ||||||
|  | 	http.Handle("/subproto", subproto) | ||||||
|  | 	server := httptest.NewServer(nil) | ||||||
|  | 	serverAddr = server.Listener.Addr().String() | ||||||
|  | 	log.Print("Test WebSocket server listening on ", serverAddr) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newConfig(t *testing.T, path string) *Config { | ||||||
|  | 	config, _ := NewConfig(fmt.Sprintf("ws://%s%s", serverAddr, path), "http://localhost") | ||||||
|  | 	return config | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestEcho(t *testing.T) { | ||||||
|  | 	once.Do(startServer) | ||||||
|  |  | ||||||
|  | 	// websocket.Dial() | ||||||
|  | 	client, err := net.Dial("tcp", serverAddr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("dialing", err) | ||||||
|  | 	} | ||||||
|  | 	conn, err := NewClient(newConfig(t, "/echo"), client) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("WebSocket handshake error: %v", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	msg := []byte("hello, world\n") | ||||||
|  | 	if _, err := conn.Write(msg); err != nil { | ||||||
|  | 		t.Errorf("Write: %v", err) | ||||||
|  | 	} | ||||||
|  | 	var actual_msg = make([]byte, 512) | ||||||
|  | 	n, err := conn.Read(actual_msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Read: %v", err) | ||||||
|  | 	} | ||||||
|  | 	actual_msg = actual_msg[0:n] | ||||||
|  | 	if !bytes.Equal(msg, actual_msg) { | ||||||
|  | 		t.Errorf("Echo: expected %q got %q", msg, actual_msg) | ||||||
|  | 	} | ||||||
|  | 	conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestAddr(t *testing.T) { | ||||||
|  | 	once.Do(startServer) | ||||||
|  |  | ||||||
|  | 	// websocket.Dial() | ||||||
|  | 	client, err := net.Dial("tcp", serverAddr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("dialing", err) | ||||||
|  | 	} | ||||||
|  | 	conn, err := NewClient(newConfig(t, "/echo"), client) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("WebSocket handshake error: %v", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ra := conn.RemoteAddr().String() | ||||||
|  | 	if !strings.HasPrefix(ra, "ws://") || !strings.HasSuffix(ra, "/echo") { | ||||||
|  | 		t.Errorf("Bad remote addr: %v", ra) | ||||||
|  | 	} | ||||||
|  | 	la := conn.LocalAddr().String() | ||||||
|  | 	if !strings.HasPrefix(la, "http://") { | ||||||
|  | 		t.Errorf("Bad local addr: %v", la) | ||||||
|  | 	} | ||||||
|  | 	conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCount(t *testing.T) { | ||||||
|  | 	once.Do(startServer) | ||||||
|  |  | ||||||
|  | 	// websocket.Dial() | ||||||
|  | 	client, err := net.Dial("tcp", serverAddr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("dialing", err) | ||||||
|  | 	} | ||||||
|  | 	conn, err := NewClient(newConfig(t, "/count"), client) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("WebSocket handshake error: %v", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var count Count | ||||||
|  | 	count.S = "hello" | ||||||
|  | 	if err := JSON.Send(conn, count); err != nil { | ||||||
|  | 		t.Errorf("Write: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if err := JSON.Receive(conn, &count); err != nil { | ||||||
|  | 		t.Errorf("Read: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if count.N != 1 { | ||||||
|  | 		t.Errorf("count: expected %d got %d", 1, count.N) | ||||||
|  | 	} | ||||||
|  | 	if count.S != "hello" { | ||||||
|  | 		t.Errorf("count: expected %q got %q", "hello", count.S) | ||||||
|  | 	} | ||||||
|  | 	if err := JSON.Send(conn, count); err != nil { | ||||||
|  | 		t.Errorf("Write: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if err := JSON.Receive(conn, &count); err != nil { | ||||||
|  | 		t.Errorf("Read: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if count.N != 2 { | ||||||
|  | 		t.Errorf("count: expected %d got %d", 2, count.N) | ||||||
|  | 	} | ||||||
|  | 	if count.S != "hellohello" { | ||||||
|  | 		t.Errorf("count: expected %q got %q", "hellohello", count.S) | ||||||
|  | 	} | ||||||
|  | 	conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestWithQuery(t *testing.T) { | ||||||
|  | 	once.Do(startServer) | ||||||
|  |  | ||||||
|  | 	client, err := net.Dial("tcp", serverAddr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("dialing", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	config := newConfig(t, "/echo") | ||||||
|  | 	config.Location, err = url.ParseRequestURI(fmt.Sprintf("ws://%s/echo?q=v", serverAddr)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("location url", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ws, err := NewClient(config, client) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("WebSocket handshake: %v", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ws.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func testWithProtocol(t *testing.T, subproto []string) (string, error) { | ||||||
|  | 	once.Do(startServer) | ||||||
|  |  | ||||||
|  | 	client, err := net.Dial("tcp", serverAddr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("dialing", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	config := newConfig(t, "/subproto") | ||||||
|  | 	config.Protocol = subproto | ||||||
|  |  | ||||||
|  | 	ws, err := NewClient(config, client) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	msg := make([]byte, 16) | ||||||
|  | 	n, err := ws.Read(msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	ws.Close() | ||||||
|  | 	return string(msg[:n]), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestWithProtocol(t *testing.T) { | ||||||
|  | 	proto, err := testWithProtocol(t, []string{"chat"}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("SubProto: unexpected error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if proto != "chat" { | ||||||
|  | 		t.Errorf("SubProto: expected %q, got %q", "chat", proto) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestWithTwoProtocol(t *testing.T) { | ||||||
|  | 	proto, err := testWithProtocol(t, []string{"test", "chat"}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("SubProto: unexpected error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if proto != "chat" { | ||||||
|  | 		t.Errorf("SubProto: expected %q, got %q", "chat", proto) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestWithBadProtocol(t *testing.T) { | ||||||
|  | 	_, err := testWithProtocol(t, []string{"test"}) | ||||||
|  | 	if err != ErrBadStatus { | ||||||
|  | 		t.Errorf("SubProto: expected %v, got %v", ErrBadStatus, err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestHTTP(t *testing.T) { | ||||||
|  | 	once.Do(startServer) | ||||||
|  |  | ||||||
|  | 	// If the client did not send a handshake that matches the protocol | ||||||
|  | 	// specification, the server MUST return an HTTP response with an | ||||||
|  | 	// appropriate error code (such as 400 Bad Request) | ||||||
|  | 	resp, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr)) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Get: error %#v", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if resp == nil { | ||||||
|  | 		t.Error("Get: resp is null") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if resp.StatusCode != http.StatusBadRequest { | ||||||
|  | 		t.Errorf("Get: expected %q got %q", http.StatusBadRequest, resp.StatusCode) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestTrailingSpaces(t *testing.T) { | ||||||
|  | 	// http://code.google.com/p/go/issues/detail?id=955 | ||||||
|  | 	// The last runs of this create keys with trailing spaces that should not be | ||||||
|  | 	// generated by the client. | ||||||
|  | 	once.Do(startServer) | ||||||
|  | 	config := newConfig(t, "/echo") | ||||||
|  | 	for i := 0; i < 30; i++ { | ||||||
|  | 		// body | ||||||
|  | 		ws, err := DialConfig(config) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Errorf("Dial #%d failed: %v", i, err) | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		ws.Close() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestDialConfigBadVersion(t *testing.T) { | ||||||
|  | 	once.Do(startServer) | ||||||
|  | 	config := newConfig(t, "/echo") | ||||||
|  | 	config.Version = 1234 | ||||||
|  |  | ||||||
|  | 	_, err := DialConfig(config) | ||||||
|  |  | ||||||
|  | 	if dialerr, ok := err.(*DialError); ok { | ||||||
|  | 		if dialerr.Err != ErrBadProtocolVersion { | ||||||
|  | 			t.Errorf("dial expected err %q but got %q", ErrBadProtocolVersion, dialerr.Err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestSmallBuffer(t *testing.T) { | ||||||
|  | 	// http://code.google.com/p/go/issues/detail?id=1145 | ||||||
|  | 	// Read should be able to handle reading a fragment of a frame. | ||||||
|  | 	once.Do(startServer) | ||||||
|  |  | ||||||
|  | 	// websocket.Dial() | ||||||
|  | 	client, err := net.Dial("tcp", serverAddr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("dialing", err) | ||||||
|  | 	} | ||||||
|  | 	conn, err := NewClient(newConfig(t, "/echo"), client) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("WebSocket handshake error: %v", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	msg := []byte("hello, world\n") | ||||||
|  | 	if _, err := conn.Write(msg); err != nil { | ||||||
|  | 		t.Errorf("Write: %v", err) | ||||||
|  | 	} | ||||||
|  | 	var small_msg = make([]byte, 8) | ||||||
|  | 	n, err := conn.Read(small_msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Read: %v", err) | ||||||
|  | 	} | ||||||
|  | 	if !bytes.Equal(msg[:len(small_msg)], small_msg) { | ||||||
|  | 		t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg) | ||||||
|  | 	} | ||||||
|  | 	var second_msg = make([]byte, len(msg)) | ||||||
|  | 	n, err = conn.Read(second_msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("Read: %v", err) | ||||||
|  | 	} | ||||||
|  | 	second_msg = second_msg[0:n] | ||||||
|  | 	if !bytes.Equal(msg[len(small_msg):], second_msg) { | ||||||
|  | 		t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg) | ||||||
|  | 	} | ||||||
|  | 	conn.Close() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var parseAuthorityTests = []struct { | ||||||
|  | 	in  *url.URL | ||||||
|  | 	out string | ||||||
|  | }{ | ||||||
|  | 	{ | ||||||
|  | 		&url.URL{ | ||||||
|  | 			Scheme: "ws", | ||||||
|  | 			Host:   "www.google.com", | ||||||
|  | 		}, | ||||||
|  | 		"www.google.com:80", | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		&url.URL{ | ||||||
|  | 			Scheme: "wss", | ||||||
|  | 			Host:   "www.google.com", | ||||||
|  | 		}, | ||||||
|  | 		"www.google.com:443", | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		&url.URL{ | ||||||
|  | 			Scheme: "ws", | ||||||
|  | 			Host:   "www.google.com:80", | ||||||
|  | 		}, | ||||||
|  | 		"www.google.com:80", | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		&url.URL{ | ||||||
|  | 			Scheme: "wss", | ||||||
|  | 			Host:   "www.google.com:443", | ||||||
|  | 		}, | ||||||
|  | 		"www.google.com:443", | ||||||
|  | 	}, | ||||||
|  | 	// some invalid ones for parseAuthority. parseAuthority doesn't | ||||||
|  | 	// concern itself with the scheme unless it actually knows about it | ||||||
|  | 	{ | ||||||
|  | 		&url.URL{ | ||||||
|  | 			Scheme: "http", | ||||||
|  | 			Host:   "www.google.com", | ||||||
|  | 		}, | ||||||
|  | 		"www.google.com", | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		&url.URL{ | ||||||
|  | 			Scheme: "http", | ||||||
|  | 			Host:   "www.google.com:80", | ||||||
|  | 		}, | ||||||
|  | 		"www.google.com:80", | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		&url.URL{ | ||||||
|  | 			Scheme: "asdf", | ||||||
|  | 			Host:   "127.0.0.1", | ||||||
|  | 		}, | ||||||
|  | 		"127.0.0.1", | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		&url.URL{ | ||||||
|  | 			Scheme: "asdf", | ||||||
|  | 			Host:   "www.google.com", | ||||||
|  | 		}, | ||||||
|  | 		"www.google.com", | ||||||
|  | 	}, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestParseAuthority(t *testing.T) { | ||||||
|  | 	for _, tt := range parseAuthorityTests { | ||||||
|  | 		out := parseAuthority(tt.in) | ||||||
|  | 		if out != tt.out { | ||||||
|  | 			t.Errorf("got %v; want %v", out, tt.out) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -100,7 +100,7 @@ func (am *Manager) Lock(addr common.Address) error { | |||||||
| 	am.mutex.Lock() | 	am.mutex.Lock() | ||||||
| 	if unl, found := am.unlocked[addr]; found { | 	if unl, found := am.unlocked[addr]; found { | ||||||
| 		am.mutex.Unlock() | 		am.mutex.Unlock() | ||||||
| 		am.expire(addr, unl, time.Duration(0) * time.Nanosecond) | 		am.expire(addr, unl, time.Duration(0)*time.Nanosecond) | ||||||
| 	} else { | 	} else { | ||||||
| 		am.mutex.Unlock() | 		am.mutex.Unlock() | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										174
									
								
								cmd/geth/js.go
									
									
									
									
									
								
							
							
						
						
									
										174
									
								
								cmd/geth/js.go
									
									
									
									
									
								
							| @@ -24,23 +24,16 @@ import ( | |||||||
| 	"os/signal" | 	"os/signal" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"sort" | 	"sort" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/cmd/utils" | 	"github.com/ethereum/go-ethereum/cmd/utils" | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/natspec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/registrar" | 	"github.com/ethereum/go-ethereum/common/registrar" | ||||||
| 	"github.com/ethereum/go-ethereum/eth" | 	"github.com/ethereum/go-ethereum/eth" | ||||||
| 	re "github.com/ethereum/go-ethereum/jsre" | 	re "github.com/ethereum/go-ethereum/jsre" | ||||||
| 	"github.com/ethereum/go-ethereum/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/api" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| 	"github.com/peterh/liner" | 	"github.com/peterh/liner" | ||||||
| 	"github.com/robertkrimen/otto" | 	"github.com/robertkrimen/otto" | ||||||
| ) | ) | ||||||
| @@ -79,82 +72,90 @@ func (r dumbterm) AppendHistory(string) {} | |||||||
| type jsre struct { | type jsre struct { | ||||||
| 	re         *re.JSRE | 	re         *re.JSRE | ||||||
| 	stack      *node.Node | 	stack      *node.Node | ||||||
| 	xeth       *xeth.XEth |  | ||||||
| 	wait       chan *big.Int | 	wait       chan *big.Int | ||||||
| 	ps1        string | 	ps1        string | ||||||
| 	atexit     func() | 	atexit     func() | ||||||
| 	corsDomain string | 	corsDomain string | ||||||
| 	client     comms.EthereumClient | 	client     rpc.Client | ||||||
| 	prompter | 	prompter | ||||||
| } | } | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	loadedModulesMethods map[string][]string | 	loadedModulesMethods  map[string][]string | ||||||
|  | 	autoCompleteStatement = "function _autocomplete(obj) {var results = []; for (var e in obj) { results.push(e); }; return results; }; _autocomplete(%s)" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func keywordCompleter(line string) []string { | func keywordCompleter(jsre *jsre, line string) []string { | ||||||
| 	results := make([]string, 0) | 	var results []string | ||||||
|  | 	parts := strings.Split(line, ".") | ||||||
|  | 	objRef := "this" | ||||||
|  | 	prefix := line | ||||||
|  | 	if len(parts) > 1 { | ||||||
|  | 		objRef = strings.Join(parts[0:len(parts) - 1], ".") | ||||||
|  | 		prefix = parts[len(parts) - 1] | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if strings.Contains(line, ".") { | 	result, _ := jsre.re.Run(fmt.Sprintf(autoCompleteStatement, objRef)) | ||||||
| 		elements := strings.Split(line, ".") | 	raw, _ := result.Export() | ||||||
| 		if len(elements) == 2 { | 	if keys, ok := raw.([]interface{}); ok { | ||||||
| 			module := elements[0] | 		for _, k := range keys { | ||||||
| 			partialMethod := elements[1] | 			if strings.HasPrefix(fmt.Sprintf("%s", k), prefix) { | ||||||
| 			if methods, found := loadedModulesMethods[module]; found { | 				if objRef == "this" { | ||||||
| 				for _, method := range methods { | 					results = append(results, fmt.Sprintf("%s", k)) | ||||||
| 					if strings.HasPrefix(method, partialMethod) { // e.g. debug.se | 				} else { | ||||||
| 						results = append(results, module+"."+method) | 					results = append(results, fmt.Sprintf("%s.%s", strings.Join(parts[:len(parts) - 1], "."), k)) | ||||||
| 					} |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} else { |  | ||||||
| 		for module, methods := range loadedModulesMethods { |  | ||||||
| 			if line == module { // user typed in full module name, show all methods |  | ||||||
| 				for _, method := range methods { |  | ||||||
| 					results = append(results, module+"."+method) |  | ||||||
| 				} |  | ||||||
| 			} else if strings.HasPrefix(module, line) { // partial method name, e.g. admi |  | ||||||
| 				results = append(results, module) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// e.g. web3<tab><tab> append dot since its an object | ||||||
|  | 	isObj, _ := jsre.re.Run(fmt.Sprintf("typeof(%s) === 'object'", line)) | ||||||
|  | 	if isObject, _ := isObj.ToBoolean(); isObject { | ||||||
|  | 		results = append(results, line + ".") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	sort.Strings(results) | ||||||
| 	return results | 	return results | ||||||
| } | } | ||||||
|  |  | ||||||
| func apiWordCompleter(line string, pos int) (head string, completions []string, tail string) { | func apiWordCompleterWithContext(jsre *jsre) liner.WordCompleter { | ||||||
| 	if len(line) == 0 || pos == 0 { | 	completer := func(line string, pos int) (head string, completions []string, tail string) { | ||||||
| 		return "", nil, "" | 		if len(line) == 0 || pos == 0 { | ||||||
|  | 			return "", nil, "" | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// chuck data to relevant part for autocompletion, e.g. in case of nested lines eth.getBalance(eth.coinb<tab><tab> | ||||||
|  | 		i := 0 | ||||||
|  | 		for i = pos - 1; i > 0; i-- { | ||||||
|  | 			if line[i] == '.' || (line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z') { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			if i >= 3 && line[i] == '3' && line[i - 3] == 'w' && line[i - 2] == 'e' && line[i - 1] == 'b' { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			i += 1 | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		begin := line[:i] | ||||||
|  | 		keyword := line[i:pos] | ||||||
|  | 		end := line[pos:] | ||||||
|  |  | ||||||
|  | 		completionWords := keywordCompleter(jsre, keyword) | ||||||
|  | 		return begin, completionWords, end | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	i := 0 | 	return completer | ||||||
| 	for i = pos - 1; i > 0; i-- { |  | ||||||
| 		if line[i] == '.' || (line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z') { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if i >= 3 && line[i] == '3' && line[i-3] == 'w' && line[i-2] == 'e' && line[i-1] == 'b' { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		i += 1 |  | ||||||
| 		break |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	begin := line[:i] |  | ||||||
| 	keyword := line[i:pos] |  | ||||||
| 	end := line[pos:] |  | ||||||
|  |  | ||||||
| 	completionWords := keywordCompleter(keyword) |  | ||||||
| 	return begin, completionWords, end |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir string, interactive bool) *jsre { | func newLightweightJSRE(docRoot string, client rpc.Client, datadir string, interactive bool) *jsre { | ||||||
| 	js := &jsre{ps1: "> "} | 	js := &jsre{ps1: "> "} | ||||||
| 	js.wait = make(chan *big.Int) | 	js.wait = make(chan *big.Int) | ||||||
| 	js.client = client | 	js.client = client | ||||||
|  |  | ||||||
| 	// update state in separare forever blocks |  | ||||||
| 	js.re = re.New(docRoot) | 	js.re = re.New(docRoot) | ||||||
| 	if err := js.apiBindings(js); err != nil { | 	if err := js.apiBindings(); err != nil { | ||||||
| 		utils.Fatalf("Unable to initialize console - %v", err) | 		utils.Fatalf("Unable to initialize console - %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -165,7 +166,7 @@ func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir str | |||||||
| 		js.withHistory(datadir, func(hist *os.File) { lr.ReadHistory(hist) }) | 		js.withHistory(datadir, func(hist *os.File) { lr.ReadHistory(hist) }) | ||||||
| 		lr.SetCtrlCAborts(true) | 		lr.SetCtrlCAborts(true) | ||||||
| 		js.loadAutoCompletion() | 		js.loadAutoCompletion() | ||||||
| 		lr.SetWordCompleter(apiWordCompleter) | 		lr.SetWordCompleter(apiWordCompleterWithContext(js)) | ||||||
| 		lr.SetTabCompletionStyle(liner.TabPrints) | 		lr.SetTabCompletionStyle(liner.TabPrints) | ||||||
| 		js.prompter = lr | 		js.prompter = lr | ||||||
| 		js.atexit = func() { | 		js.atexit = func() { | ||||||
| @@ -177,25 +178,15 @@ func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir str | |||||||
| 	return js | 	return js | ||||||
| } | } | ||||||
|  |  | ||||||
| func newJSRE(stack *node.Node, docRoot, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre { | func newJSRE(stack *node.Node, docRoot, corsDomain string, client rpc.Client, interactive bool) *jsre { | ||||||
| 	js := &jsre{stack: stack, ps1: "> "} | 	js := &jsre{stack: stack, ps1: "> "} | ||||||
| 	// set default cors domain used by startRpc from CLI flag | 	// set default cors domain used by startRpc from CLI flag | ||||||
| 	js.corsDomain = corsDomain | 	js.corsDomain = corsDomain | ||||||
| 	if f == nil { | 	js.wait = make(chan *big.Int) | ||||||
| 		f = js |  | ||||||
| 	} |  | ||||||
| 	js.xeth = xeth.New(stack, f) |  | ||||||
| 	js.wait = js.xeth.UpdateState() |  | ||||||
| 	js.client = client | 	js.client = client | ||||||
| 	if clt, ok := js.client.(*comms.InProcClient); ok { |  | ||||||
| 		if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, stack); err == nil { |  | ||||||
| 			clt.Initialize(api.Merge(offeredApis...)) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// update state in separare forever blocks |  | ||||||
| 	js.re = re.New(docRoot) | 	js.re = re.New(docRoot) | ||||||
| 	if err := js.apiBindings(f); err != nil { | 	if err := js.apiBindings(); err != nil { | ||||||
| 		utils.Fatalf("Unable to connect - %v", err) | 		utils.Fatalf("Unable to connect - %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -206,7 +197,7 @@ func newJSRE(stack *node.Node, docRoot, corsDomain string, client comms.Ethereum | |||||||
| 		js.withHistory(stack.DataDir(), func(hist *os.File) { lr.ReadHistory(hist) }) | 		js.withHistory(stack.DataDir(), func(hist *os.File) { lr.ReadHistory(hist) }) | ||||||
| 		lr.SetCtrlCAborts(true) | 		lr.SetCtrlCAborts(true) | ||||||
| 		js.loadAutoCompletion() | 		js.loadAutoCompletion() | ||||||
| 		lr.SetWordCompleter(apiWordCompleter) | 		lr.SetWordCompleter(apiWordCompleterWithContext(js)) | ||||||
| 		lr.SetTabCompletionStyle(liner.TabPrints) | 		lr.SetTabCompletionStyle(liner.TabPrints) | ||||||
| 		js.prompter = lr | 		js.prompter = lr | ||||||
| 		js.atexit = func() { | 		js.atexit = func() { | ||||||
| @@ -222,7 +213,7 @@ func (self *jsre) loadAutoCompletion() { | |||||||
| 	if modules, err := self.supportedApis(); err == nil { | 	if modules, err := self.supportedApis(); err == nil { | ||||||
| 		loadedModulesMethods = make(map[string][]string) | 		loadedModulesMethods = make(map[string][]string) | ||||||
| 		for module, _ := range modules { | 		for module, _ := range modules { | ||||||
| 			loadedModulesMethods[module] = api.AutoCompletion[module] | 			loadedModulesMethods[module] = rpc.AutoCompletion[module] | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -258,7 +249,6 @@ func (self *jsre) welcome() { | |||||||
| 			loadedModules = append(loadedModules, fmt.Sprintf("%s:%s", api, version)) | 			loadedModules = append(loadedModules, fmt.Sprintf("%s:%s", api, version)) | ||||||
| 		} | 		} | ||||||
| 		sort.Strings(loadedModules) | 		sort.Strings(loadedModules) | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -266,7 +256,7 @@ func (self *jsre) supportedApis() (map[string]string, error) { | |||||||
| 	return self.client.SupportedModules() | 	return self.client.SupportedModules() | ||||||
| } | } | ||||||
|  |  | ||||||
| func (js *jsre) apiBindings(f xeth.Frontend) error { | func (js *jsre) apiBindings() error { | ||||||
| 	apis, err := js.supportedApis() | 	apis, err := js.supportedApis() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -277,12 +267,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { | |||||||
| 		apiNames = append(apiNames, a) | 		apiNames = append(apiNames, a) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.stack) | 	jeth := utils.NewJeth(js.re, js.client) | ||||||
| 	if err != nil { |  | ||||||
| 		utils.Fatalf("Unable to determine supported api's: %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	jeth := rpc.NewJeth(api.Merge(apiImpl...), js.re, js.client, f) |  | ||||||
| 	js.re.Set("jeth", struct{}{}) | 	js.re.Set("jeth", struct{}{}) | ||||||
| 	t, _ := js.re.Get("jeth") | 	t, _ := js.re.Get("jeth") | ||||||
| 	jethObj := t.Object() | 	jethObj := t.Object() | ||||||
| @@ -313,14 +298,16 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { | |||||||
| 	// load only supported API's in javascript runtime | 	// load only supported API's in javascript runtime | ||||||
| 	shortcuts := "var eth = web3.eth; " | 	shortcuts := "var eth = web3.eth; " | ||||||
| 	for _, apiName := range apiNames { | 	for _, apiName := range apiNames { | ||||||
| 		if apiName == shared.Web3ApiName { | 		if apiName == "web3" || apiName == "rpc" { | ||||||
| 			continue // manually mapped | 			continue // manually mapped or ignore | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if err = js.re.Compile(fmt.Sprintf("%s.js", apiName), api.Javascript(apiName)); err == nil { | 		if jsFile, ok := rpc.WEB3Extensions[apiName]; ok { | ||||||
| 			shortcuts += fmt.Sprintf("var %s = web3.%s; ", apiName, apiName) | 			if err = js.re.Compile(fmt.Sprintf("%s.js", apiName), jsFile); err == nil { | ||||||
| 		} else { | 				shortcuts += fmt.Sprintf("var %s = web3.%s; ", apiName, apiName) | ||||||
| 			utils.Fatalf("Error loading %s.js: %v", apiName, err) | 			} else { | ||||||
|  | 				utils.Fatalf("Error loading %s.js: %v", apiName, err) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -375,14 +362,13 @@ func (self *jsre) ConfirmTransaction(tx string) bool { | |||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 	// If natspec is enabled, ask for permission | 	// If natspec is enabled, ask for permission | ||||||
| 	if ethereum.NatSpec { | 	if ethereum.NatSpec && false /* disabled for now */ { | ||||||
| 		notice := natspec.GetNotice(self.xeth, tx, ethereum.HTTPClient()) | 		//		notice := natspec.GetNotice(self.xeth, tx, ethereum.HTTPClient()) | ||||||
| 		fmt.Println(notice) | 		//		fmt.Println(notice) | ||||||
| 		answer, _ := self.Prompt("Confirm Transaction [y/n]") | 		//		answer, _ := self.Prompt("Confirm Transaction [y/n]") | ||||||
| 		return strings.HasPrefix(strings.Trim(answer, " "), "y") | 		//		return strings.HasPrefix(strings.Trim(answer, " "), "y") | ||||||
| 	} else { |  | ||||||
| 		return true |  | ||||||
| 	} | 	} | ||||||
|  | 	return true | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *jsre) UnlockAccount(addr []byte) bool { | func (self *jsre) UnlockAccount(addr []byte) bool { | ||||||
|   | |||||||
| @@ -32,30 +32,27 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/compiler" | 	"github.com/ethereum/go-ethereum/common/compiler" | ||||||
| 	"github.com/ethereum/go-ethereum/common/httpclient" | 	"github.com/ethereum/go-ethereum/common/httpclient" | ||||||
| 	"github.com/ethereum/go-ethereum/common/natspec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/registrar" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core" | 	"github.com/ethereum/go-ethereum/core" | ||||||
| 	"github.com/ethereum/go-ethereum/crypto" | 	"github.com/ethereum/go-ethereum/crypto" | ||||||
| 	"github.com/ethereum/go-ethereum/eth" | 	"github.com/ethereum/go-ethereum/eth" | ||||||
| 	"github.com/ethereum/go-ethereum/ethdb" | 	"github.com/ethereum/go-ethereum/ethdb" | ||||||
| 	"github.com/ethereum/go-ethereum/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" | 	"github.com/ethereum/go-ethereum/cmd/utils" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	testSolcPath = "" | 	testSolcPath = "" | ||||||
| 	solcVersion  = "0.9.23" | 	solcVersion = "0.9.23" | ||||||
|  |  | ||||||
| 	testKey     = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674" | 	testKey = "e6fab74a43941f82d89cb7faa408e227cdad3153c4720e540e855c19b15e6674" | ||||||
| 	testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" | 	testAddress = "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" | ||||||
| 	testBalance = "10000000000000000000" | 	testBalance = "10000000000000000000" | ||||||
| 	// of empty string | // of empty string | ||||||
| 	testHash = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" | 	testHash = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	versionRE   = regexp.MustCompile(strconv.Quote(`"compilerVersion":"` + solcVersion + `"`)) | 	versionRE = regexp.MustCompile(strconv.Quote(`"compilerVersion":"` + solcVersion + `"`)) | ||||||
| 	testNodeKey = crypto.ToECDSA(common.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f")) | 	testNodeKey = crypto.ToECDSA(common.Hex2Bytes("4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f")) | ||||||
| 	testGenesis = `{"` + testAddress[2:] + `": {"balance": "` + testBalance + `"}}` | 	testGenesis = `{"` + testAddress[2:] + `": {"balance": "` + testBalance + `"}}` | ||||||
| ) | ) | ||||||
| @@ -77,15 +74,16 @@ func (self *testjethre) UnlockAccount(acc []byte) bool { | |||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self *testjethre) ConfirmTransaction(tx string) bool { | // Temporary disabled while natspec hasn't been migrated | ||||||
| 	var ethereum *eth.Ethereum | //func (self *testjethre) ConfirmTransaction(tx string) bool { | ||||||
| 	self.stack.Service(ðereum) | //	var ethereum *eth.Ethereum | ||||||
|  | //	self.stack.Service(ðereum) | ||||||
| 	if ethereum.NatSpec { | // | ||||||
| 		self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.client) | //	if ethereum.NatSpec { | ||||||
| 	} | //		self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.client) | ||||||
| 	return true | //	} | ||||||
| } | //	return true | ||||||
|  | //} | ||||||
|  |  | ||||||
| func testJEthRE(t *testing.T) (string, *testjethre, *node.Node) { | func testJEthRE(t *testing.T) (string, *testjethre, *node.Node) { | ||||||
| 	return testREPL(t, nil) | 	return testREPL(t, nil) | ||||||
| @@ -118,7 +116,9 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod | |||||||
| 	if config != nil { | 	if config != nil { | ||||||
| 		config(ethConf) | 		config(ethConf) | ||||||
| 	} | 	} | ||||||
| 	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { | 	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { | ||||||
|  | 		return eth.New(ctx, ethConf) | ||||||
|  | 	}); err != nil { | ||||||
| 		t.Fatalf("failed to register ethereum protocol: %v", err) | 		t.Fatalf("failed to register ethereum protocol: %v", err) | ||||||
| 	} | 	} | ||||||
| 	// Initialize all the keys for testing | 	// Initialize all the keys for testing | ||||||
| @@ -141,9 +141,10 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod | |||||||
| 	stack.Service(ðereum) | 	stack.Service(ðereum) | ||||||
|  |  | ||||||
| 	assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") | 	assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") | ||||||
| 	client := comms.NewInProcClient(codec.JSON) | 	//client := comms.NewInProcClient(codec.JSON) | ||||||
|  | 	client := utils.NewInProcRPCClient(stack) | ||||||
| 	tf := &testjethre{client: ethereum.HTTPClient()} | 	tf := &testjethre{client: ethereum.HTTPClient()} | ||||||
| 	repl := newJSRE(stack, assetPath, "", client, false, tf) | 	repl := newJSRE(stack, assetPath, "", client, false) | ||||||
| 	tf.jsre = repl | 	tf.jsre = repl | ||||||
| 	return tmp, tf, stack | 	return tmp, tf, stack | ||||||
| } | } | ||||||
| @@ -166,8 +167,8 @@ func TestAccounts(t *testing.T) { | |||||||
| 	defer node.Stop() | 	defer node.Stop() | ||||||
| 	defer os.RemoveAll(tmp) | 	defer os.RemoveAll(tmp) | ||||||
|  |  | ||||||
| 	checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`) | 	checkEvalJSON(t, repl, `eth.accounts`, `["` + testAddress + `"]`) | ||||||
| 	checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`) | 	checkEvalJSON(t, repl, `eth.coinbase`, `"` + testAddress + `"`) | ||||||
| 	val, err := repl.re.Run(`jeth.newAccount("password")`) | 	val, err := repl.re.Run(`jeth.newAccount("password")`) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Errorf("expected no error, got %v", err) | 		t.Errorf("expected no error, got %v", err) | ||||||
| @@ -177,7 +178,7 @@ func TestAccounts(t *testing.T) { | |||||||
| 		t.Errorf("address not hex: %q", addr) | 		t.Errorf("address not hex: %q", addr) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`","`+addr+`"]`) | 	checkEvalJSON(t, repl, `eth.accounts`, `["` + testAddress + `","` + addr + `"]`) | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -205,13 +206,13 @@ func TestBlockChain(t *testing.T) { | |||||||
| 	node.Service(ðereum) | 	node.Service(ðereum) | ||||||
| 	ethereum.BlockChain().Reset() | 	ethereum.BlockChain().Reset() | ||||||
|  |  | ||||||
| 	checkEvalJSON(t, repl, `admin.exportChain(`+tmpfileq+`)`, `true`) | 	checkEvalJSON(t, repl, `admin.exportChain(` + tmpfileq + `)`, `true`) | ||||||
| 	if _, err := os.Stat(tmpfile); err != nil { | 	if _, err := os.Stat(tmpfile); err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// check import, verify that dumpBlock gives the same result. | 	// check import, verify that dumpBlock gives the same result. | ||||||
| 	checkEvalJSON(t, repl, `admin.importChain(`+tmpfileq+`)`, `true`) | 	checkEvalJSON(t, repl, `admin.importChain(` + tmpfileq + `)`, `true`) | ||||||
| 	checkEvalJSON(t, repl, `debug.dumpBlock(eth.blockNumber)`, beforeExport) | 	checkEvalJSON(t, repl, `debug.dumpBlock(eth.blockNumber)`, beforeExport) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -239,7 +240,7 @@ func TestCheckTestAccountBalance(t *testing.T) { | |||||||
| 	defer os.RemoveAll(tmp) | 	defer os.RemoveAll(tmp) | ||||||
|  |  | ||||||
| 	repl.re.Run(`primary = "` + testAddress + `"`) | 	repl.re.Run(`primary = "` + testAddress + `"`) | ||||||
| 	checkEvalJSON(t, repl, `eth.getBalance(primary)`, `"`+testBalance+`"`) | 	checkEvalJSON(t, repl, `eth.getBalance(primary)`, `"` + testBalance + `"`) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestSignature(t *testing.T) { | func TestSignature(t *testing.T) { | ||||||
| @@ -278,19 +279,20 @@ func TestContract(t *testing.T) { | |||||||
| 	defer ethereum.Stop() | 	defer ethereum.Stop() | ||||||
| 	defer os.RemoveAll(tmp) | 	defer os.RemoveAll(tmp) | ||||||
|  |  | ||||||
| 	reg := registrar.New(repl.xeth) | 	// Temporary disabled while registrar isn't migrated | ||||||
| 	_, err := reg.SetGlobalRegistrar("", coinbase) | 	//reg := registrar.New(repl.xeth) | ||||||
| 	if err != nil { | 	//_, err := reg.SetGlobalRegistrar("", coinbase) | ||||||
| 		t.Errorf("error setting HashReg: %v", err) | 	//if err != nil { | ||||||
| 	} | 	//	t.Errorf("error setting HashReg: %v", err) | ||||||
| 	_, err = reg.SetHashReg("", coinbase) | 	//} | ||||||
| 	if err != nil { | 	//_, err = reg.SetHashReg("", coinbase) | ||||||
| 		t.Errorf("error setting HashReg: %v", err) | 	//if err != nil { | ||||||
| 	} | 	//	t.Errorf("error setting HashReg: %v", err) | ||||||
| 	_, err = reg.SetUrlHint("", coinbase) | 	//} | ||||||
| 	if err != nil { | 	//_, err = reg.SetUrlHint("", coinbase) | ||||||
| 		t.Errorf("error setting HashReg: %v", err) | 	//if err != nil { | ||||||
| 	} | 	//	t.Errorf("error setting HashReg: %v", err) | ||||||
|  | 	//} | ||||||
| 	/* TODO: | 	/* TODO: | ||||||
| 	* lookup receipt and contract addresses by tx hash | 	* lookup receipt and contract addresses by tx hash | ||||||
| 	* name registration for HashReg and UrlHint addresses | 	* name registration for HashReg and UrlHint addresses | ||||||
| @@ -299,11 +301,11 @@ func TestContract(t *testing.T) { | |||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
| 	source := `contract test {\n` + | 	source := `contract test {\n` + | ||||||
| 		"   /// @notice Will multiply `a` by 7." + `\n` + | 	"   /// @notice Will multiply `a` by 7." + `\n` + | ||||||
| 		`   function multiply(uint a) returns(uint d) {\n` + | 	`   function multiply(uint a) returns(uint d) {\n` + | ||||||
| 		`       return a * 7;\n` + | 	`       return a * 7;\n` + | ||||||
| 		`   }\n` + | 	`   }\n` + | ||||||
| 		`}\n` | 	`}\n` | ||||||
|  |  | ||||||
| 	if checkEvalJSON(t, repl, `admin.stopNatSpec()`, `true`) != nil { | 	if checkEvalJSON(t, repl, `admin.stopNatSpec()`, `true`) != nil { | ||||||
| 		return | 		return | ||||||
| @@ -313,10 +315,10 @@ func TestContract(t *testing.T) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("%v", err) | 		t.Fatalf("%v", err) | ||||||
| 	} | 	} | ||||||
| 	if checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"`+testAddress+`"`) != nil { | 	if checkEvalJSON(t, repl, `primary = eth.accounts[0]`, `"` + testAddress + `"`) != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if checkEvalJSON(t, repl, `source = "`+source+`"`, `"`+source+`"`) != nil { | 	if checkEvalJSON(t, repl, `source = "` + source + `"`, `"` + source + `"`) != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -394,7 +396,7 @@ multiply7 = Multiply7.at(contractaddress); | |||||||
|  |  | ||||||
| 	var contentHash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"` | 	var contentHash = `"0x86d2b7cf1e72e9a7a3f8d96601f0151742a2f780f1526414304fbe413dc7f9bd"` | ||||||
| 	if sol != nil && solcVersion != sol.Version() { | 	if sol != nil && solcVersion != sol.Version() { | ||||||
| 		modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"`+sol.Version()+`"`)) | 		modContractInfo := versionRE.ReplaceAll(contractInfo, []byte(`"compilerVersion":"` + sol.Version() + `"`)) | ||||||
| 		fmt.Printf("modified contractinfo:\n%s\n", modContractInfo) | 		fmt.Printf("modified contractinfo:\n%s\n", modContractInfo) | ||||||
| 		contentHash = `"` + common.ToHex(crypto.Sha3([]byte(modContractInfo))) + `"` | 		contentHash = `"` + common.ToHex(crypto.Sha3([]byte(modContractInfo))) + `"` | ||||||
| 	} | 	} | ||||||
| @@ -474,11 +476,12 @@ func processTxs(repl *testjethre, t *testing.T, expTxc int) bool { | |||||||
| 	defer ethereum.StopMining() | 	defer ethereum.StopMining() | ||||||
|  |  | ||||||
| 	timer := time.NewTimer(100 * time.Second) | 	timer := time.NewTimer(100 * time.Second) | ||||||
| 	height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1)) | 	blockNr := ethereum.BlockChain().CurrentBlock().Number() | ||||||
|  | 	height := new(big.Int).Add(blockNr, big.NewInt(1)) | ||||||
| 	repl.wait <- height | 	repl.wait <- height | ||||||
| 	select { | 	select { | ||||||
| 	case <-timer.C: | 	case <-timer.C: | ||||||
| 		// if times out make sure the xeth loop does not block | 	// if times out make sure the xeth loop does not block | ||||||
| 		go func() { | 		go func() { | ||||||
| 			select { | 			select { | ||||||
| 			case repl.wait <- nil: | 			case repl.wait <- nil: | ||||||
|   | |||||||
| @@ -40,8 +40,6 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/params" | 	"github.com/ethereum/go-ethereum/params" | ||||||
| 	"github.com/ethereum/go-ethereum/rlp" | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -263,11 +261,11 @@ See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console | |||||||
| 			Name:   "attach", | 			Name:   "attach", | ||||||
| 			Usage:  `Geth Console: interactive JavaScript environment (connect to node)`, | 			Usage:  `Geth Console: interactive JavaScript environment (connect to node)`, | ||||||
| 			Description: ` | 			Description: ` | ||||||
| The Geth console is an interactive shell for the JavaScript runtime environment | 		The Geth console is an interactive shell for the JavaScript runtime environment | ||||||
| which exposes a node admin interface as well as the Ðapp JavaScript API. | 		which exposes a node admin interface as well as the Ðapp JavaScript API. | ||||||
| See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console. | 		See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console. | ||||||
| This command allows to open a console on a running geth node. | 		This command allows to open a console on a running geth node. | ||||||
| `, | 		`, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			Action: execScripts, | 			Action: execScripts, | ||||||
| @@ -309,11 +307,15 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso | |||||||
| 		utils.RPCEnabledFlag, | 		utils.RPCEnabledFlag, | ||||||
| 		utils.RPCListenAddrFlag, | 		utils.RPCListenAddrFlag, | ||||||
| 		utils.RPCPortFlag, | 		utils.RPCPortFlag, | ||||||
| 		utils.RpcApiFlag, | 		utils.RPCApiFlag, | ||||||
|  | 		utils.WSEnabledFlag, | ||||||
|  | 		utils.WSListenAddrFlag, | ||||||
|  | 		utils.WSPortFlag, | ||||||
|  | 		utils.WSApiFlag, | ||||||
|  | 		utils.WSAllowedDomainsFlag, | ||||||
| 		utils.IPCDisabledFlag, | 		utils.IPCDisabledFlag, | ||||||
| 		utils.IPCApiFlag, | 		utils.IPCApiFlag, | ||||||
| 		utils.IPCPathFlag, | 		utils.IPCPathFlag, | ||||||
| 		utils.IPCExperimental, |  | ||||||
| 		utils.ExecFlag, | 		utils.ExecFlag, | ||||||
| 		utils.WhisperEnabledFlag, | 		utils.WhisperEnabledFlag, | ||||||
| 		utils.DevModeFlag, | 		utils.DevModeFlag, | ||||||
| @@ -392,20 +394,12 @@ func geth(ctx *cli.Context) { | |||||||
| 	node.Wait() | 	node.Wait() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // attach will connect to a running geth instance attaching a JavaScript console and to it. | ||||||
| func attach(ctx *cli.Context) { | func attach(ctx *cli.Context) { | ||||||
| 	var client comms.EthereumClient | 	// attach to a running geth instance | ||||||
| 	var err error | 	client, err := utils.NewRemoteRPCClient(ctx) | ||||||
| 	if ctx.Args().Present() { |  | ||||||
| 		client, err = comms.ClientFromEndpoint(ctx.Args().First(), codec.JSON) |  | ||||||
| 	} else { |  | ||||||
| 		cfg := comms.IpcConfig{ |  | ||||||
| 			Endpoint: utils.IpcSocketPath(ctx), |  | ||||||
| 		} |  | ||||||
| 		client, err = comms.NewIpcClient(cfg, codec.JSON) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		utils.Fatalf("Unable to attach to geth node - %v", err) | 		utils.Fatalf("Unable to attach to geth - %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	repl := newLightweightJSRE( | 	repl := newLightweightJSRE( | ||||||
| @@ -431,11 +425,12 @@ func console(ctx *cli.Context) { | |||||||
| 	startNode(ctx, node) | 	startNode(ctx, node) | ||||||
|  |  | ||||||
| 	// Attach to the newly started node, and either execute script or become interactive | 	// Attach to the newly started node, and either execute script or become interactive | ||||||
| 	client := comms.NewInProcClient(codec.JSON) | 	client := utils.NewInProcRPCClient(node) | ||||||
|  |  | ||||||
| 	repl := newJSRE(node, | 	repl := newJSRE(node, | ||||||
| 		ctx.GlobalString(utils.JSpathFlag.Name), | 		ctx.GlobalString(utils.JSpathFlag.Name), | ||||||
| 		ctx.GlobalString(utils.RPCCORSDomainFlag.Name), | 		ctx.GlobalString(utils.RPCCORSDomainFlag.Name), | ||||||
| 		client, true, nil) | 		client, true) | ||||||
|  |  | ||||||
| 	if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { | 	if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { | ||||||
| 		repl.batch(script) | 		repl.batch(script) | ||||||
| @@ -454,11 +449,12 @@ func execScripts(ctx *cli.Context) { | |||||||
| 	startNode(ctx, node) | 	startNode(ctx, node) | ||||||
|  |  | ||||||
| 	// Attach to the newly started node and execute the given scripts | 	// Attach to the newly started node and execute the given scripts | ||||||
| 	client := comms.NewInProcClient(codec.JSON) | 	client := utils.NewInProcRPCClient(node) | ||||||
|  |  | ||||||
| 	repl := newJSRE(node, | 	repl := newJSRE(node, | ||||||
| 		ctx.GlobalString(utils.JSpathFlag.Name), | 		ctx.GlobalString(utils.JSpathFlag.Name), | ||||||
| 		ctx.GlobalString(utils.RPCCORSDomainFlag.Name), | 		ctx.GlobalString(utils.RPCCORSDomainFlag.Name), | ||||||
| 		client, false, nil) | 		client, false) | ||||||
|  |  | ||||||
| 	for _, file := range ctx.Args() { | 	for _, file := range ctx.Args() { | ||||||
| 		repl.exec(file) | 		repl.exec(file) | ||||||
| @@ -517,6 +513,11 @@ func startNode(ctx *cli.Context, stack *node.Node) { | |||||||
| 			utils.Fatalf("Failed to start RPC: %v", err) | 			utils.Fatalf("Failed to start RPC: %v", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if ctx.GlobalBool(utils.WSEnabledFlag.Name) { | ||||||
|  | 		if err := utils.StartWS(stack, ctx); err != nil { | ||||||
|  | 			utils.Fatalf("Failed to start WS: %v", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { | 	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { | ||||||
| 		if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil { | 		if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil { | ||||||
| 			utils.Fatalf("Failed to start mining: %v", err) | 			utils.Fatalf("Failed to start mining: %v", err) | ||||||
|   | |||||||
| @@ -21,16 +21,15 @@ import ( | |||||||
| 	"math" | 	"math" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"runtime" | 	"runtime" | ||||||
| 	"sort" |  | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"sort" | ||||||
|  |  | ||||||
| 	"github.com/codegangsta/cli" | 	"github.com/codegangsta/cli" | ||||||
| 	"github.com/ethereum/go-ethereum/cmd/utils" | 	"github.com/ethereum/go-ethereum/cmd/utils" | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" |  | ||||||
| 	"github.com/gizak/termui" | 	"github.com/gizak/termui" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -70,20 +69,18 @@ to display multiple metrics simultaneously. | |||||||
| // monitor starts a terminal UI based monitoring tool for the requested metrics. | // monitor starts a terminal UI based monitoring tool for the requested metrics. | ||||||
| func monitor(ctx *cli.Context) { | func monitor(ctx *cli.Context) { | ||||||
| 	var ( | 	var ( | ||||||
| 		client comms.EthereumClient | 		client rpc.Client | ||||||
| 		err    error | 		err    error | ||||||
| 	) | 	) | ||||||
| 	// Attach to an Ethereum node over IPC or RPC | 	// Attach to an Ethereum node over IPC or RPC | ||||||
| 	endpoint := ctx.String(monitorCommandAttachFlag.Name) | 	endpoint := ctx.String(monitorCommandAttachFlag.Name) | ||||||
| 	if client, err = comms.ClientFromEndpoint(endpoint, codec.JSON); err != nil { | 	if client, err = utils.NewRemoteRPCClientFromString(endpoint); err != nil { | ||||||
| 		utils.Fatalf("Unable to attach to geth node: %v", err) | 		utils.Fatalf("Unable to attach to geth node: %v", err) | ||||||
| 	} | 	} | ||||||
| 	defer client.Close() | 	defer client.Close() | ||||||
|  |  | ||||||
| 	xeth := rpc.NewXeth(client) |  | ||||||
|  |  | ||||||
| 	// Retrieve all the available metrics and resolve the user pattens | 	// Retrieve all the available metrics and resolve the user pattens | ||||||
| 	metrics, err := retrieveMetrics(xeth) | 	metrics, err := retrieveMetrics(client) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		utils.Fatalf("Failed to retrieve system metrics: %v", err) | 		utils.Fatalf("Failed to retrieve system metrics: %v", err) | ||||||
| 	} | 	} | ||||||
| @@ -133,7 +130,7 @@ func monitor(ctx *cli.Context) { | |||||||
| 	} | 	} | ||||||
| 	termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer))) | 	termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer))) | ||||||
|  |  | ||||||
| 	refreshCharts(xeth, monitored, data, units, charts, ctx, footer) | 	refreshCharts(client, monitored, data, units, charts, ctx, footer) | ||||||
| 	termui.Body.Align() | 	termui.Body.Align() | ||||||
| 	termui.Render(termui.Body) | 	termui.Render(termui.Body) | ||||||
|  |  | ||||||
| @@ -154,7 +151,7 @@ func monitor(ctx *cli.Context) { | |||||||
| 				termui.Render(termui.Body) | 				termui.Render(termui.Body) | ||||||
| 			} | 			} | ||||||
| 		case <-refresh: | 		case <-refresh: | ||||||
| 			if refreshCharts(xeth, monitored, data, units, charts, ctx, footer) { | 			if refreshCharts(client, monitored, data, units, charts, ctx, footer) { | ||||||
| 				termui.Body.Align() | 				termui.Body.Align() | ||||||
| 			} | 			} | ||||||
| 			termui.Render(termui.Body) | 			termui.Render(termui.Body) | ||||||
| @@ -164,8 +161,30 @@ func monitor(ctx *cli.Context) { | |||||||
|  |  | ||||||
| // retrieveMetrics contacts the attached geth node and retrieves the entire set | // retrieveMetrics contacts the attached geth node and retrieves the entire set | ||||||
| // of collected system metrics. | // of collected system metrics. | ||||||
| func retrieveMetrics(xeth *rpc.Xeth) (map[string]interface{}, error) { | func retrieveMetrics(client rpc.Client) (map[string]interface{}, error) { | ||||||
| 	return xeth.Call("debug_metrics", []interface{}{true}) | 	req := map[string]interface{}{ | ||||||
|  | 		"id":      new(int64), | ||||||
|  | 		"method":  "debug_metrics", | ||||||
|  | 		"jsonrpc": "2.0", | ||||||
|  | 		"params":  []interface{}{true}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if err := client.Send(req); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var res rpc.JSONSuccessResponse | ||||||
|  | 	if err := client.Recv(&res); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if res.Result != nil { | ||||||
|  | 		if mets, ok := res.Result.(map[string]interface{}); ok { | ||||||
|  | 			return mets, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil, fmt.Errorf("unable to retrieve metrics") | ||||||
| } | } | ||||||
|  |  | ||||||
| // resolveMetrics takes a list of input metric patterns, and resolves each to one | // resolveMetrics takes a list of input metric patterns, and resolves each to one | ||||||
| @@ -253,8 +272,8 @@ func fetchMetric(metrics map[string]interface{}, metric string) float64 { | |||||||
|  |  | ||||||
| // refreshCharts retrieves a next batch of metrics, and inserts all the new | // refreshCharts retrieves a next batch of metrics, and inserts all the new | ||||||
| // values into the active datasets and charts | // values into the active datasets and charts | ||||||
| func refreshCharts(xeth *rpc.Xeth, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) { | func refreshCharts(client rpc.Client, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) { | ||||||
| 	values, err := retrieveMetrics(xeth) | 	values, err := retrieveMetrics(client) | ||||||
| 	for i, metric := range metrics { | 	for i, metric := range metrics { | ||||||
| 		if len(data) < 512 { | 		if len(data) < 512 { | ||||||
| 			data[i] = append([]float64{fetchMetric(values, metric)}, data[i]...) | 			data[i] = append([]float64{fetchMetric(values, metric)}, data[i]...) | ||||||
|   | |||||||
| @@ -87,7 +87,12 @@ var AppHelpFlagGroups = []flagGroup{ | |||||||
| 			utils.RPCEnabledFlag, | 			utils.RPCEnabledFlag, | ||||||
| 			utils.RPCListenAddrFlag, | 			utils.RPCListenAddrFlag, | ||||||
| 			utils.RPCPortFlag, | 			utils.RPCPortFlag, | ||||||
| 			utils.RpcApiFlag, | 			utils.RPCApiFlag, | ||||||
|  | 			utils.WSEnabledFlag, | ||||||
|  | 			utils.WSListenAddrFlag, | ||||||
|  | 			utils.WSPortFlag, | ||||||
|  | 			utils.WSApiFlag, | ||||||
|  | 			utils.WSAllowedDomainsFlag, | ||||||
| 			utils.IPCDisabledFlag, | 			utils.IPCDisabledFlag, | ||||||
| 			utils.IPCApiFlag, | 			utils.IPCApiFlag, | ||||||
| 			utils.IPCPathFlag, | 			utils.IPCPathFlag, | ||||||
| @@ -158,7 +163,6 @@ var AppHelpFlagGroups = []flagGroup{ | |||||||
| 		Flags: []cli.Flag{ | 		Flags: []cli.Flag{ | ||||||
| 			utils.WhisperEnabledFlag, | 			utils.WhisperEnabledFlag, | ||||||
| 			utils.NatspecEnabledFlag, | 			utils.NatspecEnabledFlag, | ||||||
| 			utils.IPCExperimental, |  | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -26,8 +26,9 @@ import ( | |||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"runtime" | 	"runtime" | ||||||
|  |  | ||||||
|  | 	"errors" | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/accounts" | 	"github.com/ethereum/go-ethereum/accounts" | ||||||
| 	"github.com/ethereum/go-ethereum/cmd/utils" |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/crypto" | 	"github.com/ethereum/go-ethereum/crypto" | ||||||
| 	"github.com/ethereum/go-ethereum/eth" | 	"github.com/ethereum/go-ethereum/eth" | ||||||
| @@ -35,13 +36,9 @@ 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/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/api" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" |  | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" |  | ||||||
| 	"github.com/ethereum/go-ethereum/tests" | 	"github.com/ethereum/go-ethereum/tests" | ||||||
| 	"github.com/ethereum/go-ethereum/whisper" | 	"github.com/ethereum/go-ethereum/whisper" | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const defaultTestKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" | const defaultTestKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" | ||||||
| @@ -176,21 +173,25 @@ func RunTest(stack *node.Node, test *tests.BlockTest) error { | |||||||
|  |  | ||||||
| // StartRPC initializes an RPC interface to the given protocol stack. | // StartRPC initializes an RPC interface to the given protocol stack. | ||||||
| func StartRPC(stack *node.Node) error { | func StartRPC(stack *node.Node) error { | ||||||
| 	config := comms.HttpConfig{ | 	/* | ||||||
| 		ListenAddress: "127.0.0.1", | 		web3 := NewPublicWeb3API(stack) | ||||||
| 		ListenPort:    8545, | 		server.RegisterName("web3", web3) | ||||||
| 	} | 		net := NewPublicNetAPI(stack.Server(), ethereum.NetVersion()) | ||||||
| 	xeth := xeth.New(stack, nil) | 		server.RegisterName("net", net) | ||||||
| 	codec := codec.JSON | 	*/ | ||||||
|  |  | ||||||
| 	apis, err := api.ParseApiString(comms.DefaultHttpRpcApis, codec, xeth, stack) | 	for _, api := range stack.APIs() { | ||||||
| 	if err != nil { | 		if adminApi, ok := api.Service.(*node.PrivateAdminAPI); ok { | ||||||
| 		return err | 			_, err := adminApi.StartRPC("127.0.0.1", 8545, "", "admin,db,eth,debug,miner,net,shh,txpool,personal,web3") | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	return comms.StartHttp(config, codec, api.Merge(apis...)) |  | ||||||
|  | 	glog.V(logger.Error).Infof("Unable to start RPC-HTTP interface, could not find admin API") | ||||||
|  | 	return errors.New("Unable to start RPC-HTTP interface") | ||||||
| } | } | ||||||
|  |  | ||||||
| // StartRPC initializes an IPC interface to the given protocol stack. | // StartIPC initializes an IPC interface to the given protocol stack. | ||||||
| func StartIPC(stack *node.Node) error { | func StartIPC(stack *node.Node) error { | ||||||
| 	var ethereum *eth.Ethereum | 	var ethereum *eth.Ethereum | ||||||
| 	if err := stack.Service(ðereum); err != nil { | 	if err := stack.Service(ðereum); err != nil { | ||||||
| @@ -202,11 +203,7 @@ func StartIPC(stack *node.Node) error { | |||||||
| 		endpoint = filepath.Join(common.DefaultDataDir(), "geth.ipc") | 		endpoint = filepath.Join(common.DefaultDataDir(), "geth.ipc") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	config := comms.IpcConfig{ | 	listener, err := rpc.CreateIPCListener(endpoint) | ||||||
| 		Endpoint: endpoint, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	listener, err := comms.CreateListener(config) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -217,16 +214,16 @@ func StartIPC(stack *node.Node) error { | |||||||
| 	offered := stack.APIs() | 	offered := stack.APIs() | ||||||
| 	for _, api := range offered { | 	for _, api := range offered { | ||||||
| 		server.RegisterName(api.Namespace, api.Service) | 		server.RegisterName(api.Namespace, api.Service) | ||||||
| 		glog.V(logger.Debug).Infof("Register %T@%s for IPC service\n", api.Service, api.Namespace) | 		glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	web3 := utils.NewPublicWeb3API(stack) | 	//var ethereum *eth.Ethereum | ||||||
| 	server.RegisterName("web3", web3) | 	//if err := stack.Service(ðereum); err != nil { | ||||||
| 	net := utils.NewPublicNetAPI(stack.Server(), ethereum.NetVersion()) | 	//	return err | ||||||
| 	server.RegisterName("net", net) | 	//} | ||||||
|  |  | ||||||
| 	go func() { | 	go func() { | ||||||
| 		glog.V(logger.Info).Infof("Start IPC server on %s\n", config.Endpoint) | 		glog.V(logger.Info).Infof("Start IPC server on %s\n", endpoint) | ||||||
| 		for { | 		for { | ||||||
| 			conn, err := listener.Accept() | 			conn, err := listener.Accept() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
|   | |||||||
| @@ -1,74 +0,0 @@ | |||||||
| // 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 utils |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/crypto" |  | ||||||
| 	"github.com/ethereum/go-ethereum/node" |  | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" |  | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // PublicWeb3API offers helper utils |  | ||||||
| type PublicWeb3API struct { |  | ||||||
| 	stack *node.Node |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewPublicWeb3API creates a new Web3Service instance |  | ||||||
| func NewPublicWeb3API(stack *node.Node) *PublicWeb3API { |  | ||||||
| 	return &PublicWeb3API{stack} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ClientVersion returns the node name |  | ||||||
| func (s *PublicWeb3API) ClientVersion() string { |  | ||||||
| 	return s.stack.Server().Name |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Sha3 applies the ethereum sha3 implementation on the input. |  | ||||||
| // It assumes the input is hex encoded. |  | ||||||
| func (s *PublicWeb3API) Sha3(input string) string { |  | ||||||
| 	return common.ToHex(crypto.Sha3(common.FromHex(input))) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // PublicNetAPI offers network related RPC methods |  | ||||||
| type PublicNetAPI struct { |  | ||||||
| 	net            *p2p.Server |  | ||||||
| 	networkVersion int |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewPublicNetAPI creates a new net api instance. |  | ||||||
| func NewPublicNetAPI(net *p2p.Server, networkVersion int) *PublicNetAPI { |  | ||||||
| 	return &PublicNetAPI{net, networkVersion} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Listening returns an indication if the node is listening for network connections. |  | ||||||
| func (s *PublicNetAPI) Listening() bool { |  | ||||||
| 	return true // always listening |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Peercount returns the number of connected peers |  | ||||||
| func (s *PublicNetAPI) PeerCount() *rpc.HexNumber { |  | ||||||
| 	return rpc.NewHexNumber(s.net.PeerCount()) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ProtocolVersion returns the current ethereum protocol version. |  | ||||||
| func (s *PublicNetAPI) Version() string { |  | ||||||
| 	return fmt.Sprintf("%d", s.networkVersion) |  | ||||||
| } |  | ||||||
							
								
								
									
										176
									
								
								cmd/utils/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								cmd/utils/client.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,176 @@ | |||||||
|  | // 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 utils | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/codegangsta/cli" | ||||||
|  | 	"github.com/ethereum/go-ethereum/eth" | ||||||
|  | 	"github.com/ethereum/go-ethereum/logger" | ||||||
|  | 	"github.com/ethereum/go-ethereum/logger/glog" | ||||||
|  | 	"github.com/ethereum/go-ethereum/node" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // NewInProcRPCClient will start a new RPC server for the given node and returns a client to interact with it. | ||||||
|  | func NewInProcRPCClient(stack *node.Node) *inProcClient { | ||||||
|  | 	server := rpc.NewServer() | ||||||
|  |  | ||||||
|  | 	offered := stack.APIs() | ||||||
|  | 	for _, api := range offered { | ||||||
|  | 		server.RegisterName(api.Namespace, api.Service) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	web3 := node.NewPublicWeb3API(stack) | ||||||
|  | 	server.RegisterName("web3", web3) | ||||||
|  |  | ||||||
|  | 	var ethereum *eth.Ethereum | ||||||
|  | 	if err := stack.Service(ðereum); err == nil { | ||||||
|  | 		net := eth.NewPublicNetAPI(stack.Server(), ethereum.NetVersion()) | ||||||
|  | 		server.RegisterName("net", net) | ||||||
|  | 	} else { | ||||||
|  | 		glog.V(logger.Warn).Infof("%v\n", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	buf := &buf{ | ||||||
|  | 		requests:  make(chan []byte), | ||||||
|  | 		responses: make(chan []byte), | ||||||
|  | 	} | ||||||
|  | 	client := &inProcClient{ | ||||||
|  | 		server: server, | ||||||
|  | 		buf:    buf, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	go func() { | ||||||
|  | 		server.ServeCodec(rpc.NewJSONCodec(client.buf)) | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	return client | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // buf represents the connection between the RPC server and console | ||||||
|  | type buf struct { | ||||||
|  | 	readBuf   []byte      // store remaining request bytes after a partial read | ||||||
|  | 	requests  chan []byte // list with raw serialized requests | ||||||
|  | 	responses chan []byte // list with raw serialized responses | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // will read the next request in json format | ||||||
|  | func (b *buf) Read(p []byte) (int, error) { | ||||||
|  | 	// last read didn't read entire request, return remaining bytes | ||||||
|  | 	if len(b.readBuf) > 0 { | ||||||
|  | 		n := copy(p, b.readBuf) | ||||||
|  | 		if n < len(b.readBuf) { | ||||||
|  | 			b.readBuf = b.readBuf[:n] | ||||||
|  | 		} else { | ||||||
|  | 			b.readBuf = b.readBuf[:0] | ||||||
|  | 		} | ||||||
|  | 		return n, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// read next request | ||||||
|  | 	req := <-b.requests | ||||||
|  | 	n := copy(p, req) | ||||||
|  | 	if n < len(req) { | ||||||
|  | 		// buf too small, store remaining chunk for next read | ||||||
|  | 		b.readBuf = req[n:] | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return n, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Write send the given buffer to the backend | ||||||
|  | func (b *buf) Write(p []byte) (n int, err error) { | ||||||
|  | 	b.responses <- p | ||||||
|  | 	return len(p), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close cleans up obtained resources. | ||||||
|  | func (b *buf) Close() error { | ||||||
|  | 	close(b.requests) | ||||||
|  | 	close(b.responses) | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // inProcClient starts a RPC server and uses buf to communicate with it. | ||||||
|  | type inProcClient struct { | ||||||
|  | 	server *rpc.Server | ||||||
|  | 	buf    *buf | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close will stop the RPC server | ||||||
|  | func (c *inProcClient) Close() { | ||||||
|  | 	c.server.Stop() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Send a msg to the endpoint | ||||||
|  | func (c *inProcClient) Send(msg interface{}) error { | ||||||
|  | 	d, err := json.Marshal(msg) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	c.buf.requests <- d | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Recv reads a message and tries to parse it into the given msg | ||||||
|  | func (c *inProcClient) Recv(msg interface{}) error { | ||||||
|  | 	data := <-c.buf.responses | ||||||
|  | 	return json.Unmarshal(data, &msg) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Returns the collection of modules the RPC server offers. | ||||||
|  | func (c *inProcClient) SupportedModules() (map[string]string, error) { | ||||||
|  | 	return rpc.SupportedModules(c) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewRemoteRPCClient returns a RPC client which connects to a running geth instance. | ||||||
|  | // Depending on the given context this can either be a IPC or a HTTP client. | ||||||
|  | func NewRemoteRPCClient(ctx *cli.Context) (rpc.Client, error) { | ||||||
|  | 	if ctx.Args().Present() { | ||||||
|  | 		endpoint := ctx.Args().First() | ||||||
|  | 		return NewRemoteRPCClientFromString(endpoint) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// use IPC by default | ||||||
|  | 	endpoint := IPCSocketPath(ctx) | ||||||
|  | 	return rpc.NewIPCClient(endpoint) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewRemoteRPCClientFromString returns a RPC client which connects to the given | ||||||
|  | // endpoint. It must start with either `ipc:` or `rpc:` (HTTP). | ||||||
|  | func NewRemoteRPCClientFromString(endpoint string) (rpc.Client, error) { | ||||||
|  | 	if strings.HasPrefix(endpoint, "ipc:") { | ||||||
|  | 		return rpc.NewIPCClient(endpoint[4:]) | ||||||
|  | 	} | ||||||
|  | 	if strings.HasPrefix(endpoint, "rpc:") { | ||||||
|  | 		return rpc.NewHTTPClient(endpoint[4:]) | ||||||
|  | 	} | ||||||
|  | 	if strings.HasPrefix(endpoint, "http://") { | ||||||
|  | 		return rpc.NewHTTPClient(endpoint) | ||||||
|  | 	} | ||||||
|  | 	if strings.HasPrefix(endpoint, "ws:") { | ||||||
|  | 		return rpc.NewWSClient(endpoint) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil, fmt.Errorf("invalid endpoint") | ||||||
|  | } | ||||||
| @@ -23,7 +23,6 @@ import ( | |||||||
| 	"log" | 	"log" | ||||||
| 	"math" | 	"math" | ||||||
| 	"math/big" | 	"math/big" | ||||||
| 	"net" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| @@ -31,6 +30,8 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
|  | 	"errors" | ||||||
|  |  | ||||||
| 	"github.com/codegangsta/cli" | 	"github.com/codegangsta/cli" | ||||||
| 	"github.com/ethereum/ethash" | 	"github.com/ethereum/ethash" | ||||||
| 	"github.com/ethereum/go-ethereum/accounts" | 	"github.com/ethereum/go-ethereum/accounts" | ||||||
| @@ -49,14 +50,8 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/p2p/discover" | 	"github.com/ethereum/go-ethereum/p2p/discover" | ||||||
| 	"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/rpc/api" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/useragent" |  | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" |  | ||||||
| 	"github.com/ethereum/go-ethereum/whisper" | 	"github.com/ethereum/go-ethereum/whisper" | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
| @@ -282,10 +277,10 @@ var ( | |||||||
| 		Usage: "Domains from which to accept cross origin requests (browser enforced)", | 		Usage: "Domains from which to accept cross origin requests (browser enforced)", | ||||||
| 		Value: "", | 		Value: "", | ||||||
| 	} | 	} | ||||||
| 	RpcApiFlag = cli.StringFlag{ | 	RPCApiFlag = cli.StringFlag{ | ||||||
| 		Name:  "rpcapi", | 		Name:  "rpcapi", | ||||||
| 		Usage: "API's offered over the HTTP-RPC interface", | 		Usage: "API's offered over the HTTP-RPC interface", | ||||||
| 		Value: comms.DefaultHttpRpcApis, | 		Value: rpc.DefaultHttpRpcApis, | ||||||
| 	} | 	} | ||||||
| 	IPCDisabledFlag = cli.BoolFlag{ | 	IPCDisabledFlag = cli.BoolFlag{ | ||||||
| 		Name:  "ipcdisable", | 		Name:  "ipcdisable", | ||||||
| @@ -294,16 +289,36 @@ var ( | |||||||
| 	IPCApiFlag = cli.StringFlag{ | 	IPCApiFlag = cli.StringFlag{ | ||||||
| 		Name:  "ipcapi", | 		Name:  "ipcapi", | ||||||
| 		Usage: "API's offered over the IPC-RPC interface", | 		Usage: "API's offered over the IPC-RPC interface", | ||||||
| 		Value: comms.DefaultIpcApis, | 		Value: rpc.DefaultIpcApis, | ||||||
| 	} | 	} | ||||||
| 	IPCPathFlag = DirectoryFlag{ | 	IPCPathFlag = DirectoryFlag{ | ||||||
| 		Name:  "ipcpath", | 		Name:  "ipcpath", | ||||||
| 		Usage: "Filename for IPC socket/pipe", | 		Usage: "Filename for IPC socket/pipe", | ||||||
| 		Value: DirectoryString{common.DefaultIpcPath()}, | 		Value: DirectoryString{common.DefaultIpcPath()}, | ||||||
| 	} | 	} | ||||||
| 	IPCExperimental = cli.BoolFlag{ | 	WSEnabledFlag = cli.BoolFlag{ | ||||||
| 		Name:  "ipcexp", | 		Name: "ws", | ||||||
| 		Usage: "Enable the new RPC implementation", | 		Usage: "Enable the WS-RPC server", | ||||||
|  | 	} | ||||||
|  | 	WSListenAddrFlag = cli.StringFlag{ | ||||||
|  | 		Name:  "wsaddr", | ||||||
|  | 		Usage: "WS-RPC server listening interface", | ||||||
|  | 		Value: "127.0.0.1", | ||||||
|  | 	} | ||||||
|  | 	WSPortFlag = cli.IntFlag{ | ||||||
|  | 		Name:  "wsport", | ||||||
|  | 		Usage: "WS-RPC server listening port", | ||||||
|  | 		Value: 8546, | ||||||
|  | 	} | ||||||
|  | 	WSApiFlag = cli.StringFlag{ | ||||||
|  | 		Name:  "wsapi", | ||||||
|  | 		Usage: "API's offered over the WS-RPC interface", | ||||||
|  | 		Value: rpc.DefaultHttpRpcApis, | ||||||
|  | 	} | ||||||
|  | 	WSAllowedDomainsFlag = cli.StringFlag{ | ||||||
|  | 		Name:  "wsdomains", | ||||||
|  | 		Usage: "Domains from which to accept websockets requests", | ||||||
|  | 		Value: "", | ||||||
| 	} | 	} | ||||||
| 	ExecFlag = cli.StringFlag{ | 	ExecFlag = cli.StringFlag{ | ||||||
| 		Name:  "exec", | 		Name:  "exec", | ||||||
| @@ -760,7 +775,7 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database | |||||||
| 	return chain, chainDb | 	return chain, chainDb | ||||||
| } | } | ||||||
|  |  | ||||||
| func IpcSocketPath(ctx *cli.Context) (ipcpath string) { | func IPCSocketPath(ctx *cli.Context) (ipcpath string) { | ||||||
| 	if runtime.GOOS == "windows" { | 	if runtime.GOOS == "windows" { | ||||||
| 		ipcpath = common.DefaultIpcPath() | 		ipcpath = common.DefaultIpcPath() | ||||||
| 		if ctx.GlobalIsSet(IPCPathFlag.Name) { | 		if ctx.GlobalIsSet(IPCPathFlag.Name) { | ||||||
| @@ -780,79 +795,83 @@ func IpcSocketPath(ctx *cli.Context) (ipcpath string) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func StartIPC(stack *node.Node, ctx *cli.Context) error { | func StartIPC(stack *node.Node, ctx *cli.Context) error { | ||||||
| 	config := comms.IpcConfig{ |  | ||||||
| 		Endpoint: IpcSocketPath(ctx), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ethereum *eth.Ethereum | 	var ethereum *eth.Ethereum | ||||||
| 	if err := stack.Service(ðereum); err != nil { | 	if err := stack.Service(ðereum); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if ctx.GlobalIsSet(IPCExperimental.Name) { | 	endpoint := IPCSocketPath(ctx) | ||||||
| 		listener, err := comms.CreateListener(config) | 	listener, err := rpc.CreateIPCListener(endpoint) | ||||||
| 		if err != nil { | 	if err != nil { | ||||||
| 			return err | 		return err | ||||||
| 		} | 	} | ||||||
|  |  | ||||||
| 		server := rpc.NewServer() | 	server := rpc.NewServer() | ||||||
|  |  | ||||||
| 		// register package API's this node provides | 	// register package API's this node provides | ||||||
| 		offered := stack.APIs() | 	offered := stack.APIs() | ||||||
| 		for _, api := range offered { | 	for _, api := range offered { | ||||||
| 			server.RegisterName(api.Namespace, api.Service) | 		server.RegisterName(api.Namespace, api.Service) | ||||||
| 			glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace) | 		glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace) | ||||||
| 		} | 	} | ||||||
|  |  | ||||||
| 		web3 := NewPublicWeb3API(stack) | 	go func() { | ||||||
| 		server.RegisterName("web3", web3) | 		glog.V(logger.Info).Infof("Start IPC server on %s\n", endpoint) | ||||||
| 		net := NewPublicNetAPI(stack.Server(), ethereum.NetVersion()) | 		for { | ||||||
| 		server.RegisterName("net", net) | 			conn, err := listener.Accept() | ||||||
|  | 			if err != nil { | ||||||
| 		go func() { | 				glog.V(logger.Error).Infof("Unable to accept connection - %v\n", err) | ||||||
| 			glog.V(logger.Info).Infof("Start IPC server on %s\n", config.Endpoint) |  | ||||||
| 			for { |  | ||||||
| 				conn, err := listener.Accept() |  | ||||||
| 				if err != nil { |  | ||||||
| 					glog.V(logger.Error).Infof("Unable to accept connection - %v\n", err) |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				codec := rpc.NewJSONCodec(conn) |  | ||||||
| 				go server.ServeCodec(codec) |  | ||||||
| 			} | 			} | ||||||
| 		}() |  | ||||||
|  |  | ||||||
| 		return nil | 			codec := rpc.NewJSONCodec(conn) | ||||||
| 	} | 			go server.ServeCodec(codec) | ||||||
|  |  | ||||||
| 	initializer := func(conn net.Conn) (comms.Stopper, shared.EthereumApi, error) { |  | ||||||
| 		fe := useragent.NewRemoteFrontend(conn, ethereum.AccountManager()) |  | ||||||
| 		xeth := xeth.New(stack, fe) |  | ||||||
| 		apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec.JSON, xeth, stack) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, nil, err |  | ||||||
| 		} | 		} | ||||||
| 		return xeth, api.Merge(apis...), nil | 	}() | ||||||
| 	} |  | ||||||
| 	return comms.StartIpc(config, codec.JSON, initializer) | 	return nil | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // StartRPC starts a HTTP JSON-RPC API server. | // StartRPC starts a HTTP JSON-RPC API server. | ||||||
| func StartRPC(stack *node.Node, ctx *cli.Context) error { | func StartRPC(stack *node.Node, ctx *cli.Context) error { | ||||||
| 	config := comms.HttpConfig{ | 	for _, api := range stack.APIs() { | ||||||
| 		ListenAddress: ctx.GlobalString(RPCListenAddrFlag.Name), | 		if adminApi, ok := api.Service.(*node.PrivateAdminAPI); ok { | ||||||
| 		ListenPort:    uint(ctx.GlobalInt(RPCPortFlag.Name)), | 			address := ctx.GlobalString(RPCListenAddrFlag.Name) | ||||||
| 		CorsDomain:    ctx.GlobalString(RPCCORSDomainFlag.Name), | 			port := ctx.GlobalInt(RPCPortFlag.Name) | ||||||
|  | 			cors := ctx.GlobalString(RPCCORSDomainFlag.Name) | ||||||
|  | 			apiStr := "" | ||||||
|  | 			if ctx.GlobalIsSet(RPCApiFlag.Name) { | ||||||
|  | 				apiStr = ctx.GlobalString(RPCApiFlag.Name) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			_, err := adminApi.StartRPC(address, port, cors, apiStr) | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	xeth := xeth.New(stack, nil) | 	glog.V(logger.Error).Infof("Unable to start RPC-HTTP interface, could not find admin API") | ||||||
| 	codec := codec.JSON | 	return errors.New("Unable to start RPC-HTTP interface") | ||||||
|  | } | ||||||
|  |  | ||||||
| 	apis, err := api.ParseApiString(ctx.GlobalString(RpcApiFlag.Name), codec, xeth, stack) | // StartWS starts a websocket JSON-RPC API server. | ||||||
| 	if err != nil { | func StartWS(stack *node.Node, ctx *cli.Context) error { | ||||||
| 		return err | 	for _, api := range stack.APIs() { | ||||||
|  | 		if adminApi, ok := api.Service.(*node.PrivateAdminAPI); ok { | ||||||
|  | 			address := ctx.GlobalString(WSListenAddrFlag.Name) | ||||||
|  | 			port := ctx.GlobalInt(WSAllowedDomainsFlag.Name) | ||||||
|  | 			allowedDomains := ctx.GlobalString(WSAllowedDomainsFlag.Name) | ||||||
|  | 			apiStr := "" | ||||||
|  | 			if ctx.GlobalIsSet(WSApiFlag.Name) { | ||||||
|  | 				apiStr = ctx.GlobalString(WSApiFlag.Name) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			_, err := adminApi.StartWS(address, port, allowedDomains, apiStr) | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	return comms.StartHttp(config, codec, api.Merge(apis...)) |  | ||||||
|  | 	glog.V(logger.Error).Infof("Unable to start RPC-WS interface, could not find admin API") | ||||||
|  | 	return errors.New("Unable to start RPC-WS interface") | ||||||
| } | } | ||||||
|  |  | ||||||
| func StartPProf(ctx *cli.Context) { | func StartPProf(ctx *cli.Context) { | ||||||
|   | |||||||
| @@ -14,38 +14,39 @@ | |||||||
| // You should have received a copy of the GNU Lesser General Public License | // 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/>. | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||||||
| 
 | 
 | ||||||
| package rpc | package utils | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/ethereum/go-ethereum/cmd/utils" |  | ||||||
| 	"github.com/ethereum/go-ethereum/jsre" | 	"github.com/ethereum/go-ethereum/jsre" | ||||||
| 	"github.com/ethereum/go-ethereum/logger" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| 	"github.com/ethereum/go-ethereum/logger/glog" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/useragent" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/robertkrimen/otto" | 	"github.com/robertkrimen/otto" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Jeth struct { | type Jeth struct { | ||||||
| 	ethApi shared.EthereumApi |  | ||||||
| 	re     *jsre.JSRE | 	re     *jsre.JSRE | ||||||
| 	client comms.EthereumClient | 	client rpc.Client | ||||||
| 	fe     xeth.Frontend |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewJeth(ethApi shared.EthereumApi, re *jsre.JSRE, client comms.EthereumClient, fe xeth.Frontend) *Jeth { | // NewJeth create a new backend for the JSRE console | ||||||
| 	return &Jeth{ethApi, re, client, fe} | func NewJeth(re *jsre.JSRE, client rpc.Client) *Jeth { | ||||||
|  | 	return &Jeth{re, client} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) { | func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id *int64) (response otto.Value) { | ||||||
| 	m := shared.NewRpcErrorResponse(id, shared.JsonRpcVersion, code, fmt.Errorf(msg)) | 	m := rpc.JSONErrResponse{ | ||||||
|  | 		Version: "2.0", | ||||||
|  | 		Id:      id, | ||||||
|  | 		Error: rpc.JSONError{ | ||||||
|  | 			Code:    code, | ||||||
|  | 			Message: msg, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	errObj, _ := json.Marshal(m.Error) | 	errObj, _ := json.Marshal(m.Error) | ||||||
| 	errRes, _ := json.Marshal(m) | 	errRes, _ := json.Marshal(m) | ||||||
| 
 | 
 | ||||||
| @@ -71,7 +72,7 @@ func (self *Jeth) UnlockAccount(call otto.FunctionCall) (response otto.Value) { | |||||||
| 			if account, ok = accountExport.(string); ok { | 			if account, ok = accountExport.(string); ok { | ||||||
| 				if len(call.ArgumentList) == 1 { | 				if len(call.ArgumentList) == 1 { | ||||||
| 					fmt.Printf("Unlock account %s\n", account) | 					fmt.Printf("Unlock account %s\n", account) | ||||||
| 					passwd, err = utils.PromptPassword("Passphrase: ", true) | 					passwd, err = PromptPassword("Passphrase: ", true) | ||||||
| 					if err != nil { | 					if err != nil { | ||||||
| 						return otto.FalseValue() | 						return otto.FalseValue() | ||||||
| 					} | 					} | ||||||
| @@ -102,11 +103,11 @@ func (self *Jeth) UnlockAccount(call otto.FunctionCall) (response otto.Value) { | |||||||
| // NewAccount asks the user for the password and than executes the jeth.newAccount callback in the jsre | // NewAccount asks the user for the password and than executes the jeth.newAccount callback in the jsre | ||||||
| func (self *Jeth) NewAccount(call otto.FunctionCall) (response otto.Value) { | func (self *Jeth) NewAccount(call otto.FunctionCall) (response otto.Value) { | ||||||
| 	if len(call.ArgumentList) == 0 { | 	if len(call.ArgumentList) == 0 { | ||||||
| 		passwd, err := utils.PromptPassword("Passphrase: ", true) | 		passwd, err := PromptPassword("Passphrase: ", true) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return otto.FalseValue() | 			return otto.FalseValue() | ||||||
| 		} | 		} | ||||||
| 		passwd2, err := utils.PromptPassword("Repeat passphrase: ", true) | 		passwd2, err := PromptPassword("Repeat passphrase: ", true) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return otto.FalseValue() | 			return otto.FalseValue() | ||||||
| 		} | 		} | ||||||
| @@ -134,11 +135,11 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	jsonreq, err := json.Marshal(reqif) | 	jsonreq, err := json.Marshal(reqif) | ||||||
| 	var reqs []shared.Request | 	var reqs []rpc.JSONRequest | ||||||
| 	batch := true | 	batch := true | ||||||
| 	err = json.Unmarshal(jsonreq, &reqs) | 	err = json.Unmarshal(jsonreq, &reqs) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		reqs = make([]shared.Request, 1) | 		reqs = make([]rpc.JSONRequest, 1) | ||||||
| 		err = json.Unmarshal(jsonreq, &reqs[0]) | 		err = json.Unmarshal(jsonreq, &reqs[0]) | ||||||
| 		batch = false | 		batch = false | ||||||
| 	} | 	} | ||||||
| @@ -147,42 +148,38 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) { | |||||||
| 	call.Otto.Run("var ret_response = new Array(response_len);") | 	call.Otto.Run("var ret_response = new Array(response_len);") | ||||||
| 
 | 
 | ||||||
| 	for i, req := range reqs { | 	for i, req := range reqs { | ||||||
| 		var respif interface{} |  | ||||||
| 		err := self.client.Send(&req) | 		err := self.client.Send(&req) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return self.err(call, -32603, err.Error(), req.Id) | 			return self.err(call, -32603, err.Error(), req.Id) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	recv: | 		result := make(map[string]interface{}) | ||||||
| 		respif, err = self.client.Recv() | 		err = self.client.Recv(&result) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return self.err(call, -32603, err.Error(), req.Id) | 			return self.err(call, -32603, err.Error(), req.Id) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		agentreq, isRequest := respif.(*shared.Request) | 		_, isSuccessResponse := result["result"] | ||||||
| 		if isRequest { | 		_, isErrorResponse := result["error"] | ||||||
| 			self.handleRequest(agentreq) |  | ||||||
| 			goto recv // receive response after agent interaction |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		sucres, isSuccessResponse := respif.(*shared.SuccessResponse) |  | ||||||
| 		errres, isErrorResponse := respif.(*shared.ErrorResponse) |  | ||||||
| 		if !isSuccessResponse && !isErrorResponse { | 		if !isSuccessResponse && !isErrorResponse { | ||||||
| 			return self.err(call, -32603, fmt.Sprintf("Invalid response type (%T)", respif), req.Id) | 			return self.err(call, -32603, fmt.Sprintf("Invalid response"), new(int64)) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		call.Otto.Set("ret_jsonrpc", shared.JsonRpcVersion) | 		id, _ := result["id"] | ||||||
| 		call.Otto.Set("ret_id", req.Id) | 		call.Otto.Set("ret_id", id) | ||||||
| 
 | 
 | ||||||
| 		var res []byte | 		jsonver, _ := result["jsonrpc"] | ||||||
|  | 		call.Otto.Set("ret_jsonrpc", jsonver) | ||||||
|  | 
 | ||||||
|  | 		var payload []byte | ||||||
| 		if isSuccessResponse { | 		if isSuccessResponse { | ||||||
| 			res, err = json.Marshal(sucres.Result) | 			payload, _ = json.Marshal(result["result"]) | ||||||
| 		} else if isErrorResponse { | 		} else if isErrorResponse { | ||||||
| 			res, err = json.Marshal(errres.Error) | 			payload, _ = json.Marshal(result["error"]) | ||||||
| 		} | 		} | ||||||
| 
 | 		call.Otto.Set("ret_result", string(payload)) | ||||||
| 		call.Otto.Set("ret_result", string(res)) |  | ||||||
| 		call.Otto.Set("response_idx", i) | 		call.Otto.Set("response_idx", i) | ||||||
|  | 
 | ||||||
| 		response, err = call.Otto.Run(` | 		response, err = call.Otto.Run(` | ||||||
| 		ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, result: JSON.parse(ret_result) }; | 		ret_response[response_idx] = { jsonrpc: ret_jsonrpc, id: ret_id, result: JSON.parse(ret_result) }; | ||||||
| 		`) | 		`) | ||||||
| @@ -195,7 +192,7 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) { | |||||||
| 	if call.Argument(1).IsObject() { | 	if call.Argument(1).IsObject() { | ||||||
| 		call.Otto.Set("callback", call.Argument(1)) | 		call.Otto.Set("callback", call.Argument(1)) | ||||||
| 		call.Otto.Run(` | 		call.Otto.Run(` | ||||||
| 	    if (Object.prototype.toString.call(callback) == '[object Function]') { | 		if (Object.prototype.toString.call(callback) == '[object Function]') { | ||||||
| 			callback(null, ret_response); | 			callback(null, ret_response); | ||||||
| 		} | 		} | ||||||
| 		`) | 		`) | ||||||
| @@ -204,6 +201,7 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* | ||||||
| // handleRequest will handle user agent requests by interacting with the user and sending | // handleRequest will handle user agent requests by interacting with the user and sending | ||||||
| // the user response back to the geth service | // the user response back to the geth service | ||||||
| func (self *Jeth) handleRequest(req *shared.Request) bool { | func (self *Jeth) handleRequest(req *shared.Request) bool { | ||||||
| @@ -235,7 +233,7 @@ func (self *Jeth) askPassword(id interface{}, jsonrpc string, args []interface{} | |||||||
| 			return false | 			return false | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	passwd, err = utils.PromptPassword("Passphrase: ", true) | 	passwd, err = PromptPassword("Passphrase: ", true) | ||||||
| 
 | 
 | ||||||
| 	if err = self.client.Send(shared.NewRpcResponse(id, jsonrpc, passwd, err)); err != nil { | 	if err = self.client.Send(shared.NewRpcResponse(id, jsonrpc, passwd, err)); err != nil { | ||||||
| 		glog.V(logger.Info).Infof("Unable to send user agent ask password response - %v\n", err) | 		glog.V(logger.Info).Infof("Unable to send user agent ask password response - %v\n", err) | ||||||
| @@ -248,6 +246,7 @@ func (self *Jeth) confirmTransaction(id interface{}, jsonrpc string, args []inte | |||||||
| 	// Accept all tx which are send from this console | 	// Accept all tx which are send from this console | ||||||
| 	return self.client.Send(shared.NewRpcResponse(id, jsonrpc, true, nil)) == nil | 	return self.client.Send(shared.NewRpcResponse(id, jsonrpc, true, nil)) == nil | ||||||
| } | } | ||||||
|  | */ | ||||||
| 
 | 
 | ||||||
| // throwJSExeception panics on an otto value, the Otto VM will then throw msg as a javascript error. | // throwJSExeception panics on an otto value, the Otto VM will then throw msg as a javascript error. | ||||||
| func throwJSExeception(msg interface{}) otto.Value { | func throwJSExeception(msg interface{}) otto.Value { | ||||||
| @@ -13,6 +13,8 @@ | |||||||
| // | // | ||||||
| // You should have received a copy of the GNU Lesser General Public License | // 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/>. | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | // | ||||||
|  | // +build ignore | ||||||
|  |  | ||||||
| package natspec | package natspec | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,6 +13,8 @@ | |||||||
| // | // | ||||||
| // You should have received a copy of the GNU Lesser General Public License | // 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/>. | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | // | ||||||
|  | // +build ignore | ||||||
|  |  | ||||||
| package natspec | package natspec | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,6 +13,8 @@ | |||||||
| // | // | ||||||
| // You should have received a copy of the GNU Lesser General Public License | // 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/>. | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||||||
|  | // | ||||||
|  | // +build ignore | ||||||
|  |  | ||||||
| package natspec | package natspec | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										265
									
								
								common/registrar/ethreg/api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								common/registrar/ethreg/api.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,265 @@ | |||||||
|  | // 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 ethreg | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"math/big" | ||||||
|  |  | ||||||
|  | 	"github.com/ethereum/go-ethereum/accounts" | ||||||
|  | 	"github.com/ethereum/go-ethereum/common" | ||||||
|  | 	"github.com/ethereum/go-ethereum/common/compiler" | ||||||
|  | 	"github.com/ethereum/go-ethereum/core" | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/state" | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
|  | 	"github.com/ethereum/go-ethereum/crypto" | ||||||
|  | 	"github.com/ethereum/go-ethereum/ethdb" | ||||||
|  | 	"github.com/ethereum/go-ethereum/logger" | ||||||
|  | 	"github.com/ethereum/go-ethereum/logger/glog" | ||||||
|  | 	"github.com/ethereum/go-ethereum/common/registrar" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // registryAPIBackend is a backend for an Ethereum Registry. | ||||||
|  | type registryAPIBackend struct { | ||||||
|  | 	bc      *core.BlockChain | ||||||
|  | 	chainDb ethdb.Database | ||||||
|  | 	txPool  *core.TxPool | ||||||
|  | 	am      *accounts.Manager | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PrivateRegistarAPI offers various functions to access the Ethereum registry. | ||||||
|  | type PrivateRegistarAPI struct { | ||||||
|  | 	be *registryAPIBackend | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance. | ||||||
|  | func NewPrivateRegistarAPI(bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI { | ||||||
|  | 	return &PrivateRegistarAPI{®istryAPIBackend{bc, chainDb, txPool, am}} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetGlobalRegistrar allows clients to set the global registry for the node. | ||||||
|  | // This method can be used to deploy a new registry. First zero out the current | ||||||
|  | // address by calling the method with namereg = '0x0' and then call this method | ||||||
|  | // again with '' as namereg. This will submit a transaction to the network which | ||||||
|  | // will deploy a new registry on execution. The TX hash is returned. When called | ||||||
|  | // with namereg '' and the current address is not zero the current global is | ||||||
|  | // address is returned.. | ||||||
|  | func (api *PrivateRegistarAPI) SetGlobalRegistrar(namereg string, from common.Address) (string, error) { | ||||||
|  | 	return registrar.New(api.be).SetGlobalRegistrar(namereg, from) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetHashReg queries the registry for a hash. | ||||||
|  | func (api *PrivateRegistarAPI) SetHashReg(hashreg string, from common.Address) (string, error) { | ||||||
|  | 	return registrar.New(api.be).SetHashReg(hashreg, from) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetUrlHint queries the registry for an url. | ||||||
|  | func (api *PrivateRegistarAPI) SetUrlHint(hashreg string, from common.Address) (string, error) { | ||||||
|  | 	return registrar.New(api.be).SetUrlHint(hashreg, from) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SaveInfo stores contract information on the local file system. | ||||||
|  | func (api *PrivateRegistarAPI) SaveInfo(info *compiler.ContractInfo, filename string) (contenthash common.Hash, err error) { | ||||||
|  | 	return compiler.SaveInfo(info, filename) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Register registers a new content hash in the registry. | ||||||
|  | func (api *PrivateRegistarAPI) Register(sender common.Address, addr common.Address, contentHashHex string) (bool, error) { | ||||||
|  | 	block := api.be.bc.CurrentBlock() | ||||||
|  | 	state, err := state.New(block.Root(), api.be.chainDb) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	codeb := state.GetCode(addr) | ||||||
|  | 	codeHash := common.BytesToHash(crypto.Sha3(codeb)) | ||||||
|  | 	contentHash := common.HexToHash(contentHashHex) | ||||||
|  |  | ||||||
|  | 	_, err = registrar.New(api.be).SetHashToHash(sender, codeHash, contentHash) | ||||||
|  | 	return err == nil, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // RegisterUrl registers a new url in the registry. | ||||||
|  | func (api *PrivateRegistarAPI) RegisterUrl(sender common.Address, contentHashHex string, url string) (bool, error) { | ||||||
|  | 	_, err := registrar.New(api.be).SetUrlToHash(sender, common.HexToHash(contentHashHex), url) | ||||||
|  | 	return err == nil, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // callmsg is the message type used for call transations. | ||||||
|  | type callmsg struct { | ||||||
|  | 	from          *state.StateObject | ||||||
|  | 	to            *common.Address | ||||||
|  | 	gas, gasPrice *big.Int | ||||||
|  | 	value         *big.Int | ||||||
|  | 	data          []byte | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // accessor boilerplate to implement core.Message | ||||||
|  | func (m callmsg) From() (common.Address, error) { | ||||||
|  | 	return m.from.Address(), nil | ||||||
|  | } | ||||||
|  | func (m callmsg) Nonce() uint64 { | ||||||
|  | 	return m.from.Nonce() | ||||||
|  | } | ||||||
|  | func (m callmsg) To() *common.Address { | ||||||
|  | 	return m.to | ||||||
|  | } | ||||||
|  | func (m callmsg) GasPrice() *big.Int { | ||||||
|  | 	return m.gasPrice | ||||||
|  | } | ||||||
|  | func (m callmsg) Gas() *big.Int { | ||||||
|  | 	return m.gas | ||||||
|  | } | ||||||
|  | func (m callmsg) Value() *big.Int { | ||||||
|  | 	return m.value | ||||||
|  | } | ||||||
|  | func (m callmsg) Data() []byte { | ||||||
|  | 	return m.data | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Call forms a transaction from the given arguments and tries to execute it on | ||||||
|  | // a private VM with a copy of the state. Any changes are therefore only temporary | ||||||
|  | // and not part of the actual state. This allows for local execution/queries. | ||||||
|  | func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, string, error) { | ||||||
|  | 	block := be.bc.CurrentBlock() | ||||||
|  | 	statedb, err := state.New(block.Root(), be.chainDb) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var from *state.StateObject | ||||||
|  | 	if len(fromStr) == 0 { | ||||||
|  | 		accounts, err := be.am.Accounts() | ||||||
|  | 		if err != nil || len(accounts) == 0 { | ||||||
|  | 			from = statedb.GetOrNewStateObject(common.Address{}) | ||||||
|  | 		} else { | ||||||
|  | 			from = statedb.GetOrNewStateObject(accounts[0].Address) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		from = statedb.GetOrNewStateObject(common.HexToAddress(fromStr)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	from.SetBalance(common.MaxBig) | ||||||
|  |  | ||||||
|  | 	msg := callmsg{ | ||||||
|  | 		from:     from, | ||||||
|  | 		gas:      common.Big(gasStr), | ||||||
|  | 		gasPrice: common.Big(gasPriceStr), | ||||||
|  | 		value:    common.Big(valueStr), | ||||||
|  | 		data:     common.FromHex(dataStr), | ||||||
|  | 	} | ||||||
|  | 	if len(toStr) > 0 { | ||||||
|  | 		addr := common.HexToAddress(toStr) | ||||||
|  | 		msg.to = &addr | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if msg.gas.Cmp(big.NewInt(0)) == 0 { | ||||||
|  | 		msg.gas = big.NewInt(50000000) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if msg.gasPrice.Cmp(big.NewInt(0)) == 0 { | ||||||
|  | 		msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	header := be.bc.CurrentBlock().Header() | ||||||
|  | 	vmenv := core.NewEnv(statedb, be.bc, msg, header) | ||||||
|  | 	gp := new(core.GasPool).AddGas(common.MaxBig) | ||||||
|  | 	res, gas, err := core.ApplyMessage(vmenv, msg, gp) | ||||||
|  |  | ||||||
|  | 	return common.ToHex(res), gas.String(), err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StorageAt returns the data stores in the state for the given address and location. | ||||||
|  | func (be *registryAPIBackend) StorageAt(addr string, storageAddr string) string { | ||||||
|  | 	block := be.bc.CurrentBlock() | ||||||
|  | 	state, err := state.New(block.Root(), be.chainDb) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	return state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Transact forms a transaction from the given arguments and submits it to the | ||||||
|  | // transactio pool for execution. | ||||||
|  | func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { | ||||||
|  | 	if len(toStr) > 0 && toStr != "0x" && !common.IsHexAddress(toStr) { | ||||||
|  | 		return "", errors.New("invalid address") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var ( | ||||||
|  | 		from             = common.HexToAddress(fromStr) | ||||||
|  | 		to               = common.HexToAddress(toStr) | ||||||
|  | 		value            = common.Big(valueStr) | ||||||
|  | 		gas              *big.Int | ||||||
|  | 		price            *big.Int | ||||||
|  | 		data             []byte | ||||||
|  | 		contractCreation bool | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	if len(gasStr) == 0 { | ||||||
|  | 		gas = big.NewInt(90000) | ||||||
|  | 	} else { | ||||||
|  | 		gas = common.Big(gasStr) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(gasPriceStr) == 0 { | ||||||
|  | 		price = big.NewInt(10000000000000) | ||||||
|  | 	} else { | ||||||
|  | 		price = common.Big(gasPriceStr) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	data = common.FromHex(codeStr) | ||||||
|  | 	if len(toStr) == 0 { | ||||||
|  | 		contractCreation = true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	nonce := be.txPool.State().GetNonce(from) | ||||||
|  | 	if len(nonceStr) != 0 { | ||||||
|  | 		nonce = common.Big(nonceStr).Uint64() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var tx *types.Transaction | ||||||
|  | 	if contractCreation { | ||||||
|  | 		tx = types.NewContractCreation(nonce, value, gas, price, data) | ||||||
|  | 	} else { | ||||||
|  | 		tx = types.NewTransaction(nonce, to, value, gas, price, data) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	acc := accounts.Account{from} | ||||||
|  | 	signature, err := be.am.Sign(acc, tx.SigHash().Bytes()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	signedTx, err := tx.WithSignature(signature) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	be.txPool.SetLocal(signedTx) | ||||||
|  | 	if err := be.txPool.Add(signedTx); err != nil { | ||||||
|  | 		return "", nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if contractCreation { | ||||||
|  | 		addr := crypto.CreateAddress(from, nonce) | ||||||
|  | 		glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex()) | ||||||
|  | 	} else { | ||||||
|  | 		glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signedTx.Hash().Hex(), tx.To().Hex()) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return signedTx.Hash().Hex(), nil | ||||||
|  | } | ||||||
| @@ -1,48 +0,0 @@ | |||||||
| // 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 ethreg |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"math/big" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/registrar" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // implements a versioned Registrar on an archiving full node |  | ||||||
| type EthReg struct { |  | ||||||
| 	backend  *xeth.XEth |  | ||||||
| 	registry *registrar.Registrar |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func New(xe *xeth.XEth) (self *EthReg) { |  | ||||||
| 	self = &EthReg{backend: xe} |  | ||||||
| 	self.registry = registrar.New(xe) |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *EthReg) Registry() *registrar.Registrar { |  | ||||||
| 	return self.registry |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *EthReg) Resolver(n *big.Int) *registrar.Registrar { |  | ||||||
| 	xe := self.backend |  | ||||||
| 	if n != nil { |  | ||||||
| 		xe = self.backend.AtStateNum(n.Int64()) |  | ||||||
| 	} |  | ||||||
| 	return registrar.New(xe) |  | ||||||
| } |  | ||||||
							
								
								
									
										97
									
								
								eth/api.go
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								eth/api.go
									
									
									
									
									
								
							| @@ -42,8 +42,10 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/event" | 	"github.com/ethereum/go-ethereum/event" | ||||||
| 	"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/miner" | ||||||
|  | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	"github.com/ethereum/go-ethereum/rlp" | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -51,6 +53,19 @@ const ( | |||||||
| 	defaultGas      = uint64(90000) | 	defaultGas      = uint64(90000) | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // blockByNumber is a commonly used helper function which retrieves and returns the block for the given block number. It | ||||||
|  | // returns nil when no block could be found. | ||||||
|  | func blockByNumber(m *miner.Miner, bc *core.BlockChain, blockNr rpc.BlockNumber) *types.Block { | ||||||
|  | 	if blockNr == rpc.PendingBlockNumber { | ||||||
|  | 		return m.PendingBlock() | ||||||
|  | 	} | ||||||
|  | 	if blockNr == rpc.LatestBlockNumber { | ||||||
|  | 		return bc.CurrentBlock() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return bc.GetBlockByNumber(uint64(blockNr)) | ||||||
|  | } | ||||||
|  |  | ||||||
| // PublicEthereumAPI provides an API to access Ethereum related information. | // PublicEthereumAPI provides an API to access Ethereum related information. | ||||||
| // It offers only methods that operate on public data that is freely available to anyone. | // It offers only methods that operate on public data that is freely available to anyone. | ||||||
| type PublicEthereumAPI struct { | type PublicEthereumAPI struct { | ||||||
| @@ -293,11 +308,12 @@ type PublicBlockChainAPI struct { | |||||||
| 	chainDb  ethdb.Database | 	chainDb  ethdb.Database | ||||||
| 	eventMux *event.TypeMux | 	eventMux *event.TypeMux | ||||||
| 	am       *accounts.Manager | 	am       *accounts.Manager | ||||||
|  | 	miner    *miner.Miner | ||||||
| } | } | ||||||
|  |  | ||||||
| // NewPublicBlockChainAPI creates a new Etheruem blockchain API. | // NewPublicBlockChainAPI creates a new Etheruem blockchain API. | ||||||
| func NewPublicBlockChainAPI(bc *core.BlockChain, chainDb ethdb.Database, eventMux *event.TypeMux, am *accounts.Manager) *PublicBlockChainAPI { | func NewPublicBlockChainAPI(bc *core.BlockChain, m *miner.Miner, chainDb ethdb.Database, eventMux *event.TypeMux, am *accounts.Manager) *PublicBlockChainAPI { | ||||||
| 	return &PublicBlockChainAPI{bc: bc, chainDb: chainDb, eventMux: eventMux, am: am} | 	return &PublicBlockChainAPI{bc: bc, miner: m, chainDb: chainDb, eventMux: eventMux, am: am} | ||||||
| } | } | ||||||
|  |  | ||||||
| // BlockNumber returns the block number of the chain head. | // BlockNumber returns the block number of the chain head. | ||||||
| @@ -308,7 +324,7 @@ func (s *PublicBlockChainAPI) BlockNumber() *big.Int { | |||||||
| // GetBalance returns the amount of wei for the given address in the state of the given block number. | // GetBalance returns the amount of wei for the given address in the state of the given block number. | ||||||
| // When block number equals rpc.LatestBlockNumber the current block is used. | // When block number equals rpc.LatestBlockNumber the current block is used. | ||||||
| func (s *PublicBlockChainAPI) GetBalance(address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) { | func (s *PublicBlockChainAPI) GetBalance(address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) { | ||||||
| 	block := blockByNumber(s.bc, blockNr) | 	block := blockByNumber(s.miner, s.bc, blockNr) | ||||||
| 	if block == nil { | 	if block == nil { | ||||||
| 		return nil, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
| @@ -320,20 +336,10 @@ func (s *PublicBlockChainAPI) GetBalance(address common.Address, blockNr rpc.Blo | |||||||
| 	return state.GetBalance(address), nil | 	return state.GetBalance(address), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // blockByNumber is a commonly used helper function which retrieves and returns the block for the given block number. It |  | ||||||
| // returns nil when no block could be found. |  | ||||||
| func blockByNumber(bc *core.BlockChain, blockNr rpc.BlockNumber) *types.Block { |  | ||||||
| 	if blockNr == rpc.LatestBlockNumber { |  | ||||||
| 		return bc.CurrentBlock() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return bc.GetBlockByNumber(uint64(blockNr)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all | // GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all | ||||||
| // transactions in the block are returned in full detail, otherwise only the transaction hash is returned. | // transactions in the block are returned in full detail, otherwise only the transaction hash is returned. | ||||||
| func (s *PublicBlockChainAPI) GetBlockByNumber(blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { | func (s *PublicBlockChainAPI) GetBlockByNumber(blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { | ||||||
| 	if block := blockByNumber(s.bc, blockNr); block != nil { | 	if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { | ||||||
| 		return s.rpcOutputBlock(block, true, fullTx) | 		return s.rpcOutputBlock(block, true, fullTx) | ||||||
| 	} | 	} | ||||||
| 	return nil, nil | 	return nil, nil | ||||||
| @@ -355,7 +361,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(blockNr rpc.BlockNum | |||||||
| 		return nil, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if block := blockByNumber(s.bc, blockNr); block != nil { | 	if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { | ||||||
| 		uncles := block.Uncles() | 		uncles := block.Uncles() | ||||||
| 		if index.Int() < 0 || index.Int() >= len(uncles) { | 		if index.Int() < 0 || index.Int() >= len(uncles) { | ||||||
| 			glog.V(logger.Debug).Infof("uncle block on index %d not found for block #%d", index.Int(), blockNr) | 			glog.V(logger.Debug).Infof("uncle block on index %d not found for block #%d", index.Int(), blockNr) | ||||||
| @@ -388,7 +394,7 @@ func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(blockNr rpc.BlockNumber | |||||||
| 		return rpc.NewHexNumber(0) | 		return rpc.NewHexNumber(0) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if block := blockByNumber(s.bc, blockNr); block != nil { | 	if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { | ||||||
| 		return rpc.NewHexNumber(len(block.Uncles())) | 		return rpc.NewHexNumber(len(block.Uncles())) | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| @@ -433,7 +439,7 @@ func (s *PublicBlockChainAPI) GetCode(address common.Address, blockNr rpc.BlockN | |||||||
|  |  | ||||||
| // GetData returns the data stored at the given address in the state for the given block number. | // GetData returns the data stored at the given address in the state for the given block number. | ||||||
| func (s *PublicBlockChainAPI) GetData(address common.Address, blockNr rpc.BlockNumber) (string, error) { | func (s *PublicBlockChainAPI) GetData(address common.Address, blockNr rpc.BlockNumber) (string, error) { | ||||||
| 	if block := blockByNumber(s.bc, blockNr); block != nil { | 	if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { | ||||||
| 		state, err := state.New(block.Root(), s.chainDb) | 		state, err := state.New(block.Root(), s.chainDb) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return "", err | 			return "", err | ||||||
| @@ -450,7 +456,7 @@ func (s *PublicBlockChainAPI) GetData(address common.Address, blockNr rpc.BlockN | |||||||
|  |  | ||||||
| // GetStorageAt returns the storage from the state at the given address, key and block number. | // GetStorageAt returns the storage from the state at the given address, key and block number. | ||||||
| func (s *PublicBlockChainAPI) GetStorageAt(address common.Address, key string, blockNr rpc.BlockNumber) (string, error) { | func (s *PublicBlockChainAPI) GetStorageAt(address common.Address, key string, blockNr rpc.BlockNumber) (string, error) { | ||||||
| 	if block := blockByNumber(s.bc, blockNr); block != nil { | 	if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { | ||||||
| 		state, err := state.New(block.Root(), s.chainDb) | 		state, err := state.New(block.Root(), s.chainDb) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return "", err | 			return "", err | ||||||
| @@ -490,7 +496,7 @@ type CallArgs struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) { | func (s *PublicBlockChainAPI) doCall(args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) { | ||||||
| 	if block := blockByNumber(s.bc, blockNr); block != nil { | 	if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { | ||||||
| 		stateDb, err := state.New(block.Root(), s.chainDb) | 		stateDb, err := state.New(block.Root(), s.chainDb) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return "0x", nil, err | 			return "0x", nil, err | ||||||
| @@ -684,19 +690,21 @@ type PublicTransactionPoolAPI struct { | |||||||
| 	eventMux *event.TypeMux | 	eventMux *event.TypeMux | ||||||
| 	chainDb  ethdb.Database | 	chainDb  ethdb.Database | ||||||
| 	bc       *core.BlockChain | 	bc       *core.BlockChain | ||||||
|  | 	miner    *miner.Miner | ||||||
| 	am       *accounts.Manager | 	am       *accounts.Manager | ||||||
| 	txPool   *core.TxPool | 	txPool   *core.TxPool | ||||||
| 	txMu     sync.Mutex | 	txMu     sync.Mutex | ||||||
| } | } | ||||||
|  |  | ||||||
| // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. | // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. | ||||||
| func NewPublicTransactionPoolAPI(txPool *core.TxPool, chainDb ethdb.Database, eventMux *event.TypeMux, bc *core.BlockChain, am *accounts.Manager) *PublicTransactionPoolAPI { | func NewPublicTransactionPoolAPI(txPool *core.TxPool, m *miner.Miner, chainDb ethdb.Database, eventMux *event.TypeMux, bc *core.BlockChain, am *accounts.Manager) *PublicTransactionPoolAPI { | ||||||
| 	return &PublicTransactionPoolAPI{ | 	return &PublicTransactionPoolAPI{ | ||||||
| 		eventMux: eventMux, | 		eventMux: eventMux, | ||||||
| 		chainDb:  chainDb, | 		chainDb:  chainDb, | ||||||
| 		bc:       bc, | 		bc:       bc, | ||||||
| 		am:       am, | 		am:       am, | ||||||
| 		txPool:   txPool, | 		txPool:   txPool, | ||||||
|  | 		miner:    m, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -724,7 +732,7 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(blockNr rpc. | |||||||
| 		return rpc.NewHexNumber(0) | 		return rpc.NewHexNumber(0) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if block := blockByNumber(s.bc, blockNr); block != nil { | 	if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { | ||||||
| 		return rpc.NewHexNumber(len(block.Transactions())) | 		return rpc.NewHexNumber(len(block.Transactions())) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -741,7 +749,7 @@ func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(blockHash comm | |||||||
|  |  | ||||||
| // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. | // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. | ||||||
| func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(blockNr rpc.BlockNumber, index rpc.HexNumber) (*RPCTransaction, error) { | func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(blockNr rpc.BlockNumber, index rpc.HexNumber) (*RPCTransaction, error) { | ||||||
| 	if block := blockByNumber(s.bc, blockNr); block != nil { | 	if block := blockByNumber(s.miner, s.bc, blockNr); block != nil { | ||||||
| 		return newRPCTransactionFromBlockIndex(block, index.Int()) | 		return newRPCTransactionFromBlockIndex(block, index.Int()) | ||||||
| 	} | 	} | ||||||
| 	return nil, nil | 	return nil, nil | ||||||
| @@ -757,7 +765,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(blockHash c | |||||||
|  |  | ||||||
| // GetTransactionCount returns the number of transactions the given address has sent for the given block number | // GetTransactionCount returns the number of transactions the given address has sent for the given block number | ||||||
| func (s *PublicTransactionPoolAPI) GetTransactionCount(address common.Address, blockNr rpc.BlockNumber) (*rpc.HexNumber, error) { | func (s *PublicTransactionPoolAPI) GetTransactionCount(address common.Address, blockNr rpc.BlockNumber) (*rpc.HexNumber, error) { | ||||||
| 	block := blockByNumber(s.bc, blockNr) | 	block := blockByNumber(s.miner, s.bc, blockNr) | ||||||
| 	if block == nil { | 	if block == nil { | ||||||
| 		return nil, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
| @@ -1256,6 +1264,16 @@ func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) { | |||||||
| 	return true, nil | 	return true, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { | ||||||
|  | 	for _, b := range bs { | ||||||
|  | 		if !chain.HasBlock(b.Hash()) { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
| // ImportChain imports a blockchain from a local file. | // ImportChain imports a blockchain from a local file. | ||||||
| func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { | func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { | ||||||
| 	// Make sure the can access the file to import | 	// Make sure the can access the file to import | ||||||
| @@ -1284,6 +1302,11 @@ func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { | |||||||
| 		if len(blocks) == 0 { | 		if len(blocks) == 0 { | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if hasAllBlocks(api.eth.BlockChain(), blocks) { | ||||||
|  | 			blocks = blocks[:0] | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
| 		// Import the batch and reset the buffer | 		// Import the batch and reset the buffer | ||||||
| 		if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil { | 		if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil { | ||||||
| 			return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err) | 			return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err) | ||||||
| @@ -1403,3 +1426,29 @@ func (api *PrivateDebugAPI) ProcessBlock(number uint64) (bool, error) { | |||||||
| func (api *PrivateDebugAPI) SetHead(number uint64) { | func (api *PrivateDebugAPI) SetHead(number uint64) { | ||||||
| 	api.eth.BlockChain().SetHead(number) | 	api.eth.BlockChain().SetHead(number) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // PublicNetAPI offers network related RPC methods | ||||||
|  | type PublicNetAPI struct { | ||||||
|  | 	net            *p2p.Server | ||||||
|  | 	networkVersion int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewPublicNetAPI creates a new net api instance. | ||||||
|  | func NewPublicNetAPI(net *p2p.Server, networkVersion int) *PublicNetAPI { | ||||||
|  | 	return &PublicNetAPI{net, networkVersion} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Listening returns an indication if the node is listening for network connections. | ||||||
|  | func (s *PublicNetAPI) Listening() bool { | ||||||
|  | 	return true // always listening | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Peercount returns the number of connected peers | ||||||
|  | func (s *PublicNetAPI) PeerCount() *rpc.HexNumber { | ||||||
|  | 	return rpc.NewHexNumber(s.net.PeerCount()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ProtocolVersion returns the current ethereum protocol version. | ||||||
|  | func (s *PublicNetAPI) Version() string { | ||||||
|  | 	return fmt.Sprintf("%d", s.networkVersion) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -32,6 +32,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/common/compiler" | 	"github.com/ethereum/go-ethereum/common/compiler" | ||||||
| 	"github.com/ethereum/go-ethereum/common/httpclient" | 	"github.com/ethereum/go-ethereum/common/httpclient" | ||||||
|  | 	"github.com/ethereum/go-ethereum/common/registrar/ethreg" | ||||||
| 	"github.com/ethereum/go-ethereum/core" | 	"github.com/ethereum/go-ethereum/core" | ||||||
| 	"github.com/ethereum/go-ethereum/core/types" | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
| 	"github.com/ethereum/go-ethereum/eth/downloader" | 	"github.com/ethereum/go-ethereum/eth/downloader" | ||||||
| @@ -44,7 +45,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	"github.com/ethereum/go-ethereum/rlp" | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -121,14 +122,15 @@ type Ethereum struct { | |||||||
| 	eventMux *event.TypeMux | 	eventMux *event.TypeMux | ||||||
| 	miner    *miner.Miner | 	miner    *miner.Miner | ||||||
|  |  | ||||||
| 	Mining       bool | 	Mining        bool | ||||||
| 	MinerThreads int | 	MinerThreads  int | ||||||
| 	NatSpec      bool | 	NatSpec       bool | ||||||
| 	AutoDAG      bool | 	AutoDAG       bool | ||||||
| 	PowTest      bool | 	PowTest       bool | ||||||
| 	autodagquit  chan bool | 	autodagquit   chan bool | ||||||
| 	etherbase    common.Address | 	etherbase     common.Address | ||||||
| 	netVersionId int | 	netVersionId  int | ||||||
|  | 	netRPCService *PublicNetAPI | ||||||
| } | } | ||||||
|  |  | ||||||
| func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { | func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { | ||||||
| @@ -262,12 +264,12 @@ func (s *Ethereum) APIs() []rpc.API { | |||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPublicBlockChainAPI(s.BlockChain(), s.ChainDb(), s.EventMux(), s.AccountManager()), | 			Service:   NewPublicBlockChainAPI(s.BlockChain(), s.Miner(), s.ChainDb(), s.EventMux(), s.AccountManager()), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPublicTransactionPoolAPI(s.TxPool(), s.ChainDb(), s.EventMux(), s.BlockChain(), s.AccountManager()), | 			Service:   NewPublicTransactionPoolAPI(s.TxPool(), s.Miner(), s.ChainDb(), s.EventMux(), s.BlockChain(), s.AccountManager()), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "eth", | 			Namespace: "eth", | ||||||
| @@ -307,6 +309,15 @@ func (s *Ethereum) APIs() []rpc.API { | |||||||
| 			Namespace: "debug", | 			Namespace: "debug", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPrivateDebugAPI(s), | 			Service:   NewPrivateDebugAPI(s), | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "net", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   s.netRPCService, | ||||||
|  | 			Public:    true, | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "admin", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   ethreg.NewPrivateRegistarAPI(s.BlockChain(), s.ChainDb(), s.TxPool(), s.AccountManager()), | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -356,11 +367,12 @@ func (s *Ethereum) Protocols() []p2p.Protocol { | |||||||
|  |  | ||||||
| // Start implements node.Service, starting all internal goroutines needed by the | // Start implements node.Service, starting all internal goroutines needed by the | ||||||
| // Ethereum protocol implementation. | // Ethereum protocol implementation. | ||||||
| func (s *Ethereum) Start(*p2p.Server) error { | func (s *Ethereum) Start(srvr *p2p.Server) error { | ||||||
| 	if s.AutoDAG { | 	if s.AutoDAG { | ||||||
| 		s.StartAutoDAG() | 		s.StartAutoDAG() | ||||||
| 	} | 	} | ||||||
| 	s.protocolManager.Start() | 	s.protocolManager.Start() | ||||||
|  | 	s.netRPCService = NewPublicNetAPI(srvr, s.NetVersion()) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ | |||||||
| package downloader | package downloader | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // PublicDownloaderAPI provides an API which gives informatoin about the current synchronisation status. | // PublicDownloaderAPI provides an API which gives informatoin about the current synchronisation status. | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/core/vm" | 	"github.com/ethereum/go-ethereum/core/vm" | ||||||
| 	"github.com/ethereum/go-ethereum/ethdb" | 	"github.com/ethereum/go-ethereum/ethdb" | ||||||
| 	"github.com/ethereum/go-ethereum/event" | 	"github.com/ethereum/go-ethereum/event" | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
|   | |||||||
| @@ -5740,7 +5740,9 @@ Property.prototype.extractCallback = function (args) { | |||||||
|  */ |  */ | ||||||
| Property.prototype.attachToObject = function (obj) { | Property.prototype.attachToObject = function (obj) { | ||||||
|     var proto = { |     var proto = { | ||||||
|         get: this.buildGet()  |         //get: this.buildGet() | ||||||
|  |         get: this.buildGet(), | ||||||
|  |         enumerable: true | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     var names = this.name.split('.'); |     var names = this.name.split('.'); | ||||||
|   | |||||||
| @@ -264,4 +264,4 @@ func DecodeObject(ctx context.Context, address common.Address, odr OdrBackend, d | |||||||
| 	obj.balance = ext.Balance | 	obj.balance = ext.Balance | ||||||
| 	obj.codeHash = ext.CodeHash | 	obj.codeHash = ext.CodeHash | ||||||
| 	return obj, nil | 	return obj, nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/logger/glog" | 	"github.com/ethereum/go-ethereum/logger/glog" | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // PublicMinerAPI provides an API to control the miner. | // PublicMinerAPI provides an API to control the miner. | ||||||
|   | |||||||
							
								
								
									
										113
									
								
								node/api.go
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								node/api.go
									
									
									
									
									
								
							| @@ -21,11 +21,15 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/ethereum/go-ethereum/common" | ||||||
|  | 	"github.com/ethereum/go-ethereum/crypto" | ||||||
| 	"github.com/ethereum/go-ethereum/logger/glog" | 	"github.com/ethereum/go-ethereum/logger/glog" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p/discover" | 	"github.com/ethereum/go-ethereum/p2p/discover" | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| 	"github.com/rcrowley/go-metrics" | 	"github.com/rcrowley/go-metrics" | ||||||
|  |  | ||||||
|  | 	"gopkg.in/fatih/set.v0" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // PrivateAdminAPI is the collection of administrative API methods exposed only | // PrivateAdminAPI is the collection of administrative API methods exposed only | ||||||
| @@ -59,27 +63,83 @@ func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) { | |||||||
|  |  | ||||||
| // StartRPC starts the HTTP RPC API server. | // StartRPC starts the HTTP RPC API server. | ||||||
| func (api *PrivateAdminAPI) StartRPC(address string, port int, cors string, apis string) (bool, error) { | func (api *PrivateAdminAPI) StartRPC(address string, port int, cors string, apis string) (bool, error) { | ||||||
| 	/*// Parse the list of API modules to make available | 	var offeredAPIs []rpc.API | ||||||
| 	apis, err := api.ParseApiString(apis, codec.JSON, xeth.New(api.node, nil), api.node) | 	if len(apis) > 0 { | ||||||
| 	if err != nil { | 		namespaces := set.New() | ||||||
| 		return false, err | 		for _, a := range strings.Split(apis, ",") { | ||||||
|  | 			namespaces.Add(strings.TrimSpace(a)) | ||||||
|  | 		} | ||||||
|  | 		for _, api := range api.node.APIs() { | ||||||
|  | 			if namespaces.Has(api.Namespace) { | ||||||
|  | 				offeredAPIs = append(offeredAPIs, api) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} else { // use by default all public API's | ||||||
|  | 		for _, api := range api.node.APIs() { | ||||||
|  | 			if api.Public { | ||||||
|  | 				offeredAPIs = append(offeredAPIs, api) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	// Configure and start the HTTP RPC server |  | ||||||
| 	config := comms.HttpConfig{ | 	if address == "" { | ||||||
| 		ListenAddress: address, | 		address = "127.0.0.1" | ||||||
| 		ListenPort:    port, |  | ||||||
| 		CorsDomain:    cors, |  | ||||||
| 	} | 	} | ||||||
| 	if err := comms.StartHttp(config, self.codec, api.Merge(apis...)); err != nil { | 	if port == 0 { | ||||||
| 		return false, err | 		port = 8545 | ||||||
| 	} | 	} | ||||||
| 	return true, nil*/ |  | ||||||
| 	return false, fmt.Errorf("needs new RPC implementation to resolve circular dependency") | 	corsDomains := strings.Split(cors, " ") | ||||||
|  | 	err := rpc.StartHTTP(address, port, corsDomains, offeredAPIs) | ||||||
|  | 	return err == nil, err | ||||||
| } | } | ||||||
|  |  | ||||||
| // StopRPC terminates an already running HTTP RPC API endpoint. | // StopRPC terminates an already running HTTP RPC API endpoint. | ||||||
| func (api *PrivateAdminAPI) StopRPC() { | func (api *PrivateAdminAPI) StopRPC() (bool, error) { | ||||||
| 	comms.StopHttp() | 	err := rpc.StopHTTP() | ||||||
|  | 	return err == nil, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // StartWS starts the websocket RPC API server. | ||||||
|  | func (api *PrivateAdminAPI) StartWS(address string, port int, cors string, apis string) (bool, error) { | ||||||
|  | 	var offeredAPIs []rpc.API | ||||||
|  | 	if len(apis) > 0 { | ||||||
|  | 		namespaces := set.New() | ||||||
|  | 		for _, a := range strings.Split(apis, ",") { | ||||||
|  | 			namespaces.Add(strings.TrimSpace(a)) | ||||||
|  | 		} | ||||||
|  | 		for _, api := range api.node.APIs() { | ||||||
|  | 			if namespaces.Has(api.Namespace) { | ||||||
|  | 				offeredAPIs = append(offeredAPIs, api) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// use by default all public API's | ||||||
|  | 		for _, api := range api.node.APIs() { | ||||||
|  | 			if api.Public { | ||||||
|  | 				offeredAPIs = append(offeredAPIs, api) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if address == "" { | ||||||
|  | 		address = "127.0.0.1" | ||||||
|  | 	} | ||||||
|  | 	if port == 0 { | ||||||
|  | 		port = 8546 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	corsDomains := strings.Split(cors, " ") | ||||||
|  | 	 | ||||||
|  | 	err := rpc.StartWS(address, port, corsDomains, offeredAPIs) | ||||||
|  | 	return err == nil, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // StopRPC terminates an already running websocket RPC API endpoint. | ||||||
|  | func (api *PrivateAdminAPI) StopWS() (bool, error) { | ||||||
|  | 	err := rpc.StopWS() | ||||||
|  | 	return err == nil, err | ||||||
| } | } | ||||||
|  |  | ||||||
| // PublicAdminAPI is the collection of administrative API methods exposed over | // PublicAdminAPI is the collection of administrative API methods exposed over | ||||||
| @@ -247,3 +307,24 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { | |||||||
| 	}) | 	}) | ||||||
| 	return counters, nil | 	return counters, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // PublicWeb3API offers helper utils | ||||||
|  | type PublicWeb3API struct { | ||||||
|  | 	stack *Node | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewPublicWeb3API creates a new Web3Service instance | ||||||
|  | func NewPublicWeb3API(stack *Node) *PublicWeb3API { | ||||||
|  | 	return &PublicWeb3API{stack} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ClientVersion returns the node name | ||||||
|  | func (s *PublicWeb3API) ClientVersion() string { | ||||||
|  | 	return s.stack.Server().Name | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Sha3 applies the ethereum sha3 implementation on the input. | ||||||
|  | // It assumes the input is hex encoded. | ||||||
|  | func (s *PublicWeb3API) Sha3(input string) string { | ||||||
|  | 	return common.ToHex(crypto.Sha3(common.FromHex(input))) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/event" | 	"github.com/ethereum/go-ethereum/event" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| @@ -290,6 +290,11 @@ func (n *Node) APIs() []rpc.API { | |||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
| 			Service:   NewPublicDebugAPI(n), | 			Service:   NewPublicDebugAPI(n), | ||||||
| 			Public:    true, | 			Public:    true, | ||||||
|  | 		}, { | ||||||
|  | 			Namespace: "web3", | ||||||
|  | 			Version:   "1.0", | ||||||
|  | 			Service:   NewPublicWeb3API(n), | ||||||
|  | 			Public:    true, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	// Inject all the APIs owned by various services | 	// Inject all the APIs owned by various services | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/node" | 	"github.com/ethereum/go-ethereum/node" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p/discover" | 	"github.com/ethereum/go-ethereum/p2p/discover" | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // SampleService is a trivial network service that can be attached to a node for | // SampleService is a trivial network service that can be attached to a node for | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ import ( | |||||||
| 	"github.com/ethereum/go-ethereum/ethdb" | 	"github.com/ethereum/go-ethereum/ethdb" | ||||||
| 	"github.com/ethereum/go-ethereum/event" | 	"github.com/ethereum/go-ethereum/event" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ServiceContext is a collection of service independent options inherited from | // ServiceContext is a collection of service independent options inherited from | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ import ( | |||||||
| 	"reflect" | 	"reflect" | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	rpc "github.com/ethereum/go-ethereum/rpc/v2" | 	"github.com/ethereum/go-ethereum/rpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // NoopService is a trivial implementation of the Service interface. | // NoopService is a trivial implementation of the Service interface. | ||||||
|   | |||||||
							
								
								
									
										465
									
								
								rpc/api/admin.go
									
									
									
									
									
								
							
							
						
						
									
										465
									
								
								rpc/api/admin.go
									
									
									
									
									
								
							| @@ -1,465 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"math/big" |  | ||||||
| 	"os" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/compiler" |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/natspec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/registrar" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core/types" |  | ||||||
| 	"github.com/ethereum/go-ethereum/crypto" |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/node" |  | ||||||
| 	"github.com/ethereum/go-ethereum/p2p/discover" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rlp" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/comms" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/useragent" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	AdminApiversion = "1.0" |  | ||||||
| 	importBatchSize = 2500 |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	AdminMapping = map[string]adminhandler{ |  | ||||||
| 		"admin_addPeer":            (*adminApi).AddPeer, |  | ||||||
| 		"admin_peers":              (*adminApi).Peers, |  | ||||||
| 		"admin_nodeInfo":           (*adminApi).NodeInfo, |  | ||||||
| 		"admin_exportChain":        (*adminApi).ExportChain, |  | ||||||
| 		"admin_importChain":        (*adminApi).ImportChain, |  | ||||||
| 		"admin_setSolc":            (*adminApi).SetSolc, |  | ||||||
| 		"admin_datadir":            (*adminApi).DataDir, |  | ||||||
| 		"admin_startRPC":           (*adminApi).StartRPC, |  | ||||||
| 		"admin_stopRPC":            (*adminApi).StopRPC, |  | ||||||
| 		"admin_setGlobalRegistrar": (*adminApi).SetGlobalRegistrar, |  | ||||||
| 		"admin_setHashReg":         (*adminApi).SetHashReg, |  | ||||||
| 		"admin_setUrlHint":         (*adminApi).SetUrlHint, |  | ||||||
| 		"admin_saveInfo":           (*adminApi).SaveInfo, |  | ||||||
| 		"admin_register":           (*adminApi).Register, |  | ||||||
| 		"admin_registerUrl":        (*adminApi).RegisterUrl, |  | ||||||
| 		"admin_startNatSpec":       (*adminApi).StartNatSpec, |  | ||||||
| 		"admin_stopNatSpec":        (*adminApi).StopNatSpec, |  | ||||||
| 		"admin_getContractInfo":    (*adminApi).GetContractInfo, |  | ||||||
| 		"admin_httpGet":            (*adminApi).HttpGet, |  | ||||||
| 		"admin_sleepBlocks":        (*adminApi).SleepBlocks, |  | ||||||
| 		"admin_sleep":              (*adminApi).Sleep, |  | ||||||
| 		"admin_enableUserAgent":    (*adminApi).EnableUserAgent, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // admin callback handler |  | ||||||
| type adminhandler func(*adminApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // admin api provider |  | ||||||
| type adminApi struct { |  | ||||||
| 	xeth     *xeth.XEth |  | ||||||
| 	stack    *node.Node |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	codec    codec.Codec |  | ||||||
| 	coder    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new admin api instance |  | ||||||
| func NewAdminApi(xeth *xeth.XEth, stack *node.Node, codec codec.Codec) *adminApi { |  | ||||||
| 	api := &adminApi{ |  | ||||||
| 		xeth:  xeth, |  | ||||||
| 		stack: stack, |  | ||||||
| 		codec: codec, |  | ||||||
| 		coder: codec.New(nil), |  | ||||||
| 	} |  | ||||||
| 	if stack != nil { |  | ||||||
| 		stack.Service(&api.ethereum) |  | ||||||
| 	} |  | ||||||
| 	return api |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *adminApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(AdminMapping)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range AdminMapping { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *adminApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := AdminMapping[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, &shared.NotImplementedError{req.Method} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) Name() string { |  | ||||||
| 	return shared.AdminApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) ApiVersion() string { |  | ||||||
| 	return AdminApiversion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(AddPeerArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	node, err := discover.ParseNode(args.Url) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("invalid node URL: %v", err) |  | ||||||
| 	} |  | ||||||
| 	self.stack.Server().AddPeer(node) |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) Peers(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.stack.Server().PeersInfo(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.stack.Server().NodeInfo(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.stack.DataDir(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { |  | ||||||
| 	for _, b := range bs { |  | ||||||
| 		if !chain.HasBlock(b.Hash()) { |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) ImportChain(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(ImportExportChainArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	fh, err := os.Open(args.Filename) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
| 	defer fh.Close() |  | ||||||
| 	stream := rlp.NewStream(fh, 0) |  | ||||||
|  |  | ||||||
| 	// Run actual the import. |  | ||||||
| 	blocks := make(types.Blocks, importBatchSize) |  | ||||||
| 	n := 0 |  | ||||||
| 	for batch := 0; ; batch++ { |  | ||||||
|  |  | ||||||
| 		i := 0 |  | ||||||
| 		for ; i < importBatchSize; i++ { |  | ||||||
| 			var b types.Block |  | ||||||
| 			if err := stream.Decode(&b); err == io.EOF { |  | ||||||
| 				break |  | ||||||
| 			} else if err != nil { |  | ||||||
| 				return false, fmt.Errorf("at block %d: %v", n, err) |  | ||||||
| 			} |  | ||||||
| 			blocks[i] = &b |  | ||||||
| 			n++ |  | ||||||
| 		} |  | ||||||
| 		if i == 0 { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 		// Import the batch. |  | ||||||
| 		if hasAllBlocks(self.ethereum.BlockChain(), blocks[:i]) { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if _, err := self.ethereum.BlockChain().InsertChain(blocks[:i]); err != nil { |  | ||||||
| 			return false, fmt.Errorf("invalid block %d: %v", n, err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) ExportChain(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(ImportExportChainArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	fh, err := os.OpenFile(args.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
| 	defer fh.Close() |  | ||||||
| 	if err := self.ethereum.BlockChain().Export(fh); err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) SetSolc(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SetSolcArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	solc, err := self.xeth.SetSolc(args.Path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return solc.Info(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(StartRPCArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	cfg := comms.HttpConfig{ |  | ||||||
| 		ListenAddress: args.ListenAddress, |  | ||||||
| 		ListenPort:    args.ListenPort, |  | ||||||
| 		CorsDomain:    args.CorsDomain, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.stack) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = comms.StartHttp(cfg, self.codec, Merge(apis...)) |  | ||||||
| 	if err == nil { |  | ||||||
| 		return true, nil |  | ||||||
| 	} |  | ||||||
| 	return false, err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) StopRPC(req *shared.Request) (interface{}, error) { |  | ||||||
| 	comms.StopHttp() |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) SleepBlocks(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SleepBlocksArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	var timer <-chan time.Time |  | ||||||
| 	var height *big.Int |  | ||||||
| 	var err error |  | ||||||
| 	if args.Timeout > 0 { |  | ||||||
| 		timer = time.NewTimer(time.Duration(args.Timeout) * time.Second).C |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	height = new(big.Int).Add(self.xeth.CurrentBlock().Number(), big.NewInt(args.N)) |  | ||||||
| 	height, err = sleepBlocks(self.xeth.UpdateState(), height, timer) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return height.Uint64(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func sleepBlocks(wait chan *big.Int, height *big.Int, timer <-chan time.Time) (newHeight *big.Int, err error) { |  | ||||||
| 	wait <- height |  | ||||||
| 	select { |  | ||||||
| 	case <-timer: |  | ||||||
| 		// if times out make sure the xeth loop does not block |  | ||||||
| 		go func() { |  | ||||||
| 			select { |  | ||||||
| 			case wait <- nil: |  | ||||||
| 			case <-wait: |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
| 		return nil, fmt.Errorf("timeout") |  | ||||||
| 	case newHeight = <-wait: |  | ||||||
| 	} |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) Sleep(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SleepArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	time.Sleep(time.Duration(args.S) * time.Second) |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) SetGlobalRegistrar(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SetGlobalRegistrarArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	sender := common.HexToAddress(args.ContractAddress) |  | ||||||
|  |  | ||||||
| 	reg := registrar.New(self.xeth) |  | ||||||
| 	txhash, err := reg.SetGlobalRegistrar(args.NameReg, sender) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return txhash, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) SetHashReg(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SetHashRegArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	reg := registrar.New(self.xeth) |  | ||||||
| 	sender := common.HexToAddress(args.Sender) |  | ||||||
| 	txhash, err := reg.SetHashReg(args.HashReg, sender) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return txhash, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) SetUrlHint(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SetUrlHintArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	urlHint := args.UrlHint |  | ||||||
| 	sender := common.HexToAddress(args.Sender) |  | ||||||
|  |  | ||||||
| 	reg := registrar.New(self.xeth) |  | ||||||
| 	txhash, err := reg.SetUrlHint(urlHint, sender) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return txhash, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) SaveInfo(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SaveInfoArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	contenthash, err := compiler.SaveInfo(&args.ContractInfo, args.Filename) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return contenthash.Hex(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) Register(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(RegisterArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	sender := common.HexToAddress(args.Sender) |  | ||||||
| 	// sender and contract address are passed as hex strings |  | ||||||
| 	codeb := self.xeth.CodeAtBytes(args.Address) |  | ||||||
| 	codeHash := common.BytesToHash(crypto.Sha3(codeb)) |  | ||||||
| 	contentHash := common.HexToHash(args.ContentHashHex) |  | ||||||
| 	registry := registrar.New(self.xeth) |  | ||||||
|  |  | ||||||
| 	_, err := registry.SetHashToHash(sender, codeHash, contentHash) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) RegisterUrl(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(RegisterUrlArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	sender := common.HexToAddress(args.Sender) |  | ||||||
| 	registry := registrar.New(self.xeth) |  | ||||||
| 	_, err := registry.SetUrlToHash(sender, common.HexToHash(args.ContentHash), args.Url) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) StartNatSpec(req *shared.Request) (interface{}, error) { |  | ||||||
| 	self.ethereum.NatSpec = true |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) StopNatSpec(req *shared.Request) (interface{}, error) { |  | ||||||
| 	self.ethereum.NatSpec = false |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) GetContractInfo(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GetContractInfoArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	infoDoc, err := natspec.FetchDocsForContract(args.Contract, self.xeth, self.ethereum.HTTPClient()) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var info interface{} |  | ||||||
| 	err = self.coder.Decode(infoDoc, &info) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return info, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) HttpGet(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(HttpGetArgs) |  | ||||||
| 	if err := self.coder.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	resp, err := self.ethereum.HTTPClient().Get(args.Uri, args.Path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return string(resp), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *adminApi) EnableUserAgent(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if fe, ok := self.xeth.Frontend().(*useragent.RemoteFrontend); ok { |  | ||||||
| 		fe.Enable() |  | ||||||
| 	} |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
| @@ -1,468 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/compiler" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type AddPeerArgs struct { |  | ||||||
| 	Url string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *AddPeerArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) != 1 { |  | ||||||
| 		return shared.NewDecodeParamError("Expected enode as argument") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	urlstr, ok := obj[0].(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("url", "not a string") |  | ||||||
| 	} |  | ||||||
| 	args.Url = urlstr |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type ImportExportChainArgs struct { |  | ||||||
| 	Filename string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *ImportExportChainArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) != 1 { |  | ||||||
| 		return shared.NewDecodeParamError("Expected filename as argument") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	filename, ok := obj[0].(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("filename", "not a string") |  | ||||||
| 	} |  | ||||||
| 	args.Filename = filename |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SetSolcArgs struct { |  | ||||||
| 	Path string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SetSolcArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) != 1 { |  | ||||||
| 		return shared.NewDecodeParamError("Expected path as argument") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if pathstr, ok := obj[0].(string); ok { |  | ||||||
| 		args.Path = pathstr |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return shared.NewInvalidTypeError("path", "not a string") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type StartRPCArgs struct { |  | ||||||
| 	ListenAddress string |  | ||||||
| 	ListenPort    uint |  | ||||||
| 	CorsDomain    string |  | ||||||
| 	Apis          string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *StartRPCArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	args.ListenAddress = "127.0.0.1" |  | ||||||
| 	args.ListenPort = 8545 |  | ||||||
| 	args.Apis = "net,eth,web3" |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 && obj[0] != nil { |  | ||||||
| 		if addr, ok := obj[0].(string); ok { |  | ||||||
| 			args.ListenAddress = addr |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("listenAddress", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 && obj[1] != nil { |  | ||||||
| 		if port, ok := obj[1].(float64); ok && port >= 0 && port <= 64*1024 { |  | ||||||
| 			args.ListenPort = uint(port) |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("listenPort", "not a valid port number") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 3 && obj[2] != nil { |  | ||||||
| 		if corsDomain, ok := obj[2].(string); ok { |  | ||||||
| 			args.CorsDomain = corsDomain |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("corsDomain", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 4 && obj[3] != nil { |  | ||||||
| 		if apis, ok := obj[3].(string); ok { |  | ||||||
| 			args.Apis = apis |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("apis", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SleepArgs struct { |  | ||||||
| 	S int |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SleepArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
|  |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	if len(obj) >= 1 { |  | ||||||
| 		if obj[0] != nil { |  | ||||||
| 			if n, err := numString(obj[0]); err == nil { |  | ||||||
| 				args.S = int(n.Int64()) |  | ||||||
| 			} else { |  | ||||||
| 				return shared.NewInvalidTypeError("N", "not an integer: "+err.Error()) |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInsufficientParamsError(0, 1) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SleepBlocksArgs struct { |  | ||||||
| 	N       int64 |  | ||||||
| 	Timeout int64 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SleepBlocksArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
|  |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	args.N = 1 |  | ||||||
| 	args.Timeout = 0 |  | ||||||
| 	if len(obj) >= 1 && obj[0] != nil { |  | ||||||
| 		if n, err := numString(obj[0]); err == nil { |  | ||||||
| 			args.N = n.Int64() |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("N", "not an integer: "+err.Error()) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 && obj[1] != nil { |  | ||||||
| 		if n, err := numString(obj[1]); err == nil { |  | ||||||
| 			args.Timeout = n.Int64() |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Timeout", "not an integer: "+err.Error()) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SetGlobalRegistrarArgs struct { |  | ||||||
| 	NameReg         string |  | ||||||
| 	ContractAddress string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SetGlobalRegistrarArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) == 0 { |  | ||||||
| 		return shared.NewDecodeParamError("Expected namereg address") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 { |  | ||||||
| 		if namereg, ok := obj[0].(string); ok { |  | ||||||
| 			args.NameReg = namereg |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("NameReg", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 && obj[1] != nil { |  | ||||||
| 		if addr, ok := obj[1].(string); ok { |  | ||||||
| 			args.ContractAddress = addr |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("ContractAddress", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SetHashRegArgs struct { |  | ||||||
| 	HashReg string |  | ||||||
| 	Sender  string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SetHashRegArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 && obj[0] != nil { |  | ||||||
| 		if hashreg, ok := obj[0].(string); ok { |  | ||||||
| 			args.HashReg = hashreg |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("HashReg", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 && obj[1] != nil { |  | ||||||
| 		if sender, ok := obj[1].(string); ok { |  | ||||||
| 			args.Sender = sender |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Sender", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SetUrlHintArgs struct { |  | ||||||
| 	UrlHint string |  | ||||||
| 	Sender  string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SetUrlHintArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 && obj[0] != nil { |  | ||||||
| 		if urlhint, ok := obj[0].(string); ok { |  | ||||||
| 			args.UrlHint = urlhint |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("UrlHint", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 && obj[1] != nil { |  | ||||||
| 		if sender, ok := obj[1].(string); ok { |  | ||||||
| 			args.Sender = sender |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Sender", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SaveInfoArgs struct { |  | ||||||
| 	ContractInfo compiler.ContractInfo |  | ||||||
| 	Filename     string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SaveInfoArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 2 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 2) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if jsonraw, err := json.Marshal(obj[0]); err == nil { |  | ||||||
| 		if err = json.Unmarshal(jsonraw, &args.ContractInfo); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if filename, ok := obj[1].(string); ok { |  | ||||||
| 		args.Filename = filename |  | ||||||
| 	} else { |  | ||||||
| 		return shared.NewInvalidTypeError("Filename", "not a string") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type RegisterArgs struct { |  | ||||||
| 	Sender         string |  | ||||||
| 	Address        string |  | ||||||
| 	ContentHashHex string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *RegisterArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 3 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 3) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 { |  | ||||||
| 		if sender, ok := obj[0].(string); ok { |  | ||||||
| 			args.Sender = sender |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Sender", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 { |  | ||||||
| 		if address, ok := obj[1].(string); ok { |  | ||||||
| 			args.Address = address |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Address", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 3 { |  | ||||||
| 		if hex, ok := obj[2].(string); ok { |  | ||||||
| 			args.ContentHashHex = hex |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("ContentHashHex", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type RegisterUrlArgs struct { |  | ||||||
| 	Sender      string |  | ||||||
| 	ContentHash string |  | ||||||
| 	Url         string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *RegisterUrlArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 { |  | ||||||
| 		if sender, ok := obj[0].(string); ok { |  | ||||||
| 			args.Sender = sender |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Sender", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 { |  | ||||||
| 		if sender, ok := obj[1].(string); ok { |  | ||||||
| 			args.ContentHash = sender |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("ContentHash", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 3 { |  | ||||||
| 		if sender, ok := obj[2].(string); ok { |  | ||||||
| 			args.Url = sender |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Url", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type GetContractInfoArgs struct { |  | ||||||
| 	Contract string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *GetContractInfoArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 { |  | ||||||
| 		if contract, ok := obj[0].(string); ok { |  | ||||||
| 			args.Contract = contract |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Contract", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type HttpGetArgs struct { |  | ||||||
| 	Uri  string |  | ||||||
| 	Path string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *HttpGetArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 { |  | ||||||
| 		if uri, ok := obj[0].(string); ok { |  | ||||||
| 			args.Uri = uri |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Uri", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 && obj[1] != nil { |  | ||||||
| 		if path, ok := obj[1].(string); ok { |  | ||||||
| 			args.Path = path |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("Path", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,143 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| const Admin_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'admin', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'addPeer', |  | ||||||
| 			call: 'admin_addPeer', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'exportChain', |  | ||||||
| 			call: 'admin_exportChain', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'importChain', |  | ||||||
| 			call: 'admin_importChain', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'sleepBlocks', |  | ||||||
| 			call: 'admin_sleepBlocks', |  | ||||||
| 			params: 2, |  | ||||||
| 			inputFormatter: [null, null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'setSolc', |  | ||||||
| 			call: 'admin_setSolc', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'startRPC', |  | ||||||
| 			call: 'admin_startRPC', |  | ||||||
| 			params: 4, |  | ||||||
| 			inputFormatter: [null, null, null, null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'stopRPC', |  | ||||||
| 			call: 'admin_stopRPC', |  | ||||||
| 			params: 0, |  | ||||||
| 			inputFormatter: [] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'setGlobalRegistrar', |  | ||||||
| 			call: 'admin_setGlobalRegistrar', |  | ||||||
| 			params: 2, |  | ||||||
| 			inputFormatter: [null,null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'setHashReg', |  | ||||||
| 			call: 'admin_setHashReg', |  | ||||||
| 			params: 2, |  | ||||||
| 			inputFormatter: [null,null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'setUrlHint', |  | ||||||
| 			call: 'admin_setUrlHint', |  | ||||||
| 			params: 2, |  | ||||||
| 			inputFormatter: [null,null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'saveInfo', |  | ||||||
| 			call: 'admin_saveInfo', |  | ||||||
| 			params: 2, |  | ||||||
| 			inputFormatter: [null,null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'register', |  | ||||||
| 			call: 'admin_register', |  | ||||||
| 			params: 3, |  | ||||||
| 			inputFormatter: [null,null,null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'registerUrl', |  | ||||||
| 			call: 'admin_registerUrl', |  | ||||||
| 			params: 3, |  | ||||||
| 			inputFormatter: [null,null,null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'startNatSpec', |  | ||||||
| 			call: 'admin_startNatSpec', |  | ||||||
| 			params: 0, |  | ||||||
| 			inputFormatter: [] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'stopNatSpec', |  | ||||||
| 			call: 'admin_stopNatSpec', |  | ||||||
| 			params: 0, |  | ||||||
| 			inputFormatter: [] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'getContractInfo', |  | ||||||
| 			call: 'admin_getContractInfo', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null], |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'httpGet', |  | ||||||
| 			call: 'admin_httpGet', |  | ||||||
| 			params: 2, |  | ||||||
| 			inputFormatter: [null, null] |  | ||||||
| 		}) |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'nodeInfo', |  | ||||||
| 			getter: 'admin_nodeInfo' |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'peers', |  | ||||||
| 			getter: 'admin_peers' |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'datadir', |  | ||||||
| 			getter: 'admin_datadir' |  | ||||||
| 		}) |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Merge multiple API's to a single API instance |  | ||||||
| func Merge(apis ...shared.EthereumApi) shared.EthereumApi { |  | ||||||
| 	return newMergedApi(apis...) |  | ||||||
| } |  | ||||||
| @@ -1,170 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"testing" |  | ||||||
|  |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"strconv" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/compiler" |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestParseApiString(t *testing.T) { |  | ||||||
| 	apis, err := ParseApiString("", codec.JSON, nil, nil) |  | ||||||
| 	if err == nil { |  | ||||||
| 		t.Errorf("Expected an err from parsing empty API string but got nil") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(apis) != 0 { |  | ||||||
| 		t.Errorf("Expected 0 apis from empty API string") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	apis, err = ParseApiString("eth", codec.JSON, nil, nil) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("Expected nil err from parsing empty API string but got %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(apis) != 1 { |  | ||||||
| 		t.Errorf("Expected 1 apis but got %d - %v", apis, apis) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	apis, err = ParseApiString("eth,eth", codec.JSON, nil, nil) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("Expected nil err from parsing empty API string but got \"%v\"", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(apis) != 2 { |  | ||||||
| 		t.Errorf("Expected 2 apis but got %d - %v", apis, apis) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	apis, err = ParseApiString("eth,invalid", codec.JSON, nil, nil) |  | ||||||
| 	if err == nil { |  | ||||||
| 		t.Errorf("Expected an err but got no err") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const solcVersion = "0.9.23" |  | ||||||
|  |  | ||||||
| func TestCompileSolidity(t *testing.T) { |  | ||||||
|  |  | ||||||
| 	solc, err := compiler.New("") |  | ||||||
| 	if solc == nil { |  | ||||||
| 		t.Skip("no solc found: skip") |  | ||||||
| 	} else if solc.Version() != solcVersion { |  | ||||||
| 		t.Skip("WARNING: skipping test because of solc different version (%v, test written for %v, may need to update)", solc.Version(), solcVersion) |  | ||||||
| 	} |  | ||||||
| 	source := `contract test {\n` + |  | ||||||
| 		"   /// @notice Will multiply `a` by 7." + `\n` + |  | ||||||
| 		`   function multiply(uint a) returns(uint d) {\n` + |  | ||||||
| 		`       return a * 7;\n` + |  | ||||||
| 		`   }\n` + |  | ||||||
| 		`}\n` |  | ||||||
|  |  | ||||||
| 	jsonstr := `{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["` + source + `"],"id":64}` |  | ||||||
|  |  | ||||||
| 	expCode := "0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056" |  | ||||||
| 	expAbiDefinition := `[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]` |  | ||||||
| 	expUserDoc := `{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}}` |  | ||||||
| 	expDeveloperDoc := `{"methods":{}}` |  | ||||||
| 	expCompilerVersion := solc.Version() |  | ||||||
| 	expLanguage := "Solidity" |  | ||||||
| 	expLanguageVersion := "0" |  | ||||||
| 	expSource := source |  | ||||||
|  |  | ||||||
| 	eth := ð.Ethereum{} |  | ||||||
| 	xeth := xeth.NewTest(nil, nil) |  | ||||||
| 	api := NewEthApi(xeth, eth, codec.JSON) |  | ||||||
|  |  | ||||||
| 	var rpcRequest shared.Request |  | ||||||
| 	json.Unmarshal([]byte(jsonstr), &rpcRequest) |  | ||||||
|  |  | ||||||
| 	response, err := api.CompileSolidity(&rpcRequest) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("Execution failed, %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	respjson, err := json.Marshal(response) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("expected no error, got %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var contracts = make(map[string]*compiler.Contract) |  | ||||||
| 	err = json.Unmarshal(respjson, &contracts) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("expected no error, got %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(contracts) != 1 { |  | ||||||
| 		t.Errorf("expected one contract, got %v", len(contracts)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	contract := contracts["test"] |  | ||||||
|  |  | ||||||
| 	if contract.Code != expCode { |  | ||||||
| 		t.Errorf("Expected \n%s got \n%s", expCode, contract.Code) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if strconv.Quote(contract.Info.Source) != `"`+expSource+`"` { |  | ||||||
| 		t.Errorf("Expected \n'%s' got \n'%s'", expSource, strconv.Quote(contract.Info.Source)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if contract.Info.Language != expLanguage { |  | ||||||
| 		t.Errorf("Expected %s got %s", expLanguage, contract.Info.Language) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if contract.Info.LanguageVersion != expLanguageVersion { |  | ||||||
| 		t.Errorf("Expected %s got %s", expLanguageVersion, contract.Info.LanguageVersion) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if contract.Info.CompilerVersion != expCompilerVersion { |  | ||||||
| 		t.Errorf("Expected %s got %s", expCompilerVersion, contract.Info.CompilerVersion) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	userdoc, err := json.Marshal(contract.Info.UserDoc) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("expected no error, got %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	devdoc, err := json.Marshal(contract.Info.DeveloperDoc) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("expected no error, got %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	abidef, err := json.Marshal(contract.Info.AbiDefinition) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("expected no error, got %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if string(abidef) != expAbiDefinition { |  | ||||||
| 		t.Errorf("Expected \n'%s' got \n'%s'", expAbiDefinition, string(abidef)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if string(userdoc) != expUserDoc { |  | ||||||
| 		t.Errorf("Expected \n'%s' got \n'%s'", expUserDoc, string(userdoc)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if string(devdoc) != expDeveloperDoc { |  | ||||||
| 		t.Errorf("Expected %s got %s", expDeveloperDoc, string(devdoc)) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,74 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type CompileArgs struct { |  | ||||||
| 	Source string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *CompileArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
| 	argstr, ok := obj[0].(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("arg0", "is not a string") |  | ||||||
| 	} |  | ||||||
| 	args.Source = argstr |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type FilterStringArgs struct { |  | ||||||
| 	Word string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var argstr string |  | ||||||
| 	argstr, ok := obj[0].(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("filter", "not a string") |  | ||||||
| 	} |  | ||||||
| 	switch argstr { |  | ||||||
| 	case "latest", "pending": |  | ||||||
| 		break |  | ||||||
| 	default: |  | ||||||
| 		return shared.NewValidationError("Word", "Must be `latest` or `pending`") |  | ||||||
| 	} |  | ||||||
| 	args.Word = argstr |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
							
								
								
									
										2649
									
								
								rpc/api/args_test.go
									
									
									
									
									
								
							
							
						
						
									
										2649
									
								
								rpc/api/args_test.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										144
									
								
								rpc/api/db.go
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								rpc/api/db.go
									
									
									
									
									
								
							| @@ -1,144 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	DbApiversion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	DbMapping = map[string]dbhandler{ |  | ||||||
| 		"db_getString": (*dbApi).GetString, |  | ||||||
| 		"db_putString": (*dbApi).PutString, |  | ||||||
| 		"db_getHex":    (*dbApi).GetHex, |  | ||||||
| 		"db_putHex":    (*dbApi).PutHex, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // db callback handler |  | ||||||
| type dbhandler func(*dbApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // db api provider |  | ||||||
| type dbApi struct { |  | ||||||
| 	xeth     *xeth.XEth |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	methods  map[string]dbhandler |  | ||||||
| 	codec    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new db api instance |  | ||||||
| func NewDbApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *dbApi { |  | ||||||
| 	return &dbApi{ |  | ||||||
| 		xeth:     xeth, |  | ||||||
| 		ethereum: ethereum, |  | ||||||
| 		methods:  DbMapping, |  | ||||||
| 		codec:    coder.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *dbApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *dbApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, &shared.NotImplementedError{req.Method} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *dbApi) Name() string { |  | ||||||
| 	return shared.DbApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *dbApi) ApiVersion() string { |  | ||||||
| 	return DbApiversion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *dbApi) GetString(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(DbArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := args.requirements(); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ret, err := self.xeth.DbGet([]byte(args.Database + args.Key)) |  | ||||||
| 	return string(ret), err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *dbApi) PutString(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(DbArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := args.requirements(); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return self.xeth.DbPut([]byte(args.Database+args.Key), args.Value), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *dbApi) GetHex(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(DbHexArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := args.requirements(); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if res, err := self.xeth.DbGet([]byte(args.Database + args.Key)); err == nil { |  | ||||||
| 		return newHexData(res), nil |  | ||||||
| 	} else { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *dbApi) PutHex(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(DbHexArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := args.requirements(); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return self.xeth.DbPut([]byte(args.Database+args.Key), args.Value), nil |  | ||||||
| } |  | ||||||
| @@ -1,126 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type DbArgs struct { |  | ||||||
| 	Database string |  | ||||||
| 	Key      string |  | ||||||
| 	Value    []byte |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *DbArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 2 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 2) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var objstr string |  | ||||||
| 	var ok bool |  | ||||||
|  |  | ||||||
| 	if objstr, ok = obj[0].(string); !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("database", "not a string") |  | ||||||
| 	} |  | ||||||
| 	args.Database = objstr |  | ||||||
|  |  | ||||||
| 	if objstr, ok = obj[1].(string); !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("key", "not a string") |  | ||||||
| 	} |  | ||||||
| 	args.Key = objstr |  | ||||||
|  |  | ||||||
| 	if len(obj) > 2 { |  | ||||||
| 		objstr, ok = obj[2].(string) |  | ||||||
| 		if !ok { |  | ||||||
| 			return shared.NewInvalidTypeError("value", "not a string") |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		args.Value = []byte(objstr) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (a *DbArgs) requirements() error { |  | ||||||
| 	if len(a.Database) == 0 { |  | ||||||
| 		return shared.NewValidationError("Database", "cannot be blank") |  | ||||||
| 	} |  | ||||||
| 	if len(a.Key) == 0 { |  | ||||||
| 		return shared.NewValidationError("Key", "cannot be blank") |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type DbHexArgs struct { |  | ||||||
| 	Database string |  | ||||||
| 	Key      string |  | ||||||
| 	Value    []byte |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *DbHexArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 2 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 2) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var objstr string |  | ||||||
| 	var ok bool |  | ||||||
|  |  | ||||||
| 	if objstr, ok = obj[0].(string); !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("database", "not a string") |  | ||||||
| 	} |  | ||||||
| 	args.Database = objstr |  | ||||||
|  |  | ||||||
| 	if objstr, ok = obj[1].(string); !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("key", "not a string") |  | ||||||
| 	} |  | ||||||
| 	args.Key = objstr |  | ||||||
|  |  | ||||||
| 	if len(obj) > 2 { |  | ||||||
| 		objstr, ok = obj[2].(string) |  | ||||||
| 		if !ok { |  | ||||||
| 			return shared.NewInvalidTypeError("value", "not a string") |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		args.Value = common.FromHex(objstr) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (a *DbHexArgs) requirements() error { |  | ||||||
| 	if len(a.Database) == 0 { |  | ||||||
| 		return shared.NewValidationError("Database", "cannot be blank") |  | ||||||
| 	} |  | ||||||
| 	if len(a.Key) == 0 { |  | ||||||
| 		return shared.NewValidationError("Key", "cannot be blank") |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,29 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| const Db_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'db', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
							
								
								
									
										303
									
								
								rpc/api/debug.go
									
									
									
									
									
								
							
							
						
						
									
										303
									
								
								rpc/api/debug.go
									
									
									
									
									
								
							| @@ -1,303 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"strings" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/ethash" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core/state" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core/vm" |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rlp" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| 	"github.com/rcrowley/go-metrics" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	DebugApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	DebugMapping = map[string]debughandler{ |  | ||||||
| 		"debug_dumpBlock":    (*debugApi).DumpBlock, |  | ||||||
| 		"debug_getBlockRlp":  (*debugApi).GetBlockRlp, |  | ||||||
| 		"debug_printBlock":   (*debugApi).PrintBlock, |  | ||||||
| 		"debug_processBlock": (*debugApi).ProcessBlock, |  | ||||||
| 		"debug_seedHash":     (*debugApi).SeedHash, |  | ||||||
| 		"debug_setHead":      (*debugApi).SetHead, |  | ||||||
| 		"debug_metrics":      (*debugApi).Metrics, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // debug callback handler |  | ||||||
| type debughandler func(*debugApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // admin api provider |  | ||||||
| type debugApi struct { |  | ||||||
| 	xeth     *xeth.XEth |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	methods  map[string]debughandler |  | ||||||
| 	codec    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new debug api instance |  | ||||||
| func NewDebugApi(xeth *xeth.XEth, ethereum *eth.Ethereum, coder codec.Codec) *debugApi { |  | ||||||
| 	return &debugApi{ |  | ||||||
| 		xeth:     xeth, |  | ||||||
| 		ethereum: ethereum, |  | ||||||
| 		methods:  DebugMapping, |  | ||||||
| 		codec:    coder.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *debugApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *debugApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, &shared.NotImplementedError{req.Method} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) Name() string { |  | ||||||
| 	return shared.DebugApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) ApiVersion() string { |  | ||||||
| 	return DebugApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) PrintBlock(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumArg) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	block := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	return fmt.Sprintf("%s", block), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) DumpBlock(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumArg) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	block := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, fmt.Errorf("block #%d not found", args.BlockNumber) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	stateDb, err := state.New(block.Root(), self.ethereum.ChainDb()) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return stateDb.RawDump(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) GetBlockRlp(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumArg) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	block := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, fmt.Errorf("block #%d not found", args.BlockNumber) |  | ||||||
| 	} |  | ||||||
| 	encoded, err := rlp.EncodeToBytes(block) |  | ||||||
| 	return fmt.Sprintf("%x", encoded), err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) SetHead(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumArg) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	self.ethereum.BlockChain().SetHead(uint64(args.BlockNumber)) |  | ||||||
|  |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) ProcessBlock(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumArg) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	block := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, fmt.Errorf("block #%d not found", args.BlockNumber) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	old := vm.Debug |  | ||||||
| 	defer func() { vm.Debug = old }() |  | ||||||
| 	vm.Debug = true |  | ||||||
|  |  | ||||||
| 	var ( |  | ||||||
| 		blockchain = self.ethereum.BlockChain() |  | ||||||
| 		validator  = blockchain.Validator() |  | ||||||
| 		processor  = blockchain.Processor() |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	err := core.ValidateHeader(blockchain.AuxValidator(), block.Header(), blockchain.GetHeader(block.ParentHash()), true, false) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
| 	statedb, err := state.New(blockchain.GetBlock(block.ParentHash()).Root(), self.ethereum.ChainDb()) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
| 	receipts, _, usedGas, err := processor.Process(block, statedb) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
| 	err = validator.ValidateState(block, blockchain.GetBlock(block.ParentHash()), statedb, receipts, usedGas) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) SeedHash(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumArg) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if hash, err := ethash.GetSeedHash(uint64(args.BlockNumber)); err == nil { |  | ||||||
| 		return fmt.Sprintf("0x%x", hash), nil |  | ||||||
| 	} else { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *debugApi) Metrics(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(MetricsArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	// Create a rate formatter |  | ||||||
| 	units := []string{"", "K", "M", "G", "T", "E", "P"} |  | ||||||
| 	round := func(value float64, prec int) string { |  | ||||||
| 		unit := 0 |  | ||||||
| 		for value >= 1000 { |  | ||||||
| 			unit, value, prec = unit+1, value/1000, 2 |  | ||||||
| 		} |  | ||||||
| 		return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value) |  | ||||||
| 	} |  | ||||||
| 	format := func(total float64, rate float64) string { |  | ||||||
| 		return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2)) |  | ||||||
| 	} |  | ||||||
| 	// Iterate over all the metrics, and just dump for now |  | ||||||
| 	counters := make(map[string]interface{}) |  | ||||||
| 	metrics.DefaultRegistry.Each(func(name string, metric interface{}) { |  | ||||||
| 		// Create or retrieve the counter hierarchy for this metric |  | ||||||
| 		root, parts := counters, strings.Split(name, "/") |  | ||||||
| 		for _, part := range parts[:len(parts)-1] { |  | ||||||
| 			if _, ok := root[part]; !ok { |  | ||||||
| 				root[part] = make(map[string]interface{}) |  | ||||||
| 			} |  | ||||||
| 			root = root[part].(map[string]interface{}) |  | ||||||
| 		} |  | ||||||
| 		name = parts[len(parts)-1] |  | ||||||
|  |  | ||||||
| 		// Fill the counter with the metric details, formatting if requested |  | ||||||
| 		if args.Raw { |  | ||||||
| 			switch metric := metric.(type) { |  | ||||||
| 			case metrics.Meter: |  | ||||||
| 				root[name] = map[string]interface{}{ |  | ||||||
| 					"AvgRate01Min": metric.Rate1(), |  | ||||||
| 					"AvgRate05Min": metric.Rate5(), |  | ||||||
| 					"AvgRate15Min": metric.Rate15(), |  | ||||||
| 					"MeanRate":     metric.RateMean(), |  | ||||||
| 					"Overall":      float64(metric.Count()), |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 			case metrics.Timer: |  | ||||||
| 				root[name] = map[string]interface{}{ |  | ||||||
| 					"AvgRate01Min": metric.Rate1(), |  | ||||||
| 					"AvgRate05Min": metric.Rate5(), |  | ||||||
| 					"AvgRate15Min": metric.Rate15(), |  | ||||||
| 					"MeanRate":     metric.RateMean(), |  | ||||||
| 					"Overall":      float64(metric.Count()), |  | ||||||
| 					"Percentiles": map[string]interface{}{ |  | ||||||
| 						"5":  metric.Percentile(0.05), |  | ||||||
| 						"20": metric.Percentile(0.2), |  | ||||||
| 						"50": metric.Percentile(0.5), |  | ||||||
| 						"80": metric.Percentile(0.8), |  | ||||||
| 						"95": metric.Percentile(0.95), |  | ||||||
| 					}, |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 			default: |  | ||||||
| 				root[name] = "Unknown metric type" |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			switch metric := metric.(type) { |  | ||||||
| 			case metrics.Meter: |  | ||||||
| 				root[name] = map[string]interface{}{ |  | ||||||
| 					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()), |  | ||||||
| 					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()), |  | ||||||
| 					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()), |  | ||||||
| 					"Overall":  format(float64(metric.Count()), metric.RateMean()), |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 			case metrics.Timer: |  | ||||||
| 				root[name] = map[string]interface{}{ |  | ||||||
| 					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()), |  | ||||||
| 					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()), |  | ||||||
| 					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()), |  | ||||||
| 					"Overall":  format(float64(metric.Count()), metric.RateMean()), |  | ||||||
| 					"Maximum":  time.Duration(metric.Max()).String(), |  | ||||||
| 					"Minimum":  time.Duration(metric.Min()).String(), |  | ||||||
| 					"Percentiles": map[string]interface{}{ |  | ||||||
| 						"5":  time.Duration(metric.Percentile(0.05)).String(), |  | ||||||
| 						"20": time.Duration(metric.Percentile(0.2)).String(), |  | ||||||
| 						"50": time.Duration(metric.Percentile(0.5)).String(), |  | ||||||
| 						"80": time.Duration(metric.Percentile(0.8)).String(), |  | ||||||
| 						"95": time.Duration(metric.Percentile(0.95)).String(), |  | ||||||
| 					}, |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 			default: |  | ||||||
| 				root[name] = "Unknown metric type" |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
| 	return counters, nil |  | ||||||
| } |  | ||||||
| @@ -1,87 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"math/big" |  | ||||||
| 	"reflect" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type WaitForBlockArgs struct { |  | ||||||
| 	MinHeight int |  | ||||||
| 	Timeout   int // in seconds |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *WaitForBlockArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) > 2 { |  | ||||||
| 		return fmt.Errorf("waitForArgs needs 0, 1, 2 arguments") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// default values when not provided |  | ||||||
| 	args.MinHeight = -1 |  | ||||||
| 	args.Timeout = -1 |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 { |  | ||||||
| 		var minHeight *big.Int |  | ||||||
| 		if minHeight, err = numString(obj[0]); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		args.MinHeight = int(minHeight.Int64()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 { |  | ||||||
| 		timeout, err := numString(obj[1]) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		args.Timeout = int(timeout.Int64()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type MetricsArgs struct { |  | ||||||
| 	Raw bool |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *MetricsArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	if len(obj) > 1 { |  | ||||||
| 		return fmt.Errorf("metricsArgs needs 0, 1 arguments") |  | ||||||
| 	} |  | ||||||
| 	// default values when not provided |  | ||||||
| 	if len(obj) >= 1 && obj[0] != nil { |  | ||||||
| 		if value, ok := obj[0].(bool); !ok { |  | ||||||
| 			return fmt.Errorf("invalid argument %v", reflect.TypeOf(obj[0])) |  | ||||||
| 		} else { |  | ||||||
| 			args.Raw = value |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,83 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| const Debug_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'debug', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'printBlock', |  | ||||||
| 			call: 'debug_printBlock', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'getBlockRlp', |  | ||||||
| 			call: 'debug_getBlockRlp', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'setHead', |  | ||||||
| 			call: 'debug_setHead', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'processBlock', |  | ||||||
| 			call: 'debug_processBlock', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'seedHash', |  | ||||||
| 			call: 'debug_seedHash', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'dumpBlock', |  | ||||||
| 			call: 'debug_dumpBlock', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'metrics', |  | ||||||
| 			call: 'debug_metrics', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'verbosity', |  | ||||||
| 			call: 'debug_verbosity', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [web3._extend.utils.fromDecimal] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'vmodule', |  | ||||||
| 			call: 'debug_vmodule', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
							
								
								
									
										721
									
								
								rpc/api/eth.go
									
									
									
									
									
								
							
							
						
						
									
										721
									
								
								rpc/api/eth.go
									
									
									
									
									
								
							| @@ -1,721 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"math/big" |  | ||||||
|  |  | ||||||
| 	"fmt" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/common/natspec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rlp" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| 	"gopkg.in/fatih/set.v0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	EthApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // eth api provider |  | ||||||
| // See https://github.com/ethereum/wiki/wiki/JSON-RPC |  | ||||||
| type ethApi struct { |  | ||||||
| 	xeth     *xeth.XEth |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	methods  map[string]ethhandler |  | ||||||
| 	codec    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // eth callback handler |  | ||||||
| type ethhandler func(*ethApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	ethMapping = map[string]ethhandler{ |  | ||||||
| 		"eth_accounts":                            (*ethApi).Accounts, |  | ||||||
| 		"eth_blockNumber":                         (*ethApi).BlockNumber, |  | ||||||
| 		"eth_getBalance":                          (*ethApi).GetBalance, |  | ||||||
| 		"eth_protocolVersion":                     (*ethApi).ProtocolVersion, |  | ||||||
| 		"eth_coinbase":                            (*ethApi).Coinbase, |  | ||||||
| 		"eth_mining":                              (*ethApi).IsMining, |  | ||||||
| 		"eth_syncing":                             (*ethApi).IsSyncing, |  | ||||||
| 		"eth_gasPrice":                            (*ethApi).GasPrice, |  | ||||||
| 		"eth_getStorage":                          (*ethApi).GetStorage, |  | ||||||
| 		"eth_storageAt":                           (*ethApi).GetStorage, |  | ||||||
| 		"eth_getStorageAt":                        (*ethApi).GetStorageAt, |  | ||||||
| 		"eth_getTransactionCount":                 (*ethApi).GetTransactionCount, |  | ||||||
| 		"eth_getBlockTransactionCountByHash":      (*ethApi).GetBlockTransactionCountByHash, |  | ||||||
| 		"eth_getBlockTransactionCountByNumber":    (*ethApi).GetBlockTransactionCountByNumber, |  | ||||||
| 		"eth_getUncleCountByBlockHash":            (*ethApi).GetUncleCountByBlockHash, |  | ||||||
| 		"eth_getUncleCountByBlockNumber":          (*ethApi).GetUncleCountByBlockNumber, |  | ||||||
| 		"eth_getData":                             (*ethApi).GetData, |  | ||||||
| 		"eth_getCode":                             (*ethApi).GetData, |  | ||||||
| 		"eth_getNatSpec":                          (*ethApi).GetNatSpec, |  | ||||||
| 		"eth_sign":                                (*ethApi).Sign, |  | ||||||
| 		"eth_sendRawTransaction":                  (*ethApi).SubmitTransaction, |  | ||||||
| 		"eth_submitTransaction":                   (*ethApi).SubmitTransaction, |  | ||||||
| 		"eth_sendTransaction":                     (*ethApi).SendTransaction, |  | ||||||
| 		"eth_signTransaction":                     (*ethApi).SignTransaction, |  | ||||||
| 		"eth_transact":                            (*ethApi).SendTransaction, |  | ||||||
| 		"eth_estimateGas":                         (*ethApi).EstimateGas, |  | ||||||
| 		"eth_call":                                (*ethApi).Call, |  | ||||||
| 		"eth_flush":                               (*ethApi).Flush, |  | ||||||
| 		"eth_getBlockByHash":                      (*ethApi).GetBlockByHash, |  | ||||||
| 		"eth_getBlockByNumber":                    (*ethApi).GetBlockByNumber, |  | ||||||
| 		"eth_getTransactionByHash":                (*ethApi).GetTransactionByHash, |  | ||||||
| 		"eth_getTransactionByBlockNumberAndIndex": (*ethApi).GetTransactionByBlockNumberAndIndex, |  | ||||||
| 		"eth_getTransactionByBlockHashAndIndex":   (*ethApi).GetTransactionByBlockHashAndIndex, |  | ||||||
| 		"eth_getUncleByBlockHashAndIndex":         (*ethApi).GetUncleByBlockHashAndIndex, |  | ||||||
| 		"eth_getUncleByBlockNumberAndIndex":       (*ethApi).GetUncleByBlockNumberAndIndex, |  | ||||||
| 		"eth_getCompilers":                        (*ethApi).GetCompilers, |  | ||||||
| 		"eth_compileSolidity":                     (*ethApi).CompileSolidity, |  | ||||||
| 		"eth_newFilter":                           (*ethApi).NewFilter, |  | ||||||
| 		"eth_newBlockFilter":                      (*ethApi).NewBlockFilter, |  | ||||||
| 		"eth_newPendingTransactionFilter":         (*ethApi).NewPendingTransactionFilter, |  | ||||||
| 		"eth_uninstallFilter":                     (*ethApi).UninstallFilter, |  | ||||||
| 		"eth_getFilterChanges":                    (*ethApi).GetFilterChanges, |  | ||||||
| 		"eth_getFilterLogs":                       (*ethApi).GetFilterLogs, |  | ||||||
| 		"eth_getLogs":                             (*ethApi).GetLogs, |  | ||||||
| 		"eth_hashrate":                            (*ethApi).Hashrate, |  | ||||||
| 		"eth_getWork":                             (*ethApi).GetWork, |  | ||||||
| 		"eth_submitWork":                          (*ethApi).SubmitWork, |  | ||||||
| 		"eth_submitHashrate":                      (*ethApi).SubmitHashrate, |  | ||||||
| 		"eth_resend":                              (*ethApi).Resend, |  | ||||||
| 		"eth_pendingTransactions":                 (*ethApi).PendingTransactions, |  | ||||||
| 		"eth_getTransactionReceipt":               (*ethApi).GetTransactionReceipt, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // create new ethApi instance |  | ||||||
| func NewEthApi(xeth *xeth.XEth, eth *eth.Ethereum, codec codec.Codec) *ethApi { |  | ||||||
| 	return ðApi{xeth, eth, ethMapping, codec.New(nil)} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *ethApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *ethApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, shared.NewNotImplementedError(req.Method) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) Name() string { |  | ||||||
| 	return shared.EthApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) ApiVersion() string { |  | ||||||
| 	return EthApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) Accounts(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.xeth.Accounts(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) Hashrate(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return newHexNum(self.xeth.HashRate()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) BlockNumber(req *shared.Request) (interface{}, error) { |  | ||||||
| 	num := self.xeth.CurrentBlock().Number() |  | ||||||
| 	return newHexNum(num.Bytes()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetBalance(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GetBalanceArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return self.xeth.AtStateNum(args.BlockNumber).BalanceAt(args.Address), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) ProtocolVersion(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.xeth.EthVersion(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) Coinbase(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return newHexData(self.xeth.Coinbase()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) IsMining(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.xeth.IsMining(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) IsSyncing(req *shared.Request) (interface{}, error) { |  | ||||||
| 	origin, current, height := self.ethereum.Downloader().Progress() |  | ||||||
| 	if current < height { |  | ||||||
| 		return map[string]interface{}{ |  | ||||||
| 			"startingBlock": newHexNum(big.NewInt(int64(origin)).Bytes()), |  | ||||||
| 			"currentBlock":  newHexNum(big.NewInt(int64(current)).Bytes()), |  | ||||||
| 			"highestBlock":  newHexNum(big.NewInt(int64(height)).Bytes()), |  | ||||||
| 		}, nil |  | ||||||
| 	} |  | ||||||
| 	return false, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GasPrice(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return newHexNum(self.xeth.DefaultGasPrice().Bytes()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetStorage(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GetStorageArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return self.xeth.AtStateNum(args.BlockNumber).State().SafeGet(args.Address).Storage(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetStorageAt(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GetStorageAtArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return self.xeth.AtStateNum(args.BlockNumber).StorageAt(args.Address, args.Key), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetTransactionCount(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GetTxCountArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	count := self.xeth.AtStateNum(args.BlockNumber).TxCountAt(args.Address) |  | ||||||
| 	return fmt.Sprintf("%#x", count), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetBlockTransactionCountByHash(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(HashArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	block := self.xeth.EthBlockByHash(args.Hash) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	return fmt.Sprintf("%#x", len(block.Transactions())), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetBlockTransactionCountByNumber(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumArg) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	block := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	return fmt.Sprintf("%#x", len(block.Transactions())), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetUncleCountByBlockHash(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(HashArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	block := self.xeth.EthBlockByHash(args.Hash) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	return fmt.Sprintf("%#x", len(block.Uncles())), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetUncleCountByBlockNumber(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumArg) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	block := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	return fmt.Sprintf("%#x", len(block.Uncles())), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetData(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GetDataArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	v := self.xeth.AtStateNum(args.BlockNumber).CodeAtBytes(args.Address) |  | ||||||
| 	return newHexData(v), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) Sign(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(NewSigArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	v, err := self.xeth.Sign(args.From, args.Data, false) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return v, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) SubmitTransaction(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(NewDataArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	v, err := self.xeth.PushTx(args.Data) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return v, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // JsonTransaction is returned as response by the JSON RPC. It contains the |  | ||||||
| // signed RLP encoded transaction as Raw and the signed transaction object as Tx. |  | ||||||
| type JsonTransaction struct { |  | ||||||
| 	Raw string `json:"raw"` |  | ||||||
| 	Tx  *tx    `json:"tx"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) SignTransaction(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(NewTxArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// nonce may be nil ("guess" mode) |  | ||||||
| 	var nonce string |  | ||||||
| 	if args.Nonce != nil { |  | ||||||
| 		nonce = args.Nonce.String() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var gas, price string |  | ||||||
| 	if args.Gas != nil { |  | ||||||
| 		gas = args.Gas.String() |  | ||||||
| 	} |  | ||||||
| 	if args.GasPrice != nil { |  | ||||||
| 		price = args.GasPrice.String() |  | ||||||
| 	} |  | ||||||
| 	tx, err := self.xeth.SignTransaction(args.From, args.To, nonce, args.Value.String(), gas, price, args.Data) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	data, err := rlp.EncodeToBytes(tx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return JsonTransaction{"0x" + common.Bytes2Hex(data), newTx(tx)}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) SendTransaction(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(NewTxArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// nonce may be nil ("guess" mode) |  | ||||||
| 	var nonce string |  | ||||||
| 	if args.Nonce != nil { |  | ||||||
| 		nonce = args.Nonce.String() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var gas, price string |  | ||||||
| 	if args.Gas != nil { |  | ||||||
| 		gas = args.Gas.String() |  | ||||||
| 	} |  | ||||||
| 	if args.GasPrice != nil { |  | ||||||
| 		price = args.GasPrice.String() |  | ||||||
| 	} |  | ||||||
| 	v, err := self.xeth.Transact(args.From, args.To, nonce, args.Value.String(), gas, price, args.Data) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return v, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetNatSpec(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(NewTxArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var jsontx = fmt.Sprintf(`{"params":[{"to":"%s","data": "%s"}]}`, args.To, args.Data) |  | ||||||
| 	notice := natspec.GetNotice(self.xeth, jsontx, self.ethereum.HTTPClient()) |  | ||||||
|  |  | ||||||
| 	return notice, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) EstimateGas(req *shared.Request) (interface{}, error) { |  | ||||||
| 	_, gas, err := self.doCall(req.Params) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// TODO unwrap the parent method's ToHex call |  | ||||||
| 	if len(gas) == 0 { |  | ||||||
| 		return newHexNum(0), nil |  | ||||||
| 	} else { |  | ||||||
| 		return newHexNum(common.String2Big(gas)), err |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) Call(req *shared.Request) (interface{}, error) { |  | ||||||
| 	v, _, err := self.doCall(req.Params) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// TODO unwrap the parent method's ToHex call |  | ||||||
| 	if v == "0x0" { |  | ||||||
| 		return newHexData([]byte{}), nil |  | ||||||
| 	} else { |  | ||||||
| 		return newHexData(common.FromHex(v)), nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) Flush(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return nil, shared.NewNotImplementedError(req.Method) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) doCall(params json.RawMessage) (string, string, error) { |  | ||||||
| 	args := new(CallArgs) |  | ||||||
| 	if err := self.codec.Decode(params, &args); err != nil { |  | ||||||
| 		return "", "", err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return self.xeth.AtStateNum(args.BlockNumber).Call(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetBlockByHash(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GetBlockByHashArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	block := self.xeth.EthBlockByHash(args.BlockHash) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	return NewBlockRes(block, self.xeth.Td(block.Hash()), args.IncludeTxs), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetBlockByNumber(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GetBlockByNumberArgs) |  | ||||||
| 	if err := json.Unmarshal(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	block := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	return NewBlockRes(block, self.xeth.Td(block.Hash()), args.IncludeTxs), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetTransactionByHash(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(HashArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	tx, bhash, bnum, txi := self.xeth.EthTransactionByHash(args.Hash) |  | ||||||
| 	if tx != nil { |  | ||||||
| 		v := NewTransactionRes(tx) |  | ||||||
| 		// if the blockhash is 0, assume this is a pending transaction |  | ||||||
| 		if bytes.Compare(bhash.Bytes(), bytes.Repeat([]byte{0}, 32)) != 0 { |  | ||||||
| 			v.BlockHash = newHexData(bhash) |  | ||||||
| 			v.BlockNumber = newHexNum(bnum) |  | ||||||
| 			v.TxIndex = newHexNum(txi) |  | ||||||
| 		} |  | ||||||
| 		return v, nil |  | ||||||
| 	} |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetTransactionByBlockHashAndIndex(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(HashIndexArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	raw := self.xeth.EthBlockByHash(args.Hash) |  | ||||||
| 	if raw == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	block := NewBlockRes(raw, self.xeth.Td(raw.Hash()), true) |  | ||||||
| 	if args.Index >= int64(len(block.Transactions)) || args.Index < 0 { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} else { |  | ||||||
| 		return block.Transactions[args.Index], nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetTransactionByBlockNumberAndIndex(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumIndexArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	raw := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	if raw == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	block := NewBlockRes(raw, self.xeth.Td(raw.Hash()), true) |  | ||||||
| 	if args.Index >= int64(len(block.Transactions)) || args.Index < 0 { |  | ||||||
| 		// return NewValidationError("Index", "does not exist") |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	return block.Transactions[args.Index], nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetUncleByBlockHashAndIndex(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(HashIndexArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	raw := self.xeth.EthBlockByHash(args.Hash) |  | ||||||
| 	if raw == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	block := NewBlockRes(raw, self.xeth.Td(raw.Hash()), false) |  | ||||||
| 	if args.Index >= int64(len(block.Uncles)) || args.Index < 0 { |  | ||||||
| 		// return NewValidationError("Index", "does not exist") |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	return block.Uncles[args.Index], nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetUncleByBlockNumberAndIndex(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockNumIndexArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	raw := self.xeth.EthBlockByNumber(args.BlockNumber) |  | ||||||
| 	if raw == nil { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
| 	block := NewBlockRes(raw, self.xeth.Td(raw.Hash()), true) |  | ||||||
| 	if args.Index >= int64(len(block.Uncles)) || args.Index < 0 { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} else { |  | ||||||
| 		return block.Uncles[args.Index], nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetCompilers(req *shared.Request) (interface{}, error) { |  | ||||||
| 	var lang string |  | ||||||
| 	if solc, _ := self.xeth.Solc(); solc != nil { |  | ||||||
| 		lang = "Solidity" |  | ||||||
| 	} |  | ||||||
| 	c := []string{lang} |  | ||||||
| 	return c, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) CompileSolidity(req *shared.Request) (interface{}, error) { |  | ||||||
| 	solc, _ := self.xeth.Solc() |  | ||||||
| 	if solc == nil { |  | ||||||
| 		return nil, shared.NewNotAvailableError(req.Method, "solc (solidity compiler) not found") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	args := new(SourceArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	contracts, err := solc.Compile(args.Source) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return contracts, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) NewFilter(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockFilterArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	id := self.xeth.NewLogFilter(args.Earliest, args.Latest, args.Skip, args.Max, args.Address, args.Topics) |  | ||||||
| 	return newHexNum(big.NewInt(int64(id)).Bytes()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) NewBlockFilter(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return newHexNum(self.xeth.NewBlockFilter()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) NewPendingTransactionFilter(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return newHexNum(self.xeth.NewTransactionFilter()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) UninstallFilter(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(FilterIdArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	return self.xeth.UninstallFilter(args.Id), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetFilterChanges(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(FilterIdArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	switch self.xeth.GetFilterType(args.Id) { |  | ||||||
| 	case xeth.BlockFilterTy: |  | ||||||
| 		return NewHashesRes(self.xeth.BlockFilterChanged(args.Id)), nil |  | ||||||
| 	case xeth.TransactionFilterTy: |  | ||||||
| 		return NewHashesRes(self.xeth.TransactionFilterChanged(args.Id)), nil |  | ||||||
| 	case xeth.LogFilterTy: |  | ||||||
| 		return NewLogsRes(self.xeth.LogFilterChanged(args.Id)), nil |  | ||||||
| 	default: |  | ||||||
| 		return []string{}, nil // reply empty string slice |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetFilterLogs(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(FilterIdArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return NewLogsRes(self.xeth.Logs(args.Id)), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetLogs(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(BlockFilterArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	return NewLogsRes(self.xeth.AllLogs(args.Earliest, args.Latest, args.Skip, args.Max, args.Address, args.Topics)), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetWork(req *shared.Request) (interface{}, error) { |  | ||||||
| 	self.xeth.SetMining(true, 0) |  | ||||||
| 	ret, err := self.xeth.RemoteMining().GetWork() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, shared.NewNotReadyError("mining work") |  | ||||||
| 	} else { |  | ||||||
| 		return ret, nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) SubmitWork(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SubmitWorkArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	return self.xeth.RemoteMining().SubmitWork(args.Nonce, common.HexToHash(args.Digest), common.HexToHash(args.Header)), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) SubmitHashrate(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SubmitHashRateArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return false, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	self.xeth.RemoteMining().SubmitHashrate(common.HexToHash(args.Id), args.Rate) |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) Resend(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(ResendArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	from := common.HexToAddress(args.Tx.From) |  | ||||||
|  |  | ||||||
| 	pending := self.ethereum.TxPool().GetTransactions() |  | ||||||
| 	for _, p := range pending { |  | ||||||
| 		if pFrom, err := p.From(); err == nil && pFrom == from && p.SigHash() == args.Tx.tx.SigHash() { |  | ||||||
| 			self.ethereum.TxPool().RemoveTx(common.HexToHash(args.Tx.Hash)) |  | ||||||
| 			return self.xeth.Transact(args.Tx.From, args.Tx.To, args.Tx.Nonce, args.Tx.Value, args.GasLimit, args.GasPrice, args.Tx.Data) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, fmt.Errorf("Transaction %s not found", args.Tx.Hash) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) PendingTransactions(req *shared.Request) (interface{}, error) { |  | ||||||
| 	txs := self.ethereum.TxPool().GetTransactions() |  | ||||||
|  |  | ||||||
| 	// grab the accounts from the account manager. This will help with determining which |  | ||||||
| 	// transactions should be returned. |  | ||||||
| 	accounts, err := self.ethereum.AccountManager().Accounts() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Add the accouns to a new set |  | ||||||
| 	accountSet := set.New() |  | ||||||
| 	for _, account := range accounts { |  | ||||||
| 		accountSet.Add(account.Address) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ltxs []*tx |  | ||||||
| 	for _, tx := range txs { |  | ||||||
| 		if from, _ := tx.From(); accountSet.Has(from) { |  | ||||||
| 			ltxs = append(ltxs, newTx(tx)) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return ltxs, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ethApi) GetTransactionReceipt(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(HashArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	txhash := common.BytesToHash(common.FromHex(args.Hash)) |  | ||||||
| 	tx, bhash, bnum, txi := self.xeth.EthTransactionByHash(args.Hash) |  | ||||||
| 	rec := self.xeth.GetTxReceipt(txhash) |  | ||||||
| 	// We could have an error of "not found". Should disambiguate |  | ||||||
| 	// if err != nil { |  | ||||||
| 	// 	return err, nil |  | ||||||
| 	// } |  | ||||||
| 	if rec != nil && tx != nil { |  | ||||||
| 		v := NewReceiptRes(rec) |  | ||||||
| 		v.BlockHash = newHexData(bhash) |  | ||||||
| 		v.BlockNumber = newHexNum(bnum) |  | ||||||
| 		v.TransactionIndex = newHexNum(txi) |  | ||||||
| 		return v, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
							
								
								
									
										1104
									
								
								rpc/api/eth_args.go
									
									
									
									
									
								
							
							
						
						
									
										1104
									
								
								rpc/api/eth_args.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,66 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| // JS api provided by web3.js |  | ||||||
| // eth_sign not standard |  | ||||||
|  |  | ||||||
| const Eth_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'eth', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'sign', |  | ||||||
| 			call: 'eth_sign', |  | ||||||
| 			params: 2, |  | ||||||
| 			inputFormatter: [web3._extend.utils.toAddress, null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'resend', |  | ||||||
| 			call: 'eth_resend', |  | ||||||
| 			params: 3, |  | ||||||
| 			inputFormatter: [web3._extend.formatters.inputTransactionFormatter, web3._extend.utils.fromDecimal, web3._extend.utils.fromDecimal] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'getNatSpec', |  | ||||||
| 			call: 'eth_getNatSpec', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [web3._extend.formatters.inputTransactionFormatter] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'signTransaction', |  | ||||||
| 			call: 'eth_signTransaction', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [web3._extend.formatters.inputTransactionFormatter] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'submitTransaction', |  | ||||||
| 			call: 'eth_submitTransaction', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [web3._extend.formatters.inputTransactionFormatter] |  | ||||||
| 		}) |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'pendingTransactions', |  | ||||||
| 			getter: 'eth_pendingTransactions' |  | ||||||
| 		}) |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
| @@ -1,88 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/ethereum/go-ethereum/logger" |  | ||||||
| 	"github.com/ethereum/go-ethereum/logger/glog" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	MergedApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // combines multiple API's |  | ||||||
| type MergedApi struct { |  | ||||||
| 	apis    map[string]string |  | ||||||
| 	methods map[string]shared.EthereumApi |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create new merged api instance |  | ||||||
| func newMergedApi(apis ...shared.EthereumApi) *MergedApi { |  | ||||||
| 	mergedApi := new(MergedApi) |  | ||||||
| 	mergedApi.apis = make(map[string]string, len(apis)) |  | ||||||
| 	mergedApi.methods = make(map[string]shared.EthereumApi) |  | ||||||
|  |  | ||||||
| 	for _, api := range apis { |  | ||||||
| 		if api != nil { |  | ||||||
| 			mergedApi.apis[api.Name()] = api.ApiVersion() |  | ||||||
| 			for _, method := range api.Methods() { |  | ||||||
| 				mergedApi.methods[method] = api |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return mergedApi |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Supported RPC methods |  | ||||||
| func (self *MergedApi) Methods() []string { |  | ||||||
| 	all := make([]string, len(self.methods)) |  | ||||||
| 	for method, _ := range self.methods { |  | ||||||
| 		all = append(all, method) |  | ||||||
| 	} |  | ||||||
| 	return all |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Call the correct API's Execute method for the given request |  | ||||||
| func (self *MergedApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	glog.V(logger.Detail).Infof("%s %s", req.Method, req.Params) |  | ||||||
|  |  | ||||||
| 	if res, _ := self.handle(req); res != nil { |  | ||||||
| 		return res, nil |  | ||||||
| 	} |  | ||||||
| 	if api, found := self.methods[req.Method]; found { |  | ||||||
| 		return api.Execute(req) |  | ||||||
| 	} |  | ||||||
| 	return nil, shared.NewNotImplementedError(req.Method) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *MergedApi) Name() string { |  | ||||||
| 	return shared.MergedApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *MergedApi) ApiVersion() string { |  | ||||||
| 	return MergedApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *MergedApi) handle(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if req.Method == "modules" { // provided API's |  | ||||||
| 		return self.apis, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
							
								
								
									
										177
									
								
								rpc/api/miner.go
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								rpc/api/miner.go
									
									
									
									
									
								
							| @@ -1,177 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/ethereum/ethash" |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	MinerApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	MinerMapping = map[string]minerhandler{ |  | ||||||
| 		"miner_hashrate":     (*minerApi).Hashrate, |  | ||||||
| 		"miner_makeDAG":      (*minerApi).MakeDAG, |  | ||||||
| 		"miner_setExtra":     (*minerApi).SetExtra, |  | ||||||
| 		"miner_setGasPrice":  (*minerApi).SetGasPrice, |  | ||||||
| 		"miner_setEtherbase": (*minerApi).SetEtherbase, |  | ||||||
| 		"miner_startAutoDAG": (*minerApi).StartAutoDAG, |  | ||||||
| 		"miner_start":        (*minerApi).StartMiner, |  | ||||||
| 		"miner_stopAutoDAG":  (*minerApi).StopAutoDAG, |  | ||||||
| 		"miner_stop":         (*minerApi).StopMiner, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // miner callback handler |  | ||||||
| type minerhandler func(*minerApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // miner api provider |  | ||||||
| type minerApi struct { |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	methods  map[string]minerhandler |  | ||||||
| 	codec    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new miner api instance |  | ||||||
| func NewMinerApi(ethereum *eth.Ethereum, coder codec.Codec) *minerApi { |  | ||||||
| 	return &minerApi{ |  | ||||||
| 		ethereum: ethereum, |  | ||||||
| 		methods:  MinerMapping, |  | ||||||
| 		codec:    coder.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *minerApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, &shared.NotImplementedError{req.Method} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *minerApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) Name() string { |  | ||||||
| 	return shared.MinerApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) ApiVersion() string { |  | ||||||
| 	return MinerApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) StartMiner(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(StartMinerArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if args.Threads == -1 { // (not specified by user, use default) |  | ||||||
| 		args.Threads = self.ethereum.MinerThreads |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	self.ethereum.StartAutoDAG() |  | ||||||
| 	err := self.ethereum.StartMining(args.Threads, "") |  | ||||||
| 	if err == nil { |  | ||||||
| 		return true, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return false, err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) StopMiner(req *shared.Request) (interface{}, error) { |  | ||||||
| 	self.ethereum.StopMining() |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) Hashrate(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.ethereum.Miner().HashRate(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) SetExtra(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SetExtraArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := self.ethereum.Miner().SetExtra([]byte(args.Data)); err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) SetGasPrice(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(GasPriceArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	self.ethereum.Miner().SetGasPrice(common.String2Big(args.Price)) |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) SetEtherbase(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(SetEtherbaseArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
| 	self.ethereum.SetEtherbase(args.Etherbase) |  | ||||||
| 	return nil, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) StartAutoDAG(req *shared.Request) (interface{}, error) { |  | ||||||
| 	self.ethereum.StartAutoDAG() |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) StopAutoDAG(req *shared.Request) (interface{}, error) { |  | ||||||
| 	self.ethereum.StopAutoDAG() |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *minerApi) MakeDAG(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(MakeDAGArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if args.BlockNumber < 0 { |  | ||||||
| 		return false, shared.NewValidationError("BlockNumber", "BlockNumber must be positive") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err := ethash.MakeDAG(uint64(args.BlockNumber), "") |  | ||||||
| 	if err == nil { |  | ||||||
| 		return true, nil |  | ||||||
| 	} |  | ||||||
| 	return false, err |  | ||||||
| } |  | ||||||
| @@ -1,142 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
|  |  | ||||||
| 	"math/big" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type StartMinerArgs struct { |  | ||||||
| 	Threads int |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *StartMinerArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) == 0 || obj[0] == nil { |  | ||||||
| 		args.Threads = -1 |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var num *big.Int |  | ||||||
| 	if num, err = numString(obj[0]); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	args.Threads = int(num.Int64()) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SetExtraArgs struct { |  | ||||||
| 	Data string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SetExtraArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	extrastr, ok := obj[0].(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("Price", "not a string") |  | ||||||
| 	} |  | ||||||
| 	args.Data = extrastr |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type GasPriceArgs struct { |  | ||||||
| 	Price string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *GasPriceArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if pricestr, ok := obj[0].(string); ok { |  | ||||||
| 		args.Price = pricestr |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return shared.NewInvalidTypeError("Price", "not a string") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type SetEtherbaseArgs struct { |  | ||||||
| 	Etherbase common.Address |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *SetEtherbaseArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if addr, ok := obj[0].(string); ok { |  | ||||||
| 		args.Etherbase = common.HexToAddress(addr) |  | ||||||
| 		if (args.Etherbase == common.Address{}) { |  | ||||||
| 			return shared.NewInvalidTypeError("Etherbase", "not a valid address") |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return shared.NewInvalidTypeError("Etherbase", "not a string") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type MakeDAGArgs struct { |  | ||||||
| 	BlockNumber int64 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *MakeDAGArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	args.BlockNumber = -1 |  | ||||||
| 	var obj []interface{} |  | ||||||
|  |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := blockHeight(obj[0], &args.BlockNumber); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,83 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| const Miner_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'miner', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'start', |  | ||||||
| 			call: 'miner_start', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'stop', |  | ||||||
| 			call: 'miner_stop', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'setEtherbase', |  | ||||||
| 			call: 'miner_setEtherbase', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [web3._extend.formatters.formatInputInt], |  | ||||||
| 			outputFormatter: web3._extend.formatters.formatOutputBool |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'setExtra', |  | ||||||
| 			call: 'miner_setExtra', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'setGasPrice', |  | ||||||
| 			call: 'miner_setGasPrice', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [web3._extend.utils.fromDecial] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'startAutoDAG', |  | ||||||
| 			call: 'miner_startAutoDAG', |  | ||||||
| 			params: 0, |  | ||||||
| 			inputFormatter: [] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'stopAutoDAG', |  | ||||||
| 			call: 'miner_stopAutoDAG', |  | ||||||
| 			params: 0, |  | ||||||
| 			inputFormatter: [] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'makeDAG', |  | ||||||
| 			call: 'miner_makeDAG', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [web3._extend.formatters.inputDefaultBlockNumberFormatter] |  | ||||||
| 		}) |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'hashrate', |  | ||||||
| 			getter: 'miner_hashrate', |  | ||||||
| 			outputFormatter: web3._extend.utils.toDecimal |  | ||||||
| 		}) |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
| @@ -1,99 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	NetApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	netMapping = map[string]nethandler{ |  | ||||||
| 		"net_peerCount": (*netApi).PeerCount, |  | ||||||
| 		"net_listening": (*netApi).IsListening, |  | ||||||
| 		"net_version":   (*netApi).Version, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // net callback handler |  | ||||||
| type nethandler func(*netApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // net api provider |  | ||||||
| type netApi struct { |  | ||||||
| 	xeth     *xeth.XEth |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	methods  map[string]nethandler |  | ||||||
| 	codec    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new net api instance |  | ||||||
| func NewNetApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *netApi { |  | ||||||
| 	return &netApi{ |  | ||||||
| 		xeth:     xeth, |  | ||||||
| 		ethereum: eth, |  | ||||||
| 		methods:  netMapping, |  | ||||||
| 		codec:    coder.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *netApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *netApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, shared.NewNotImplementedError(req.Method) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *netApi) Name() string { |  | ||||||
| 	return shared.NetApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *netApi) ApiVersion() string { |  | ||||||
| 	return NetApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Number of connected peers |  | ||||||
| func (self *netApi) PeerCount(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return newHexNum(self.xeth.PeerCount()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *netApi) IsListening(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.xeth.IsListening(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *netApi) Version(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.xeth.NetworkVersion(), nil |  | ||||||
| } |  | ||||||
| @@ -1,39 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| const Net_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'net', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'addPeer', |  | ||||||
| 			call: 'net_addPeer', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null] |  | ||||||
| 		}) |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'version', |  | ||||||
| 			getter: 'net_version' |  | ||||||
| 		}) |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
| @@ -1,522 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"encoding/binary" |  | ||||||
| 	"encoding/hex" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"math/big" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/core/types" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type hexdata struct { |  | ||||||
| 	data  []byte |  | ||||||
| 	isNil bool |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (d *hexdata) String() string { |  | ||||||
| 	return "0x" + common.Bytes2Hex(d.data) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (d *hexdata) MarshalJSON() ([]byte, error) { |  | ||||||
| 	if d.isNil { |  | ||||||
| 		return json.Marshal(nil) |  | ||||||
| 	} |  | ||||||
| 	return json.Marshal(d.String()) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newHexData(input interface{}) *hexdata { |  | ||||||
| 	d := new(hexdata) |  | ||||||
|  |  | ||||||
| 	if input == nil { |  | ||||||
| 		d.isNil = true |  | ||||||
| 		return d |  | ||||||
| 	} |  | ||||||
| 	switch input := input.(type) { |  | ||||||
| 	case []byte: |  | ||||||
| 		d.data = input |  | ||||||
| 	case common.Hash: |  | ||||||
| 		d.data = input.Bytes() |  | ||||||
| 	case *common.Hash: |  | ||||||
| 		if input == nil { |  | ||||||
| 			d.isNil = true |  | ||||||
| 		} else { |  | ||||||
| 			d.data = input.Bytes() |  | ||||||
| 		} |  | ||||||
| 	case common.Address: |  | ||||||
| 		d.data = input.Bytes() |  | ||||||
| 	case *common.Address: |  | ||||||
| 		if input == nil { |  | ||||||
| 			d.isNil = true |  | ||||||
| 		} else { |  | ||||||
| 			d.data = input.Bytes() |  | ||||||
| 		} |  | ||||||
| 	case types.Bloom: |  | ||||||
| 		d.data = input.Bytes() |  | ||||||
| 	case *types.Bloom: |  | ||||||
| 		if input == nil { |  | ||||||
| 			d.isNil = true |  | ||||||
| 		} else { |  | ||||||
| 			d.data = input.Bytes() |  | ||||||
| 		} |  | ||||||
| 	case *big.Int: |  | ||||||
| 		if input == nil { |  | ||||||
| 			d.isNil = true |  | ||||||
| 		} else { |  | ||||||
| 			d.data = input.Bytes() |  | ||||||
| 		} |  | ||||||
| 	case int64: |  | ||||||
| 		d.data = big.NewInt(input).Bytes() |  | ||||||
| 	case uint64: |  | ||||||
| 		buff := make([]byte, 8) |  | ||||||
| 		binary.BigEndian.PutUint64(buff, input) |  | ||||||
| 		d.data = buff |  | ||||||
| 	case int: |  | ||||||
| 		d.data = big.NewInt(int64(input)).Bytes() |  | ||||||
| 	case uint: |  | ||||||
| 		d.data = big.NewInt(int64(input)).Bytes() |  | ||||||
| 	case int8: |  | ||||||
| 		d.data = big.NewInt(int64(input)).Bytes() |  | ||||||
| 	case uint8: |  | ||||||
| 		d.data = big.NewInt(int64(input)).Bytes() |  | ||||||
| 	case int16: |  | ||||||
| 		d.data = big.NewInt(int64(input)).Bytes() |  | ||||||
| 	case uint16: |  | ||||||
| 		buff := make([]byte, 2) |  | ||||||
| 		binary.BigEndian.PutUint16(buff, input) |  | ||||||
| 		d.data = buff |  | ||||||
| 	case int32: |  | ||||||
| 		d.data = big.NewInt(int64(input)).Bytes() |  | ||||||
| 	case uint32: |  | ||||||
| 		buff := make([]byte, 4) |  | ||||||
| 		binary.BigEndian.PutUint32(buff, input) |  | ||||||
| 		d.data = buff |  | ||||||
| 	case string: // hexstring |  | ||||||
| 		// aaargh ffs TODO: avoid back-and-forth hex encodings where unneeded |  | ||||||
| 		bytes, err := hex.DecodeString(strings.TrimPrefix(input, "0x")) |  | ||||||
| 		if err != nil { |  | ||||||
| 			d.isNil = true |  | ||||||
| 		} else { |  | ||||||
| 			d.data = bytes |  | ||||||
| 		} |  | ||||||
| 	default: |  | ||||||
| 		d.isNil = true |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return d |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type hexnum struct { |  | ||||||
| 	data  []byte |  | ||||||
| 	isNil bool |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (d *hexnum) String() string { |  | ||||||
| 	// Get hex string from bytes |  | ||||||
| 	out := common.Bytes2Hex(d.data) |  | ||||||
| 	// Trim leading 0s |  | ||||||
| 	out = strings.TrimLeft(out, "0") |  | ||||||
| 	// Output "0x0" when value is 0 |  | ||||||
| 	if len(out) == 0 { |  | ||||||
| 		out = "0" |  | ||||||
| 	} |  | ||||||
| 	return "0x" + out |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (d *hexnum) MarshalJSON() ([]byte, error) { |  | ||||||
| 	if d.isNil { |  | ||||||
| 		return json.Marshal(nil) |  | ||||||
| 	} |  | ||||||
| 	return json.Marshal(d.String()) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newHexNum(input interface{}) *hexnum { |  | ||||||
| 	d := new(hexnum) |  | ||||||
|  |  | ||||||
| 	d.data = newHexData(input).data |  | ||||||
|  |  | ||||||
| 	return d |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type BlockRes struct { |  | ||||||
| 	fullTx bool |  | ||||||
|  |  | ||||||
| 	BlockNumber     *hexnum           `json:"number"` |  | ||||||
| 	BlockHash       *hexdata          `json:"hash"` |  | ||||||
| 	ParentHash      *hexdata          `json:"parentHash"` |  | ||||||
| 	Nonce           *hexdata          `json:"nonce"` |  | ||||||
| 	Sha3Uncles      *hexdata          `json:"sha3Uncles"` |  | ||||||
| 	LogsBloom       *hexdata          `json:"logsBloom"` |  | ||||||
| 	TransactionRoot *hexdata          `json:"transactionsRoot"` |  | ||||||
| 	StateRoot       *hexdata          `json:"stateRoot"` |  | ||||||
| 	ReceiptRoot     *hexdata          `json:"receiptRoot"` |  | ||||||
| 	Miner           *hexdata          `json:"miner"` |  | ||||||
| 	Difficulty      *hexnum           `json:"difficulty"` |  | ||||||
| 	TotalDifficulty *hexnum           `json:"totalDifficulty"` |  | ||||||
| 	Size            *hexnum           `json:"size"` |  | ||||||
| 	ExtraData       *hexdata          `json:"extraData"` |  | ||||||
| 	GasLimit        *hexnum           `json:"gasLimit"` |  | ||||||
| 	GasUsed         *hexnum           `json:"gasUsed"` |  | ||||||
| 	UnixTimestamp   *hexnum           `json:"timestamp"` |  | ||||||
| 	Transactions    []*TransactionRes `json:"transactions"` |  | ||||||
| 	Uncles          []*UncleRes       `json:"uncles"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (b *BlockRes) MarshalJSON() ([]byte, error) { |  | ||||||
| 	if b.fullTx { |  | ||||||
| 		var ext struct { |  | ||||||
| 			BlockNumber     *hexnum           `json:"number"` |  | ||||||
| 			BlockHash       *hexdata          `json:"hash"` |  | ||||||
| 			ParentHash      *hexdata          `json:"parentHash"` |  | ||||||
| 			Nonce           *hexdata          `json:"nonce"` |  | ||||||
| 			Sha3Uncles      *hexdata          `json:"sha3Uncles"` |  | ||||||
| 			LogsBloom       *hexdata          `json:"logsBloom"` |  | ||||||
| 			TransactionRoot *hexdata          `json:"transactionsRoot"` |  | ||||||
| 			StateRoot       *hexdata          `json:"stateRoot"` |  | ||||||
| 			ReceiptRoot     *hexdata          `json:"receiptRoot"` |  | ||||||
| 			Miner           *hexdata          `json:"miner"` |  | ||||||
| 			Difficulty      *hexnum           `json:"difficulty"` |  | ||||||
| 			TotalDifficulty *hexnum           `json:"totalDifficulty"` |  | ||||||
| 			Size            *hexnum           `json:"size"` |  | ||||||
| 			ExtraData       *hexdata          `json:"extraData"` |  | ||||||
| 			GasLimit        *hexnum           `json:"gasLimit"` |  | ||||||
| 			GasUsed         *hexnum           `json:"gasUsed"` |  | ||||||
| 			UnixTimestamp   *hexnum           `json:"timestamp"` |  | ||||||
| 			Transactions    []*TransactionRes `json:"transactions"` |  | ||||||
| 			Uncles          []*hexdata        `json:"uncles"` |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		ext.BlockNumber = b.BlockNumber |  | ||||||
| 		ext.BlockHash = b.BlockHash |  | ||||||
| 		ext.ParentHash = b.ParentHash |  | ||||||
| 		ext.Nonce = b.Nonce |  | ||||||
| 		ext.Sha3Uncles = b.Sha3Uncles |  | ||||||
| 		ext.LogsBloom = b.LogsBloom |  | ||||||
| 		ext.TransactionRoot = b.TransactionRoot |  | ||||||
| 		ext.StateRoot = b.StateRoot |  | ||||||
| 		ext.ReceiptRoot = b.ReceiptRoot |  | ||||||
| 		ext.Miner = b.Miner |  | ||||||
| 		ext.Difficulty = b.Difficulty |  | ||||||
| 		ext.TotalDifficulty = b.TotalDifficulty |  | ||||||
| 		ext.Size = b.Size |  | ||||||
| 		ext.ExtraData = b.ExtraData |  | ||||||
| 		ext.GasLimit = b.GasLimit |  | ||||||
| 		ext.GasUsed = b.GasUsed |  | ||||||
| 		ext.UnixTimestamp = b.UnixTimestamp |  | ||||||
| 		ext.Transactions = b.Transactions |  | ||||||
| 		ext.Uncles = make([]*hexdata, len(b.Uncles)) |  | ||||||
| 		for i, u := range b.Uncles { |  | ||||||
| 			ext.Uncles[i] = u.BlockHash |  | ||||||
| 		} |  | ||||||
| 		return json.Marshal(ext) |  | ||||||
| 	} else { |  | ||||||
| 		var ext struct { |  | ||||||
| 			BlockNumber     *hexnum    `json:"number"` |  | ||||||
| 			BlockHash       *hexdata   `json:"hash"` |  | ||||||
| 			ParentHash      *hexdata   `json:"parentHash"` |  | ||||||
| 			Nonce           *hexdata   `json:"nonce"` |  | ||||||
| 			Sha3Uncles      *hexdata   `json:"sha3Uncles"` |  | ||||||
| 			LogsBloom       *hexdata   `json:"logsBloom"` |  | ||||||
| 			TransactionRoot *hexdata   `json:"transactionsRoot"` |  | ||||||
| 			StateRoot       *hexdata   `json:"stateRoot"` |  | ||||||
| 			ReceiptRoot     *hexdata   `json:"receiptRoot"` |  | ||||||
| 			Miner           *hexdata   `json:"miner"` |  | ||||||
| 			Difficulty      *hexnum    `json:"difficulty"` |  | ||||||
| 			TotalDifficulty *hexnum    `json:"totalDifficulty"` |  | ||||||
| 			Size            *hexnum    `json:"size"` |  | ||||||
| 			ExtraData       *hexdata   `json:"extraData"` |  | ||||||
| 			GasLimit        *hexnum    `json:"gasLimit"` |  | ||||||
| 			GasUsed         *hexnum    `json:"gasUsed"` |  | ||||||
| 			UnixTimestamp   *hexnum    `json:"timestamp"` |  | ||||||
| 			Transactions    []*hexdata `json:"transactions"` |  | ||||||
| 			Uncles          []*hexdata `json:"uncles"` |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		ext.BlockNumber = b.BlockNumber |  | ||||||
| 		ext.BlockHash = b.BlockHash |  | ||||||
| 		ext.ParentHash = b.ParentHash |  | ||||||
| 		ext.Nonce = b.Nonce |  | ||||||
| 		ext.Sha3Uncles = b.Sha3Uncles |  | ||||||
| 		ext.LogsBloom = b.LogsBloom |  | ||||||
| 		ext.TransactionRoot = b.TransactionRoot |  | ||||||
| 		ext.StateRoot = b.StateRoot |  | ||||||
| 		ext.ReceiptRoot = b.ReceiptRoot |  | ||||||
| 		ext.Miner = b.Miner |  | ||||||
| 		ext.Difficulty = b.Difficulty |  | ||||||
| 		ext.TotalDifficulty = b.TotalDifficulty |  | ||||||
| 		ext.Size = b.Size |  | ||||||
| 		ext.ExtraData = b.ExtraData |  | ||||||
| 		ext.GasLimit = b.GasLimit |  | ||||||
| 		ext.GasUsed = b.GasUsed |  | ||||||
| 		ext.UnixTimestamp = b.UnixTimestamp |  | ||||||
| 		ext.Transactions = make([]*hexdata, len(b.Transactions)) |  | ||||||
| 		for i, tx := range b.Transactions { |  | ||||||
| 			ext.Transactions[i] = tx.Hash |  | ||||||
| 		} |  | ||||||
| 		ext.Uncles = make([]*hexdata, len(b.Uncles)) |  | ||||||
| 		for i, u := range b.Uncles { |  | ||||||
| 			ext.Uncles[i] = u.BlockHash |  | ||||||
| 		} |  | ||||||
| 		return json.Marshal(ext) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewBlockRes(block *types.Block, td *big.Int, fullTx bool) *BlockRes { |  | ||||||
| 	if block == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	res := new(BlockRes) |  | ||||||
| 	res.fullTx = fullTx |  | ||||||
| 	res.BlockNumber = newHexNum(block.Number()) |  | ||||||
| 	res.BlockHash = newHexData(block.Hash()) |  | ||||||
| 	res.ParentHash = newHexData(block.ParentHash()) |  | ||||||
| 	res.Nonce = newHexData(block.Nonce()) |  | ||||||
| 	res.Sha3Uncles = newHexData(block.UncleHash()) |  | ||||||
| 	res.LogsBloom = newHexData(block.Bloom()) |  | ||||||
| 	res.TransactionRoot = newHexData(block.TxHash()) |  | ||||||
| 	res.StateRoot = newHexData(block.Root()) |  | ||||||
| 	res.ReceiptRoot = newHexData(block.ReceiptHash()) |  | ||||||
| 	res.Miner = newHexData(block.Coinbase()) |  | ||||||
| 	res.Difficulty = newHexNum(block.Difficulty()) |  | ||||||
| 	res.TotalDifficulty = newHexNum(td) |  | ||||||
| 	res.Size = newHexNum(block.Size().Int64()) |  | ||||||
| 	res.ExtraData = newHexData(block.Extra()) |  | ||||||
| 	res.GasLimit = newHexNum(block.GasLimit()) |  | ||||||
| 	res.GasUsed = newHexNum(block.GasUsed()) |  | ||||||
| 	res.UnixTimestamp = newHexNum(block.Time()) |  | ||||||
|  |  | ||||||
| 	txs := block.Transactions() |  | ||||||
| 	res.Transactions = make([]*TransactionRes, len(txs)) |  | ||||||
| 	for i, tx := range txs { |  | ||||||
| 		res.Transactions[i] = NewTransactionRes(tx) |  | ||||||
| 		res.Transactions[i].BlockHash = res.BlockHash |  | ||||||
| 		res.Transactions[i].BlockNumber = res.BlockNumber |  | ||||||
| 		res.Transactions[i].TxIndex = newHexNum(i) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	uncles := block.Uncles() |  | ||||||
| 	res.Uncles = make([]*UncleRes, len(uncles)) |  | ||||||
| 	for i, uncle := range uncles { |  | ||||||
| 		res.Uncles[i] = NewUncleRes(uncle) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return res |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type TransactionRes struct { |  | ||||||
| 	Hash        *hexdata `json:"hash"` |  | ||||||
| 	Nonce       *hexnum  `json:"nonce"` |  | ||||||
| 	BlockHash   *hexdata `json:"blockHash"` |  | ||||||
| 	BlockNumber *hexnum  `json:"blockNumber"` |  | ||||||
| 	TxIndex     *hexnum  `json:"transactionIndex"` |  | ||||||
| 	From        *hexdata `json:"from"` |  | ||||||
| 	To          *hexdata `json:"to"` |  | ||||||
| 	Value       *hexnum  `json:"value"` |  | ||||||
| 	Gas         *hexnum  `json:"gas"` |  | ||||||
| 	GasPrice    *hexnum  `json:"gasPrice"` |  | ||||||
| 	Input       *hexdata `json:"input"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewTransactionRes(tx *types.Transaction) *TransactionRes { |  | ||||||
| 	if tx == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var v = new(TransactionRes) |  | ||||||
| 	v.Hash = newHexData(tx.Hash()) |  | ||||||
| 	v.Nonce = newHexNum(tx.Nonce()) |  | ||||||
| 	// v.BlockHash = |  | ||||||
| 	// v.BlockNumber = |  | ||||||
| 	// v.TxIndex = |  | ||||||
| 	from, _ := tx.From() |  | ||||||
| 	v.From = newHexData(from) |  | ||||||
| 	v.To = newHexData(tx.To()) |  | ||||||
| 	v.Value = newHexNum(tx.Value()) |  | ||||||
| 	v.Gas = newHexNum(tx.Gas()) |  | ||||||
| 	v.GasPrice = newHexNum(tx.GasPrice()) |  | ||||||
| 	v.Input = newHexData(tx.Data()) |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type UncleRes struct { |  | ||||||
| 	BlockNumber     *hexnum  `json:"number"` |  | ||||||
| 	BlockHash       *hexdata `json:"hash"` |  | ||||||
| 	ParentHash      *hexdata `json:"parentHash"` |  | ||||||
| 	Nonce           *hexdata `json:"nonce"` |  | ||||||
| 	Sha3Uncles      *hexdata `json:"sha3Uncles"` |  | ||||||
| 	ReceiptHash     *hexdata `json:"receiptHash"` |  | ||||||
| 	LogsBloom       *hexdata `json:"logsBloom"` |  | ||||||
| 	TransactionRoot *hexdata `json:"transactionsRoot"` |  | ||||||
| 	StateRoot       *hexdata `json:"stateRoot"` |  | ||||||
| 	Miner           *hexdata `json:"miner"` |  | ||||||
| 	Difficulty      *hexnum  `json:"difficulty"` |  | ||||||
| 	ExtraData       *hexdata `json:"extraData"` |  | ||||||
| 	GasLimit        *hexnum  `json:"gasLimit"` |  | ||||||
| 	GasUsed         *hexnum  `json:"gasUsed"` |  | ||||||
| 	UnixTimestamp   *hexnum  `json:"timestamp"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewUncleRes(h *types.Header) *UncleRes { |  | ||||||
| 	if h == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var v = new(UncleRes) |  | ||||||
| 	v.BlockNumber = newHexNum(h.Number) |  | ||||||
| 	v.BlockHash = newHexData(h.Hash()) |  | ||||||
| 	v.ParentHash = newHexData(h.ParentHash) |  | ||||||
| 	v.Sha3Uncles = newHexData(h.UncleHash) |  | ||||||
| 	v.Nonce = newHexData(h.Nonce[:]) |  | ||||||
| 	v.LogsBloom = newHexData(h.Bloom) |  | ||||||
| 	v.TransactionRoot = newHexData(h.TxHash) |  | ||||||
| 	v.StateRoot = newHexData(h.Root) |  | ||||||
| 	v.Miner = newHexData(h.Coinbase) |  | ||||||
| 	v.Difficulty = newHexNum(h.Difficulty) |  | ||||||
| 	v.ExtraData = newHexData(h.Extra) |  | ||||||
| 	v.GasLimit = newHexNum(h.GasLimit) |  | ||||||
| 	v.GasUsed = newHexNum(h.GasUsed) |  | ||||||
| 	v.UnixTimestamp = newHexNum(h.Time) |  | ||||||
| 	v.ReceiptHash = newHexData(h.ReceiptHash) |  | ||||||
|  |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // type FilterLogRes struct { |  | ||||||
| // 	Hash             string `json:"hash"` |  | ||||||
| // 	Address          string `json:"address"` |  | ||||||
| // 	Data             string `json:"data"` |  | ||||||
| // 	BlockNumber      string `json:"blockNumber"` |  | ||||||
| // 	TransactionHash  string `json:"transactionHash"` |  | ||||||
| // 	BlockHash        string `json:"blockHash"` |  | ||||||
| // 	TransactionIndex string `json:"transactionIndex"` |  | ||||||
| // 	LogIndex         string `json:"logIndex"` |  | ||||||
| // } |  | ||||||
|  |  | ||||||
| // type FilterWhisperRes struct { |  | ||||||
| // 	Hash       string `json:"hash"` |  | ||||||
| // 	From       string `json:"from"` |  | ||||||
| // 	To         string `json:"to"` |  | ||||||
| // 	Expiry     string `json:"expiry"` |  | ||||||
| // 	Sent       string `json:"sent"` |  | ||||||
| // 	Ttl        string `json:"ttl"` |  | ||||||
| // 	Topics     string `json:"topics"` |  | ||||||
| // 	Payload    string `json:"payload"` |  | ||||||
| // 	WorkProved string `json:"workProved"` |  | ||||||
| // } |  | ||||||
|  |  | ||||||
| type ReceiptRes struct { |  | ||||||
| 	TransactionHash   *hexdata       `json:"transactionHash"` |  | ||||||
| 	TransactionIndex  *hexnum        `json:"transactionIndex"` |  | ||||||
| 	BlockNumber       *hexnum        `json:"blockNumber"` |  | ||||||
| 	BlockHash         *hexdata       `json:"blockHash"` |  | ||||||
| 	CumulativeGasUsed *hexnum        `json:"cumulativeGasUsed"` |  | ||||||
| 	GasUsed           *hexnum        `json:"gasUsed"` |  | ||||||
| 	ContractAddress   *hexdata       `json:"contractAddress"` |  | ||||||
| 	Logs              *[]interface{} `json:"logs"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewReceiptRes(rec *types.Receipt) *ReceiptRes { |  | ||||||
| 	if rec == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var v = new(ReceiptRes) |  | ||||||
| 	v.TransactionHash = newHexData(rec.TxHash) |  | ||||||
| 	if rec.GasUsed != nil { |  | ||||||
| 		v.GasUsed = newHexNum(rec.GasUsed.Bytes()) |  | ||||||
| 	} |  | ||||||
| 	v.CumulativeGasUsed = newHexNum(rec.CumulativeGasUsed) |  | ||||||
|  |  | ||||||
| 	// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation |  | ||||||
| 	if bytes.Compare(rec.ContractAddress.Bytes(), bytes.Repeat([]byte{0}, 20)) != 0 { |  | ||||||
| 		v.ContractAddress = newHexData(rec.ContractAddress) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	logs := make([]interface{}, len(rec.Logs)) |  | ||||||
| 	for i, log := range rec.Logs { |  | ||||||
| 		logs[i] = NewLogRes(log) |  | ||||||
| 	} |  | ||||||
| 	v.Logs = &logs |  | ||||||
|  |  | ||||||
| 	return v |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func numString(raw interface{}) (*big.Int, error) { |  | ||||||
| 	var number *big.Int |  | ||||||
| 	// Parse as integer |  | ||||||
| 	num, ok := raw.(float64) |  | ||||||
| 	if ok { |  | ||||||
| 		number = big.NewInt(int64(num)) |  | ||||||
| 		return number, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Parse as string/hexstring |  | ||||||
| 	str, ok := raw.(string) |  | ||||||
| 	if ok { |  | ||||||
| 		number = common.String2Big(str) |  | ||||||
| 		return number, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, shared.NewInvalidTypeError("", "not a number or string") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func blockHeight(raw interface{}, number *int64) error { |  | ||||||
| 	// Parse as integer |  | ||||||
| 	num, ok := raw.(float64) |  | ||||||
| 	if ok { |  | ||||||
| 		*number = int64(num) |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Parse as string/hexstring |  | ||||||
| 	str, ok := raw.(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("", "not a number or string") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	switch str { |  | ||||||
| 	case "earliest": |  | ||||||
| 		*number = 0 |  | ||||||
| 	case "latest": |  | ||||||
| 		*number = -1 |  | ||||||
| 	case "pending": |  | ||||||
| 		*number = -2 |  | ||||||
| 	default: |  | ||||||
| 		if common.HasHexPrefix(str) { |  | ||||||
| 			*number = common.String2Big(str).Int64() |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("blockNumber", "is not a valid string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func blockHeightFromJson(msg json.RawMessage, number *int64) error { |  | ||||||
| 	var raw interface{} |  | ||||||
| 	if err := json.Unmarshal(msg, &raw); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	return blockHeight(raw, number) |  | ||||||
| } |  | ||||||
| @@ -1,139 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	PersonalApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	personalMapping = map[string]personalhandler{ |  | ||||||
| 		"personal_listAccounts":  (*personalApi).ListAccounts, |  | ||||||
| 		"personal_newAccount":    (*personalApi).NewAccount, |  | ||||||
| 		"personal_unlockAccount": (*personalApi).UnlockAccount, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // net callback handler |  | ||||||
| type personalhandler func(*personalApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // net api provider |  | ||||||
| type personalApi struct { |  | ||||||
| 	xeth     *xeth.XEth |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	methods  map[string]personalhandler |  | ||||||
| 	codec    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new net api instance |  | ||||||
| func NewPersonalApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *personalApi { |  | ||||||
| 	return &personalApi{ |  | ||||||
| 		xeth:     xeth, |  | ||||||
| 		ethereum: eth, |  | ||||||
| 		methods:  personalMapping, |  | ||||||
| 		codec:    coder.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *personalApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *personalApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, shared.NewNotImplementedError(req.Method) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *personalApi) Name() string { |  | ||||||
| 	return shared.PersonalApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *personalApi) ApiVersion() string { |  | ||||||
| 	return PersonalApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *personalApi) ListAccounts(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.xeth.Accounts(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *personalApi) NewAccount(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(NewAccountArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	var passwd string |  | ||||||
| 	if args.Passphrase == nil { |  | ||||||
| 		fe := self.xeth.Frontend() |  | ||||||
| 		if fe == nil { |  | ||||||
| 			return false, fmt.Errorf("unable to create account: unable to interact with user") |  | ||||||
| 		} |  | ||||||
| 		var ok bool |  | ||||||
| 		passwd, ok = fe.AskPassword() |  | ||||||
| 		if !ok { |  | ||||||
| 			return false, fmt.Errorf("unable to create account: no password given") |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		passwd = *args.Passphrase |  | ||||||
| 	} |  | ||||||
| 	am := self.ethereum.AccountManager() |  | ||||||
| 	acc, err := am.NewAccount(passwd) |  | ||||||
| 	return acc.Address.Hex(), err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *personalApi) UnlockAccount(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(UnlockAccountArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if args.Passphrase == nil { |  | ||||||
| 		fe := self.xeth.Frontend() |  | ||||||
| 		if fe == nil { |  | ||||||
| 			return false, fmt.Errorf("No password provided") |  | ||||||
| 		} |  | ||||||
| 		return fe.UnlockAccount(common.HexToAddress(args.Address).Bytes()), nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	am := self.ethereum.AccountManager() |  | ||||||
| 	addr := common.HexToAddress(args.Address) |  | ||||||
|  |  | ||||||
| 	err := am.TimedUnlock(addr, *args.Passphrase, time.Duration(args.Duration)*time.Second) |  | ||||||
| 	return err == nil, err |  | ||||||
| } |  | ||||||
| @@ -1,85 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type NewAccountArgs struct { |  | ||||||
| 	Passphrase *string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *NewAccountArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 1 && obj[0] != nil { |  | ||||||
| 		if passphrasestr, ok := obj[0].(string); ok { |  | ||||||
| 			args.Passphrase = &passphrasestr |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("passphrase", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type UnlockAccountArgs struct { |  | ||||||
| 	Address    string |  | ||||||
| 	Passphrase *string |  | ||||||
| 	Duration   int |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *UnlockAccountArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	args.Duration = 0 |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if addrstr, ok := obj[0].(string); ok { |  | ||||||
| 		args.Address = addrstr |  | ||||||
| 	} else { |  | ||||||
| 		return shared.NewInvalidTypeError("address", "not a string") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 2 && obj[1] != nil { |  | ||||||
| 		if passphrasestr, ok := obj[1].(string); ok { |  | ||||||
| 			args.Passphrase = &passphrasestr |  | ||||||
| 		} else { |  | ||||||
| 			return shared.NewInvalidTypeError("passphrase", "not a string") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) >= 3 && obj[2] != nil { |  | ||||||
| 		if duration, ok := obj[2].(float64); ok { |  | ||||||
| 			args.Duration = int(duration) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,51 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| const Personal_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'personal', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'newAccount', |  | ||||||
| 			call: 'personal_newAccount', |  | ||||||
| 			params: 1, |  | ||||||
| 			inputFormatter: [null], |  | ||||||
| 			outputFormatter: web3._extend.utils.toAddress |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'unlockAccount', |  | ||||||
| 			call: 'personal_unlockAccount', |  | ||||||
| 			params: 3, |  | ||||||
| 			inputFormatter: [null, null, null] |  | ||||||
| 		}), |  | ||||||
| 		new web3._extend.Method({ |  | ||||||
| 			name: 'lockAccount', |  | ||||||
| 			call: 'personal_lockAccount', |  | ||||||
| 			params: 1 |  | ||||||
| 		}) |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'listAccounts', |  | ||||||
| 			getter: 'personal_listAccounts' |  | ||||||
| 		}) |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
							
								
								
									
										196
									
								
								rpc/api/shh.go
									
									
									
									
									
								
							
							
						
						
									
										196
									
								
								rpc/api/shh.go
									
									
									
									
									
								
							| @@ -1,196 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"math/big" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	ShhApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	shhMapping = map[string]shhhandler{ |  | ||||||
| 		"shh_version":          (*shhApi).Version, |  | ||||||
| 		"shh_post":             (*shhApi).Post, |  | ||||||
| 		"shh_hasIdentity":      (*shhApi).HasIdentity, |  | ||||||
| 		"shh_newIdentity":      (*shhApi).NewIdentity, |  | ||||||
| 		"shh_newFilter":        (*shhApi).NewFilter, |  | ||||||
| 		"shh_uninstallFilter":  (*shhApi).UninstallFilter, |  | ||||||
| 		"shh_getMessages":      (*shhApi).GetMessages, |  | ||||||
| 		"shh_getFilterChanges": (*shhApi).GetFilterChanges, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func newWhisperOfflineError(method string) error { |  | ||||||
| 	return shared.NewNotAvailableError(method, "whisper offline") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // net callback handler |  | ||||||
| type shhhandler func(*shhApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // shh api provider |  | ||||||
| type shhApi struct { |  | ||||||
| 	xeth     *xeth.XEth |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	methods  map[string]shhhandler |  | ||||||
| 	codec    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new whisper api instance |  | ||||||
| func NewShhApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *shhApi { |  | ||||||
| 	return &shhApi{ |  | ||||||
| 		xeth:     xeth, |  | ||||||
| 		ethereum: eth, |  | ||||||
| 		methods:  shhMapping, |  | ||||||
| 		codec:    coder.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *shhApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *shhApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, shared.NewNotImplementedError(req.Method) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) Name() string { |  | ||||||
| 	return shared.ShhApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) ApiVersion() string { |  | ||||||
| 	return ShhApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) Version(req *shared.Request) (interface{}, error) { |  | ||||||
| 	w := self.xeth.Whisper() |  | ||||||
| 	if w == nil { |  | ||||||
| 		return nil, newWhisperOfflineError(req.Method) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return w.Version(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) Post(req *shared.Request) (interface{}, error) { |  | ||||||
| 	w := self.xeth.Whisper() |  | ||||||
| 	if w == nil { |  | ||||||
| 		return nil, newWhisperOfflineError(req.Method) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	args := new(WhisperMessageArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err := w.Post(args.Payload, args.To, args.From, args.Topics, args.Priority, args.Ttl) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) HasIdentity(req *shared.Request) (interface{}, error) { |  | ||||||
| 	w := self.xeth.Whisper() |  | ||||||
| 	if w == nil { |  | ||||||
| 		return nil, newWhisperOfflineError(req.Method) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	args := new(WhisperIdentityArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return w.HasIdentity(args.Identity), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) NewIdentity(req *shared.Request) (interface{}, error) { |  | ||||||
| 	w := self.xeth.Whisper() |  | ||||||
| 	if w == nil { |  | ||||||
| 		return nil, newWhisperOfflineError(req.Method) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return w.NewIdentity(), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) NewFilter(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(WhisperFilterArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	id := self.xeth.NewWhisperFilter(args.To, args.From, args.Topics) |  | ||||||
| 	return newHexNum(big.NewInt(int64(id)).Bytes()), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) UninstallFilter(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(FilterIdArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return self.xeth.UninstallWhisperFilter(args.Id), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) GetFilterChanges(req *shared.Request) (interface{}, error) { |  | ||||||
| 	w := self.xeth.Whisper() |  | ||||||
| 	if w == nil { |  | ||||||
| 		return nil, newWhisperOfflineError(req.Method) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Retrieve all the new messages arrived since the last request |  | ||||||
| 	args := new(FilterIdArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return self.xeth.WhisperMessagesChanged(args.Id), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *shhApi) GetMessages(req *shared.Request) (interface{}, error) { |  | ||||||
| 	w := self.xeth.Whisper() |  | ||||||
| 	if w == nil { |  | ||||||
| 		return nil, newWhisperOfflineError(req.Method) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Retrieve all the cached messages matching a specific, existing filter |  | ||||||
| 	args := new(FilterIdArgs) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return self.xeth.WhisperMessages(args.Id), nil |  | ||||||
| } |  | ||||||
| @@ -1,174 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"math/big" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type WhisperMessageArgs struct { |  | ||||||
| 	Payload  string |  | ||||||
| 	To       string |  | ||||||
| 	From     string |  | ||||||
| 	Topics   []string |  | ||||||
| 	Priority uint32 |  | ||||||
| 	Ttl      uint32 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *WhisperMessageArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []struct { |  | ||||||
| 		Payload  string |  | ||||||
| 		To       string |  | ||||||
| 		From     string |  | ||||||
| 		Topics   []string |  | ||||||
| 		Priority interface{} |  | ||||||
| 		Ttl      interface{} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err = json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
| 	args.Payload = obj[0].Payload |  | ||||||
| 	args.To = obj[0].To |  | ||||||
| 	args.From = obj[0].From |  | ||||||
| 	args.Topics = obj[0].Topics |  | ||||||
|  |  | ||||||
| 	var num *big.Int |  | ||||||
| 	if num, err = numString(obj[0].Priority); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	args.Priority = uint32(num.Int64()) |  | ||||||
|  |  | ||||||
| 	if num, err = numString(obj[0].Ttl); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	args.Ttl = uint32(num.Int64()) |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type WhisperIdentityArgs struct { |  | ||||||
| 	Identity string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (args *WhisperIdentityArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	var obj []interface{} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	argstr, ok := obj[0].(string) |  | ||||||
| 	if !ok { |  | ||||||
| 		return shared.NewInvalidTypeError("arg0", "not a string") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	args.Identity = argstr |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type WhisperFilterArgs struct { |  | ||||||
| 	To     string |  | ||||||
| 	From   string |  | ||||||
| 	Topics [][]string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a |  | ||||||
| // JSON message blob into a WhisperFilterArgs structure. |  | ||||||
| func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) { |  | ||||||
| 	// Unmarshal the JSON message and sanity check |  | ||||||
| 	var obj []struct { |  | ||||||
| 		To     interface{} `json:"to"` |  | ||||||
| 		From   interface{} `json:"from"` |  | ||||||
| 		Topics interface{} `json:"topics"` |  | ||||||
| 	} |  | ||||||
| 	if err := json.Unmarshal(b, &obj); err != nil { |  | ||||||
| 		return shared.NewDecodeParamError(err.Error()) |  | ||||||
| 	} |  | ||||||
| 	if len(obj) < 1 { |  | ||||||
| 		return shared.NewInsufficientParamsError(len(obj), 1) |  | ||||||
| 	} |  | ||||||
| 	// Retrieve the simple data contents of the filter arguments |  | ||||||
| 	if obj[0].To == nil { |  | ||||||
| 		args.To = "" |  | ||||||
| 	} else { |  | ||||||
| 		argstr, ok := obj[0].To.(string) |  | ||||||
| 		if !ok { |  | ||||||
| 			return shared.NewInvalidTypeError("to", "is not a string") |  | ||||||
| 		} |  | ||||||
| 		args.To = argstr |  | ||||||
| 	} |  | ||||||
| 	if obj[0].From == nil { |  | ||||||
| 		args.From = "" |  | ||||||
| 	} else { |  | ||||||
| 		argstr, ok := obj[0].From.(string) |  | ||||||
| 		if !ok { |  | ||||||
| 			return shared.NewInvalidTypeError("from", "is not a string") |  | ||||||
| 		} |  | ||||||
| 		args.From = argstr |  | ||||||
| 	} |  | ||||||
| 	// Construct the nested topic array |  | ||||||
| 	if obj[0].Topics != nil { |  | ||||||
| 		// Make sure we have an actual topic array |  | ||||||
| 		list, ok := obj[0].Topics.([]interface{}) |  | ||||||
| 		if !ok { |  | ||||||
| 			return shared.NewInvalidTypeError("topics", "is not an array") |  | ||||||
| 		} |  | ||||||
| 		// Iterate over each topic and handle nil, string or array |  | ||||||
| 		topics := make([][]string, len(list)) |  | ||||||
| 		for idx, field := range list { |  | ||||||
| 			switch value := field.(type) { |  | ||||||
| 			case nil: |  | ||||||
| 				topics[idx] = []string{} |  | ||||||
|  |  | ||||||
| 			case string: |  | ||||||
| 				topics[idx] = []string{value} |  | ||||||
|  |  | ||||||
| 			case []interface{}: |  | ||||||
| 				topics[idx] = make([]string, len(value)) |  | ||||||
| 				for i, nested := range value { |  | ||||||
| 					switch value := nested.(type) { |  | ||||||
| 					case nil: |  | ||||||
| 						topics[idx][i] = "" |  | ||||||
|  |  | ||||||
| 					case string: |  | ||||||
| 						topics[idx][i] = value |  | ||||||
|  |  | ||||||
| 					default: |  | ||||||
| 						return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d][%d]", idx, i), "is not a string") |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			default: |  | ||||||
| 				return shared.NewInvalidTypeError(fmt.Sprintf("topic[%d]", idx), "not a string or array") |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		args.Topics = topics |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| const Shh_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'shh', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
|  |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'version', |  | ||||||
| 			getter: 'shh_version' |  | ||||||
| 		}) |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
| @@ -1,92 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	TxPoolApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	txpoolMapping = map[string]txpoolhandler{ |  | ||||||
| 		"txpool_status": (*txPoolApi).Status, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // net callback handler |  | ||||||
| type txpoolhandler func(*txPoolApi, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // txpool api provider |  | ||||||
| type txPoolApi struct { |  | ||||||
| 	xeth     *xeth.XEth |  | ||||||
| 	ethereum *eth.Ethereum |  | ||||||
| 	methods  map[string]txpoolhandler |  | ||||||
| 	codec    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new txpool api instance |  | ||||||
| func NewTxPoolApi(xeth *xeth.XEth, eth *eth.Ethereum, coder codec.Codec) *txPoolApi { |  | ||||||
| 	return &txPoolApi{ |  | ||||||
| 		xeth:     xeth, |  | ||||||
| 		ethereum: eth, |  | ||||||
| 		methods:  txpoolMapping, |  | ||||||
| 		codec:    coder.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *txPoolApi) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *txPoolApi) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, shared.NewNotImplementedError(req.Method) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *txPoolApi) Name() string { |  | ||||||
| 	return shared.TxPoolApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *txPoolApi) ApiVersion() string { |  | ||||||
| 	return TxPoolApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *txPoolApi) Status(req *shared.Request) (interface{}, error) { |  | ||||||
| 	pending, queue := self.ethereum.TxPool().Stats() |  | ||||||
| 	return map[string]int{ |  | ||||||
| 		"pending": pending, |  | ||||||
| 		"queued":  queue, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| const TxPool_JS = ` |  | ||||||
| web3._extend({ |  | ||||||
| 	property: 'txpool', |  | ||||||
| 	methods: |  | ||||||
| 	[ |  | ||||||
| 	], |  | ||||||
| 	properties: |  | ||||||
| 	[ |  | ||||||
| 		new web3._extend.Property({ |  | ||||||
| 			name: 'status', |  | ||||||
| 			getter: 'txpool_status' |  | ||||||
| 		}) |  | ||||||
| 	] |  | ||||||
| }); |  | ||||||
| ` |  | ||||||
							
								
								
									
										226
									
								
								rpc/api/utils.go
									
									
									
									
									
								
							
							
						
						
									
										226
									
								
								rpc/api/utils.go
									
									
									
									
									
								
							| @@ -1,226 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"fmt" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/eth" |  | ||||||
| 	"github.com/ethereum/go-ethereum/node" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// Mapping between the different methods each api supports |  | ||||||
| 	AutoCompletion = map[string][]string{ |  | ||||||
| 		"admin": []string{ |  | ||||||
| 			"addPeer", |  | ||||||
| 			"datadir", |  | ||||||
| 			"enableUserAgent", |  | ||||||
| 			"exportChain", |  | ||||||
| 			"getContractInfo", |  | ||||||
| 			"httpGet", |  | ||||||
| 			"importChain", |  | ||||||
| 			"nodeInfo", |  | ||||||
| 			"peers", |  | ||||||
| 			"register", |  | ||||||
| 			"registerUrl", |  | ||||||
| 			"saveInfo", |  | ||||||
| 			"setGlobalRegistrar", |  | ||||||
| 			"setHashReg", |  | ||||||
| 			"setUrlHint", |  | ||||||
| 			"setSolc", |  | ||||||
| 			"sleep", |  | ||||||
| 			"sleepBlocks", |  | ||||||
| 			"startNatSpec", |  | ||||||
| 			"startRPC", |  | ||||||
| 			"stopNatSpec", |  | ||||||
| 			"stopRPC", |  | ||||||
| 			"verbosity", |  | ||||||
| 		}, |  | ||||||
| 		"db": []string{ |  | ||||||
| 			"getString", |  | ||||||
| 			"putString", |  | ||||||
| 			"getHex", |  | ||||||
| 			"putHex", |  | ||||||
| 		}, |  | ||||||
| 		"debug": []string{ |  | ||||||
| 			"dumpBlock", |  | ||||||
| 			"getBlockRlp", |  | ||||||
| 			"metrics", |  | ||||||
| 			"printBlock", |  | ||||||
| 			"processBlock", |  | ||||||
| 			"seedHash", |  | ||||||
| 			"setHead", |  | ||||||
| 		}, |  | ||||||
| 		"eth": []string{ |  | ||||||
| 			"accounts", |  | ||||||
| 			"blockNumber", |  | ||||||
| 			"call", |  | ||||||
| 			"contract", |  | ||||||
| 			"coinbase", |  | ||||||
| 			"compile.lll", |  | ||||||
| 			"compile.serpent", |  | ||||||
| 			"compile.solidity", |  | ||||||
| 			"contract", |  | ||||||
| 			"defaultAccount", |  | ||||||
| 			"defaultBlock", |  | ||||||
| 			"estimateGas", |  | ||||||
| 			"filter", |  | ||||||
| 			"getBalance", |  | ||||||
| 			"getBlock", |  | ||||||
| 			"getBlockTransactionCount", |  | ||||||
| 			"getBlockUncleCount", |  | ||||||
| 			"getCode", |  | ||||||
| 			"getNatSpec", |  | ||||||
| 			"getCompilers", |  | ||||||
| 			"gasPrice", |  | ||||||
| 			"getStorageAt", |  | ||||||
| 			"getTransaction", |  | ||||||
| 			"getTransactionCount", |  | ||||||
| 			"getTransactionFromBlock", |  | ||||||
| 			"getTransactionReceipt", |  | ||||||
| 			"getUncle", |  | ||||||
| 			"hashrate", |  | ||||||
| 			"mining", |  | ||||||
| 			"namereg", |  | ||||||
| 			"pendingTransactions", |  | ||||||
| 			"resend", |  | ||||||
| 			"sendRawTransaction", |  | ||||||
| 			"sendTransaction", |  | ||||||
| 			"sign", |  | ||||||
| 			"syncing", |  | ||||||
| 		}, |  | ||||||
| 		"miner": []string{ |  | ||||||
| 			"hashrate", |  | ||||||
| 			"makeDAG", |  | ||||||
| 			"setEtherbase", |  | ||||||
| 			"setExtra", |  | ||||||
| 			"setGasPrice", |  | ||||||
| 			"startAutoDAG", |  | ||||||
| 			"start", |  | ||||||
| 			"stopAutoDAG", |  | ||||||
| 			"stop", |  | ||||||
| 		}, |  | ||||||
| 		"net": []string{ |  | ||||||
| 			"peerCount", |  | ||||||
| 			"listening", |  | ||||||
| 		}, |  | ||||||
| 		"personal": []string{ |  | ||||||
| 			"listAccounts", |  | ||||||
| 			"newAccount", |  | ||||||
| 			"unlockAccount", |  | ||||||
| 		}, |  | ||||||
| 		"shh": []string{ |  | ||||||
| 			"post", |  | ||||||
| 			"newIdentity", |  | ||||||
| 			"hasIdentity", |  | ||||||
| 			"newGroup", |  | ||||||
| 			"addToGroup", |  | ||||||
| 			"filter", |  | ||||||
| 		}, |  | ||||||
| 		"txpool": []string{ |  | ||||||
| 			"status", |  | ||||||
| 		}, |  | ||||||
| 		"web3": []string{ |  | ||||||
| 			"sha3", |  | ||||||
| 			"version", |  | ||||||
| 			"fromWei", |  | ||||||
| 			"toWei", |  | ||||||
| 			"toHex", |  | ||||||
| 			"toAscii", |  | ||||||
| 			"fromAscii", |  | ||||||
| 			"toBigNumber", |  | ||||||
| 			"isAddress", |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Parse a comma separated API string to individual api's |  | ||||||
| func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, stack *node.Node) ([]shared.EthereumApi, error) { |  | ||||||
| 	if len(strings.TrimSpace(apistr)) == 0 { |  | ||||||
| 		return nil, fmt.Errorf("Empty apistr provided") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	names := strings.Split(apistr, ",") |  | ||||||
| 	apis := make([]shared.EthereumApi, len(names)) |  | ||||||
|  |  | ||||||
| 	var eth *eth.Ethereum |  | ||||||
| 	if stack != nil { |  | ||||||
| 		if err := stack.Service(ð); err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	for i, name := range names { |  | ||||||
| 		switch strings.ToLower(strings.TrimSpace(name)) { |  | ||||||
| 		case shared.AdminApiName: |  | ||||||
| 			apis[i] = NewAdminApi(xeth, stack, codec) |  | ||||||
| 		case shared.DebugApiName: |  | ||||||
| 			apis[i] = NewDebugApi(xeth, eth, codec) |  | ||||||
| 		case shared.DbApiName: |  | ||||||
| 			apis[i] = NewDbApi(xeth, eth, codec) |  | ||||||
| 		case shared.EthApiName: |  | ||||||
| 			apis[i] = NewEthApi(xeth, eth, codec) |  | ||||||
| 		case shared.MinerApiName: |  | ||||||
| 			apis[i] = NewMinerApi(eth, codec) |  | ||||||
| 		case shared.NetApiName: |  | ||||||
| 			apis[i] = NewNetApi(xeth, eth, codec) |  | ||||||
| 		case shared.ShhApiName: |  | ||||||
| 			apis[i] = NewShhApi(xeth, eth, codec) |  | ||||||
| 		case shared.TxPoolApiName: |  | ||||||
| 			apis[i] = NewTxPoolApi(xeth, eth, codec) |  | ||||||
| 		case shared.PersonalApiName: |  | ||||||
| 			apis[i] = NewPersonalApi(xeth, eth, codec) |  | ||||||
| 		case shared.Web3ApiName: |  | ||||||
| 			apis[i] = NewWeb3Api(xeth, codec) |  | ||||||
| 		case "rpc": // gives information about the RPC interface |  | ||||||
| 			continue |  | ||||||
| 		default: |  | ||||||
| 			return nil, fmt.Errorf("Unknown API '%s'", name) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return apis, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func Javascript(name string) string { |  | ||||||
| 	switch strings.ToLower(strings.TrimSpace(name)) { |  | ||||||
| 	case shared.AdminApiName: |  | ||||||
| 		return Admin_JS |  | ||||||
| 	case shared.DebugApiName: |  | ||||||
| 		return Debug_JS |  | ||||||
| 	case shared.DbApiName: |  | ||||||
| 		return Db_JS |  | ||||||
| 	case shared.EthApiName: |  | ||||||
| 		return Eth_JS |  | ||||||
| 	case shared.MinerApiName: |  | ||||||
| 		return Miner_JS |  | ||||||
| 	case shared.NetApiName: |  | ||||||
| 		return Net_JS |  | ||||||
| 	case shared.ShhApiName: |  | ||||||
| 		return Shh_JS |  | ||||||
| 	case shared.TxPoolApiName: |  | ||||||
| 		return TxPool_JS |  | ||||||
| 	case shared.PersonalApiName: |  | ||||||
| 		return Personal_JS |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
| @@ -1,99 +0,0 @@ | |||||||
| // 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 api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/ethereum/go-ethereum/common" |  | ||||||
| 	"github.com/ethereum/go-ethereum/crypto" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/ethereum/go-ethereum/xeth" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	Web3ApiVersion = "1.0" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// mapping between methods and handlers |  | ||||||
| 	Web3Mapping = map[string]web3handler{ |  | ||||||
| 		"web3_sha3":          (*web3Api).Sha3, |  | ||||||
| 		"web3_clientVersion": (*web3Api).ClientVersion, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // web3 callback handler |  | ||||||
| type web3handler func(*web3Api, *shared.Request) (interface{}, error) |  | ||||||
|  |  | ||||||
| // web3 api provider |  | ||||||
| type web3Api struct { |  | ||||||
| 	xeth    *xeth.XEth |  | ||||||
| 	methods map[string]web3handler |  | ||||||
| 	codec   codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // create a new web3 api instance |  | ||||||
| func NewWeb3Api(xeth *xeth.XEth, coder codec.Codec) *web3Api { |  | ||||||
| 	return &web3Api{ |  | ||||||
| 		xeth:    xeth, |  | ||||||
| 		methods: Web3Mapping, |  | ||||||
| 		codec:   coder.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // collection with supported methods |  | ||||||
| func (self *web3Api) Methods() []string { |  | ||||||
| 	methods := make([]string, len(self.methods)) |  | ||||||
| 	i := 0 |  | ||||||
| 	for k := range self.methods { |  | ||||||
| 		methods[i] = k |  | ||||||
| 		i++ |  | ||||||
| 	} |  | ||||||
| 	return methods |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Execute given request |  | ||||||
| func (self *web3Api) Execute(req *shared.Request) (interface{}, error) { |  | ||||||
| 	if callback, ok := self.methods[req.Method]; ok { |  | ||||||
| 		return callback(self, req) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, &shared.NotImplementedError{req.Method} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *web3Api) Name() string { |  | ||||||
| 	return shared.Web3ApiName |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *web3Api) ApiVersion() string { |  | ||||||
| 	return Web3ApiVersion |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Calculates the sha3 over req.Params.Data |  | ||||||
| func (self *web3Api) Sha3(req *shared.Request) (interface{}, error) { |  | ||||||
| 	args := new(Sha3Args) |  | ||||||
| 	if err := self.codec.Decode(req.Params, &args); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return common.ToHex(crypto.Sha3(common.FromHex(args.Data))), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // returns the xeth client vrsion |  | ||||||
| func (self *web3Api) ClientVersion(req *shared.Request) (interface{}, error) { |  | ||||||
| 	return self.xeth.ClientVersion(), nil |  | ||||||
| } |  | ||||||
| @@ -1,65 +0,0 @@ | |||||||
| // 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 codec |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net" |  | ||||||
| 	"strconv" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type Codec int |  | ||||||
|  |  | ||||||
| // (de)serialization support for rpc interface |  | ||||||
| type ApiCoder interface { |  | ||||||
| 	// Parse message to request from underlying stream |  | ||||||
| 	ReadRequest() ([]*shared.Request, bool, error) |  | ||||||
| 	// Parse response message from underlying stream |  | ||||||
| 	ReadResponse() (interface{}, error) |  | ||||||
| 	// Read raw message from underlying stream |  | ||||||
| 	Recv() (interface{}, error) |  | ||||||
| 	// Encode response to encoded form in underlying stream |  | ||||||
| 	WriteResponse(interface{}) error |  | ||||||
| 	// Decode single message from data |  | ||||||
| 	Decode([]byte, interface{}) error |  | ||||||
| 	// Encode msg to encoded form |  | ||||||
| 	Encode(msg interface{}) ([]byte, error) |  | ||||||
| 	// close the underlying stream |  | ||||||
| 	Close() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // supported codecs |  | ||||||
| const ( |  | ||||||
| 	JSON Codec = iota |  | ||||||
| 	nCodecs |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// collection with supported coders |  | ||||||
| 	coders = make([]func(net.Conn) ApiCoder, nCodecs) |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // create a new coder instance |  | ||||||
| func (c Codec) New(conn net.Conn) ApiCoder { |  | ||||||
| 	switch c { |  | ||||||
| 	case JSON: |  | ||||||
| 		return NewJsonCoder(conn) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	panic("codec: request for codec #" + strconv.Itoa(int(c)) + " is unavailable") |  | ||||||
| } |  | ||||||
| @@ -1,149 +0,0 @@ | |||||||
| // 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 codec |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"net" |  | ||||||
| 	"time" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	READ_TIMEOUT      = 60 // in seconds |  | ||||||
| 	MAX_REQUEST_SIZE  = 1024 * 1024 |  | ||||||
| 	MAX_RESPONSE_SIZE = 1024 * 1024 |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Json serialization support |  | ||||||
| type JsonCodec struct { |  | ||||||
| 	c net.Conn |  | ||||||
| 	d *json.Decoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Create new JSON coder instance |  | ||||||
| func NewJsonCoder(conn net.Conn) ApiCoder { |  | ||||||
| 	return &JsonCodec{ |  | ||||||
| 		c: conn, |  | ||||||
| 		d: json.NewDecoder(conn), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Read incoming request and parse it to RPC request |  | ||||||
| func (self *JsonCodec) ReadRequest() (requests []*shared.Request, isBatch bool, err error) { |  | ||||||
| 	deadline := time.Now().Add(READ_TIMEOUT * time.Second) |  | ||||||
| 	if err := self.c.SetDeadline(deadline); err != nil { |  | ||||||
| 		return nil, false, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var incoming json.RawMessage |  | ||||||
| 	err = self.d.Decode(&incoming) |  | ||||||
| 	if err == nil { |  | ||||||
| 		isBatch = incoming[0] == '[' |  | ||||||
| 		if isBatch { |  | ||||||
| 			requests = make([]*shared.Request, 0) |  | ||||||
| 			err = json.Unmarshal(incoming, &requests) |  | ||||||
| 		} else { |  | ||||||
| 			requests = make([]*shared.Request, 1) |  | ||||||
| 			var singleRequest shared.Request |  | ||||||
| 			if err = json.Unmarshal(incoming, &singleRequest); err == nil { |  | ||||||
| 				requests[0] = &singleRequest |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	self.c.Close() |  | ||||||
| 	return nil, false, err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *JsonCodec) Recv() (interface{}, error) { |  | ||||||
| 	var msg json.RawMessage |  | ||||||
| 	err := self.d.Decode(&msg) |  | ||||||
| 	if err != nil { |  | ||||||
| 		self.c.Close() |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return msg, err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *JsonCodec) ReadResponse() (interface{}, error) { |  | ||||||
| 	in, err := self.Recv() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if msg, ok := in.(json.RawMessage); ok { |  | ||||||
| 		var req *shared.Request |  | ||||||
| 		if err = json.Unmarshal(msg, &req); err == nil && strings.HasPrefix(req.Method, "agent_") { |  | ||||||
| 			return req, nil |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		var failure *shared.ErrorResponse |  | ||||||
| 		if err = json.Unmarshal(msg, &failure); err == nil && failure.Error != nil { |  | ||||||
| 			return failure, fmt.Errorf(failure.Error.Message) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		var success *shared.SuccessResponse |  | ||||||
| 		if err = json.Unmarshal(msg, &success); err == nil { |  | ||||||
| 			return success, nil |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return in, err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Decode data |  | ||||||
| func (self *JsonCodec) Decode(data []byte, msg interface{}) error { |  | ||||||
| 	return json.Unmarshal(data, msg) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Encode message |  | ||||||
| func (self *JsonCodec) Encode(msg interface{}) ([]byte, error) { |  | ||||||
| 	return json.Marshal(msg) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Parse JSON data from conn to obj |  | ||||||
| func (self *JsonCodec) WriteResponse(res interface{}) error { |  | ||||||
| 	data, err := json.Marshal(res) |  | ||||||
| 	if err != nil { |  | ||||||
| 		self.c.Close() |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bytesWritten := 0 |  | ||||||
|  |  | ||||||
| 	for bytesWritten < len(data) { |  | ||||||
| 		n, err := self.c.Write(data[bytesWritten:]) |  | ||||||
| 		if err != nil { |  | ||||||
| 			self.c.Close() |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		bytesWritten += n |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Close decoder and encoder |  | ||||||
| func (self *JsonCodec) Close() { |  | ||||||
| 	self.c.Close() |  | ||||||
| } |  | ||||||
| @@ -1,157 +0,0 @@ | |||||||
| // 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 codec |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"io" |  | ||||||
| 	"net" |  | ||||||
| 	"testing" |  | ||||||
| 	"time" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type jsonTestConn struct { |  | ||||||
| 	buffer *bytes.Buffer |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newJsonTestConn(data []byte) *jsonTestConn { |  | ||||||
| 	return &jsonTestConn{ |  | ||||||
| 		buffer: bytes.NewBuffer(data), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *jsonTestConn) Read(p []byte) (n int, err error) { |  | ||||||
| 	return self.buffer.Read(p) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *jsonTestConn) Write(p []byte) (n int, err error) { |  | ||||||
| 	return self.buffer.Write(p) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *jsonTestConn) Close() error { |  | ||||||
| 	// not implemented |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *jsonTestConn) LocalAddr() net.Addr { |  | ||||||
| 	// not implemented |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *jsonTestConn) RemoteAddr() net.Addr { |  | ||||||
| 	// not implemented |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *jsonTestConn) SetDeadline(t time.Time) error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *jsonTestConn) SetReadDeadline(t time.Time) error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *jsonTestConn) SetWriteDeadline(t time.Time) error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestJsonDecoderWithValidRequest(t *testing.T) { |  | ||||||
| 	reqdata := []byte(`{"jsonrpc":"2.0","method":"modules","params":[],"id":64}`) |  | ||||||
| 	decoder := newJsonTestConn(reqdata) |  | ||||||
|  |  | ||||||
| 	jsonDecoder := NewJsonCoder(decoder) |  | ||||||
| 	requests, batch, err := jsonDecoder.ReadRequest() |  | ||||||
|  |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("Read valid request failed - %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(requests) != 1 { |  | ||||||
| 		t.Errorf("Expected to get a single request but got %d", len(requests)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if batch { |  | ||||||
| 		t.Errorf("Got batch indication while expecting single request") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if requests[0].Id != float64(64) { |  | ||||||
| 		t.Errorf("Expected req.Id == 64 but got %v", requests[0].Id) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if requests[0].Method != "modules" { |  | ||||||
| 		t.Errorf("Expected req.Method == 'modules' got '%s'", requests[0].Method) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestJsonDecoderWithValidBatchRequest(t *testing.T) { |  | ||||||
| 	reqdata := []byte(`[{"jsonrpc":"2.0","method":"modules","params":[],"id":64}, |  | ||||||
| 		{"jsonrpc":"2.0","method":"modules","params":[],"id":64}]`) |  | ||||||
| 	decoder := newJsonTestConn(reqdata) |  | ||||||
|  |  | ||||||
| 	jsonDecoder := NewJsonCoder(decoder) |  | ||||||
| 	requests, batch, err := jsonDecoder.ReadRequest() |  | ||||||
|  |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Errorf("Read valid batch request failed - %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(requests) != 2 { |  | ||||||
| 		t.Errorf("Expected to get two requests but got %d", len(requests)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if !batch { |  | ||||||
| 		t.Errorf("Got no batch indication while expecting batch request") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for i := 0; i < len(requests); i++ { |  | ||||||
| 		if requests[i].Id != float64(64) { |  | ||||||
| 			t.Errorf("Expected req.Id == 64 but got %v", requests[i].Id) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if requests[i].Method != "modules" { |  | ||||||
| 			t.Errorf("Expected req.Method == 'modules' got '%s'", requests[i].Method) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestJsonDecoderWithInvalidIncompleteMessage(t *testing.T) { |  | ||||||
| 	reqdata := []byte(`{"jsonrpc":"2.0","method":"modules","pa`) |  | ||||||
| 	decoder := newJsonTestConn(reqdata) |  | ||||||
|  |  | ||||||
| 	jsonDecoder := NewJsonCoder(decoder) |  | ||||||
| 	requests, batch, err := jsonDecoder.ReadRequest() |  | ||||||
|  |  | ||||||
| 	if err != io.ErrUnexpectedEOF { |  | ||||||
| 		t.Errorf("Expected to read an incomplete request err but got %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// remaining message |  | ||||||
| 	decoder.Write([]byte(`rams":[],"id:64"}`)) |  | ||||||
| 	requests, batch, err = jsonDecoder.ReadRequest() |  | ||||||
|  |  | ||||||
| 	if err == nil { |  | ||||||
| 		t.Errorf("Expected an error but got nil") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(requests) != 0 { |  | ||||||
| 		t.Errorf("Expected to get no requests but got %d", len(requests)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if batch { |  | ||||||
| 		t.Errorf("Got batch indication while expecting non batch") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,150 +0,0 @@ | |||||||
| // 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 comms |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"io" |  | ||||||
| 	"net" |  | ||||||
|  |  | ||||||
| 	"fmt" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"strconv" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/logger" |  | ||||||
| 	"github.com/ethereum/go-ethereum/logger/glog" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	maxHttpSizeReqLength = 1024 * 1024 // 1MB |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// List with all API's which are offered over the in proc interface by default |  | ||||||
| 	DefaultInProcApis = shared.AllApis |  | ||||||
|  |  | ||||||
| 	// List with all API's which are offered over the IPC interface by default |  | ||||||
| 	DefaultIpcApis = shared.AllApis |  | ||||||
|  |  | ||||||
| 	// List with API's which are offered over thr HTTP/RPC interface by default |  | ||||||
| 	DefaultHttpRpcApis = strings.Join([]string{ |  | ||||||
| 		shared.DbApiName, shared.EthApiName, shared.NetApiName, shared.Web3ApiName, |  | ||||||
| 	}, ",") |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type EthereumClient interface { |  | ||||||
| 	// Close underlying connection |  | ||||||
| 	Close() |  | ||||||
| 	// Send request |  | ||||||
| 	Send(interface{}) error |  | ||||||
| 	// Receive response |  | ||||||
| 	Recv() (interface{}, error) |  | ||||||
| 	// List with modules this client supports |  | ||||||
| 	SupportedModules() (map[string]string, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func handle(id int, conn net.Conn, api shared.EthereumApi, c codec.Codec) { |  | ||||||
| 	codec := c.New(conn) |  | ||||||
|  |  | ||||||
| 	defer func() { |  | ||||||
| 		if r := recover(); r != nil { |  | ||||||
| 			glog.Errorf("panic: %v\n", r) |  | ||||||
| 		} |  | ||||||
| 		codec.Close() |  | ||||||
| 	}() |  | ||||||
|  |  | ||||||
| 	for { |  | ||||||
| 		requests, isBatch, err := codec.ReadRequest() |  | ||||||
| 		if err == io.EOF { |  | ||||||
| 			return |  | ||||||
| 		} else if err != nil { |  | ||||||
| 			glog.V(logger.Debug).Infof("Closed IPC Conn %06d recv err - %v\n", id, err) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if isBatch { |  | ||||||
| 			responses := make([]*interface{}, len(requests)) |  | ||||||
| 			responseCount := 0 |  | ||||||
| 			for _, req := range requests { |  | ||||||
| 				res, err := api.Execute(req) |  | ||||||
| 				if req.Id != nil { |  | ||||||
| 					rpcResponse := shared.NewRpcResponse(req.Id, req.Jsonrpc, res, err) |  | ||||||
| 					responses[responseCount] = rpcResponse |  | ||||||
| 					responseCount += 1 |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			err = codec.WriteResponse(responses[:responseCount]) |  | ||||||
| 			if err != nil { |  | ||||||
| 				glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			var rpcResponse interface{} |  | ||||||
| 			res, err := api.Execute(requests[0]) |  | ||||||
|  |  | ||||||
| 			rpcResponse = shared.NewRpcResponse(requests[0].Id, requests[0].Jsonrpc, res, err) |  | ||||||
| 			err = codec.WriteResponse(rpcResponse) |  | ||||||
| 			if err != nil { |  | ||||||
| 				glog.V(logger.Debug).Infof("Closed IPC Conn %06d send err - %v\n", id, err) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Endpoint must be in the form of: |  | ||||||
| // ${protocol}:${path} |  | ||||||
| // e.g. ipc:/tmp/geth.ipc |  | ||||||
| //      rpc:localhost:8545 |  | ||||||
| func ClientFromEndpoint(endpoint string, c codec.Codec) (EthereumClient, error) { |  | ||||||
| 	if strings.HasPrefix(endpoint, "ipc:") { |  | ||||||
| 		cfg := IpcConfig{ |  | ||||||
| 			Endpoint: endpoint[4:], |  | ||||||
| 		} |  | ||||||
| 		return NewIpcClient(cfg, codec.JSON) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if strings.HasPrefix(endpoint, "rpc:") { |  | ||||||
| 		parts := strings.Split(endpoint, ":") |  | ||||||
| 		addr := "http://localhost" |  | ||||||
| 		port := uint(8545) |  | ||||||
| 		if len(parts) >= 3 { |  | ||||||
| 			addr = parts[1] + ":" + parts[2] |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if len(parts) >= 4 { |  | ||||||
| 			p, err := strconv.Atoi(parts[3]) |  | ||||||
|  |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, err |  | ||||||
| 			} |  | ||||||
| 			port = uint(p) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		cfg := HttpConfig{ |  | ||||||
| 			ListenAddress: addr, |  | ||||||
| 			ListenPort:    port, |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return NewHttpClient(cfg, codec.JSON), nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, fmt.Errorf("Invalid endpoint") |  | ||||||
| } |  | ||||||
| @@ -1,345 +0,0 @@ | |||||||
| // 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 comms |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"net" |  | ||||||
| 	"net/http" |  | ||||||
| 	"strings" |  | ||||||
| 	"sync" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"bytes" |  | ||||||
| 	"io" |  | ||||||
| 	"io/ioutil" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/logger" |  | ||||||
| 	"github.com/ethereum/go-ethereum/logger/glog" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| 	"github.com/rs/cors" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	serverIdleTimeout  = 10 * time.Second // idle keep-alive connections |  | ||||||
| 	serverReadTimeout  = 15 * time.Second // per-request read timeout |  | ||||||
| 	serverWriteTimeout = 15 * time.Second // per-request read timeout |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	httpServerMu sync.Mutex |  | ||||||
| 	httpServer   *stopServer |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type HttpConfig struct { |  | ||||||
| 	ListenAddress string |  | ||||||
| 	ListenPort    uint |  | ||||||
| 	CorsDomain    string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // stopServer augments http.Server with idle connection tracking. |  | ||||||
| // Idle keep-alive connections are shut down when Close is called. |  | ||||||
| type stopServer struct { |  | ||||||
| 	*http.Server |  | ||||||
| 	l net.Listener |  | ||||||
| 	// connection tracking state |  | ||||||
| 	mu       sync.Mutex |  | ||||||
| 	shutdown bool // true when Stop has returned |  | ||||||
| 	idle     map[net.Conn]struct{} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type handler struct { |  | ||||||
| 	codec codec.Codec |  | ||||||
| 	api   shared.EthereumApi |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // StartHTTP starts listening for RPC requests sent via HTTP. |  | ||||||
| func StartHttp(cfg HttpConfig, codec codec.Codec, api shared.EthereumApi) error { |  | ||||||
| 	httpServerMu.Lock() |  | ||||||
| 	defer httpServerMu.Unlock() |  | ||||||
|  |  | ||||||
| 	addr := fmt.Sprintf("%s:%d", cfg.ListenAddress, cfg.ListenPort) |  | ||||||
| 	if httpServer != nil { |  | ||||||
| 		if addr != httpServer.Addr { |  | ||||||
| 			return fmt.Errorf("RPC service already running on %s ", httpServer.Addr) |  | ||||||
| 		} |  | ||||||
| 		return nil // RPC service already running on given host/port |  | ||||||
| 	} |  | ||||||
| 	// Set up the request handler, wrapping it with CORS headers if configured. |  | ||||||
| 	handler := http.Handler(&handler{codec, api}) |  | ||||||
| 	if len(cfg.CorsDomain) > 0 { |  | ||||||
| 		opts := cors.Options{ |  | ||||||
| 			AllowedMethods: []string{"POST"}, |  | ||||||
| 			AllowedOrigins: strings.Split(cfg.CorsDomain, " "), |  | ||||||
| 		} |  | ||||||
| 		handler = cors.New(opts).Handler(handler) |  | ||||||
| 	} |  | ||||||
| 	// Start the server. |  | ||||||
| 	s, err := listenHTTP(addr, handler) |  | ||||||
| 	if err != nil { |  | ||||||
| 		glog.V(logger.Error).Infof("Can't listen on %s:%d: %v", cfg.ListenAddress, cfg.ListenPort, err) |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	httpServer = s |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { |  | ||||||
| 	w.Header().Set("Content-Type", "application/json") |  | ||||||
|  |  | ||||||
| 	// Limit request size to resist DoS |  | ||||||
| 	if req.ContentLength > maxHttpSizeReqLength { |  | ||||||
| 		err := fmt.Errorf("Request too large") |  | ||||||
| 		response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err) |  | ||||||
| 		sendJSON(w, &response) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	defer req.Body.Close() |  | ||||||
| 	payload, err := ioutil.ReadAll(req.Body) |  | ||||||
| 	if err != nil { |  | ||||||
| 		err := fmt.Errorf("Could not read request body") |  | ||||||
| 		response := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32700, err) |  | ||||||
| 		sendJSON(w, &response) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	c := h.codec.New(nil) |  | ||||||
| 	var rpcReq shared.Request |  | ||||||
| 	if err = c.Decode(payload, &rpcReq); err == nil { |  | ||||||
| 		reply, err := h.api.Execute(&rpcReq) |  | ||||||
| 		res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err) |  | ||||||
| 		sendJSON(w, &res) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var reqBatch []shared.Request |  | ||||||
| 	if err = c.Decode(payload, &reqBatch); err == nil { |  | ||||||
| 		resBatch := make([]*interface{}, len(reqBatch)) |  | ||||||
| 		resCount := 0 |  | ||||||
| 		for i, rpcReq := range reqBatch { |  | ||||||
| 			reply, err := h.api.Execute(&rpcReq) |  | ||||||
| 			if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal |  | ||||||
| 				resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err) |  | ||||||
| 				resCount += 1 |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		// make response omitting nil entries |  | ||||||
| 		sendJSON(w, resBatch[:resCount]) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// invalid request |  | ||||||
| 	err = fmt.Errorf("Could not decode request") |  | ||||||
| 	res := shared.NewRpcErrorResponse(-1, shared.JsonRpcVersion, -32600, err) |  | ||||||
| 	sendJSON(w, res) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func sendJSON(w io.Writer, v interface{}) { |  | ||||||
| 	if glog.V(logger.Detail) { |  | ||||||
| 		if payload, err := json.MarshalIndent(v, "", "\t"); err == nil { |  | ||||||
| 			glog.Infof("Sending payload: %s", payload) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if err := json.NewEncoder(w).Encode(v); err != nil { |  | ||||||
| 		glog.V(logger.Error).Infoln("Error sending JSON:", err) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Stop closes all active HTTP connections and shuts down the server. |  | ||||||
| func StopHttp() { |  | ||||||
| 	httpServerMu.Lock() |  | ||||||
| 	defer httpServerMu.Unlock() |  | ||||||
| 	if httpServer != nil { |  | ||||||
| 		httpServer.Close() |  | ||||||
| 		httpServer = nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func listenHTTP(addr string, h http.Handler) (*stopServer, error) { |  | ||||||
| 	l, err := net.Listen("tcp", addr) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	s := &stopServer{l: l, idle: make(map[net.Conn]struct{})} |  | ||||||
| 	s.Server = &http.Server{ |  | ||||||
| 		Addr:         addr, |  | ||||||
| 		Handler:      h, |  | ||||||
| 		ReadTimeout:  serverReadTimeout, |  | ||||||
| 		WriteTimeout: serverWriteTimeout, |  | ||||||
| 		ConnState:    s.connState, |  | ||||||
| 	} |  | ||||||
| 	go s.Serve(l) |  | ||||||
| 	return s, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *stopServer) connState(c net.Conn, state http.ConnState) { |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	defer s.mu.Unlock() |  | ||||||
| 	// Close c immediately if we're past shutdown. |  | ||||||
| 	if s.shutdown { |  | ||||||
| 		if state != http.StateClosed { |  | ||||||
| 			c.Close() |  | ||||||
| 		} |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if state == http.StateIdle { |  | ||||||
| 		s.idle[c] = struct{}{} |  | ||||||
| 	} else { |  | ||||||
| 		delete(s.idle, c) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *stopServer) Close() { |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	defer s.mu.Unlock() |  | ||||||
| 	// Shut down the acceptor. No new connections can be created. |  | ||||||
| 	s.l.Close() |  | ||||||
| 	// Drop all idle connections. Non-idle connections will be |  | ||||||
| 	// closed by connState as soon as they become idle. |  | ||||||
| 	s.shutdown = true |  | ||||||
| 	for c := range s.idle { |  | ||||||
| 		glog.V(logger.Detail).Infof("closing idle connection %v", c.RemoteAddr()) |  | ||||||
| 		c.Close() |  | ||||||
| 		delete(s.idle, c) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type httpClient struct { |  | ||||||
| 	address string |  | ||||||
| 	port    uint |  | ||||||
| 	codec   codec.ApiCoder |  | ||||||
| 	lastRes interface{} |  | ||||||
| 	lastErr error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Create a new in process client |  | ||||||
| func NewHttpClient(cfg HttpConfig, c codec.Codec) *httpClient { |  | ||||||
| 	return &httpClient{ |  | ||||||
| 		address: cfg.ListenAddress, |  | ||||||
| 		port:    cfg.ListenPort, |  | ||||||
| 		codec:   c.New(nil), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *httpClient) Close() { |  | ||||||
| 	// do nothing |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *httpClient) Send(req interface{}) error { |  | ||||||
| 	var body []byte |  | ||||||
| 	var err error |  | ||||||
|  |  | ||||||
| 	self.lastRes = nil |  | ||||||
| 	self.lastErr = nil |  | ||||||
|  |  | ||||||
| 	if body, err = self.codec.Encode(req); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	httpReq, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	httpReq.Header.Set("Content-Type", "application/json") |  | ||||||
|  |  | ||||||
| 	client := http.Client{} |  | ||||||
| 	resp, err := client.Do(httpReq) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	defer resp.Body.Close() |  | ||||||
|  |  | ||||||
| 	if resp.Status == "200 OK" { |  | ||||||
| 		reply, _ := ioutil.ReadAll(resp.Body) |  | ||||||
| 		var rpcSuccessResponse shared.SuccessResponse |  | ||||||
| 		if err = self.codec.Decode(reply, &rpcSuccessResponse); err == nil { |  | ||||||
| 			self.lastRes = &rpcSuccessResponse |  | ||||||
| 			self.lastErr = err |  | ||||||
| 			return nil |  | ||||||
| 		} else { |  | ||||||
| 			var rpcErrorResponse shared.ErrorResponse |  | ||||||
| 			if err = self.codec.Decode(reply, &rpcErrorResponse); err == nil { |  | ||||||
| 				self.lastRes = &rpcErrorResponse |  | ||||||
| 				self.lastErr = err |  | ||||||
| 				return nil |  | ||||||
| 			} else { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return fmt.Errorf("Not implemented") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *httpClient) Recv() (interface{}, error) { |  | ||||||
| 	return self.lastRes, self.lastErr |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *httpClient) SupportedModules() (map[string]string, error) { |  | ||||||
| 	var body []byte |  | ||||||
| 	var err error |  | ||||||
|  |  | ||||||
| 	payload := shared.Request{ |  | ||||||
| 		Id:      1, |  | ||||||
| 		Jsonrpc: "2.0", |  | ||||||
| 		Method:  "modules", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if body, err = self.codec.Encode(payload); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	req, err := http.NewRequest("POST", fmt.Sprintf("%s:%d", self.address, self.port), bytes.NewBuffer(body)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	req.Header.Set("Content-Type", "application/json") |  | ||||||
|  |  | ||||||
| 	client := http.Client{} |  | ||||||
| 	resp, err := client.Do(req) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	defer resp.Body.Close() |  | ||||||
|  |  | ||||||
| 	if resp.Status == "200 OK" { |  | ||||||
| 		reply, _ := ioutil.ReadAll(resp.Body) |  | ||||||
| 		var rpcRes shared.SuccessResponse |  | ||||||
| 		if err = self.codec.Decode(reply, &rpcRes); err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		result := make(map[string]string) |  | ||||||
| 		if modules, ok := rpcRes.Result.(map[string]interface{}); ok { |  | ||||||
| 			for a, v := range modules { |  | ||||||
| 				result[a] = fmt.Sprintf("%s", v) |  | ||||||
| 			} |  | ||||||
| 			return result, nil |  | ||||||
| 		} |  | ||||||
| 		err = fmt.Errorf("Unable to parse module response - %v", rpcRes.Result) |  | ||||||
| 	} else { |  | ||||||
| 		fmt.Printf("resp.Status = %s\n", resp.Status) |  | ||||||
| 		fmt.Printf("err = %v\n", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, err |  | ||||||
| } |  | ||||||
| @@ -1,82 +0,0 @@ | |||||||
| // 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 comms |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type InProcClient struct { |  | ||||||
| 	api         shared.EthereumApi |  | ||||||
| 	codec       codec.Codec |  | ||||||
| 	lastId      interface{} |  | ||||||
| 	lastJsonrpc string |  | ||||||
| 	lastErr     error |  | ||||||
| 	lastRes     interface{} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Create a new in process client |  | ||||||
| func NewInProcClient(codec codec.Codec) *InProcClient { |  | ||||||
| 	return &InProcClient{ |  | ||||||
| 		codec: codec, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *InProcClient) Close() { |  | ||||||
| 	// do nothing |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Need to setup api support |  | ||||||
| func (self *InProcClient) Initialize(offeredApi shared.EthereumApi) { |  | ||||||
| 	self.api = offeredApi |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *InProcClient) Send(req interface{}) error { |  | ||||||
| 	if r, ok := req.(*shared.Request); ok { |  | ||||||
| 		self.lastId = r.Id |  | ||||||
| 		self.lastJsonrpc = r.Jsonrpc |  | ||||||
| 		self.lastRes, self.lastErr = self.api.Execute(r) |  | ||||||
| 		return self.lastErr |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return fmt.Errorf("Invalid request (%T)", req) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *InProcClient) Recv() (interface{}, error) { |  | ||||||
| 	return *shared.NewRpcResponse(self.lastId, self.lastJsonrpc, self.lastRes, self.lastErr), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *InProcClient) SupportedModules() (map[string]string, error) { |  | ||||||
| 	req := shared.Request{ |  | ||||||
| 		Id:      1, |  | ||||||
| 		Jsonrpc: "2.0", |  | ||||||
| 		Method:  "modules", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if res, err := self.api.Execute(&req); err == nil { |  | ||||||
| 		if result, ok := res.(map[string]string); ok { |  | ||||||
| 			return result, nil |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, fmt.Errorf("Invalid response") |  | ||||||
| } |  | ||||||
							
								
								
									
										158
									
								
								rpc/comms/ipc.go
									
									
									
									
									
								
							
							
						
						
									
										158
									
								
								rpc/comms/ipc.go
									
									
									
									
									
								
							| @@ -1,158 +0,0 @@ | |||||||
| // 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 comms |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"math/rand" |  | ||||||
| 	"net" |  | ||||||
| 	"os" |  | ||||||
|  |  | ||||||
| 	"encoding/json" |  | ||||||
|  |  | ||||||
| 	"github.com/ethereum/go-ethereum/logger" |  | ||||||
| 	"github.com/ethereum/go-ethereum/logger/glog" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/codec" |  | ||||||
| 	"github.com/ethereum/go-ethereum/rpc/shared" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type Stopper interface { |  | ||||||
| 	Stop() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type InitFunc func(conn net.Conn) (Stopper, shared.EthereumApi, error) |  | ||||||
|  |  | ||||||
| type IpcConfig struct { |  | ||||||
| 	Endpoint string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type ipcClient struct { |  | ||||||
| 	endpoint string |  | ||||||
| 	c        net.Conn |  | ||||||
| 	codec    codec.Codec |  | ||||||
| 	coder    codec.ApiCoder |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ipcClient) Close() { |  | ||||||
| 	self.coder.Close() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ipcClient) Send(msg interface{}) error { |  | ||||||
| 	var err error |  | ||||||
| 	if err = self.coder.WriteResponse(msg); err != nil { |  | ||||||
| 		if err = self.reconnect(); err == nil { |  | ||||||
| 			err = self.coder.WriteResponse(msg) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ipcClient) Recv() (interface{}, error) { |  | ||||||
| 	return self.coder.ReadResponse() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (self *ipcClient) SupportedModules() (map[string]string, error) { |  | ||||||
| 	req := shared.Request{ |  | ||||||
| 		Id:      1, |  | ||||||
| 		Jsonrpc: "2.0", |  | ||||||
| 		Method:  "rpc_modules", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := self.coder.WriteResponse(req); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	res, _ := self.coder.ReadResponse() |  | ||||||
| 	if sucRes, ok := res.(*shared.SuccessResponse); ok { |  | ||||||
| 		data, _ := json.Marshal(sucRes.Result) |  | ||||||
| 		modules := make(map[string]string) |  | ||||||
| 		if err := json.Unmarshal(data, &modules); err == nil { |  | ||||||
| 			return modules, nil |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// old version uses modules instead of rpc_modules, this can be removed after full migration |  | ||||||
| 	req.Method = "modules" |  | ||||||
| 	if err := self.coder.WriteResponse(req); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	res, err := self.coder.ReadResponse() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if sucRes, ok := res.(*shared.SuccessResponse); ok { |  | ||||||
| 		data, _ := json.Marshal(sucRes.Result) |  | ||||||
| 		modules := make(map[string]string) |  | ||||||
| 		err = json.Unmarshal(data, &modules) |  | ||||||
| 		if err == nil { |  | ||||||
| 			return modules, nil |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil, fmt.Errorf("Invalid response") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Create a new IPC client, UNIX domain socket on posix, named pipe on Windows |  | ||||||
| func NewIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) { |  | ||||||
| 	return newIpcClient(cfg, codec) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Start IPC server |  | ||||||
| func StartIpc(cfg IpcConfig, codec codec.Codec, initializer InitFunc) error { |  | ||||||
| 	l, err := ipcListen(cfg) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	go ipcLoop(cfg, codec, initializer, l) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // CreateListener creates an listener, on Unix platforms this is a unix socket, on Windows this is a named pipe |  | ||||||
| func CreateListener(cfg IpcConfig) (net.Listener, error) { |  | ||||||
| 	return ipcListen(cfg) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func ipcLoop(cfg IpcConfig, codec codec.Codec, initializer InitFunc, l net.Listener) { |  | ||||||
| 	glog.V(logger.Info).Infof("IPC service started (%s)\n", cfg.Endpoint) |  | ||||||
| 	defer os.Remove(cfg.Endpoint) |  | ||||||
| 	defer l.Close() |  | ||||||
| 	for { |  | ||||||
| 		conn, err := l.Accept() |  | ||||||
| 		if err != nil { |  | ||||||
| 			glog.V(logger.Debug).Infof("accept: %v", err) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		id := newIpcConnId() |  | ||||||
| 		go func() { |  | ||||||
| 			defer conn.Close() |  | ||||||
| 			glog.V(logger.Debug).Infof("new connection with id %06d started", id) |  | ||||||
| 			stopper, api, err := initializer(conn) |  | ||||||
| 			if err != nil { |  | ||||||
| 				glog.V(logger.Error).Infof("Unable to initialize IPC connection: %v", err) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 			defer stopper.Stop() |  | ||||||
| 			handle(id, conn, api, codec) |  | ||||||
| 		}() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newIpcConnId() int { |  | ||||||
| 	return rand.Int() % 1000000 |  | ||||||
| } |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user