From f27e826b140089cbeb722feec96b1aae3e7645a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 23 Nov 2015 13:03:31 +0200 Subject: [PATCH 01/27] jrse: fix #1082, fail if setTimeout/setInterval lack callback --- jsre/jsre.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/jsre/jsre.go b/jsre/jsre.go index af7d507c6d..a4c9d970be 100644 --- a/jsre/jsre.go +++ b/jsre/jsre.go @@ -85,7 +85,6 @@ func (self *JSRE) runEventLoop() { ready := make(chan *jsTimer) newTimer := func(call otto.FunctionCall, interval bool) (*jsTimer, otto.Value) { - delay, _ := call.Argument(1).ToInteger() if 0 >= delay { delay = 1 @@ -105,7 +104,6 @@ func (self *JSRE) runEventLoop() { if err != nil { panic(err) } - return timer, value } @@ -127,8 +125,20 @@ func (self *JSRE) runEventLoop() { } return otto.UndefinedValue() } - vm.Set("setTimeout", setTimeout) - vm.Set("setInterval", setInterval) + vm.Set("_setTimeout", setTimeout) + vm.Set("_setInterval", setInterval) + vm.Run(`var setTimeout = function(args) { + if (arguments.length < 1) { + throw TypeError("Failed to execute 'setTimeout': 1 argument required, but only 0 present."); + } + return _setTimeout.apply(this, arguments); + }`) + vm.Run(`var setInterval = function(args) { + if (arguments.length < 1) { + throw TypeError("Failed to execute 'setInterval': 1 argument required, but only 0 present."); + } + return _setInterval.apply(this, arguments); + }`) vm.Set("clearTimeout", clearTimeout) vm.Set("clearInterval", clearTimeout) @@ -154,7 +164,7 @@ loop: if err != nil { fmt.Println("js error:", err, arguments) } - + _, inreg := registry[timer] // when clearInterval is called from within the callback don't reset it if timer.interval && inreg { timer.timer.Reset(timer.duration) From 2c42e54519afaa5426e9c389fa2ee911b0699baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 24 Nov 2015 17:24:43 +0200 Subject: [PATCH 02/27] Makefile: add support for iOS cross compilation --- Godeps/Godeps.json | 2 +- .../src/github.com/nsf/termbox-go/README.md | 2 ++ .../src/github.com/nsf/termbox-go/api.go | 24 ++++++++++++------- .../github.com/nsf/termbox-go/api_windows.go | 4 ++++ ...calls_darwin_386.go => syscalls_darwin.go} | 0 .../src/github.com/nsf/termbox-go/termbox.go | 14 +++++++---- .../nsf/termbox-go/termbox_windows.go | 4 ++-- Makefile | 17 ++++++++++++- 8 files changed, 51 insertions(+), 16 deletions(-) rename Godeps/_workspace/src/github.com/nsf/termbox-go/{syscalls_darwin_386.go => syscalls_darwin.go} (100%) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index cf23ad6a68..153e61d148 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -55,7 +55,7 @@ }, { "ImportPath": "github.com/nsf/termbox-go", - "Rev": "675ffd907b7401b8a709a5ef2249978af5616bb2" + "Rev": "c4d5eeeb18b378c361f9f2a731680e8b835969ed" }, { "ImportPath": "github.com/pborman/uuid", diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md b/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md index 334d751024..5fc1874b11 100644 --- a/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/README.md @@ -16,6 +16,8 @@ There are also some interesting projects using termbox-go: - [httopd](https://github.com/verdverm/httopd) is top for httpd logs. - [mop](https://github.com/michaeldv/mop) is stock market tracker for hackers. - [termui](https://github.com/gizak/termui) is a terminal dashboard. + - [termloop](https://github.com/JoelOtter/termloop) is a terminal game engine. + - [xterm-color-chart](https://github.com/kutuluk/xterm-color-chart) is a XTerm 256 color chart. ### API reference [godoc.org/github.com/nsf/termbox-go](http://godoc.org/github.com/nsf/termbox-go) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go index b08bca61a5..1e284060e6 100644 --- a/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api.go @@ -351,7 +351,7 @@ func PollEvent() Event { // terminal's window size in characters). But it doesn't always match the size // of the terminal window, after the terminal size has changed, the internal // back buffer will get in sync only after Clear or Flush function calls. -func Size() (int, int) { +func Size() (width int, height int) { return termw, termh } @@ -380,6 +380,12 @@ func SetInputMode(mode InputMode) InputMode { if mode == InputCurrent { return input_mode } + if mode&(InputEsc|InputAlt) == 0 { + mode |= InputEsc + } + if mode&(InputEsc|InputAlt) == InputEsc|InputAlt { + mode &^= InputAlt + } if mode&InputMouse != 0 { out.WriteString(funcs[t_enter_mouse]) } else { @@ -391,6 +397,7 @@ func SetInputMode(mode InputMode) InputMode { } // Sets the termbox output mode. Termbox has four output options: +// // 1. OutputNormal => [1..8] // This mode provides 8 different colors: // black, red, green, yellow, blue, magenta, cyan, white @@ -402,10 +409,10 @@ func SetInputMode(mode InputMode) InputMode { // // 2. Output256 => [1..256] // In this mode you can leverage the 256 terminal mode: -// 0x00 - 0x07: the 8 colors as in OutputNormal -// 0x08 - 0x0f: Color* | AttrBold -// 0x10 - 0xe7: 216 different colors -// 0xe8 - 0xff: 24 different shades of grey +// 0x01 - 0x08: the 8 colors as in OutputNormal +// 0x09 - 0x10: Color* | AttrBold +// 0x11 - 0xe8: 216 different colors +// 0xe9 - 0x1ff: 24 different shades of grey // // Example usage: // SetCell(x, y, '@', 184, 240); @@ -415,11 +422,12 @@ func SetInputMode(mode InputMode) InputMode { // This mode supports the 3rd range of the 256 mode only. // But you dont need to provide an offset. // -// 4. OutputGrayscale => [1..24] -// This mode supports the 4th range of the 256 mode only. +// 4. OutputGrayscale => [1..26] +// This mode supports the 4th range of the 256 mode +// and black and white colors from 3th range of the 256 mode // But you dont need to provide an offset. // -// In all modes, 0 represents the default color. +// In all modes, 0x00 represents the default color. // // `go run _demos/output.go` to see its impact on your terminal. // diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go index 78d954b36c..203544bbff 100644 --- a/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/api_windows.go @@ -80,6 +80,10 @@ func Close() { // stop event producer cancel_comm <- true set_event(interrupt) + select { + case <-input_comm: + default: + } <-cancel_done_comm set_console_cursor_info(out, &orig_cursor_info) diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin.go similarity index 100% rename from Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin_386.go rename to Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin.go diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go index 0aee8aca90..f754880d29 100644 --- a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox.go @@ -72,6 +72,12 @@ var ( input_comm = make(chan input_event) interrupt_comm = make(chan struct{}) intbuf = make([]byte, 0, 16) + + // grayscale indexes + grayscale = []Attribute{ + 0, 17, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 232, + } ) func write_cursor(x, y int) { @@ -171,17 +177,17 @@ func send_attr(fg, bg Attribute) { case OutputGrayscale: fgcol = fg & 0x1F bgcol = bg & 0x1F - if fgcol > 24 { + if fgcol > 26 { fgcol = ColorDefault } - if bgcol > 24 { + if bgcol > 26 { bgcol = ColorDefault } if fgcol != ColorDefault { - fgcol += 0xe8 + fgcol = grayscale[fgcol] } if bgcol != ColorDefault { - bgcol += 0xe8 + bgcol = grayscale[bgcol] } default: fgcol = fg & 0x0F diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go index 17d1bdc84b..f345d0eb00 100644 --- a/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/termbox_windows.go @@ -129,7 +129,7 @@ func create_console_screen_buffer() (h syscall.Handle, err error) { err = syscall.EINVAL } } - return syscall.Handle(r0), nil + return syscall.Handle(r0), err } func get_console_screen_buffer_info(h syscall.Handle, info *console_screen_buffer_info) (err error) { @@ -305,7 +305,7 @@ func create_event() (out syscall.Handle, err error) { err = syscall.EINVAL } } - return syscall.Handle(r0), nil + return syscall.Handle(r0), err } func wait_for_multiple_objects(objects []syscall.Handle) (err error) { diff --git a/Makefile b/Makefile index 41cbc1ce6c..00db7cde76 100644 --- a/Makefile +++ b/Makefile @@ -7,10 +7,11 @@ .PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64 .PHONY: geth-windows geth-windows-386 geth-windows-amd64 .PHONY: geth-android geth-android-16 geth-android-21 +.PHONY: geth-ios geth-ios-5.0 geth-ios-8.1 GOBIN = build/bin -CROSSDEPS = https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2 +CROSSDEPS = https://gmplib.org/download/gmp/gmp-6.1.0.tar.bz2 GO ?= latest geth: @@ -83,6 +84,20 @@ geth-android-21: xgo @echo "Android 21 cross compilation done:" @ls -l $(GOBIN)/geth-android-21-* +geth-ios: xgo geth-ios-5.0 geth-ios-8.1 + @echo "iOS cross compilation done:" + @ls -l $(GOBIN)/geth-ios-* + +geth-ios-5.0: + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios-5.0/* -v $(shell build/flags.sh) ./cmd/geth + @echo "iOS 5.0 cross compilation done:" + @ls -l $(GOBIN)/geth-ios-5.0-* + +geth-ios-8.1: + build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios-8.1/* -v $(shell build/flags.sh) ./cmd/geth + @echo "iOS 8.1 cross compilation done:" + @ls -l $(GOBIN)/geth-ios-8.1-* + evm: build/env.sh $(GOROOT)/bin/go install -v $(shell build/flags.sh) ./cmd/evm @echo "Done building." From 83a22b457c492a7622b5f8f4b420d0dbaa47b173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 24 Nov 2015 19:49:08 +0200 Subject: [PATCH 03/27] Makefile: support library build modes --- Godeps/Godeps.json | 2 +- .../nsf/termbox-go/syscalls_darwin.go | 2 ++ Makefile | 23 ++++++++++--------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 153e61d148..b467215d1e 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -55,7 +55,7 @@ }, { "ImportPath": "github.com/nsf/termbox-go", - "Rev": "c4d5eeeb18b378c361f9f2a731680e8b835969ed" + "Rev": "ca2931516914070bb7f934c83e408689cea8dfb7" }, { "ImportPath": "github.com/pborman/uuid", diff --git a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin.go b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin.go index e03624ebc7..25b78f7ab7 100644 --- a/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin.go +++ b/Godeps/_workspace/src/github.com/nsf/termbox-go/syscalls_darwin.go @@ -1,6 +1,8 @@ // Created by cgo -godefs - DO NOT EDIT // cgo -godefs syscalls.go +// +build !amd64 + package termbox type syscall_Termios struct { diff --git a/Makefile b/Makefile index 00db7cde76..5fc5e9a9de 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ GOBIN = build/bin CROSSDEPS = https://gmplib.org/download/gmp/gmp-6.1.0.tar.bz2 +MODE ?= default GO ?= latest geth: @@ -28,17 +29,17 @@ geth-linux: xgo geth-linux-arm geth-linux-386 geth-linux-amd64 @ls -l $(GOBIN)/geth-linux-* geth-linux-arm: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm -v $(shell build/flags.sh) ./cmd/geth @echo "Linux ARM cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep arm geth-linux-386: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/386 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/386 -v $(shell build/flags.sh) ./cmd/geth @echo "Linux 386 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep 386 geth-linux-amd64: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/amd64 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/amd64 -v $(shell build/flags.sh) ./cmd/geth @echo "Linux amd64 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep amd64 @@ -47,12 +48,12 @@ geth-darwin: xgo geth-darwin-386 geth-darwin-amd64 @ls -l $(GOBIN)/geth-darwin-* geth-darwin-386: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=darwin/386 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=darwin/386 -v $(shell build/flags.sh) ./cmd/geth @echo "Darwin 386 cross compilation done:" @ls -l $(GOBIN)/geth-darwin-* | grep 386 geth-darwin-amd64: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=darwin/amd64 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=darwin/amd64 -v $(shell build/flags.sh) ./cmd/geth @echo "Darwin amd64 cross compilation done:" @ls -l $(GOBIN)/geth-darwin-* | grep amd64 @@ -61,12 +62,12 @@ geth-windows: xgo geth-windows-386 geth-windows-amd64 @ls -l $(GOBIN)/geth-windows-* geth-windows-386: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=windows/386 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=windows/386 -v $(shell build/flags.sh) ./cmd/geth @echo "Windows 386 cross compilation done:" @ls -l $(GOBIN)/geth-windows-* | grep 386 geth-windows-amd64: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=windows/amd64 -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=windows/amd64 -v $(shell build/flags.sh) ./cmd/geth @echo "Windows amd64 cross compilation done:" @ls -l $(GOBIN)/geth-windows-* | grep amd64 @@ -75,12 +76,12 @@ geth-android: xgo geth-android-16 geth-android-21 @ls -l $(GOBIN)/geth-android-* geth-android-16: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android-16/* -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android-16/* -v $(shell build/flags.sh) ./cmd/geth @echo "Android 16 cross compilation done:" @ls -l $(GOBIN)/geth-android-16-* geth-android-21: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android-21/* -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android-21/* -v $(shell build/flags.sh) ./cmd/geth @echo "Android 21 cross compilation done:" @ls -l $(GOBIN)/geth-android-21-* @@ -89,12 +90,12 @@ geth-ios: xgo geth-ios-5.0 geth-ios-8.1 @ls -l $(GOBIN)/geth-ios-* geth-ios-5.0: - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios-5.0/* -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios-5.0/* -v $(shell build/flags.sh) ./cmd/geth @echo "iOS 5.0 cross compilation done:" @ls -l $(GOBIN)/geth-ios-5.0-* geth-ios-8.1: - build/env.sh $(GOBIN)/xgo --go=$(GO) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios-8.1/* -v $(shell build/flags.sh) ./cmd/geth + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios-8.1/* -v $(shell build/flags.sh) ./cmd/geth @echo "iOS 8.1 cross compilation done:" @ls -l $(GOBIN)/geth-ios-8.1-* From 5f0a4416db4339176e31fab5f4b7b79f4e7cf20b Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 20 Nov 2015 19:23:55 +0100 Subject: [PATCH 04/27] whisper: fixed broadcast race Whisper's expire and broadcast loops happen in two separate go routines. Whenever an envelope is being expired it's removed from the set of envelopes and it looses all information about the envelope, including the "known hash". After the envelope has been removed it can be re-accepted by a broadcasting peer putting back the envelope in the set of envelopes. Since the envelope broadcast loop is separate of the expire loop expired messages may be broadcast to other peer, resulting in messages **never** being dropped. This PR includes an expire check before adding new messages to the set of envelopes. --- whisper/peer_test.go | 7 +++++-- whisper/whisper.go | 5 +++++ whisper/whisper_test.go | 9 +++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/whisper/peer_test.go b/whisper/peer_test.go index 594671ee14..b3d2031c19 100644 --- a/whisper/peer_test.go +++ b/whisper/peer_test.go @@ -239,14 +239,17 @@ func TestPeerMessageExpiration(t *testing.T) { } payload := []interface{}{envelope} if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil { - t.Fatalf("message mismatch: %v", err) + // A premature empty message may have been broadcast, check the next too + if err := p2p.ExpectMsg(tester.stream, messagesCode, payload); err != nil { + t.Fatalf("message mismatch: %v", err) + } } // Check that the message is inside the cache if !peer.known.Has(envelope.Hash()) { t.Fatalf("message not found in cache") } // Discard messages until expiration and check cache again - exp := time.Now().Add(time.Second + expirationCycle) + exp := time.Now().Add(time.Second + 2*expirationCycle + 100*time.Millisecond) for time.Now().Before(exp) { if err := p2p.ExpectMsg(tester.stream, messagesCode, []interface{}{}); err != nil { t.Fatalf("message mismatch: %v", err) diff --git a/whisper/whisper.go b/whisper/whisper.go index 676d8ae7a3..a341f23e48 100644 --- a/whisper/whisper.go +++ b/whisper/whisper.go @@ -234,6 +234,11 @@ func (self *Whisper) add(envelope *Envelope) error { self.poolMu.Lock() defer self.poolMu.Unlock() + // short circuit when a received envelope has already expired + if envelope.Expiry <= uint32(time.Now().Unix()) { + return nil + } + // Insert the message into the tracked pool hash := envelope.Hash() if _, ok := self.messages[hash]; ok { diff --git a/whisper/whisper_test.go b/whisper/whisper_test.go index 1a9a8667ad..b83ce0fe70 100644 --- a/whisper/whisper_test.go +++ b/whisper/whisper_test.go @@ -207,4 +207,13 @@ func TestMessageExpiration(t *testing.T) { if found { t.Fatalf("message not expired from cache") } + + node.add(envelope) + node.poolMu.RLock() + _, found = node.messages[envelope.Hash()] + node.poolMu.RUnlock() + if found { + t.Fatalf("message was added to cache") + } + } From b1e014344494d2713f6091299a5b86dc53e1fb4e Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Tue, 24 Nov 2015 09:37:29 +0100 Subject: [PATCH 05/27] cmd, crypto: fixed nil public keys and updated web3 --- cmd/geth/js.go | 4 +- jsre/ethereum_js.go | 7266 +++++++++++++++++++++++++++++++++++++------ xeth/xeth.go | 4 +- 3 files changed, 6278 insertions(+), 996 deletions(-) diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 4d5462539b..17f781f06b 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -299,12 +299,12 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { utils.Fatalf("Error loading web3.js: %v", err) } - _, err = js.re.Run("var web3 = require('web3');") + _, err = js.re.Run("var Web3 = require('web3');") if err != nil { utils.Fatalf("Error requiring web3: %v", err) } - _, err = js.re.Run("web3.setProvider(jeth)") + _, err = js.re.Run("var web3 = new Web3(jeth);") if err != nil { utils.Fatalf("Error setting web3 provider: %v", err) } diff --git a/jsre/ethereum_js.go b/jsre/ethereum_js.go index 2d7dbfec0a..7063a90ec6 100644 --- a/jsre/ethereum_js.go +++ b/jsre/ethereum_js.go @@ -272,6 +272,7 @@ module.exports=[ "type": "event" } ] + },{}],2:[function(require,module,exports){ module.exports=[ { @@ -381,6 +382,7 @@ module.exports=[ "type": "event" } ] + },{}],3:[function(require,module,exports){ module.exports=[ { @@ -528,6 +530,7 @@ module.exports=[ "type": "event" } ] + },{}],4:[function(require,module,exports){ var f = require('./formatters'); var SolidityType = require('./type'); @@ -635,22 +638,22 @@ module.exports = SolidityTypeBytes; },{"./formatters":9,"./type":14}],7:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file coder.js * @author Marek Kotewicz * @date 2015 @@ -680,7 +683,7 @@ var SolidityCoder = function (types) { * * @method _requireType * @param {String} type - * @returns {SolidityType} + * @returns {SolidityType} * @throws {Error} throws if no matching type is found */ SolidityCoder.prototype._requireType = function (type) { @@ -723,10 +726,12 @@ SolidityCoder.prototype.encodeParams = function (types, params) { }); var dynamicOffset = solidityTypes.reduce(function (acc, solidityType, index) { - return acc + solidityType.staticPartLength(types[index]); + var staticPartLength = solidityType.staticPartLength(types[index]); + var roundedStaticPartLength = Math.floor((staticPartLength + 31) / 32) * 32; + return acc + roundedStaticPartLength; }, 0); - var result = this.encodeMultiWithOffset(types, solidityTypes, encodeds, dynamicOffset); + var result = this.encodeMultiWithOffset(types, solidityTypes, encodeds, dynamicOffset); return result; }; @@ -751,7 +756,7 @@ SolidityCoder.prototype.encodeMultiWithOffset = function (types, solidityTypes, // TODO: figure out nested arrays }); - + types.forEach(function (type, i) { if (isDynamic(i)) { var e = self.encodeWithOffset(types[i], solidityTypes[i], encodeds[i], dynamicOffset); @@ -771,7 +776,7 @@ SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded var nestedName = solidityType.nestedName(type); var nestedStaticPartLength = solidityType.staticPartLength(nestedName); var result = encoded[0]; - + (function () { var previousLength = 2; // in int if (solidityType.isDynamicArray(nestedName)) { @@ -781,7 +786,7 @@ SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded } } })(); - + // first element is length, skip it (function () { for (var i = 0; i < encoded.length - 1; i++) { @@ -792,7 +797,7 @@ SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded return result; })(); - + } else if (solidityType.isStaticArray(type)) { return (function () { var nestedName = solidityType.nestedName(type); @@ -805,7 +810,7 @@ SolidityCoder.prototype.encodeWithOffset = function (type, solidityType, encoded var previousLength = 0; // in int for (var i = 0; i < encoded.length; i++) { // calculate length of previous item - previousLength += +(encoded[i - 1] || [])[0] || 0; + previousLength += +(encoded[i - 1] || [])[0] || 0; result += f.formatInputInt(offset + i * nestedStaticPartLength + previousLength * 32).encode(); } })(); @@ -848,7 +853,7 @@ SolidityCoder.prototype.decodeParam = function (type, bytes) { SolidityCoder.prototype.decodeParams = function (types, bytes) { var solidityTypes = this.getSolidityTypes(types); var offsets = this.getOffsets(types, solidityTypes); - + return solidityTypes.map(function (solidityType, index) { return solidityType.decode(bytes, offsets[index], types[index], index); }); @@ -857,18 +862,17 @@ SolidityCoder.prototype.decodeParams = function (types, bytes) { SolidityCoder.prototype.getOffsets = function (types, solidityTypes) { var lengths = solidityTypes.map(function (solidityType, index) { return solidityType.staticPartLength(types[index]); - // get length }); - - for (var i = 0; i < lengths.length; i++) { + + for (var i = 1; i < lengths.length; i++) { // sum with length of previous element - var previous = (lengths[i - 1] || 0); - lengths[i] += previous; + lengths[i] += lengths[i - 1]; } return lengths.map(function (length, index) { // remove the current length, so the length is sum of previous elements - return length - solidityTypes[index].staticPartLength(types[index]); + var staticPartLength = solidityTypes[index].staticPartLength(types[index]); + return length - staticPartLength; }); }; @@ -923,22 +927,22 @@ module.exports = SolidityTypeDynamicBytes; },{"./formatters":9,"./type":14}],9:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file formatters.js * @author Marek Kotewicz * @date 2015 @@ -1082,7 +1086,7 @@ var formatOutputUInt = function (param) { * @returns {BigNumber} input bytes formatted to real */ var formatOutputReal = function (param) { - return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128)); + return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128)); }; /** @@ -1093,7 +1097,7 @@ var formatOutputReal = function (param) { * @returns {BigNumber} input bytes formatted to ureal */ var formatOutputUReal = function (param) { - return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128)); + return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128)); }; /** @@ -1213,22 +1217,22 @@ module.exports = SolidityTypeInt; },{"./formatters":9,"./type":14}],11:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file param.js * @author Marek Kotewicz * @date 2015 @@ -1247,7 +1251,7 @@ var SolidityParam = function (value, offset) { /** * This method should be used to get length of params's dynamic part - * + * * @method dynamicPartLength * @returns {Number} length of dynamic part (in bytes) */ @@ -1275,7 +1279,7 @@ SolidityParam.prototype.withOffset = function (offset) { * @param {SolidityParam} result of combination */ SolidityParam.prototype.combine = function (param) { - return new SolidityParam(this.value + param.value); + return new SolidityParam(this.value + param.value); }; /** @@ -1307,8 +1311,8 @@ SolidityParam.prototype.offsetAsBytes = function () { */ SolidityParam.prototype.staticPart = function () { if (!this.isDynamic()) { - return this.value; - } + return this.value; + } return this.offsetAsBytes(); }; @@ -1340,7 +1344,7 @@ SolidityParam.prototype.encode = function () { * @returns {String} */ SolidityParam.encodeList = function (params) { - + // updating offsets var totalOffset = params.length * 32; var offsetParams = params.map(function (param) { @@ -1466,13 +1470,13 @@ SolidityType.prototype.staticPartLength = function (name) { /** * Should be used to determine if type is dynamic array - * eg: + * eg: * "type[]" => true * "type[4]" => false * * @method isDynamicArray * @param {String} name - * @return {Bool} true if the type is dynamic array + * @return {Bool} true if the type is dynamic array */ SolidityType.prototype.isDynamicArray = function (name) { var nestedTypes = this.nestedTypes(name); @@ -1481,13 +1485,13 @@ SolidityType.prototype.isDynamicArray = function (name) { /** * Should be used to determine if type is static array - * eg: + * eg: * "type[]" => false * "type[4]" => true * * @method isStaticArray * @param {String} name - * @return {Bool} true if the type is static array + * @return {Bool} true if the type is static array */ SolidityType.prototype.isStaticArray = function (name) { var nestedTypes = this.nestedTypes(name); @@ -1496,7 +1500,7 @@ SolidityType.prototype.isStaticArray = function (name) { /** * Should return length of static array - * eg. + * eg. * "int[32]" => 32 * "int256[14]" => 14 * "int[2][3]" => 3 @@ -1571,7 +1575,7 @@ SolidityType.prototype.nestedTypes = function (name) { * Should be used to encode the value * * @method encode - * @param {Object} value + * @param {Object} value * @param {String} name * @return {String} encoded value */ @@ -1585,7 +1589,7 @@ SolidityType.prototype.encode = function (value, name) { var result = []; result.push(f.formatInputInt(length).encode()); - + value.forEach(function (v) { result.push(self.encode(v, nestedName)); }); @@ -1633,9 +1637,10 @@ SolidityType.prototype.decode = function (bytes, offset, name) { var nestedName = self.nestedName(name); var nestedStaticPartLength = self.staticPartLength(nestedName); // in bytes + var roundedNestedStaticPartLength = Math.floor((nestedStaticPartLength + 31) / 32) * 32; var result = []; - for (var i = 0; i < length * nestedStaticPartLength; i += nestedStaticPartLength) { + for (var i = 0; i < length * roundedNestedStaticPartLength; i += roundedNestedStaticPartLength) { result.push(self.decode(bytes, arrayStart + i, nestedName)); } @@ -1650,21 +1655,22 @@ SolidityType.prototype.decode = function (bytes, offset, name) { var nestedName = self.nestedName(name); var nestedStaticPartLength = self.staticPartLength(nestedName); // in bytes + var roundedNestedStaticPartLength = Math.floor((nestedStaticPartLength + 31) / 32) * 32; var result = []; - for (var i = 0; i < length * nestedStaticPartLength; i += nestedStaticPartLength) { + for (var i = 0; i < length * roundedNestedStaticPartLength; i += roundedNestedStaticPartLength) { result.push(self.decode(bytes, arrayStart + i, nestedName)); } return result; })(); } else if (this.isDynamicType(name)) { - + return (function () { var dynamicOffset = parseInt('0x' + bytes.substr(offset * 2, 64)); // in bytes var length = parseInt('0x' + bytes.substr(dynamicOffset * 2, 64)); // in bytes var roundedLength = Math.floor((length + 31) / 32); // in int - + return self._outputFormatter(new SolidityParam(bytes.substr(dynamicOffset * 2, ( 1 + roundedLength) * 64), 0)); })(); } @@ -1764,20 +1770,20 @@ if (typeof XMLHttpRequest === 'undefined') { },{}],18:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file config.js * @authors: @@ -1787,13 +1793,13 @@ if (typeof XMLHttpRequest === 'undefined') { /** * Utils - * + * * @module utils */ /** * Utility functions - * + * * @class [utils] config * @constructor */ @@ -1845,62 +1851,60 @@ module.exports = { },{"bignumber.js":"bignumber.js"}],19:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file sha3.js * @author Marek Kotewicz * @date 2015 */ - -var utils = require('./utils'); +var CryptoJS = require('crypto-js'); var sha3 = require('crypto-js/sha3'); -module.exports = function (str, isNew) { - if (str.substr(0, 2) === '0x' && !isNew) { - console.warn('requirement of using web3.fromAscii before sha3 is deprecated'); - console.warn('new usage: \'web3.sha3("hello")\''); - console.warn('see https://github.com/ethereum/web3.js/pull/205'); - console.warn('if you need to hash hex value, you can do \'sha3("0xfff", true)\''); - str = utils.toUtf8(str); +module.exports = function (value, options) { + if (options && options.encoding === 'hex') { + if (value.length > 2 && value.substr(0, 2) === '0x') { + value = value.substr(2); + } + value = CryptoJS.enc.Hex.parse(value); } - return sha3(str, { + return sha3(value, { outputLength: 256 }).toString(); }; -},{"./utils":20,"crypto-js/sha3":48}],20:[function(require,module,exports){ +},{"crypto-js":57,"crypto-js/sha3":78}],20:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** * @file utils.js @@ -1994,6 +1998,8 @@ var toUtf8 = function(hex) { } for (; i < l; i+=2) { var code = parseInt(hex.substr(i, 2), 16); + if (code === 0) + break; str += String.fromCharCode(code); } @@ -2023,7 +2029,7 @@ var toAscii = function(hex) { }; /** - * Shold be called to get hex representation (prefixed by 0x) of utf8 string + * Should be called to get hex representation (prefixed by 0x) of utf8 a string * * @method fromUtf8 * @param {String} string @@ -2034,7 +2040,10 @@ var fromUtf8 = function(str) { str = utf8.encode(str); var hex = ""; for(var i = 0; i < str.length; i++) { - var n = str.charCodeAt(i).toString(16); + var code = str.charCodeAt(i); + if (code === 0) + break; + var n = code.toString(16); hex += n.length < 2 ? '0' + n : n; } @@ -2042,7 +2051,7 @@ var fromUtf8 = function(str) { }; /** - * Shold be called to get hex representation (prefixed by 0x) of ascii string + * Should be called to get hex representation (prefixed by 0x) of ascii string * * @method fromAscii * @param {String} string @@ -2301,7 +2310,6 @@ var toAddress = function (address) { return '0x' + padLeft(toHex(address).substr(2), 40); }; - /** * Returns true if object is BigNumber, otherwise false * @@ -2414,29 +2422,30 @@ module.exports = { isJson: isJson }; -},{"bignumber.js":"bignumber.js","utf8":50}],21:[function(require,module,exports){ +},{"bignumber.js":"bignumber.js","utf8":83}],21:[function(require,module,exports){ module.exports={ - "version": "0.13.0" + "version": "0.15.1" } },{}],22:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** @file web3.js +/** + * @file web3.js * @authors: * Jeffrey Wilcke * Marek Kotewicz @@ -2446,181 +2455,136 @@ module.exports={ * @date 2014 */ -var version = require('./version.json'); -var net = require('./web3/methods/net'); -var eth = require('./web3/methods/eth'); -var db = require('./web3/methods/db'); -var shh = require('./web3/methods/shh'); -var watches = require('./web3/methods/watches'); -var Filter = require('./web3/filter'); -var IsSyncing = require('./web3/syncing'); -var utils = require('./utils/utils'); -var formatters = require('./web3/formatters'); var RequestManager = require('./web3/requestmanager'); -var c = require('./utils/config'); -var Property = require('./web3/property'); -var Batch = require('./web3/batch'); +var Iban = require('./web3/iban'); +var Eth = require('./web3/methods/eth'); +var DB = require('./web3/methods/db'); +var Shh = require('./web3/methods/shh'); +var Net = require('./web3/methods/net'); +var Settings = require('./web3/settings'); +var version = require('./version.json'); +var utils = require('./utils/utils'); var sha3 = require('./utils/sha3'); +var extend = require('./web3/extend'); +var Batch = require('./web3/batch'); +var Property = require('./web3/property'); +var HttpProvider = require('./web3/httpprovider'); +var IpcProvider = require('./web3/ipcprovider'); -var web3Properties = [ - new Property({ - name: 'version.client', - getter: 'web3_clientVersion' - }), - new Property({ - name: 'version.network', - getter: 'net_version', - inputFormatter: utils.toDecimal - }), - new Property({ - name: 'version.ethereum', - getter: 'eth_protocolVersion', - inputFormatter: utils.toDecimal - }), - new Property({ - name: 'version.whisper', - getter: 'shh_version', - inputFormatter: utils.toDecimal - }) -]; -/// creates methods in a given object based on method description on input -/// setups api calls for these methods -var setupMethods = function (obj, methods) { - methods.forEach(function (method) { - method.attachToObject(obj); - }); -}; -/// creates properties in a given object based on properties description on input -/// setups api calls for these properties -var setupProperties = function (obj, properties) { - properties.forEach(function (property) { - property.attachToObject(obj); - }); -}; - -/// setups web3 object, and it's in-browser executed methods -var web3 = {}; -web3.providers = {}; -web3.currentProvider = null; -web3.version = {}; -web3.version.api = version.version; -web3.eth = {}; - -web3.eth.isSyncing = function (callback) { - return new IsSyncing(callback); -}; - -/*jshint maxparams:4 */ -web3.eth.filter = function (fil, callback) { - return new Filter(fil, watches.eth(), formatters.outputLogFormatter, callback); -}; -/*jshint maxparams:3 */ - -web3.shh = {}; -web3.shh.filter = function (fil, callback) { - return new Filter(fil, watches.shh(), formatters.outputPostFormatter, callback); -}; -web3.net = {}; -web3.db = {}; -web3.setProvider = function (provider) { +function Web3 (provider) { + this._requestManager = new RequestManager(provider); this.currentProvider = provider; - RequestManager.getInstance().setProvider(provider); -}; -web3.isConnected = function(){ - return (this.currentProvider && this.currentProvider.isConnected()); -}; -web3.reset = function (keepIsSyncing) { - RequestManager.getInstance().reset(keepIsSyncing); - c.defaultBlock = 'latest'; - c.defaultAccount = undefined; -}; -web3.toHex = utils.toHex; -web3.toAscii = utils.toAscii; -web3.toUtf8 = utils.toUtf8; -web3.fromAscii = utils.fromAscii; -web3.fromUtf8 = utils.fromUtf8; -web3.toDecimal = utils.toDecimal; -web3.fromDecimal = utils.fromDecimal; -web3.toBigNumber = utils.toBigNumber; -web3.toWei = utils.toWei; -web3.fromWei = utils.fromWei; -web3.isAddress = utils.isAddress; -web3.isIBAN = utils.isIBAN; -web3.sha3 = sha3; -web3.createBatch = function () { - return new Batch(); + this.eth = new Eth(this); + this.db = new DB(this); + this.shh = new Shh(this); + this.net = new Net(this); + this.settings = new Settings(); + this.version = { + api: version.version + }; + this.providers = { + HttpProvider: HttpProvider, + IpcProvider: IpcProvider + }; + this._extend = extend(this); + this._extend({ + properties: properties() + }); +} + +// expose providers on the class +Web3.providers = { + HttpProvider: HttpProvider, + IpcProvider: IpcProvider }; -// ADD defaultblock -Object.defineProperty(web3.eth, 'defaultBlock', { - get: function () { - return c.defaultBlock; - }, - set: function (val) { - c.defaultBlock = val; - return val; - } -}); - -Object.defineProperty(web3.eth, 'defaultAccount', { - get: function () { - return c.defaultAccount; - }, - set: function (val) { - c.defaultAccount = val; - return val; - } -}); - - -// EXTEND -web3._extend = function(extension){ - /*jshint maxcomplexity: 6 */ - - if(extension.property && !web3[extension.property]) - web3[extension.property] = {}; - - setupMethods(web3[extension.property] || web3, extension.methods || []); - setupProperties(web3[extension.property] || web3, extension.properties || []); +Web3.prototype.setProvider = function (provider) { + this._requestManager.setProvider(provider); + this.currentProvider = provider; }; -web3._extend.formatters = formatters; -web3._extend.utils = utils; -web3._extend.Method = require('./web3/method'); -web3._extend.Property = require('./web3/property'); + +Web3.prototype.reset = function (keepIsSyncing) { + this._requestManager.reset(keepIsSyncing); + this.settings = new Settings(); +}; + +Web3.prototype.toHex = utils.toHex; +Web3.prototype.toAscii = utils.toAscii; +Web3.prototype.toUtf8 = utils.toUtf8; +Web3.prototype.fromAscii = utils.fromAscii; +Web3.prototype.fromUtf8 = utils.fromUtf8; +Web3.prototype.toDecimal = utils.toDecimal; +Web3.prototype.fromDecimal = utils.fromDecimal; +Web3.prototype.toBigNumber = utils.toBigNumber; +Web3.prototype.toWei = utils.toWei; +Web3.prototype.fromWei = utils.fromWei; +Web3.prototype.isAddress = utils.isAddress; +Web3.prototype.isIBAN = utils.isIBAN; +Web3.prototype.sha3 = sha3; + +/** + * Transforms direct icap to address + */ +Web3.prototype.fromICAP = function (icap) { + var iban = new Iban(icap); + return iban.address(); +}; + +var properties = function () { + return [ + new Property({ + name: 'version.node', + getter: 'web3_clientVersion' + }), + new Property({ + name: 'version.network', + getter: 'net_version', + inputFormatter: utils.toDecimal + }), + new Property({ + name: 'version.ethereum', + getter: 'eth_protocolVersion', + inputFormatter: utils.toDecimal + }), + new Property({ + name: 'version.whisper', + getter: 'shh_version', + inputFormatter: utils.toDecimal + }) + ]; +}; + +Web3.prototype.isConnected = function(){ + return (this.currentProvider && this.currentProvider.isConnected()); +}; + +Web3.prototype.createBatch = function () { + return new Batch(this); +}; + +module.exports = Web3; -/// setups all api methods -setupProperties(web3, web3Properties); -setupMethods(web3.net, net.methods); -setupProperties(web3.net, net.properties); -setupMethods(web3.eth, eth.methods); -setupProperties(web3.eth, eth.properties); -setupMethods(web3.db, db.methods); -setupMethods(web3.shh, shh.methods); - -module.exports = web3; - - -},{"./utils/config":18,"./utils/sha3":19,"./utils/utils":20,"./version.json":21,"./web3/batch":24,"./web3/filter":28,"./web3/formatters":29,"./web3/method":35,"./web3/methods/db":36,"./web3/methods/eth":37,"./web3/methods/net":38,"./web3/methods/shh":39,"./web3/methods/watches":40,"./web3/property":42,"./web3/requestmanager":43,"./web3/syncing":44}],23:[function(require,module,exports){ +},{"./utils/sha3":19,"./utils/utils":20,"./version.json":21,"./web3/batch":24,"./web3/extend":28,"./web3/httpprovider":32,"./web3/iban":33,"./web3/ipcprovider":34,"./web3/methods/db":37,"./web3/methods/eth":38,"./web3/methods/net":39,"./web3/methods/shh":40,"./web3/property":43,"./web3/requestmanager":44,"./web3/settings":45}],23:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file allevents.js * @author Marek Kotewicz * @date 2014 @@ -2633,7 +2597,8 @@ var utils = require('../utils/utils'); var Filter = require('./filter'); var watches = require('./methods/watches'); -var AllSolidityEvents = function (json, address) { +var AllSolidityEvents = function (requestManager, json, address) { + this._requestManager = requestManager; this._json = json; this._address = address; }; @@ -2667,7 +2632,7 @@ AllSolidityEvents.prototype.decode = function (data) { return data; } - var event = new SolidityEvent(match, this._address); + var event = new SolidityEvent(this._requestManager, match, this._address); return event.decode(data); }; @@ -2681,7 +2646,7 @@ AllSolidityEvents.prototype.execute = function (options, callback) { var o = this.encode(options); var formatter = this.decode.bind(this); - return new Filter(o, watches.eth(), formatter, callback); + return new Filter(this._requestManager, o, watches.eth(), formatter, callback); }; AllSolidityEvents.prototype.attachToContract = function (contract) { @@ -2692,34 +2657,34 @@ AllSolidityEvents.prototype.attachToContract = function (contract) { module.exports = AllSolidityEvents; -},{"../utils/sha3":19,"../utils/utils":20,"./event":27,"./filter":28,"./formatters":29,"./methods/watches":40}],24:[function(require,module,exports){ +},{"../utils/sha3":19,"../utils/utils":20,"./event":27,"./filter":29,"./formatters":30,"./methods/watches":41}],24:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file batch.js * @author Marek Kotewicz * @date 2015 */ -var RequestManager = require('./requestmanager'); var Jsonrpc = require('./jsonrpc'); var errors = require('./errors'); -var Batch = function () { +var Batch = function (web3) { + this.requestManager = web3._requestManager; this.requests = []; }; @@ -2740,7 +2705,7 @@ Batch.prototype.add = function (request) { */ Batch.prototype.execute = function () { var requests = this.requests; - RequestManager.getInstance().sendBatch(requests, function (err, results) { + this.requestManager.sendBatch(requests, function (err, results) { results = results || []; requests.map(function (request, index) { return results[index] || {}; @@ -2754,36 +2719,35 @@ Batch.prototype.execute = function () { requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result)); } }); - }); + }); }; module.exports = Batch; -},{"./errors":26,"./jsonrpc":34,"./requestmanager":43}],25:[function(require,module,exports){ +},{"./errors":26,"./jsonrpc":35}],25:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file contract.js * @author Marek Kotewicz * @date 2014 */ -var web3 = require('../web3'); var utils = require('../utils/utils'); var coder = require('../solidity/coder'); var SolidityEvent = require('./event'); @@ -2816,11 +2780,11 @@ var encodeConstructorParams = function (abi, params) { * @param {Contract} contract * @param {Array} abi */ -var addFunctionsToContract = function (contract, abi) { - abi.filter(function (json) { +var addFunctionsToContract = function (contract) { + contract.abi.filter(function (json) { return json.type === 'function'; }).map(function (json) { - return new SolidityFunction(json, contract.address); + return new SolidityFunction(contract._eth, json, contract.address); }).forEach(function (f) { f.attachToContract(contract); }); @@ -2833,31 +2797,21 @@ var addFunctionsToContract = function (contract, abi) { * @param {Contract} contract * @param {Array} abi */ -var addEventsToContract = function (contract, abi) { - var events = abi.filter(function (json) { +var addEventsToContract = function (contract) { + var events = contract.abi.filter(function (json) { return json.type === 'event'; }); - var All = new AllEvents(events, contract.address); + var All = new AllEvents(contract._eth._requestManager, events, contract.address); All.attachToContract(contract); - + events.map(function (json) { - return new SolidityEvent(json, contract.address); + return new SolidityEvent(contract._eth._requestManager, json, contract.address); }).forEach(function (e) { e.attachToContract(contract); }); }; -/** - * Should be called to create new ContractFactory - * - * @method contract - * @param {Array} abi - * @returns {ContractFactory} new contract factory - */ -var contract = function (abi) { - return new ContractFactory(abi); -}; /** * Should be called to check if the contract gets properly deployed on the blockchain. @@ -2867,24 +2821,22 @@ var contract = function (abi) { * @param {Function} callback * @returns {Undefined} */ -var checkForContractAddress = function(contract, abi, callback){ +var checkForContractAddress = function(contract, callback){ var count = 0, callbackFired = false; // wait for receipt - var filter = web3.eth.filter('latest', function(e){ - if(!e && !callbackFired) { + var filter = contract._eth.filter('latest', function(e){ + if (!e && !callbackFired) { count++; - // console.log('Checking for contract address', count); - // stop watching after 50 blocks (timeout) - if(count > 50) { - + if (count > 50) { + filter.stopWatching(); callbackFired = true; - if(callback) + if (callback) callback(new Error('Contract transaction couldn\'t be found after 50 blocks')); else throw new Error('Contract transaction couldn\'t be found after 50 blocks'); @@ -2892,15 +2844,15 @@ var checkForContractAddress = function(contract, abi, callback){ } else { - web3.eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){ + contract._eth.getTransactionReceipt(contract.transactionHash, function(e, receipt){ if(receipt && !callbackFired) { - web3.eth.getCode(receipt.contractAddress, function(e, code){ - /*jshint maxcomplexity: 5 */ + contract._eth.getCode(receipt.contractAddress, function(e, code){ + /*jshint maxcomplexity: 6 */ - if(callbackFired) + if(callbackFired || !code) return; - + filter.stopWatching(); callbackFired = true; @@ -2910,9 +2862,9 @@ var checkForContractAddress = function(contract, abi, callback){ contract.address = receipt.contractAddress; - // attach events and methods - addFunctionsToContract(contract, abi); - addEventsToContract(contract, abi); + // attach events and methods again after we have + addFunctionsToContract(contract); + addEventsToContract(contract); // call callback for the second time if(callback) @@ -2938,13 +2890,27 @@ var checkForContractAddress = function(contract, abi, callback){ * @method ContractFactory * @param {Array} abi */ -var ContractFactory = function (abi) { +var ContractFactory = function (eth, abi) { + this.eth = eth; this.abi = abi; + + this.new.getData = this.getData.bind(this); }; /** - * Should be called to create new contract on a blockchain + * Should be called to create new ContractFactory * + * @method contract + * @param {Array} abi + * @returns {ContractFactory} new contract factory + */ +//var contract = function (abi) { + //return new ContractFactory(abi); +//}; + +/** + * Should be called to create new contract on a blockchain + * * @method new * @param {Any} contract constructor param1 (optional) * @param {Any} contract constructor param2 (optional) @@ -2953,8 +2919,7 @@ var ContractFactory = function (abi) { * @returns {Contract} returns contract instance */ ContractFactory.prototype.new = function () { - var _this = this; - var contract = new Contract(this.abi); + var contract = new Contract(this.eth, this.abi); // parse arguments var options = {}; // required! @@ -2970,16 +2935,13 @@ ContractFactory.prototype.new = function () { options = args.pop(); } - // throw an error if there are no options - var bytes = encodeConstructorParams(this.abi, args); options.data += bytes; - - if(callback) { + if (callback) { // wait for the contract address adn check if the code was deployed - web3.eth.sendTransaction(options, function (err, hash) { + this.eth.sendTransaction(options, function (err, hash) { if (err) { callback(err); } else { @@ -2989,14 +2951,14 @@ ContractFactory.prototype.new = function () { // call callback for the first time callback(null, contract); - checkForContractAddress(contract, _this.abi, callback); + checkForContractAddress(contract, callback); } }); } else { - var hash = web3.eth.sendTransaction(options); + var hash = this.eth.sendTransaction(options); // add the transaction hash contract.transactionHash = hash; - checkForContractAddress(contract, _this.abi); + checkForContractAddress(contract); } return contract; @@ -3012,19 +2974,39 @@ ContractFactory.prototype.new = function () { * otherwise calls callback function (err, contract) */ ContractFactory.prototype.at = function (address, callback) { - var contract = new Contract(this.abi, address); - // TODO: address is required - - // attach functions - addFunctionsToContract(contract, this.abi); - addEventsToContract(contract, this.abi); + var contract = new Contract(this.eth, this.abi, address); + // this functions are not part of prototype, + // because we dont want to spoil the interface + addFunctionsToContract(contract); + addEventsToContract(contract); + if (callback) { callback(null, contract); - } + } return contract; }; +/** + * Gets the data, which is data to deploy plus constructor params + * + * @method getData + */ +ContractFactory.prototype.getData = function () { + var options = {}; // required! + var args = Array.prototype.slice.call(arguments); + + var last = args[args.length - 1]; + if (utils.isObject(last) && !utils.isArray(last)) { + options = args.pop(); + } + + var bytes = encodeConstructorParams(this.abi, args); + options.data += bytes; + + return options.data; +}; + /** * Should be called to create new contract instance * @@ -3032,31 +3014,34 @@ ContractFactory.prototype.at = function (address, callback) { * @param {Array} abi * @param {Address} contract address */ -var Contract = function (abi, address) { +var Contract = function (eth, abi, address) { + this._eth = eth; + this.transactionHash = null; this.address = address; + this.abi = abi; }; -module.exports = contract; +module.exports = ContractFactory; -},{"../solidity/coder":7,"../utils/utils":20,"../web3":22,"./allevents":23,"./event":27,"./function":30}],26:[function(require,module,exports){ +},{"../solidity/coder":7,"../utils/utils":20,"./allevents":23,"./event":27,"./function":31}],26:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file errors.js * @author Marek Kotewicz * @date 2015 @@ -3067,13 +3052,13 @@ module.exports = { return new Error('Invalid number of input parameters'); }, InvalidConnection: function (host){ - return new Error('CONNECTION ERROR: Couldn\'t connect to node '+ host +', is it running?'); + return new Error('CONNECTION ERROR: Couldn\'t connect to node '+ host +'.'); }, InvalidProvider: function () { - return new Error('Providor not set or invalid'); + return new Error('Provider not set or invalid'); }, InvalidResponse: function (result){ - var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: '+ result; + var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response: ' + JSON.stringify(result); return new Error(message); } }; @@ -3081,22 +3066,22 @@ module.exports = { },{}],27:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file event.js * @author Marek Kotewicz * @date 2014 @@ -3112,7 +3097,8 @@ var watches = require('./methods/watches'); /** * This prototype should be used to create event filters */ -var SolidityEvent = function (json, address) { +var SolidityEvent = function (requestManager, json, address) { + this._requestManager = requestManager; this._params = json.inputs; this._name = utils.transformToFullName(json); this._address = address; @@ -3166,7 +3152,7 @@ SolidityEvent.prototype.signature = function () { /** * Should be used to encode indexed params and options to one final object - * + * * @method encode * @param {Object} indexed * @param {Object} options @@ -3197,7 +3183,7 @@ SolidityEvent.prototype.encode = function (indexed, options) { if (value === undefined || value === null) { return null; } - + if (utils.isArray(value)) { return value.map(function (v) { return '0x' + coder.encodeParam(i.type, v); @@ -3219,17 +3205,17 @@ SolidityEvent.prototype.encode = function (indexed, options) { * @return {Object} result object with decoded indexed && not indexed params */ SolidityEvent.prototype.decode = function (data) { - + data.data = data.data || ''; data.topics = data.topics || []; var argTopics = this._anonymous ? data.topics : data.topics.slice(1); var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(""); - var indexedParams = coder.decodeParams(this.types(true), indexedData); + var indexedParams = coder.decodeParams(this.types(true), indexedData); var notIndexedData = data.data.slice(2); var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData); - + var result = formatters.outputLogFormatter(data); result.event = this.displayName(); result.address = data.address; @@ -3264,10 +3250,10 @@ SolidityEvent.prototype.execute = function (indexed, options, callback) { indexed = {}; } } - + var o = this.encode(indexed, options); var formatter = this.decode.bind(this); - return new Filter(o, watches.eth(), formatter, callback); + return new Filter(this._requestManager, o, watches.eth(), formatter, callback); }; /** @@ -3288,22 +3274,72 @@ SolidityEvent.prototype.attachToContract = function (contract) { module.exports = SolidityEvent; -},{"../solidity/coder":7,"../utils/sha3":19,"../utils/utils":20,"./filter":28,"./formatters":29,"./methods/watches":40}],28:[function(require,module,exports){ -/* - This file is part of ethereum.js. +},{"../solidity/coder":7,"../utils/sha3":19,"../utils/utils":20,"./filter":29,"./formatters":30,"./methods/watches":41}],28:[function(require,module,exports){ +var formatters = require('./formatters'); +var utils = require('./../utils/utils'); +var Method = require('./method'); +var Property = require('./property'); - ethereum.js is free software: you can redistribute it and/or modify +// TODO: refactor, so the input params are not altered. +// it's necessary to make same 'extension' work with multiple providers +var extend = function (web3) { + /* jshint maxcomplexity:5 */ + var ex = function (extension) { + + var extendedObject; + if (extension.property) { + if (!web3[extension.property]) { + web3[extension.property] = {}; + } + extendedObject = web3[extension.property]; + } else { + extendedObject = web3; + } + + if (extension.methods) { + extension.methods.forEach(function (method) { + method.attachToObject(extendedObject); + method.setRequestManager(web3._requestManager); + }); + } + + if (extension.properties) { + extension.properties.forEach(function (property) { + property.attachToObject(extendedObject); + property.setRequestManager(web3._requestManager); + }); + } + }; + + ex.formatters = formatters; + ex.utils = utils; + ex.Method = Method; + ex.Property = Property; + + return ex; +}; + + + +module.exports = extend; + + +},{"./../utils/utils":20,"./formatters":30,"./method":36,"./property":43}],29:[function(require,module,exports){ +/* + This file is part of web3.js. + + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file filter.js * @authors: @@ -3315,7 +3351,6 @@ module.exports = SolidityEvent; * @date 2014 */ -var RequestManager = require('./requestmanager'); var formatters = require('./formatters'); var utils = require('../utils/utils'); @@ -3345,7 +3380,7 @@ var getOptions = function (options) { if (utils.isString(options)) { return options; - } + } options = options || {}; @@ -3355,14 +3390,14 @@ var getOptions = function (options) { return (utils.isArray(topic)) ? topic.map(toTopic) : toTopic(topic); }); - // lazy load return { topics: options.topics, + from: options.from, to: options.to, address: options.address, fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock), - toBlock: formatters.inputBlockNumberFormatter(options.toBlock) - }; + toBlock: formatters.inputBlockNumberFormatter(options.toBlock) + }; }; /** @@ -3370,7 +3405,7 @@ Adds the callback and sets up the methods, to iterate over the results. @method getLogsAtStart @param {Object} self -@param {funciton} +@param {funciton} */ var getLogsAtStart = function(self, callback){ // call getFilterLogs for the first watch callback start @@ -3415,19 +3450,21 @@ var pollFilter = function(self) { } }; - RequestManager.getInstance().startPolling({ + self.requestManager.startPolling({ method: self.implementation.poll.call, params: [self.filterId], }, self.filterId, onMessage, self.stopWatching.bind(self)); }; -var Filter = function (options, methods, formatter, callback) { +var Filter = function (requestManager, options, methods, formatter, callback) { var self = this; var implementation = {}; methods.forEach(function (method) { + method.setRequestManager(requestManager); method.attachToObject(implementation); }); + this.requestManager = requestManager; this.options = getOptions(options); this.implementation = implementation; this.filterId = null; @@ -3479,7 +3516,7 @@ Filter.prototype.watch = function (callback) { }; Filter.prototype.stopWatching = function () { - RequestManager.getInstance().stopPolling(this.filterId); + this.requestManager.stopPolling(this.filterId); // remove filter async this.implementation.uninstallFilter(this.filterId, function(){}); this.callbacks = []; @@ -3519,24 +3556,24 @@ Filter.prototype.get = function (callback) { module.exports = Filter; -},{"../utils/utils":20,"./formatters":29,"./requestmanager":43}],29:[function(require,module,exports){ +},{"../utils/utils":20,"./formatters":30}],30:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file formatters.js * @author Marek Kotewicz * @author Fabian Vogelsteller @@ -3603,7 +3640,7 @@ var inputCallFormatter = function (options){ options[key] = utils.fromDecimal(options[key]); }); - return options; + return options; }; /** @@ -3628,12 +3665,12 @@ var inputTransactionFormatter = function (options){ options[key] = utils.fromDecimal(options[key]); }); - return options; + return options; }; /** * Formats the output of a transaction to its proper values - * + * * @method outputTransactionFormatter * @param {Object} tx * @returns {Object} @@ -3652,7 +3689,7 @@ var outputTransactionFormatter = function (tx){ /** * Formats the output of a transaction receipt to its proper values - * + * * @method outputTransactionReceiptFormatter * @param {Object} receipt * @returns {Object} @@ -3678,7 +3715,7 @@ var outputTransactionReceiptFormatter = function (receipt){ * Formats the output of a block to its proper values * * @method outputBlockFormatter - * @param {Object} block + * @param {Object} block * @returns {Object} */ var outputBlockFormatter = function(block) { @@ -3706,7 +3743,7 @@ var outputBlockFormatter = function(block) { /** * Formats the output of a log - * + * * @method outputLogFormatter * @param {Object} log object * @returns {Object} log @@ -3731,7 +3768,7 @@ var outputLogFormatter = function(log) { */ var inputPostFormatter = function(post) { - post.payload = utils.toHex(post.payload); + // post.payload = utils.toHex(post.payload); post.ttl = utils.fromDecimal(post.ttl); post.workToProve = utils.fromDecimal(post.workToProve); post.priority = utils.fromDecimal(post.priority); @@ -3743,10 +3780,11 @@ var inputPostFormatter = function(post) { // format the following options post.topics = post.topics.map(function(topic){ - return utils.fromUtf8(topic); + // convert only if not hex + return (topic.indexOf('0x') === 0) ? topic : utils.fromUtf8(topic); }); - return post; + return post; }; /** @@ -3762,19 +3800,19 @@ var outputPostFormatter = function(post){ post.sent = utils.toDecimal(post.sent); post.ttl = utils.toDecimal(post.ttl); post.workProved = utils.toDecimal(post.workProved); - post.payloadRaw = post.payload; - post.payload = utils.toUtf8(post.payload); + // post.payloadRaw = post.payload; + // post.payload = utils.toAscii(post.payload); - if (utils.isJson(post.payload)) { - post.payload = JSON.parse(post.payload); - } + // if (utils.isJson(post.payload)) { + // post.payload = JSON.parse(post.payload); + // } // format the following options if (!post.topics) { post.topics = []; } post.topics = post.topics.map(function(topic){ - return utils.toUtf8(topic); + return utils.toAscii(topic); }); return post; @@ -3819,22 +3857,22 @@ module.exports = { }; -},{"../utils/config":18,"../utils/utils":20,"./iban":32}],30:[function(require,module,exports){ +},{"../utils/config":18,"../utils/utils":20,"./iban":33}],31:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** * @file function.js @@ -3842,7 +3880,6 @@ module.exports = { * @date 2015 */ -var web3 = require('../web3'); var coder = require('../solidity/coder'); var utils = require('../utils/utils'); var formatters = require('./formatters'); @@ -3851,7 +3888,8 @@ var sha3 = require('../utils/sha3'); /** * This prototype should be used to call/sendTransaction to solidity functions */ -var SolidityFunction = function (json, address) { +var SolidityFunction = function (eth, json, address) { + this._eth = eth; this._inputTypes = json.inputs.map(function (i) { return i.type; }); @@ -3931,12 +3969,12 @@ SolidityFunction.prototype.call = function () { if (!callback) { - var output = web3.eth.call(payload, defaultBlock); + var output = this._eth.call(payload, defaultBlock); return this.unpackOutput(output); - } - + } + var self = this; - web3.eth.call(payload, defaultBlock, function (error, output) { + this._eth.call(payload, defaultBlock, function (error, output) { callback(error, self.unpackOutput(output)); }); }; @@ -3945,7 +3983,6 @@ SolidityFunction.prototype.call = function () { * Should be used to sendTransaction to solidity function * * @method sendTransaction - * @param {Object} options */ SolidityFunction.prototype.sendTransaction = function () { var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); @@ -3953,17 +3990,16 @@ SolidityFunction.prototype.sendTransaction = function () { var payload = this.toPayload(args); if (!callback) { - return web3.eth.sendTransaction(payload); + return this._eth.sendTransaction(payload); } - web3.eth.sendTransaction(payload, callback); + this._eth.sendTransaction(payload, callback); }; /** * Should be used to estimateGas of solidity function * * @method estimateGas - * @param {Object} options */ SolidityFunction.prototype.estimateGas = function () { var args = Array.prototype.slice.call(arguments); @@ -3971,10 +4007,23 @@ SolidityFunction.prototype.estimateGas = function () { var payload = this.toPayload(args); if (!callback) { - return web3.eth.estimateGas(payload); + return this._eth.estimateGas(payload); } - web3.eth.estimateGas(payload, callback); + this._eth.estimateGas(payload, callback); +}; + +/** + * Return the encoded data of the call + * + * @method getData + * @return {String} the encoded data + */ +SolidityFunction.prototype.getData = function () { + var args = Array.prototype.slice.call(arguments); + var payload = this.toPayload(args); + + return payload.data; }; /** @@ -4008,11 +4057,11 @@ SolidityFunction.prototype.request = function () { var callback = this.extractCallback(args); var payload = this.toPayload(args); var format = this.unpackOutput.bind(this); - + return { method: this._constant ? 'eth_call' : 'eth_sendTransaction', callback: callback, - params: [payload], + params: [payload], format: format }; }; @@ -4046,6 +4095,7 @@ SolidityFunction.prototype.attachToContract = function (contract) { execute.call = this.call.bind(this); execute.sendTransaction = this.sendTransaction.bind(this); execute.estimateGas = this.estimateGas.bind(this); + execute.getData = this.getData.bind(this); var displayName = this.displayName(); if (!contract[displayName]) { contract[displayName] = execute; @@ -4056,22 +4106,22 @@ SolidityFunction.prototype.attachToContract = function (contract) { module.exports = SolidityFunction; -},{"../solidity/coder":7,"../utils/sha3":19,"../utils/utils":20,"../web3":22,"./formatters":29}],31:[function(require,module,exports){ +},{"../solidity/coder":7,"../utils/sha3":19,"../utils/utils":20,"./formatters":30}],32:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file httpprovider.js * @authors: @@ -4143,7 +4193,7 @@ HttpProvider.prototype.send = function (payload) { try { result = JSON.parse(result); } catch(e) { - throw errors.InvalidResponse(request.responseText); + throw errors.InvalidResponse(request.responseText); } return result; @@ -4157,7 +4207,7 @@ HttpProvider.prototype.send = function (payload) { * @param {Function} callback triggered on end with (err, result) */ HttpProvider.prototype.sendAsync = function (payload, callback) { - var request = this.prepareRequest(true); + var request = this.prepareRequest(true); request.onreadystatechange = function() { if (request.readyState === 4) { @@ -4167,13 +4217,13 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { try { result = JSON.parse(result); } catch(e) { - error = errors.InvalidResponse(request.responseText); + error = errors.InvalidResponse(request.responseText); } callback(error, result); } }; - + try { request.send(JSON.stringify(payload)); } catch(error) { @@ -4204,24 +4254,24 @@ HttpProvider.prototype.isConnected = function() { module.exports = HttpProvider; -},{"./errors":26,"xmlhttprequest":17}],32:[function(require,module,exports){ +},{"./errors":26,"xmlhttprequest":17}],33:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file iban.js * @author Marek Kotewicz * @date 2015 @@ -4421,7 +4471,7 @@ Iban.prototype.address = function () { var base36 = this._iban.substr(4); var asBn = new BigNumber(base36, 36); return padLeft(asBn.toString(16), 20); - } + } return ''; }; @@ -4433,22 +4483,22 @@ Iban.prototype.toString = function () { module.exports = Iban; -},{"bignumber.js":"bignumber.js"}],33:[function(require,module,exports){ +},{"bignumber.js":"bignumber.js"}],34:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file ipcprovider.js * @authors: @@ -4461,23 +4511,12 @@ module.exports = Iban; var utils = require('../utils/utils'); var errors = require('./errors'); -var errorTimeout = function (method, id) { - var err = { - "jsonrpc": "2.0", - "error": { - "code": -32603, - "message": "IPC Request timed out for method \'" + method + "\'" - }, - "id": id - }; - return JSON.stringify(err); -}; var IpcProvider = function (path, net) { var _this = this; this.responseCallbacks = {}; this.path = path; - + this.connection = net.connect({path: this.path}); this.connection.on('error', function(e){ @@ -4487,7 +4526,7 @@ var IpcProvider = function (path, net) { this.connection.on('end', function(){ _this._timeout(); - }); + }); // LISTEN FOR CONNECTION RESPONSES @@ -4526,7 +4565,7 @@ Will parse the response and make an array out of it. IpcProvider.prototype._parseResponse = function(data) { var _this = this, returnValues = []; - + // DE-CHUNKER var dechunkedData = data .replace(/\}\{/g,'}|--|{') // }{ @@ -4594,7 +4633,7 @@ Timeout all requests when the end/error event is fired IpcProvider.prototype._timeout = function() { for(var key in this.responseCallbacks) { if(this.responseCallbacks.hasOwnProperty(key)){ - this.responseCallbacks[key](errorTimeout(this.responseCallbacks[key].method, key)); + this.responseCallbacks[key](errors.InvalidConnection('on IPC')); delete this.responseCallbacks[key]; } } @@ -4630,7 +4669,7 @@ IpcProvider.prototype.send = function (payload) { try { result = JSON.parse(data); } catch(e) { - throw errors.InvalidResponse(data); + throw errors.InvalidResponse(data); } return result; @@ -4653,22 +4692,22 @@ IpcProvider.prototype.sendAsync = function (payload, callback) { module.exports = IpcProvider; -},{"../utils/utils":20,"./errors":26}],34:[function(require,module,exports){ +},{"../utils/utils":20,"./errors":26}],35:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file jsonrpc.js * @authors: @@ -4746,22 +4785,22 @@ Jsonrpc.prototype.toBatchPayload = function (messages) { module.exports = Jsonrpc; -},{}],35:[function(require,module,exports){ +},{}],36:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** * @file method.js @@ -4769,7 +4808,6 @@ module.exports = Jsonrpc; * @date 2015 */ -var RequestManager = require('./requestmanager'); var utils = require('../utils/utils'); var errors = require('./errors'); @@ -4779,6 +4817,11 @@ var Method = function (options) { this.params = options.params || 0; this.inputFormatter = options.inputFormatter; this.outputFormatter = options.outputFormatter; + this.requestManager = null; +}; + +Method.prototype.setRequestManager = function (rm) { + this.requestManager = rm; }; /** @@ -4807,7 +4850,7 @@ Method.prototype.extractCallback = function (args) { /** * Should be called to check if the number of arguments is correct - * + * * @method validateArgs * @param {Array} arguments * @throws {Error} if it is not @@ -4820,7 +4863,7 @@ Method.prototype.validateArgs = function (args) { /** * Should be called to format input args of method - * + * * @method formatInput * @param {Array} * @return {Array} @@ -4846,26 +4889,6 @@ Method.prototype.formatOutput = function (result) { return this.outputFormatter && result ? this.outputFormatter(result) : result; }; -/** - * Should attach function to method - * - * @method attachToObject - * @param {Object} - * @param {Function} - */ -Method.prototype.attachToObject = function (obj) { - var func = this.send.bind(this); - func.request = this.request.bind(this); - func.call = this.call; // that's ugly. filter.js uses it - var name = this.name.split('.'); - if (name.length > 1) { - obj[name[0]] = obj[name[0]] || {}; - obj[name[0]][name[1]] = func; - } else { - obj[name[0]] = func; - } -}; - /** * Should create payload from given input args * @@ -4886,6 +4909,33 @@ Method.prototype.toPayload = function (args) { }; }; +Method.prototype.attachToObject = function (obj) { + var func = this.buildCall(); + func.call = this.call; // TODO!!! that's ugly. filter.js uses it + var name = this.name.split('.'); + if (name.length > 1) { + obj[name[0]] = obj[name[0]] || {}; + obj[name[0]][name[1]] = func; + } else { + obj[name[0]] = func; + } +}; + +Method.prototype.buildCall = function() { + var method = this; + var send = function () { + var payload = method.toPayload(Array.prototype.slice.call(arguments)); + if (payload.callback) { + return method.requestManager.sendAsync(payload, function (err, result) { + payload.callback(err, method.formatOutput(result)); + }); + } + return method.formatOutput(method.requestManager.send(payload)); + }; + send.request = this.request.bind(this); + return send; +}; + /** * Should be called to create pure JSONRPC request which can be used in batch request * @@ -4899,43 +4949,25 @@ Method.prototype.request = function () { return payload; }; -/** - * Should send request to the API - * - * @method send - * @param list of params - * @return result - */ -Method.prototype.send = function () { - var payload = this.toPayload(Array.prototype.slice.call(arguments)); - if (payload.callback) { - var self = this; - return RequestManager.getInstance().sendAsync(payload, function (err, result) { - payload.callback(err, self.formatOutput(result)); - }); - } - return this.formatOutput(RequestManager.getInstance().send(payload)); -}; - module.exports = Method; -},{"../utils/utils":20,"./errors":26,"./requestmanager":43}],36:[function(require,module,exports){ +},{"../utils/utils":20,"./errors":26}],37:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file db.js * @authors: @@ -4945,55 +4977,65 @@ module.exports = Method; var Method = require('../method'); -var putString = new Method({ - name: 'putString', - call: 'db_putString', - params: 3 -}); +var DB = function (web3) { + this._requestManager = web3._requestManager; - -var getString = new Method({ - name: 'getString', - call: 'db_getString', - params: 2 -}); - -var putHex = new Method({ - name: 'putHex', - call: 'db_putHex', - params: 3 -}); - -var getHex = new Method({ - name: 'getHex', - call: 'db_getHex', - params: 2 -}); - -var methods = [ - putString, getString, putHex, getHex -]; - -module.exports = { - methods: methods + var self = this; + + methods().forEach(function(method) { + method.attachToObject(self); + method.setRequestManager(web3._requestManager); + }); }; -},{"../method":35}],37:[function(require,module,exports){ -/* - This file is part of ethereum.js. +var methods = function () { + var putString = new Method({ + name: 'putString', + call: 'db_putString', + params: 3 + }); - ethereum.js is free software: you can redistribute it and/or modify + var getString = new Method({ + name: 'getString', + call: 'db_getString', + params: 2 + }); + + var putHex = new Method({ + name: 'putHex', + call: 'db_putHex', + params: 3 + }); + + var getHex = new Method({ + name: 'getHex', + call: 'db_getHex', + params: 2 + }); + + return [ + putString, getString, putHex, getHex + ]; +}; + +module.exports = DB; + +},{"../method":36}],38:[function(require,module,exports){ +/* + This file is part of web3.js. + + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** * @file eth.js @@ -5002,38 +5044,20 @@ module.exports = { * @date 2015 */ -/** - * Web3 - * - * @module web3 - */ - -/** - * Eth methods and properties - * - * An example method object can look as follows: - * - * { - * name: 'getBlock', - * call: blockCall, - * params: 2, - * outputFormatter: formatters.outputBlockFormatter, - * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter - * utils.toHex, // formats paramter 1 - * function(param){ return !!param; } // formats paramter 2 - * ] - * }, - * - * @class [web3] eth - * @constructor - */ - "use strict"; var formatters = require('../formatters'); var utils = require('../../utils/utils'); var Method = require('../method'); var Property = require('../property'); +var c = require('../../utils/config'); +var Contract = require('../contract'); +var watches = require('./watches'); +var Filter = require('../filter'); +var IsSyncing = require('../syncing'); +var namereg = require('../namereg'); +var Iban = require('../iban'); +var transfer = require('../transfer'); var blockCall = function (args) { return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "eth_getBlockByHash" : "eth_getBlockByNumber"; @@ -5055,243 +5079,300 @@ var uncleCountCall = function (args) { return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber'; }; -/// @returns an array of objects describing web3.eth api methods +function Eth(web3) { + this._requestManager = web3._requestManager; -var getBalance = new Method({ - name: 'getBalance', - call: 'eth_getBalance', - params: 2, - inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter], - outputFormatter: formatters.outputBigNumberFormatter + var self = this; + + methods().forEach(function(method) { + method.attachToObject(self); + method.setRequestManager(self._requestManager); + }); + + properties().forEach(function(p) { + p.attachToObject(self); + p.setRequestManager(self._requestManager); + }); + + + this.iban = Iban; + this.sendIBANTransaction = transfer.bind(null, this); +} + +Object.defineProperty(Eth.prototype, 'defaultBlock', { + get: function () { + return c.defaultBlock; + }, + set: function (val) { + c.defaultBlock = val; + return val; + } }); -var getStorageAt = new Method({ - name: 'getStorageAt', - call: 'eth_getStorageAt', - params: 3, - inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter] +Object.defineProperty(Eth.prototype, 'defaultAccount', { + get: function () { + return c.defaultAccount; + }, + set: function (val) { + c.defaultAccount = val; + return val; + } }); -var getCode = new Method({ - name: 'getCode', - call: 'eth_getCode', - params: 2, - inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter] -}); - -var getBlock = new Method({ - name: 'getBlock', - call: blockCall, - params: 2, - inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }], - outputFormatter: formatters.outputBlockFormatter -}); - -var getUncle = new Method({ - name: 'getUncle', - call: uncleCall, - params: 2, - inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex], - outputFormatter: formatters.outputBlockFormatter, - -}); - -var getCompilers = new Method({ - name: 'getCompilers', - call: 'eth_getCompilers', - params: 0 -}); - -var getBlockTransactionCount = new Method({ - name: 'getBlockTransactionCount', - call: getBlockTransactionCountCall, - params: 1, - inputFormatter: [formatters.inputBlockNumberFormatter], - outputFormatter: utils.toDecimal -}); - -var getBlockUncleCount = new Method({ - name: 'getBlockUncleCount', - call: uncleCountCall, - params: 1, - inputFormatter: [formatters.inputBlockNumberFormatter], - outputFormatter: utils.toDecimal -}); - -var getTransaction = new Method({ - name: 'getTransaction', - call: 'eth_getTransactionByHash', - params: 1, - outputFormatter: formatters.outputTransactionFormatter -}); - -var getTransactionFromBlock = new Method({ - name: 'getTransactionFromBlock', - call: transactionFromBlockCall, - params: 2, - inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex], - outputFormatter: formatters.outputTransactionFormatter -}); - -var getTransactionReceipt = new Method({ - name: 'getTransactionReceipt', - call: 'eth_getTransactionReceipt', - params: 1, - outputFormatter: formatters.outputTransactionReceiptFormatter -}); - -var getTransactionCount = new Method({ - name: 'getTransactionCount', - call: 'eth_getTransactionCount', - params: 2, - inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter], - outputFormatter: utils.toDecimal -}); - -var sendRawTransaction = new Method({ - name: 'sendRawTransaction', - call: 'eth_sendRawTransaction', - params: 1, - inputFormatter: [null] -}); - -var sendTransaction = new Method({ - name: 'sendTransaction', - call: 'eth_sendTransaction', - params: 1, - inputFormatter: [formatters.inputTransactionFormatter] -}); - -var call = new Method({ - name: 'call', - call: 'eth_call', - params: 2, - inputFormatter: [formatters.inputCallFormatter, formatters.inputDefaultBlockNumberFormatter] -}); - -var estimateGas = new Method({ - name: 'estimateGas', - call: 'eth_estimateGas', - params: 1, - inputFormatter: [formatters.inputCallFormatter], - outputFormatter: utils.toDecimal -}); - -var compileSolidity = new Method({ - name: 'compile.solidity', - call: 'eth_compileSolidity', - params: 1 -}); - -var compileLLL = new Method({ - name: 'compile.lll', - call: 'eth_compileLLL', - params: 1 -}); - -var compileSerpent = new Method({ - name: 'compile.serpent', - call: 'eth_compileSerpent', - params: 1 -}); - -var submitWork = new Method({ - name: 'submitWork', - call: 'eth_submitWork', - params: 3 -}); - -var getWork = new Method({ - name: 'getWork', - call: 'eth_getWork', - params: 0 -}); - -var methods = [ - getBalance, - getStorageAt, - getCode, - getBlock, - getUncle, - getCompilers, - getBlockTransactionCount, - getBlockUncleCount, - getTransaction, - getTransactionFromBlock, - getTransactionReceipt, - getTransactionCount, - call, - estimateGas, - sendRawTransaction, - sendTransaction, - compileSolidity, - compileLLL, - compileSerpent, - submitWork, - getWork -]; - -/// @returns an array of objects describing web3.eth api properties - - - -var properties = [ - new Property({ - name: 'coinbase', - getter: 'eth_coinbase' - }), - new Property({ - name: 'mining', - getter: 'eth_mining' - }), - new Property({ - name: 'hashrate', - getter: 'eth_hashrate', - outputFormatter: utils.toDecimal - }), - new Property({ - name: 'syncing', - getter: 'eth_syncing', - outputFormatter: formatters.outputSyncingFormatter - }), - new Property({ - name: 'gasPrice', - getter: 'eth_gasPrice', +var methods = function () { + var getBalance = new Method({ + name: 'getBalance', + call: 'eth_getBalance', + params: 2, + inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter], outputFormatter: formatters.outputBigNumberFormatter - }), - new Property({ - name: 'accounts', - getter: 'eth_accounts' - }), - new Property({ - name: 'blockNumber', - getter: 'eth_blockNumber', - outputFormatter: utils.toDecimal - }) -]; + }); -module.exports = { - methods: methods, - properties: properties + var getStorageAt = new Method({ + name: 'getStorageAt', + call: 'eth_getStorageAt', + params: 3, + inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter] + }); + + var getCode = new Method({ + name: 'getCode', + call: 'eth_getCode', + params: 2, + inputFormatter: [formatters.inputAddressFormatter, formatters.inputDefaultBlockNumberFormatter] + }); + + var getBlock = new Method({ + name: 'getBlock', + call: blockCall, + params: 2, + inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }], + outputFormatter: formatters.outputBlockFormatter + }); + + var getUncle = new Method({ + name: 'getUncle', + call: uncleCall, + params: 2, + inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex], + outputFormatter: formatters.outputBlockFormatter, + + }); + + var getCompilers = new Method({ + name: 'getCompilers', + call: 'eth_getCompilers', + params: 0 + }); + + var getBlockTransactionCount = new Method({ + name: 'getBlockTransactionCount', + call: getBlockTransactionCountCall, + params: 1, + inputFormatter: [formatters.inputBlockNumberFormatter], + outputFormatter: utils.toDecimal + }); + + var getBlockUncleCount = new Method({ + name: 'getBlockUncleCount', + call: uncleCountCall, + params: 1, + inputFormatter: [formatters.inputBlockNumberFormatter], + outputFormatter: utils.toDecimal + }); + + var getTransaction = new Method({ + name: 'getTransaction', + call: 'eth_getTransactionByHash', + params: 1, + outputFormatter: formatters.outputTransactionFormatter + }); + + var getTransactionFromBlock = new Method({ + name: 'getTransactionFromBlock', + call: transactionFromBlockCall, + params: 2, + inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex], + outputFormatter: formatters.outputTransactionFormatter + }); + + var getTransactionReceipt = new Method({ + name: 'getTransactionReceipt', + call: 'eth_getTransactionReceipt', + params: 1, + outputFormatter: formatters.outputTransactionReceiptFormatter + }); + + var getTransactionCount = new Method({ + name: 'getTransactionCount', + call: 'eth_getTransactionCount', + params: 2, + inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter], + outputFormatter: utils.toDecimal + }); + + var sendRawTransaction = new Method({ + name: 'sendRawTransaction', + call: 'eth_sendRawTransaction', + params: 1, + inputFormatter: [null] + }); + + var sendTransaction = new Method({ + name: 'sendTransaction', + call: 'eth_sendTransaction', + params: 1, + inputFormatter: [formatters.inputTransactionFormatter] + }); + + var call = new Method({ + name: 'call', + call: 'eth_call', + params: 2, + inputFormatter: [formatters.inputCallFormatter, formatters.inputDefaultBlockNumberFormatter] + }); + + var estimateGas = new Method({ + name: 'estimateGas', + call: 'eth_estimateGas', + params: 1, + inputFormatter: [formatters.inputCallFormatter], + outputFormatter: utils.toDecimal + }); + + var compileSolidity = new Method({ + name: 'compile.solidity', + call: 'eth_compileSolidity', + params: 1 + }); + + var compileLLL = new Method({ + name: 'compile.lll', + call: 'eth_compileLLL', + params: 1 + }); + + var compileSerpent = new Method({ + name: 'compile.serpent', + call: 'eth_compileSerpent', + params: 1 + }); + + var submitWork = new Method({ + name: 'submitWork', + call: 'eth_submitWork', + params: 3 + }); + + var getWork = new Method({ + name: 'getWork', + call: 'eth_getWork', + params: 0 + }); + + return [ + getBalance, + getStorageAt, + getCode, + getBlock, + getUncle, + getCompilers, + getBlockTransactionCount, + getBlockUncleCount, + getTransaction, + getTransactionFromBlock, + getTransactionReceipt, + getTransactionCount, + call, + estimateGas, + sendRawTransaction, + sendTransaction, + compileSolidity, + compileLLL, + compileSerpent, + submitWork, + getWork + ]; }; -},{"../../utils/utils":20,"../formatters":29,"../method":35,"../property":42}],38:[function(require,module,exports){ -/* - This file is part of ethereum.js. +var properties = function () { + return [ + new Property({ + name: 'coinbase', + getter: 'eth_coinbase' + }), + new Property({ + name: 'mining', + getter: 'eth_mining' + }), + new Property({ + name: 'hashrate', + getter: 'eth_hashrate', + outputFormatter: utils.toDecimal + }), + new Property({ + name: 'syncing', + getter: 'eth_syncing', + outputFormatter: formatters.outputSyncingFormatter + }), + new Property({ + name: 'gasPrice', + getter: 'eth_gasPrice', + outputFormatter: formatters.outputBigNumberFormatter + }), + new Property({ + name: 'accounts', + getter: 'eth_accounts' + }), + new Property({ + name: 'blockNumber', + getter: 'eth_blockNumber', + outputFormatter: utils.toDecimal + }) + ]; +}; - ethereum.js is free software: you can redistribute it and/or modify +Eth.prototype.contract = function (abi) { + var factory = new Contract(this, abi); + return factory; +}; + +Eth.prototype.filter = function (fil, callback) { + return new Filter(this._requestManager, fil, watches.eth(), formatters.outputLogFormatter, callback); +}; + +Eth.prototype.namereg = function () { + return this.contract(namereg.global.abi).at(namereg.global.address); +}; + +Eth.prototype.icapNamereg = function () { + return this.contract(namereg.icap.abi).at(namereg.icap.address); +}; + +Eth.prototype.isSyncing = function (callback) { + return new IsSyncing(this._requestManager, callback); +}; + +module.exports = Eth; + + +},{"../../utils/config":18,"../../utils/utils":20,"../contract":25,"../filter":29,"../formatters":30,"../iban":33,"../method":36,"../namereg":42,"../property":43,"../syncing":46,"../transfer":47,"./watches":41}],39:[function(require,module,exports){ +/* + This file is part of web3.js. + + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file eth.js * @authors: @@ -5302,46 +5383,50 @@ module.exports = { var utils = require('../../utils/utils'); var Property = require('../property'); -/// @returns an array of objects describing web3.eth api methods -var methods = [ -]; +var Net = function (web3) { + this._requestManager = web3._requestManager; -/// @returns an array of objects describing web3.eth api properties -var properties = [ - new Property({ - name: 'listening', - getter: 'net_listening' - }), - new Property({ - name: 'peerCount', - getter: 'net_peerCount', - outputFormatter: utils.toDecimal - }) -]; + var self = this; - -module.exports = { - methods: methods, - properties: properties + properties().forEach(function(p) { + p.attachToObject(self); + p.setRequestManager(web3._requestManager); + }); }; +/// @returns an array of objects describing web3.eth api properties +var properties = function () { + return [ + new Property({ + name: 'listening', + getter: 'net_listening' + }), + new Property({ + name: 'peerCount', + getter: 'net_peerCount', + outputFormatter: utils.toDecimal + }) + ]; +}; -},{"../../utils/utils":20,"../property":42}],39:[function(require,module,exports){ +module.exports = Net; + +},{"../../utils/utils":20,"../property":43}],40:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file shh.js * @authors: @@ -5351,67 +5436,85 @@ module.exports = { var Method = require('../method'); var formatters = require('../formatters'); +var Filter = require('../filter'); +var watches = require('./watches'); -var post = new Method({ - name: 'post', - call: 'shh_post', - params: 1, - inputFormatter: [formatters.inputPostFormatter] -}); +var Shh = function (web3) { + this._requestManager = web3._requestManager; -var newIdentity = new Method({ - name: 'newIdentity', - call: 'shh_newIdentity', - params: 0 -}); + var self = this; -var hasIdentity = new Method({ - name: 'hasIdentity', - call: 'shh_hasIdentity', - params: 1 -}); - -var newGroup = new Method({ - name: 'newGroup', - call: 'shh_newGroup', - params: 0 -}); - -var addToGroup = new Method({ - name: 'addToGroup', - call: 'shh_addToGroup', - params: 0 -}); - -var methods = [ - post, - newIdentity, - hasIdentity, - newGroup, - addToGroup -]; - -module.exports = { - methods: methods + methods().forEach(function(method) { + method.attachToObject(self); + method.setRequestManager(self._requestManager); + }); }; +Shh.prototype.filter = function (fil, callback) { + return new Filter(this._requestManager, fil, watches.shh(), formatters.outputPostFormatter, callback); +}; -},{"../formatters":29,"../method":35}],40:[function(require,module,exports){ +var methods = function () { + + var post = new Method({ + name: 'post', + call: 'shh_post', + params: 1, + inputFormatter: [formatters.inputPostFormatter] + }); + + var newIdentity = new Method({ + name: 'newIdentity', + call: 'shh_newIdentity', + params: 0 + }); + + var hasIdentity = new Method({ + name: 'hasIdentity', + call: 'shh_hasIdentity', + params: 1 + }); + + var newGroup = new Method({ + name: 'newGroup', + call: 'shh_newGroup', + params: 0 + }); + + var addToGroup = new Method({ + name: 'addToGroup', + call: 'shh_addToGroup', + params: 0 + }); + + return [ + post, + newIdentity, + hasIdentity, + newGroup, + addToGroup + ]; +}; + +module.exports = Shh; + + +},{"../filter":29,"../formatters":30,"../method":36,"./watches":41}],41:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file watches.js * @authors: @@ -5512,58 +5615,63 @@ module.exports = { }; -},{"../method":35}],41:[function(require,module,exports){ +},{"../method":36}],42:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file namereg.js * @author Marek Kotewicz * @date 2015 */ -var contract = require('./contract'); var globalRegistrarAbi = require('../contracts/GlobalRegistrar.json'); var icapRegistrarAbi= require('../contracts/ICAPRegistrar.json'); var globalNameregAddress = '0xc6d9d2cd449a754c494264e1809c50e34d64562b'; -var ibanNameregAddress = '0xa1a111bc074c9cfa781f0c38e63bd51c91b8af00'; +var icapNameregAddress = '0xa1a111bc074c9cfa781f0c38e63bd51c91b8af00'; module.exports = { - namereg: contract(globalRegistrarAbi).at(globalNameregAddress), - ibanNamereg: contract(icapRegistrarAbi).at(ibanNameregAddress) + global: { + abi: globalRegistrarAbi, + address: globalNameregAddress + }, + icap: { + abi: icapRegistrarAbi, + address: icapNameregAddress + } }; -},{"../contracts/GlobalRegistrar.json":1,"../contracts/ICAPRegistrar.json":2,"./contract":25}],42:[function(require,module,exports){ +},{"../contracts/GlobalRegistrar.json":1,"../contracts/ICAPRegistrar.json":2}],43:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** * @file property.js @@ -5572,7 +5680,6 @@ module.exports = { * @date 2015 */ -var RequestManager = require('./requestmanager'); var utils = require('../utils/utils'); var Property = function (options) { @@ -5581,11 +5688,16 @@ var Property = function (options) { this.setter = options.setter; this.outputFormatter = options.outputFormatter; this.inputFormatter = options.inputFormatter; + this.requestManager = null; +}; + +Property.prototype.setRequestManager = function (rm) { + this.requestManager = rm; }; /** * Should be called to format input args of method - * + * * @method formatInput * @param {Array} * @return {Array} @@ -5618,16 +5730,17 @@ Property.prototype.extractCallback = function (args) { } }; + /** * Should attach function to method - * + * * @method attachToObject * @param {Object} * @param {Function} */ Property.prototype.attachToObject = function (obj) { var proto = { - get: this.get.bind(this), + get: this.buildGet() }; var names = this.name.split('.'); @@ -5639,45 +5752,33 @@ Property.prototype.attachToObject = function (obj) { } Object.defineProperty(obj, name, proto); + obj[asyncGetterName(name)] = this.buildAsyncGet(); +}; - var toAsyncName = function (prefix, name) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); +var asyncGetterName = function (name) { + return 'get' + name.charAt(0).toUpperCase() + name.slice(1); +}; + +Property.prototype.buildGet = function () { + var property = this; + return function get() { + return property.formatOutput(property.requestManager.send({ + method: property.getter + })); }; - - var func = this.getAsync.bind(this); - func.request = this.request.bind(this); - - obj[toAsyncName('get', name)] = func; }; -/** - * Should be used to get value of the property - * - * @method get - * @return {Object} value of the property - */ -Property.prototype.get = function () { - return this.formatOutput(RequestManager.getInstance().send({ - method: this.getter - })); -}; - -/** - * Should be used to asynchrounously get value of property - * - * @method getAsync - * @param {Function} - */ -Property.prototype.getAsync = function (callback) { - var self = this; - RequestManager.getInstance().sendAsync({ - method: this.getter - }, function (err, result) { - if (err) { - return callback(err); - } - callback(err, self.formatOutput(result)); - }); +Property.prototype.buildAsyncGet = function () { + var property = this; + var get = function (callback) { + property.requestManager.sendAsync({ + method: property.getter + }, function (err, result) { + callback(err, property.formatOutput(result)); + }); + }; + get.request = this.request.bind(this); + return get; }; /** @@ -5700,24 +5801,24 @@ Property.prototype.request = function () { module.exports = Property; -},{"../utils/utils":20,"./requestmanager":43}],43:[function(require,module,exports){ +},{"../utils/utils":20}],44:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file requestmanager.js * @author Jeffrey Wilcke * @author Marek Kotewicz @@ -5739,24 +5840,9 @@ var errors = require('./errors'); * Singleton */ var RequestManager = function (provider) { - // singleton pattern - if (arguments.callee._singletonInstance) { - return arguments.callee._singletonInstance; - } - arguments.callee._singletonInstance = this; - this.provider = provider; this.polls = {}; this.timeout = null; - this.isPolling = false; -}; - -/** - * @return {RequestManager} singleton - */ -RequestManager.getInstance = function () { - var instance = new RequestManager(); - return instance; }; /** @@ -5799,7 +5885,7 @@ RequestManager.prototype.sendAsync = function (data, callback) { if (err) { return callback(err); } - + if (!Jsonrpc.getInstance().isValidResponse(result)) { return callback(errors.InvalidResponse(result)); } @@ -5832,7 +5918,7 @@ RequestManager.prototype.sendBatch = function (data, callback) { } callback(err, results); - }); + }); }; /** @@ -5843,11 +5929,6 @@ RequestManager.prototype.sendBatch = function (data, callback) { */ RequestManager.prototype.setProvider = function (p) { this.provider = p; - - if (this.provider && !this.isPolling) { - this.poll(); - this.isPolling = true; - } }; /** @@ -5863,6 +5944,12 @@ RequestManager.prototype.setProvider = function (p) { */ RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) { this.polls[pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall}; + + + // start polling + if (!this.timeout) { + this.poll(); + } }; /** @@ -5873,6 +5960,12 @@ RequestManager.prototype.startPolling = function (data, pollId, callback, uninst */ RequestManager.prototype.stopPolling = function (pollId) { delete this.polls[pollId]; + + // stop polling + if(Object.keys(this.polls).length === 0 && this.timeout) { + clearTimeout(this.timeout); + this.timeout = null; + } }; /** @@ -5881,6 +5974,8 @@ RequestManager.prototype.stopPolling = function (pollId) { * @method reset */ RequestManager.prototype.reset = function (keepIsSyncing) { + /*jshint maxcomplexity:5 */ + for (var key in this.polls) { // remove all polls, except sync polls, // they need to be removed manually by calling syncing.stopWatching() @@ -5890,11 +5985,11 @@ RequestManager.prototype.reset = function (keepIsSyncing) { } } - if (this.timeout) { + // stop polling + if(Object.keys(this.polls).length === 0 && this.timeout) { clearTimeout(this.timeout); this.timeout = null; } - this.poll(); }; /** @@ -5927,7 +6022,7 @@ RequestManager.prototype.poll = function () { } var payload = Jsonrpc.getInstance().toBatchPayload(pollsData); - + // map the request id to they poll id var pollsIdMap = {}; payload.forEach(function(load, index){ @@ -5957,7 +6052,7 @@ RequestManager.prototype.poll = function () { } else return false; }).filter(function (result) { - return !!result; + return !!result; }).filter(function (result) { var valid = Jsonrpc.getInstance().isValidResponse(result); if (!valid) { @@ -5973,22 +6068,33 @@ RequestManager.prototype.poll = function () { module.exports = RequestManager; -},{"../utils/config":18,"../utils/utils":20,"./errors":26,"./jsonrpc":34}],44:[function(require,module,exports){ -/* - This file is part of ethereum.js. +},{"../utils/config":18,"../utils/utils":20,"./errors":26,"./jsonrpc":35}],45:[function(require,module,exports){ - ethereum.js is free software: you can redistribute it and/or modify + +var Settings = function () { + this.defaultBlock = 'latest'; + this.defaultAccount = undefined; +}; + +module.exports = Settings; + + +},{}],46:[function(require,module,exports){ +/* + This file is part of web3.js. + + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ /** @file syncing.js * @authors: @@ -5996,12 +6102,10 @@ module.exports = RequestManager; * @date 2015 */ -var RequestManager = require('./requestmanager'); -var Method = require('./method'); var formatters = require('./formatters'); var utils = require('../utils/utils'); - +var count = 1; /** Adds the callback and sets up the methods, to iterate over the results. @@ -6010,7 +6114,6 @@ Adds the callback and sets up the methods, to iterate over the results. @param {Object} self */ var pollSyncing = function(self) { - var lastSyncState = false; var onMessage = function (error, sync) { if (error) { @@ -6019,44 +6122,39 @@ var pollSyncing = function(self) { }); } - if(utils.isObject(sync)) - sync = self.implementation.outputFormatter(sync); + if(utils.isObject(sync) && sync.startingBlock) + sync = formatters.outputSyncingFormatter(sync); self.callbacks.forEach(function (callback) { - if(lastSyncState !== sync) { - + if (self.lastSyncState !== sync) { + // call the callback with true first so the app can stop anything, before receiving the sync data - if(!lastSyncState && utils.isObject(sync)) + if(!self.lastSyncState && utils.isObject(sync)) callback(null, true); - + // call on the next CPU cycle, so the actions of the sync stop can be processes first setTimeout(function() { callback(null, sync); - }, 1); - - lastSyncState = sync; + }, 0); + + self.lastSyncState = sync; } }); }; - RequestManager.getInstance().startPolling({ - method: self.implementation.call, + self.requestManager.startPolling({ + method: 'eth_syncing', params: [], }, self.pollId, onMessage, self.stopWatching.bind(self)); }; -var IsSyncing = function (callback) { - this.pollId = 'syncPoll_'+ Math.floor(Math.random() * 1000); +var IsSyncing = function (requestManager, callback) { + this.requestManager = requestManager; + this.pollId = 'syncPoll_'+ count++; this.callbacks = []; - this.implementation = new Method({ - name: 'isSyncing', - call: 'eth_syncing', - params: 0, - outputFormatter: formatters.outputSyncingFormatter - }); - this.addCallback(callback); + this.lastSyncState = false; pollSyncing(this); return this; @@ -6069,40 +6167,37 @@ IsSyncing.prototype.addCallback = function (callback) { }; IsSyncing.prototype.stopWatching = function () { - RequestManager.getInstance().stopPolling(this.pollId); + this.requestManager.stopPolling(this.pollId); this.callbacks = []; }; module.exports = IsSyncing; -},{"../utils/utils":20,"./formatters":29,"./method":35,"./requestmanager":43}],45:[function(require,module,exports){ +},{"../utils/utils":20,"./formatters":30}],47:[function(require,module,exports){ /* - This file is part of ethereum.js. + This file is part of web3.js. - ethereum.js is free software: you can redistribute it and/or modify + web3.js 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. - ethereum.js is distributed in the hope that it will be useful, + web3.js 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 ethereum.js. If not, see . + along with web3.js. If not, see . */ -/** +/** * @file transfer.js * @author Marek Kotewicz * @date 2015 */ -var web3 = require('../web3'); var Iban = require('./iban'); -var namereg = require('./namereg').ibanNamereg; -var contract = require('./contract'); var exchangeAbi = require('../contracts/SmartExchange.json'); /** @@ -6114,25 +6209,25 @@ var exchangeAbi = require('../contracts/SmartExchange.json'); * @param {Value} value to be tranfered * @param {Function} callback, callback */ -var transfer = function (from, to, value, callback) { - var iban = new Iban(to); +var transfer = function (eth, from, to, value, callback) { + var iban = new Iban(to); if (!iban.isValid()) { throw new Error('invalid iban address'); } if (iban.isDirect()) { - return transferToAddress(from, iban.address(), value, callback); + return transferToAddress(eth, from, iban.address(), value, callback); } - + if (!callback) { - var address = namereg.addr(iban.institution()); - return deposit(from, address, value, iban.client()); + var address = eth.icapNamereg().addr(iban.institution()); + return deposit(eth, from, address, value, iban.client()); } - namereg.addr(iban.institution(), function (err, address) { - return deposit(from, address, value, iban.client(), callback); + eth.icapNamereg().addr(iban.institution(), function (err, address) { + return deposit(eth, from, address, value, iban.client(), callback); }); - + }; /** @@ -6144,8 +6239,8 @@ var transfer = function (from, to, value, callback) { * @param {Value} value to be tranfered * @param {Function} callback, callback */ -var transferToAddress = function (from, to, value, callback) { - return web3.eth.sendTransaction({ +var transferToAddress = function (eth, from, to, value, callback) { + return eth.sendTransaction({ address: to, from: from, value: value @@ -6162,9 +6257,9 @@ var transferToAddress = function (from, to, value, callback) { * @param {String} client unique identifier * @param {Function} callback, callback */ -var deposit = function (from, to, value, client, callback) { +var deposit = function (eth, from, to, value, client, callback) { var abi = exchangeAbi; - return contract(abi).at(to).deposit(client, { + return eth.contract(abi).at(to).deposit(client, { from: from, value: value }, callback); @@ -6173,9 +6268,1113 @@ var deposit = function (from, to, value, client, callback) { module.exports = transfer; -},{"../contracts/SmartExchange.json":3,"../web3":22,"./contract":25,"./iban":32,"./namereg":41}],46:[function(require,module,exports){ +},{"../contracts/SmartExchange.json":3,"./iban":33}],48:[function(require,module,exports){ -},{}],47:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Lookup tables + var SBOX = []; + var INV_SBOX = []; + var SUB_MIX_0 = []; + var SUB_MIX_1 = []; + var SUB_MIX_2 = []; + var SUB_MIX_3 = []; + var INV_SUB_MIX_0 = []; + var INV_SUB_MIX_1 = []; + var INV_SUB_MIX_2 = []; + var INV_SUB_MIX_3 = []; + + // Compute lookup tables + (function () { + // Compute double table + var d = []; + for (var i = 0; i < 256; i++) { + if (i < 128) { + d[i] = i << 1; + } else { + d[i] = (i << 1) ^ 0x11b; + } + } + + // Walk GF(2^8) + var x = 0; + var xi = 0; + for (var i = 0; i < 256; i++) { + // Compute sbox + var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4); + sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63; + SBOX[x] = sx; + INV_SBOX[sx] = x; + + // Compute multiplication + var x2 = d[x]; + var x4 = d[x2]; + var x8 = d[x4]; + + // Compute sub bytes, mix columns tables + var t = (d[sx] * 0x101) ^ (sx * 0x1010100); + SUB_MIX_0[x] = (t << 24) | (t >>> 8); + SUB_MIX_1[x] = (t << 16) | (t >>> 16); + SUB_MIX_2[x] = (t << 8) | (t >>> 24); + SUB_MIX_3[x] = t; + + // Compute inv sub bytes, inv mix columns tables + var t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100); + INV_SUB_MIX_0[sx] = (t << 24) | (t >>> 8); + INV_SUB_MIX_1[sx] = (t << 16) | (t >>> 16); + INV_SUB_MIX_2[sx] = (t << 8) | (t >>> 24); + INV_SUB_MIX_3[sx] = t; + + // Compute next counter + if (!x) { + x = xi = 1; + } else { + x = x2 ^ d[d[d[x8 ^ x2]]]; + xi ^= d[d[xi]]; + } + } + }()); + + // Precomputed Rcon lookup + var RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + + /** + * AES block cipher algorithm. + */ + var AES = C_algo.AES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + var keySize = key.sigBytes / 4; + + // Compute number of rounds + var nRounds = this._nRounds = keySize + 6 + + // Compute number of key schedule rows + var ksRows = (nRounds + 1) * 4; + + // Compute key schedule + var keySchedule = this._keySchedule = []; + for (var ksRow = 0; ksRow < ksRows; ksRow++) { + if (ksRow < keySize) { + keySchedule[ksRow] = keyWords[ksRow]; + } else { + var t = keySchedule[ksRow - 1]; + + if (!(ksRow % keySize)) { + // Rot word + t = (t << 8) | (t >>> 24); + + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + + // Mix Rcon + t ^= RCON[(ksRow / keySize) | 0] << 24; + } else if (keySize > 6 && ksRow % keySize == 4) { + // Sub word + t = (SBOX[t >>> 24] << 24) | (SBOX[(t >>> 16) & 0xff] << 16) | (SBOX[(t >>> 8) & 0xff] << 8) | SBOX[t & 0xff]; + } + + keySchedule[ksRow] = keySchedule[ksRow - keySize] ^ t; + } + } + + // Compute inv key schedule + var invKeySchedule = this._invKeySchedule = []; + for (var invKsRow = 0; invKsRow < ksRows; invKsRow++) { + var ksRow = ksRows - invKsRow; + + if (invKsRow % 4) { + var t = keySchedule[ksRow]; + } else { + var t = keySchedule[ksRow - 4]; + } + + if (invKsRow < 4 || ksRow <= 4) { + invKeySchedule[invKsRow] = t; + } else { + invKeySchedule[invKsRow] = INV_SUB_MIX_0[SBOX[t >>> 24]] ^ INV_SUB_MIX_1[SBOX[(t >>> 16) & 0xff]] ^ + INV_SUB_MIX_2[SBOX[(t >>> 8) & 0xff]] ^ INV_SUB_MIX_3[SBOX[t & 0xff]]; + } + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX); + }, + + decryptBlock: function (M, offset) { + // Swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + + this._doCryptBlock(M, offset, this._invKeySchedule, INV_SUB_MIX_0, INV_SUB_MIX_1, INV_SUB_MIX_2, INV_SUB_MIX_3, INV_SBOX); + + // Inv swap 2nd and 4th rows + var t = M[offset + 1]; + M[offset + 1] = M[offset + 3]; + M[offset + 3] = t; + }, + + _doCryptBlock: function (M, offset, keySchedule, SUB_MIX_0, SUB_MIX_1, SUB_MIX_2, SUB_MIX_3, SBOX) { + // Shortcut + var nRounds = this._nRounds; + + // Get input, add round key + var s0 = M[offset] ^ keySchedule[0]; + var s1 = M[offset + 1] ^ keySchedule[1]; + var s2 = M[offset + 2] ^ keySchedule[2]; + var s3 = M[offset + 3] ^ keySchedule[3]; + + // Key schedule row counter + var ksRow = 4; + + // Rounds + for (var round = 1; round < nRounds; round++) { + // Shift rows, sub bytes, mix columns, add round key + var t0 = SUB_MIX_0[s0 >>> 24] ^ SUB_MIX_1[(s1 >>> 16) & 0xff] ^ SUB_MIX_2[(s2 >>> 8) & 0xff] ^ SUB_MIX_3[s3 & 0xff] ^ keySchedule[ksRow++]; + var t1 = SUB_MIX_0[s1 >>> 24] ^ SUB_MIX_1[(s2 >>> 16) & 0xff] ^ SUB_MIX_2[(s3 >>> 8) & 0xff] ^ SUB_MIX_3[s0 & 0xff] ^ keySchedule[ksRow++]; + var t2 = SUB_MIX_0[s2 >>> 24] ^ SUB_MIX_1[(s3 >>> 16) & 0xff] ^ SUB_MIX_2[(s0 >>> 8) & 0xff] ^ SUB_MIX_3[s1 & 0xff] ^ keySchedule[ksRow++]; + var t3 = SUB_MIX_0[s3 >>> 24] ^ SUB_MIX_1[(s0 >>> 16) & 0xff] ^ SUB_MIX_2[(s1 >>> 8) & 0xff] ^ SUB_MIX_3[s2 & 0xff] ^ keySchedule[ksRow++]; + + // Update state + s0 = t0; + s1 = t1; + s2 = t2; + s3 = t3; + } + + // Shift rows, sub bytes, add round key + var t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]; + var t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]; + var t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]; + var t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]; + + // Set output + M[offset] = t0; + M[offset + 1] = t1; + M[offset + 2] = t2; + M[offset + 3] = t3; + }, + + keySize: 256/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.AES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.AES.decrypt(ciphertext, key, cfg); + */ + C.AES = BlockCipher._createHelper(AES); + }()); + + + return CryptoJS.AES; + +})); +},{"./cipher-core":50,"./core":51,"./enc-base64":52,"./evpkdf":54,"./md5":59}],50:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Cipher core components. + */ + CryptoJS.lib.Cipher || (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var Base64 = C_enc.Base64; + var C_algo = C.algo; + var EvpKDF = C_algo.EvpKDF; + + /** + * Abstract base cipher template. + * + * @property {number} keySize This cipher's key size. Default: 4 (128 bits) + * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) + * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. + * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. + */ + var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + * + * @property {WordArray} iv The IV to use for this operation. + */ + cfg: Base.extend(), + + /** + * Creates this cipher in encryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); + */ + createEncryptor: function (key, cfg) { + return this.create(this._ENC_XFORM_MODE, key, cfg); + }, + + /** + * Creates this cipher in decryption mode. + * + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {Cipher} A cipher instance. + * + * @static + * + * @example + * + * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); + */ + createDecryptor: function (key, cfg) { + return this.create(this._DEC_XFORM_MODE, key, cfg); + }, + + /** + * Initializes a newly created cipher. + * + * @param {number} xformMode Either the encryption or decryption transormation mode constant. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @example + * + * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); + */ + init: function (xformMode, key, cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Store transform mode and key + this._xformMode = xformMode; + this._key = key; + + // Set initial values + this.reset(); + }, + + /** + * Resets this cipher to its initial state. + * + * @example + * + * cipher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-cipher logic + this._doReset(); + }, + + /** + * Adds data to be encrypted or decrypted. + * + * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. + * + * @return {WordArray} The data after processing. + * + * @example + * + * var encrypted = cipher.process('data'); + * var encrypted = cipher.process(wordArray); + */ + process: function (dataUpdate) { + // Append + this._append(dataUpdate); + + // Process available blocks + return this._process(); + }, + + /** + * Finalizes the encryption or decryption process. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. + * + * @return {WordArray} The data after final processing. + * + * @example + * + * var encrypted = cipher.finalize(); + * var encrypted = cipher.finalize('data'); + * var encrypted = cipher.finalize(wordArray); + */ + finalize: function (dataUpdate) { + // Final data update + if (dataUpdate) { + this._append(dataUpdate); + } + + // Perform concrete-cipher logic + var finalProcessedData = this._doFinalize(); + + return finalProcessedData; + }, + + keySize: 128/32, + + ivSize: 128/32, + + _ENC_XFORM_MODE: 1, + + _DEC_XFORM_MODE: 2, + + /** + * Creates shortcut functions to a cipher's object interface. + * + * @param {Cipher} cipher The cipher to create a helper for. + * + * @return {Object} An object with encrypt and decrypt shortcut functions. + * + * @static + * + * @example + * + * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); + */ + _createHelper: (function () { + function selectCipherStrategy(key) { + if (typeof key == 'string') { + return PasswordBasedCipher; + } else { + return SerializableCipher; + } + } + + return function (cipher) { + return { + encrypt: function (message, key, cfg) { + return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); + }, + + decrypt: function (ciphertext, key, cfg) { + return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); + } + }; + }; + }()) + }); + + /** + * Abstract base stream cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) + */ + var StreamCipher = C_lib.StreamCipher = Cipher.extend({ + _doFinalize: function () { + // Process partial blocks + var finalProcessedBlocks = this._process(!!'flush'); + + return finalProcessedBlocks; + }, + + blockSize: 1 + }); + + /** + * Mode namespace. + */ + var C_mode = C.mode = {}; + + /** + * Abstract base block cipher mode template. + */ + var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ + /** + * Creates this mode for encryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); + */ + createEncryptor: function (cipher, iv) { + return this.Encryptor.create(cipher, iv); + }, + + /** + * Creates this mode for decryption. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @static + * + * @example + * + * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); + */ + createDecryptor: function (cipher, iv) { + return this.Decryptor.create(cipher, iv); + }, + + /** + * Initializes a newly created mode. + * + * @param {Cipher} cipher A block cipher instance. + * @param {Array} iv The IV words. + * + * @example + * + * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); + */ + init: function (cipher, iv) { + this._cipher = cipher; + this._iv = iv; + } + }); + + /** + * Cipher Block Chaining mode. + */ + var CBC = C_mode.CBC = (function () { + /** + * Abstract base CBC mode. + */ + var CBC = BlockCipherMode.extend(); + + /** + * CBC encryptor. + */ + CBC.Encryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // XOR and encrypt + xorBlock.call(this, words, offset, blockSize); + cipher.encryptBlock(words, offset); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + /** + * CBC decryptor. + */ + CBC.Decryptor = CBC.extend({ + /** + * Processes the data block at offset. + * + * @param {Array} words The data words to operate on. + * @param {number} offset The offset where the block starts. + * + * @example + * + * mode.processBlock(data.words, offset); + */ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + // Decrypt and XOR + cipher.decryptBlock(words, offset); + xorBlock.call(this, words, offset, blockSize); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function xorBlock(words, offset, blockSize) { + // Shortcut + var iv = this._iv; + + // Choose mixing block + if (iv) { + var block = iv; + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + var block = this._prevBlock; + } + + // XOR blocks + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= block[i]; + } + } + + return CBC; + }()); + + /** + * Padding namespace. + */ + var C_pad = C.pad = {}; + + /** + * PKCS #5/7 padding strategy. + */ + var Pkcs7 = C_pad.Pkcs7 = { + /** + * Pads data using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to pad. + * @param {number} blockSize The multiple that the data should be padded to. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.pad(wordArray, 4); + */ + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Create padding word + var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; + + // Create padding + var paddingWords = []; + for (var i = 0; i < nPaddingBytes; i += 4) { + paddingWords.push(paddingWord); + } + var padding = WordArray.create(paddingWords, nPaddingBytes); + + // Add padding + data.concat(padding); + }, + + /** + * Unpads data that had been padded using the algorithm defined in PKCS #5/7. + * + * @param {WordArray} data The data to unpad. + * + * @static + * + * @example + * + * CryptoJS.pad.Pkcs7.unpad(wordArray); + */ + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + /** + * Abstract base block cipher template. + * + * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) + */ + var BlockCipher = C_lib.BlockCipher = Cipher.extend({ + /** + * Configuration options. + * + * @property {Mode} mode The block mode to use. Default: CBC + * @property {Padding} padding The padding strategy to use. Default: Pkcs7 + */ + cfg: Cipher.cfg.extend({ + mode: CBC, + padding: Pkcs7 + }), + + reset: function () { + // Reset cipher + Cipher.reset.call(this); + + // Shortcuts + var cfg = this.cfg; + var iv = cfg.iv; + var mode = cfg.mode; + + // Reset block mode + if (this._xformMode == this._ENC_XFORM_MODE) { + var modeCreator = mode.createEncryptor; + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + var modeCreator = mode.createDecryptor; + + // Keep at least one block in the buffer for unpadding + this._minBufferSize = 1; + } + this._mode = modeCreator.call(mode, this, iv && iv.words); + }, + + _doProcessBlock: function (words, offset) { + this._mode.processBlock(words, offset); + }, + + _doFinalize: function () { + // Shortcut + var padding = this.cfg.padding; + + // Finalize + if (this._xformMode == this._ENC_XFORM_MODE) { + // Pad data + padding.pad(this._data, this.blockSize); + + // Process final blocks + var finalProcessedBlocks = this._process(!!'flush'); + } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { + // Process final blocks + var finalProcessedBlocks = this._process(!!'flush'); + + // Unpad data + padding.unpad(finalProcessedBlocks); + } + + return finalProcessedBlocks; + }, + + blockSize: 128/32 + }); + + /** + * A collection of cipher parameters. + * + * @property {WordArray} ciphertext The raw ciphertext. + * @property {WordArray} key The key to this ciphertext. + * @property {WordArray} iv The IV used in the ciphering operation. + * @property {WordArray} salt The salt used with a key derivation function. + * @property {Cipher} algorithm The cipher algorithm. + * @property {Mode} mode The block mode used in the ciphering operation. + * @property {Padding} padding The padding scheme used in the ciphering operation. + * @property {number} blockSize The block size of the cipher. + * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. + */ + var CipherParams = C_lib.CipherParams = Base.extend({ + /** + * Initializes a newly created cipher params object. + * + * @param {Object} cipherParams An object with any of the possible cipher parameters. + * + * @example + * + * var cipherParams = CryptoJS.lib.CipherParams.create({ + * ciphertext: ciphertextWordArray, + * key: keyWordArray, + * iv: ivWordArray, + * salt: saltWordArray, + * algorithm: CryptoJS.algo.AES, + * mode: CryptoJS.mode.CBC, + * padding: CryptoJS.pad.PKCS7, + * blockSize: 4, + * formatter: CryptoJS.format.OpenSSL + * }); + */ + init: function (cipherParams) { + this.mixIn(cipherParams); + }, + + /** + * Converts this cipher params object to a string. + * + * @param {Format} formatter (Optional) The formatting strategy to use. + * + * @return {string} The stringified cipher params. + * + * @throws Error If neither the formatter nor the default formatter is set. + * + * @example + * + * var string = cipherParams + ''; + * var string = cipherParams.toString(); + * var string = cipherParams.toString(CryptoJS.format.OpenSSL); + */ + toString: function (formatter) { + return (formatter || this.formatter).stringify(this); + } + }); + + /** + * Format namespace. + */ + var C_format = C.format = {}; + + /** + * OpenSSL formatting strategy. + */ + var OpenSSLFormatter = C_format.OpenSSL = { + /** + * Converts a cipher params object to an OpenSSL-compatible string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The OpenSSL-compatible string. + * + * @static + * + * @example + * + * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); + */ + stringify: function (cipherParams) { + // Shortcuts + var ciphertext = cipherParams.ciphertext; + var salt = cipherParams.salt; + + // Format + if (salt) { + var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); + } else { + var wordArray = ciphertext; + } + + return wordArray.toString(Base64); + }, + + /** + * Converts an OpenSSL-compatible string to a cipher params object. + * + * @param {string} openSSLStr The OpenSSL-compatible string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); + */ + parse: function (openSSLStr) { + // Parse base64 + var ciphertext = Base64.parse(openSSLStr); + + // Shortcut + var ciphertextWords = ciphertext.words; + + // Test for salt + if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { + // Extract salt + var salt = WordArray.create(ciphertextWords.slice(2, 4)); + + // Remove salt from ciphertext + ciphertextWords.splice(0, 4); + ciphertext.sigBytes -= 16; + } + + return CipherParams.create({ ciphertext: ciphertext, salt: salt }); + } + }; + + /** + * A cipher wrapper that returns ciphertext as a serializable cipher params object. + */ + var SerializableCipher = C_lib.SerializableCipher = Base.extend({ + /** + * Configuration options. + * + * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL + */ + cfg: Base.extend({ + format: OpenSSLFormatter + }), + + /** + * Encrypts a message. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); + * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Encrypt + var encryptor = cipher.createEncryptor(key, cfg); + var ciphertext = encryptor.finalize(message); + + // Shortcut + var cipherCfg = encryptor.cfg; + + // Create and return serializable cipher params + return CipherParams.create({ + ciphertext: ciphertext, + key: key, + iv: cipherCfg.iv, + algorithm: cipher, + mode: cipherCfg.mode, + padding: cipherCfg.padding, + blockSize: cipher.blockSize, + formatter: cfg.format + }); + }, + + /** + * Decrypts serialized ciphertext. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {WordArray} key The key. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, key, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Decrypt + var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); + + return plaintext; + }, + + /** + * Converts serialized ciphertext to CipherParams, + * else assumed CipherParams already and returns ciphertext unchanged. + * + * @param {CipherParams|string} ciphertext The ciphertext. + * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. + * + * @return {CipherParams} The unserialized ciphertext. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); + */ + _parse: function (ciphertext, format) { + if (typeof ciphertext == 'string') { + return format.parse(ciphertext, this); + } else { + return ciphertext; + } + } + }); + + /** + * Key derivation function namespace. + */ + var C_kdf = C.kdf = {}; + + /** + * OpenSSL key derivation function. + */ + var OpenSSLKdf = C_kdf.OpenSSL = { + /** + * Derives a key and IV from a password. + * + * @param {string} password The password to derive from. + * @param {number} keySize The size in words of the key to generate. + * @param {number} ivSize The size in words of the IV to generate. + * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. + * + * @return {CipherParams} A cipher params object with the key, IV, and salt. + * + * @static + * + * @example + * + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); + * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); + */ + execute: function (password, keySize, ivSize, salt) { + // Generate random salt + if (!salt) { + salt = WordArray.random(64/8); + } + + // Derive key and IV + var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); + + // Separate key and IV + var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); + key.sigBytes = keySize * 4; + + // Return params + return CipherParams.create({ key: key, iv: iv, salt: salt }); + } + }; + + /** + * A serializable cipher wrapper that derives the key from a password, + * and returns ciphertext as a serializable cipher params object. + */ + var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ + /** + * Configuration options. + * + * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL + */ + cfg: SerializableCipher.cfg.extend({ + kdf: OpenSSLKdf + }), + + /** + * Encrypts a message using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {WordArray|string} message The message to encrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {CipherParams} A cipher params object. + * + * @static + * + * @example + * + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); + * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); + */ + encrypt: function (cipher, message, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Encrypt + var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); + + // Mix in derived params + ciphertext.mixIn(derivedParams); + + return ciphertext; + }, + + /** + * Decrypts serialized ciphertext using a password. + * + * @param {Cipher} cipher The cipher algorithm to use. + * @param {CipherParams|string} ciphertext The ciphertext to decrypt. + * @param {string} password The password. + * @param {Object} cfg (Optional) The configuration options to use for this operation. + * + * @return {WordArray} The plaintext. + * + * @static + * + * @example + * + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); + * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); + */ + decrypt: function (cipher, ciphertext, password, cfg) { + // Apply config defaults + cfg = this.cfg.extend(cfg); + + // Convert string to CipherParams + ciphertext = this._parse(ciphertext, cfg.format); + + // Derive key and other params + var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt); + + // Add IV to config + cfg.iv = derivedParams.iv; + + // Decrypt + var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); + + return plaintext; + } + }); + }()); + + +})); +},{"./core":51}],51:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -6918,7 +8117,2924 @@ module.exports = transfer; return CryptoJS; })); -},{}],48:[function(require,module,exports){ +},{}],52:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * Base64 encoding strategy. + */ + var Base64 = C_enc.Base64 = { + /** + * Converts a word array to a Base64 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Base64 string. + * + * @static + * + * @example + * + * var base64String = CryptoJS.enc.Base64.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = this._map; + + // Clamp excess bits + wordArray.clamp(); + + // Convert + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64 string to a word array. + * + * @param {string} base64Str The Base64 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64.parse(base64String); + */ + parse: function (base64Str) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = this._map; + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex != -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); + var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); + words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + + return WordArray.create(words, nBytes); + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; + }()); + + + return CryptoJS.enc.Base64; + +})); +},{"./core":51}],53:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + + /** + * UTF-16 BE encoding strategy. + */ + var Utf16BE = C_enc.Utf16 = C_enc.Utf16BE = { + /** + * Converts a word array to a UTF-16 BE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 BE string. + * + * @static + * + * @example + * + * var utf16String = CryptoJS.enc.Utf16.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = (words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff; + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 BE string to a word array. + * + * @param {string} utf16Str The UTF-16 BE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16.parse(utf16String); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= utf16Str.charCodeAt(i) << (16 - (i % 2) * 16); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + /** + * UTF-16 LE encoding strategy. + */ + C_enc.Utf16LE = { + /** + * Converts a word array to a UTF-16 LE string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-16 LE string. + * + * @static + * + * @example + * + * var utf16Str = CryptoJS.enc.Utf16LE.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var utf16Chars = []; + for (var i = 0; i < sigBytes; i += 2) { + var codePoint = swapEndian((words[i >>> 2] >>> (16 - (i % 4) * 8)) & 0xffff); + utf16Chars.push(String.fromCharCode(codePoint)); + } + + return utf16Chars.join(''); + }, + + /** + * Converts a UTF-16 LE string to a word array. + * + * @param {string} utf16Str The UTF-16 LE string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf16LE.parse(utf16Str); + */ + parse: function (utf16Str) { + // Shortcut + var utf16StrLength = utf16Str.length; + + // Convert + var words = []; + for (var i = 0; i < utf16StrLength; i++) { + words[i >>> 1] |= swapEndian(utf16Str.charCodeAt(i) << (16 - (i % 2) * 16)); + } + + return WordArray.create(words, utf16StrLength * 2); + } + }; + + function swapEndian(word) { + return ((word << 8) & 0xff00ff00) | ((word >>> 8) & 0x00ff00ff); + } + }()); + + + return CryptoJS.enc.Utf16; + +})); +},{"./core":51}],54:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha1"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha1", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var MD5 = C_algo.MD5; + + /** + * This key derivation function is meant to conform with EVP_BytesToKey. + * www.openssl.org/docs/crypto/EVP_BytesToKey.html + */ + var EvpKDF = C_algo.EvpKDF = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hash algorithm to use. Default: MD5 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: MD5, + iterations: 1 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.EvpKDF.create(); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + // Shortcut + var cfg = this.cfg; + + // Init hasher + var hasher = cfg.hasher.create(); + + // Initial values + var derivedKey = WordArray.create(); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + if (block) { + hasher.update(block); + } + var block = hasher.update(password).finalize(salt); + hasher.reset(); + + // Iterations + for (var i = 1; i < iterations; i++) { + block = hasher.finalize(block); + hasher.reset(); + } + + derivedKey.concat(block); + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Derives a key from a password. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.EvpKDF(password, salt); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 }); + * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.EvpKDF = function (password, salt, cfg) { + return EvpKDF.create(cfg).compute(password, salt); + }; + }()); + + + return CryptoJS.EvpKDF; + +})); +},{"./core":51,"./hmac":56,"./sha1":75}],55:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var CipherParams = C_lib.CipherParams; + var C_enc = C.enc; + var Hex = C_enc.Hex; + var C_format = C.format; + + var HexFormatter = C_format.Hex = { + /** + * Converts the ciphertext of a cipher params object to a hexadecimally encoded string. + * + * @param {CipherParams} cipherParams The cipher params object. + * + * @return {string} The hexadecimally encoded string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.format.Hex.stringify(cipherParams); + */ + stringify: function (cipherParams) { + return cipherParams.ciphertext.toString(Hex); + }, + + /** + * Converts a hexadecimally encoded ciphertext string to a cipher params object. + * + * @param {string} input The hexadecimally encoded string. + * + * @return {CipherParams} The cipher params object. + * + * @static + * + * @example + * + * var cipherParams = CryptoJS.format.Hex.parse(hexString); + */ + parse: function (input) { + var ciphertext = Hex.parse(input); + return CipherParams.create({ ciphertext: ciphertext }); + } + }; + }()); + + + return CryptoJS.format.Hex; + +})); +},{"./cipher-core":50,"./core":51}],56:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var C_enc = C.enc; + var Utf8 = C_enc.Utf8; + var C_algo = C.algo; + + /** + * HMAC algorithm. + */ + var HMAC = C_algo.HMAC = Base.extend({ + /** + * Initializes a newly created HMAC. + * + * @param {Hasher} hasher The hash algorithm to use. + * @param {WordArray|string} key The secret key. + * + * @example + * + * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); + */ + init: function (hasher, key) { + // Init hasher + hasher = this._hasher = new hasher.init(); + + // Convert string to WordArray, else assume WordArray already + if (typeof key == 'string') { + key = Utf8.parse(key); + } + + // Shortcuts + var hasherBlockSize = hasher.blockSize; + var hasherBlockSizeBytes = hasherBlockSize * 4; + + // Allow arbitrary length keys + if (key.sigBytes > hasherBlockSizeBytes) { + key = hasher.finalize(key); + } + + // Clamp excess bits + key.clamp(); + + // Clone key for inner and outer pads + var oKey = this._oKey = key.clone(); + var iKey = this._iKey = key.clone(); + + // Shortcuts + var oKeyWords = oKey.words; + var iKeyWords = iKey.words; + + // XOR keys with pad constants + for (var i = 0; i < hasherBlockSize; i++) { + oKeyWords[i] ^= 0x5c5c5c5c; + iKeyWords[i] ^= 0x36363636; + } + oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes; + + // Set initial values + this.reset(); + }, + + /** + * Resets this HMAC to its initial state. + * + * @example + * + * hmacHasher.reset(); + */ + reset: function () { + // Shortcut + var hasher = this._hasher; + + // Reset + hasher.reset(); + hasher.update(this._iKey); + }, + + /** + * Updates this HMAC with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {HMAC} This HMAC instance. + * + * @example + * + * hmacHasher.update('message'); + * hmacHasher.update(wordArray); + */ + update: function (messageUpdate) { + this._hasher.update(messageUpdate); + + // Chainable + return this; + }, + + /** + * Finalizes the HMAC computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The HMAC. + * + * @example + * + * var hmac = hmacHasher.finalize(); + * var hmac = hmacHasher.finalize('message'); + * var hmac = hmacHasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Shortcut + var hasher = this._hasher; + + // Compute HMAC + var innerHash = hasher.finalize(messageUpdate); + hasher.reset(); + var hmac = hasher.finalize(this._oKey.clone().concat(innerHash)); + + return hmac; + } + }); + }()); + + +})); +},{"./core":51}],57:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./lib-typedarrays"), require("./enc-utf16"), require("./enc-base64"), require("./md5"), require("./sha1"), require("./sha256"), require("./sha224"), require("./sha512"), require("./sha384"), require("./sha3"), require("./ripemd160"), require("./hmac"), require("./pbkdf2"), require("./evpkdf"), require("./cipher-core"), require("./mode-cfb"), require("./mode-ctr"), require("./mode-ctr-gladman"), require("./mode-ofb"), require("./mode-ecb"), require("./pad-ansix923"), require("./pad-iso10126"), require("./pad-iso97971"), require("./pad-zeropadding"), require("./pad-nopadding"), require("./format-hex"), require("./aes"), require("./tripledes"), require("./rc4"), require("./rabbit"), require("./rabbit-legacy")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./lib-typedarrays", "./enc-utf16", "./enc-base64", "./md5", "./sha1", "./sha256", "./sha224", "./sha512", "./sha384", "./sha3", "./ripemd160", "./hmac", "./pbkdf2", "./evpkdf", "./cipher-core", "./mode-cfb", "./mode-ctr", "./mode-ctr-gladman", "./mode-ofb", "./mode-ecb", "./pad-ansix923", "./pad-iso10126", "./pad-iso97971", "./pad-zeropadding", "./pad-nopadding", "./format-hex", "./aes", "./tripledes", "./rc4", "./rabbit", "./rabbit-legacy"], factory); + } + else { + // Global (browser) + root.CryptoJS = factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + return CryptoJS; + +})); +},{"./aes":49,"./cipher-core":50,"./core":51,"./enc-base64":52,"./enc-utf16":53,"./evpkdf":54,"./format-hex":55,"./hmac":56,"./lib-typedarrays":58,"./md5":59,"./mode-cfb":60,"./mode-ctr":62,"./mode-ctr-gladman":61,"./mode-ecb":63,"./mode-ofb":64,"./pad-ansix923":65,"./pad-iso10126":66,"./pad-iso97971":67,"./pad-nopadding":68,"./pad-zeropadding":69,"./pbkdf2":70,"./rabbit":72,"./rabbit-legacy":71,"./rc4":73,"./ripemd160":74,"./sha1":75,"./sha224":76,"./sha256":77,"./sha3":78,"./sha384":79,"./sha512":80,"./tripledes":81,"./x64-core":82}],58:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Check if typed arrays are supported + if (typeof ArrayBuffer != 'function') { + return; + } + + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + + // Reference original init + var superInit = WordArray.init; + + // Augment WordArray.init to handle typed arrays + var subInit = WordArray.init = function (typedArray) { + // Convert buffers to uint8 + if (typedArray instanceof ArrayBuffer) { + typedArray = new Uint8Array(typedArray); + } + + // Convert other array views to uint8 + if ( + typedArray instanceof Int8Array || + (typeof Uint8ClampedArray !== "undefined" && typedArray instanceof Uint8ClampedArray) || + typedArray instanceof Int16Array || + typedArray instanceof Uint16Array || + typedArray instanceof Int32Array || + typedArray instanceof Uint32Array || + typedArray instanceof Float32Array || + typedArray instanceof Float64Array + ) { + typedArray = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); + } + + // Handle Uint8Array + if (typedArray instanceof Uint8Array) { + // Shortcut + var typedArrayByteLength = typedArray.byteLength; + + // Extract bytes + var words = []; + for (var i = 0; i < typedArrayByteLength; i++) { + words[i >>> 2] |= typedArray[i] << (24 - (i % 4) * 8); + } + + // Initialize this word array + superInit.call(this, words, typedArrayByteLength); + } else { + // Else call normal init + superInit.apply(this, arguments); + } + }; + + subInit.prototype = WordArray; + }()); + + + return CryptoJS.lib.WordArray; + +})); +},{"./core":51}],59:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var T = []; + + // Compute constants + (function () { + for (var i = 0; i < 64; i++) { + T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0; + } + }()); + + /** + * MD5 hash algorithm. + */ + var MD5 = C_algo.MD5 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + + // Shortcuts + var H = this._hash.words; + + var M_offset_0 = M[offset + 0]; + var M_offset_1 = M[offset + 1]; + var M_offset_2 = M[offset + 2]; + var M_offset_3 = M[offset + 3]; + var M_offset_4 = M[offset + 4]; + var M_offset_5 = M[offset + 5]; + var M_offset_6 = M[offset + 6]; + var M_offset_7 = M[offset + 7]; + var M_offset_8 = M[offset + 8]; + var M_offset_9 = M[offset + 9]; + var M_offset_10 = M[offset + 10]; + var M_offset_11 = M[offset + 11]; + var M_offset_12 = M[offset + 12]; + var M_offset_13 = M[offset + 13]; + var M_offset_14 = M[offset + 14]; + var M_offset_15 = M[offset + 15]; + + // Working varialbes + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + + // Computation + a = FF(a, b, c, d, M_offset_0, 7, T[0]); + d = FF(d, a, b, c, M_offset_1, 12, T[1]); + c = FF(c, d, a, b, M_offset_2, 17, T[2]); + b = FF(b, c, d, a, M_offset_3, 22, T[3]); + a = FF(a, b, c, d, M_offset_4, 7, T[4]); + d = FF(d, a, b, c, M_offset_5, 12, T[5]); + c = FF(c, d, a, b, M_offset_6, 17, T[6]); + b = FF(b, c, d, a, M_offset_7, 22, T[7]); + a = FF(a, b, c, d, M_offset_8, 7, T[8]); + d = FF(d, a, b, c, M_offset_9, 12, T[9]); + c = FF(c, d, a, b, M_offset_10, 17, T[10]); + b = FF(b, c, d, a, M_offset_11, 22, T[11]); + a = FF(a, b, c, d, M_offset_12, 7, T[12]); + d = FF(d, a, b, c, M_offset_13, 12, T[13]); + c = FF(c, d, a, b, M_offset_14, 17, T[14]); + b = FF(b, c, d, a, M_offset_15, 22, T[15]); + + a = GG(a, b, c, d, M_offset_1, 5, T[16]); + d = GG(d, a, b, c, M_offset_6, 9, T[17]); + c = GG(c, d, a, b, M_offset_11, 14, T[18]); + b = GG(b, c, d, a, M_offset_0, 20, T[19]); + a = GG(a, b, c, d, M_offset_5, 5, T[20]); + d = GG(d, a, b, c, M_offset_10, 9, T[21]); + c = GG(c, d, a, b, M_offset_15, 14, T[22]); + b = GG(b, c, d, a, M_offset_4, 20, T[23]); + a = GG(a, b, c, d, M_offset_9, 5, T[24]); + d = GG(d, a, b, c, M_offset_14, 9, T[25]); + c = GG(c, d, a, b, M_offset_3, 14, T[26]); + b = GG(b, c, d, a, M_offset_8, 20, T[27]); + a = GG(a, b, c, d, M_offset_13, 5, T[28]); + d = GG(d, a, b, c, M_offset_2, 9, T[29]); + c = GG(c, d, a, b, M_offset_7, 14, T[30]); + b = GG(b, c, d, a, M_offset_12, 20, T[31]); + + a = HH(a, b, c, d, M_offset_5, 4, T[32]); + d = HH(d, a, b, c, M_offset_8, 11, T[33]); + c = HH(c, d, a, b, M_offset_11, 16, T[34]); + b = HH(b, c, d, a, M_offset_14, 23, T[35]); + a = HH(a, b, c, d, M_offset_1, 4, T[36]); + d = HH(d, a, b, c, M_offset_4, 11, T[37]); + c = HH(c, d, a, b, M_offset_7, 16, T[38]); + b = HH(b, c, d, a, M_offset_10, 23, T[39]); + a = HH(a, b, c, d, M_offset_13, 4, T[40]); + d = HH(d, a, b, c, M_offset_0, 11, T[41]); + c = HH(c, d, a, b, M_offset_3, 16, T[42]); + b = HH(b, c, d, a, M_offset_6, 23, T[43]); + a = HH(a, b, c, d, M_offset_9, 4, T[44]); + d = HH(d, a, b, c, M_offset_12, 11, T[45]); + c = HH(c, d, a, b, M_offset_15, 16, T[46]); + b = HH(b, c, d, a, M_offset_2, 23, T[47]); + + a = II(a, b, c, d, M_offset_0, 6, T[48]); + d = II(d, a, b, c, M_offset_7, 10, T[49]); + c = II(c, d, a, b, M_offset_14, 15, T[50]); + b = II(b, c, d, a, M_offset_5, 21, T[51]); + a = II(a, b, c, d, M_offset_12, 6, T[52]); + d = II(d, a, b, c, M_offset_3, 10, T[53]); + c = II(c, d, a, b, M_offset_10, 15, T[54]); + b = II(b, c, d, a, M_offset_1, 21, T[55]); + a = II(a, b, c, d, M_offset_8, 6, T[56]); + d = II(d, a, b, c, M_offset_15, 10, T[57]); + c = II(c, d, a, b, M_offset_6, 15, T[58]); + b = II(b, c, d, a, M_offset_13, 21, T[59]); + a = II(a, b, c, d, M_offset_4, 6, T[60]); + d = II(d, a, b, c, M_offset_11, 10, T[61]); + c = II(c, d, a, b, M_offset_2, 15, T[62]); + b = II(b, c, d, a, M_offset_9, 21, T[63]); + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + + var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000); + var nBitsTotalL = nBitsTotal; + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = ( + (((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) | + (((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00) + ); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) | + (((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00) + ); + + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 4; i++) { + // Shortcut + var H_i = H[i]; + + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + function FF(a, b, c, d, x, s, t) { + var n = a + ((b & c) | (~b & d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function GG(a, b, c, d, x, s, t) { + var n = a + ((b & d) | (c & ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function HH(a, b, c, d, x, s, t) { + var n = a + (b ^ c ^ d) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + function II(a, b, c, d, x, s, t) { + var n = a + (c ^ (b | ~d)) + x + t; + return ((n << s) | (n >>> (32 - s))) + b; + } + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.MD5('message'); + * var hash = CryptoJS.MD5(wordArray); + */ + C.MD5 = Hasher._createHelper(MD5); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacMD5(message, key); + */ + C.HmacMD5 = Hasher._createHmacHelper(MD5); + }(Math)); + + + return CryptoJS.MD5; + +})); +},{"./core":51}],60:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Cipher Feedback block mode. + */ + CryptoJS.mode.CFB = (function () { + var CFB = CryptoJS.lib.BlockCipherMode.extend(); + + CFB.Encryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // Remember this block to use with next block + this._prevBlock = words.slice(offset, offset + blockSize); + } + }); + + CFB.Decryptor = CFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher; + var blockSize = cipher.blockSize; + + // Remember this block to use with next block + var thisBlock = words.slice(offset, offset + blockSize); + + generateKeystreamAndEncrypt.call(this, words, offset, blockSize, cipher); + + // This block becomes the previous block + this._prevBlock = thisBlock; + } + }); + + function generateKeystreamAndEncrypt(words, offset, blockSize, cipher) { + // Shortcut + var iv = this._iv; + + // Generate keystream + if (iv) { + var keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } else { + var keystream = this._prevBlock; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + + return CFB; + }()); + + + return CryptoJS.mode.CFB; + +})); +},{"./cipher-core":50,"./core":51}],61:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** @preserve + * Counter block mode compatible with Dr Brian Gladman fileenc.c + * derived from CryptoJS.mode.CTR + * Jan Hruby jhruby.web@gmail.com + */ + CryptoJS.mode.CTRGladman = (function () { + var CTRGladman = CryptoJS.lib.BlockCipherMode.extend(); + + function incWord(word) + { + if (((word >> 24) & 0xff) === 0xff) { //overflow + var b1 = (word >> 16)&0xff; + var b2 = (word >> 8)&0xff; + var b3 = word & 0xff; + + if (b1 === 0xff) // overflow b1 + { + b1 = 0; + if (b2 === 0xff) + { + b2 = 0; + if (b3 === 0xff) + { + b3 = 0; + } + else + { + ++b3; + } + } + else + { + ++b2; + } + } + else + { + ++b1; + } + + word = 0; + word += (b1 << 16); + word += (b2 << 8); + word += b3; + } + else + { + word += (0x01 << 24); + } + return word; + } + + function incCounter(counter) + { + if ((counter[0] = incWord(counter[0])) === 0) + { + // encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8 + counter[1] = incWord(counter[1]); + } + return counter; + } + + var Encryptor = CTRGladman.Encryptor = CTRGladman.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + + incCounter(counter); + + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTRGladman.Decryptor = Encryptor; + + return CTRGladman; + }()); + + + + + return CryptoJS.mode.CTRGladman; + +})); +},{"./cipher-core":50,"./core":51}],62:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Counter block mode. + */ + CryptoJS.mode.CTR = (function () { + var CTR = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = CTR.Encryptor = CTR.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var counter = this._counter; + + // Generate keystream + if (iv) { + counter = this._counter = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + var keystream = counter.slice(0); + cipher.encryptBlock(keystream, 0); + + // Increment counter + counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0 + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + CTR.Decryptor = Encryptor; + + return CTR; + }()); + + + return CryptoJS.mode.CTR; + +})); +},{"./cipher-core":50,"./core":51}],63:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Electronic Codebook block mode. + */ + CryptoJS.mode.ECB = (function () { + var ECB = CryptoJS.lib.BlockCipherMode.extend(); + + ECB.Encryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.encryptBlock(words, offset); + } + }); + + ECB.Decryptor = ECB.extend({ + processBlock: function (words, offset) { + this._cipher.decryptBlock(words, offset); + } + }); + + return ECB; + }()); + + + return CryptoJS.mode.ECB; + +})); +},{"./cipher-core":50,"./core":51}],64:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Output Feedback block mode. + */ + CryptoJS.mode.OFB = (function () { + var OFB = CryptoJS.lib.BlockCipherMode.extend(); + + var Encryptor = OFB.Encryptor = OFB.extend({ + processBlock: function (words, offset) { + // Shortcuts + var cipher = this._cipher + var blockSize = cipher.blockSize; + var iv = this._iv; + var keystream = this._keystream; + + // Generate keystream + if (iv) { + keystream = this._keystream = iv.slice(0); + + // Remove IV for subsequent blocks + this._iv = undefined; + } + cipher.encryptBlock(keystream, 0); + + // Encrypt + for (var i = 0; i < blockSize; i++) { + words[offset + i] ^= keystream[i]; + } + } + }); + + OFB.Decryptor = Encryptor; + + return OFB; + }()); + + + return CryptoJS.mode.OFB; + +})); +},{"./cipher-core":50,"./core":51}],65:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ANSI X.923 padding strategy. + */ + CryptoJS.pad.AnsiX923 = { + pad: function (data, blockSize) { + // Shortcuts + var dataSigBytes = data.sigBytes; + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - dataSigBytes % blockSizeBytes; + + // Compute last byte position + var lastBytePos = dataSigBytes + nPaddingBytes - 1; + + // Pad + data.clamp(); + data.words[lastBytePos >>> 2] |= nPaddingBytes << (24 - (lastBytePos % 4) * 8); + data.sigBytes += nPaddingBytes; + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + return CryptoJS.pad.Ansix923; + +})); +},{"./cipher-core":50,"./core":51}],66:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ISO 10126 padding strategy. + */ + CryptoJS.pad.Iso10126 = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Count padding bytes + var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; + + // Pad + data.concat(CryptoJS.lib.WordArray.random(nPaddingBytes - 1)). + concat(CryptoJS.lib.WordArray.create([nPaddingBytes << 24], 1)); + }, + + unpad: function (data) { + // Get number of padding bytes from last byte + var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; + + // Remove padding + data.sigBytes -= nPaddingBytes; + } + }; + + + return CryptoJS.pad.Iso10126; + +})); +},{"./cipher-core":50,"./core":51}],67:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * ISO/IEC 9797-1 Padding Method 2. + */ + CryptoJS.pad.Iso97971 = { + pad: function (data, blockSize) { + // Add 0x80 byte + data.concat(CryptoJS.lib.WordArray.create([0x80000000], 1)); + + // Zero pad the rest + CryptoJS.pad.ZeroPadding.pad(data, blockSize); + }, + + unpad: function (data) { + // Remove zero padding + CryptoJS.pad.ZeroPadding.unpad(data); + + // Remove one more byte -- the 0x80 byte + data.sigBytes--; + } + }; + + + return CryptoJS.pad.Iso97971; + +})); +},{"./cipher-core":50,"./core":51}],68:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * A noop padding strategy. + */ + CryptoJS.pad.NoPadding = { + pad: function () { + }, + + unpad: function () { + } + }; + + + return CryptoJS.pad.NoPadding; + +})); +},{"./cipher-core":50,"./core":51}],69:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** + * Zero padding strategy. + */ + CryptoJS.pad.ZeroPadding = { + pad: function (data, blockSize) { + // Shortcut + var blockSizeBytes = blockSize * 4; + + // Pad + data.clamp(); + data.sigBytes += blockSizeBytes - ((data.sigBytes % blockSizeBytes) || blockSizeBytes); + }, + + unpad: function (data) { + // Shortcut + var dataWords = data.words; + + // Unpad + var i = data.sigBytes - 1; + while (!((dataWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff)) { + i--; + } + data.sigBytes = i + 1; + } + }; + + + return CryptoJS.pad.ZeroPadding; + +})); +},{"./cipher-core":50,"./core":51}],70:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha1"), require("./hmac")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha1", "./hmac"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA1 = C_algo.SHA1; + var HMAC = C_algo.HMAC; + + /** + * Password-Based Key Derivation Function 2 algorithm. + */ + var PBKDF2 = C_algo.PBKDF2 = Base.extend({ + /** + * Configuration options. + * + * @property {number} keySize The key size in words to generate. Default: 4 (128 bits) + * @property {Hasher} hasher The hasher to use. Default: SHA1 + * @property {number} iterations The number of iterations to perform. Default: 1 + */ + cfg: Base.extend({ + keySize: 128/32, + hasher: SHA1, + iterations: 1 + }), + + /** + * Initializes a newly created key derivation function. + * + * @param {Object} cfg (Optional) The configuration options to use for the derivation. + * + * @example + * + * var kdf = CryptoJS.algo.PBKDF2.create(); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8 }); + * var kdf = CryptoJS.algo.PBKDF2.create({ keySize: 8, iterations: 1000 }); + */ + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + }, + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * + * @return {WordArray} The derived key. + * + * @example + * + * var key = kdf.compute(password, salt); + */ + compute: function (password, salt) { + // Shortcut + var cfg = this.cfg; + + // Init HMAC + var hmac = HMAC.create(cfg.hasher, password); + + // Initial values + var derivedKey = WordArray.create(); + var blockIndex = WordArray.create([0x00000001]); + + // Shortcuts + var derivedKeyWords = derivedKey.words; + var blockIndexWords = blockIndex.words; + var keySize = cfg.keySize; + var iterations = cfg.iterations; + + // Generate key + while (derivedKeyWords.length < keySize) { + var block = hmac.update(salt).finalize(blockIndex); + hmac.reset(); + + // Shortcuts + var blockWords = block.words; + var blockWordsLength = blockWords.length; + + // Iterations + var intermediate = block; + for (var i = 1; i < iterations; i++) { + intermediate = hmac.finalize(intermediate); + hmac.reset(); + + // Shortcut + var intermediateWords = intermediate.words; + + // XOR intermediate with block + for (var j = 0; j < blockWordsLength; j++) { + blockWords[j] ^= intermediateWords[j]; + } + } + + derivedKey.concat(block); + blockIndexWords[0]++; + } + derivedKey.sigBytes = keySize * 4; + + return derivedKey; + } + }); + + /** + * Computes the Password-Based Key Derivation Function 2. + * + * @param {WordArray|string} password The password. + * @param {WordArray|string} salt A salt. + * @param {Object} cfg (Optional) The configuration options to use for this computation. + * + * @return {WordArray} The derived key. + * + * @static + * + * @example + * + * var key = CryptoJS.PBKDF2(password, salt); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8 }); + * var key = CryptoJS.PBKDF2(password, salt, { keySize: 8, iterations: 1000 }); + */ + C.PBKDF2 = function (password, salt, cfg) { + return PBKDF2.create(cfg).compute(password, salt); + }; + }()); + + + return CryptoJS.PBKDF2; + +})); +},{"./core":51,"./hmac":56,"./sha1":75}],71:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm. + * + * This is a legacy version that neglected to convert the key to little-endian. + * This error doesn't affect the cipher's security, + * but it does affect its compatibility with other implementations. + */ + var RabbitLegacy = C_algo.RabbitLegacy = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RabbitLegacy.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RabbitLegacy.decrypt(ciphertext, key, cfg); + */ + C.RabbitLegacy = StreamCipher._createHelper(RabbitLegacy); + }()); + + + return CryptoJS.RabbitLegacy; + +})); +},{"./cipher-core":50,"./core":51,"./enc-base64":52,"./evpkdf":54,"./md5":59}],72:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + // Reusable objects + var S = []; + var C_ = []; + var G = []; + + /** + * Rabbit stream cipher algorithm + */ + var Rabbit = C_algo.Rabbit = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var K = this._key.words; + var iv = this.cfg.iv; + + // Swap endian + for (var i = 0; i < 4; i++) { + K[i] = (((K[i] << 8) | (K[i] >>> 24)) & 0x00ff00ff) | + (((K[i] << 24) | (K[i] >>> 8)) & 0xff00ff00); + } + + // Generate initial state values + var X = this._X = [ + K[0], (K[3] << 16) | (K[2] >>> 16), + K[1], (K[0] << 16) | (K[3] >>> 16), + K[2], (K[1] << 16) | (K[0] >>> 16), + K[3], (K[2] << 16) | (K[1] >>> 16) + ]; + + // Generate initial counter values + var C = this._C = [ + (K[2] << 16) | (K[2] >>> 16), (K[0] & 0xffff0000) | (K[1] & 0x0000ffff), + (K[3] << 16) | (K[3] >>> 16), (K[1] & 0xffff0000) | (K[2] & 0x0000ffff), + (K[0] << 16) | (K[0] >>> 16), (K[2] & 0xffff0000) | (K[3] & 0x0000ffff), + (K[1] << 16) | (K[1] >>> 16), (K[3] & 0xffff0000) | (K[0] & 0x0000ffff) + ]; + + // Carry bit + this._b = 0; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + + // Modify the counters + for (var i = 0; i < 8; i++) { + C[i] ^= X[(i + 4) & 7]; + } + + // IV setup + if (iv) { + // Shortcuts + var IV = iv.words; + var IV_0 = IV[0]; + var IV_1 = IV[1]; + + // Generate four subvectors + var i0 = (((IV_0 << 8) | (IV_0 >>> 24)) & 0x00ff00ff) | (((IV_0 << 24) | (IV_0 >>> 8)) & 0xff00ff00); + var i2 = (((IV_1 << 8) | (IV_1 >>> 24)) & 0x00ff00ff) | (((IV_1 << 24) | (IV_1 >>> 8)) & 0xff00ff00); + var i1 = (i0 >>> 16) | (i2 & 0xffff0000); + var i3 = (i2 << 16) | (i0 & 0x0000ffff); + + // Modify counter values + C[0] ^= i0; + C[1] ^= i1; + C[2] ^= i2; + C[3] ^= i3; + C[4] ^= i0; + C[5] ^= i1; + C[6] ^= i2; + C[7] ^= i3; + + // Iterate the system four times + for (var i = 0; i < 4; i++) { + nextState.call(this); + } + } + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var X = this._X; + + // Iterate the system + nextState.call(this); + + // Generate four keystream words + S[0] = X[0] ^ (X[5] >>> 16) ^ (X[3] << 16); + S[1] = X[2] ^ (X[7] >>> 16) ^ (X[5] << 16); + S[2] = X[4] ^ (X[1] >>> 16) ^ (X[7] << 16); + S[3] = X[6] ^ (X[3] >>> 16) ^ (X[1] << 16); + + for (var i = 0; i < 4; i++) { + // Swap endian + S[i] = (((S[i] << 8) | (S[i] >>> 24)) & 0x00ff00ff) | + (((S[i] << 24) | (S[i] >>> 8)) & 0xff00ff00); + + // Encrypt + M[offset + i] ^= S[i]; + } + }, + + blockSize: 128/32, + + ivSize: 64/32 + }); + + function nextState() { + // Shortcuts + var X = this._X; + var C = this._C; + + // Save old counter values + for (var i = 0; i < 8; i++) { + C_[i] = C[i]; + } + + // Calculate new counter values + C[0] = (C[0] + 0x4d34d34d + this._b) | 0; + C[1] = (C[1] + 0xd34d34d3 + ((C[0] >>> 0) < (C_[0] >>> 0) ? 1 : 0)) | 0; + C[2] = (C[2] + 0x34d34d34 + ((C[1] >>> 0) < (C_[1] >>> 0) ? 1 : 0)) | 0; + C[3] = (C[3] + 0x4d34d34d + ((C[2] >>> 0) < (C_[2] >>> 0) ? 1 : 0)) | 0; + C[4] = (C[4] + 0xd34d34d3 + ((C[3] >>> 0) < (C_[3] >>> 0) ? 1 : 0)) | 0; + C[5] = (C[5] + 0x34d34d34 + ((C[4] >>> 0) < (C_[4] >>> 0) ? 1 : 0)) | 0; + C[6] = (C[6] + 0x4d34d34d + ((C[5] >>> 0) < (C_[5] >>> 0) ? 1 : 0)) | 0; + C[7] = (C[7] + 0xd34d34d3 + ((C[6] >>> 0) < (C_[6] >>> 0) ? 1 : 0)) | 0; + this._b = (C[7] >>> 0) < (C_[7] >>> 0) ? 1 : 0; + + // Calculate the g-values + for (var i = 0; i < 8; i++) { + var gx = X[i] + C[i]; + + // Construct high and low argument for squaring + var ga = gx & 0xffff; + var gb = gx >>> 16; + + // Calculate high and low result of squaring + var gh = ((((ga * ga) >>> 17) + ga * gb) >>> 15) + gb * gb; + var gl = (((gx & 0xffff0000) * gx) | 0) + (((gx & 0x0000ffff) * gx) | 0); + + // High XOR low + G[i] = gh ^ gl; + } + + // Calculate new state values + X[0] = (G[0] + ((G[7] << 16) | (G[7] >>> 16)) + ((G[6] << 16) | (G[6] >>> 16))) | 0; + X[1] = (G[1] + ((G[0] << 8) | (G[0] >>> 24)) + G[7]) | 0; + X[2] = (G[2] + ((G[1] << 16) | (G[1] >>> 16)) + ((G[0] << 16) | (G[0] >>> 16))) | 0; + X[3] = (G[3] + ((G[2] << 8) | (G[2] >>> 24)) + G[1]) | 0; + X[4] = (G[4] + ((G[3] << 16) | (G[3] >>> 16)) + ((G[2] << 16) | (G[2] >>> 16))) | 0; + X[5] = (G[5] + ((G[4] << 8) | (G[4] >>> 24)) + G[3]) | 0; + X[6] = (G[6] + ((G[5] << 16) | (G[5] >>> 16)) + ((G[4] << 16) | (G[4] >>> 16))) | 0; + X[7] = (G[7] + ((G[6] << 8) | (G[6] >>> 24)) + G[5]) | 0; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.Rabbit.encrypt(message, key, cfg); + * var plaintext = CryptoJS.Rabbit.decrypt(ciphertext, key, cfg); + */ + C.Rabbit = StreamCipher._createHelper(Rabbit); + }()); + + + return CryptoJS.Rabbit; + +})); +},{"./cipher-core":50,"./core":51,"./enc-base64":52,"./evpkdf":54,"./md5":59}],73:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var StreamCipher = C_lib.StreamCipher; + var C_algo = C.algo; + + /** + * RC4 stream cipher algorithm. + */ + var RC4 = C_algo.RC4 = StreamCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + var keySigBytes = key.sigBytes; + + // Init sbox + var S = this._S = []; + for (var i = 0; i < 256; i++) { + S[i] = i; + } + + // Key setup + for (var i = 0, j = 0; i < 256; i++) { + var keyByteIndex = i % keySigBytes; + var keyByte = (keyWords[keyByteIndex >>> 2] >>> (24 - (keyByteIndex % 4) * 8)) & 0xff; + + j = (j + S[i] + keyByte) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + } + + // Counters + this._i = this._j = 0; + }, + + _doProcessBlock: function (M, offset) { + M[offset] ^= generateKeystreamWord.call(this); + }, + + keySize: 256/32, + + ivSize: 0 + }); + + function generateKeystreamWord() { + // Shortcuts + var S = this._S; + var i = this._i; + var j = this._j; + + // Generate keystream word + var keystreamWord = 0; + for (var n = 0; n < 4; n++) { + i = (i + 1) % 256; + j = (j + S[i]) % 256; + + // Swap + var t = S[i]; + S[i] = S[j]; + S[j] = t; + + keystreamWord |= S[(S[i] + S[j]) % 256] << (24 - n * 8); + } + + // Update counters + this._i = i; + this._j = j; + + return keystreamWord; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4.decrypt(ciphertext, key, cfg); + */ + C.RC4 = StreamCipher._createHelper(RC4); + + /** + * Modified RC4 stream cipher algorithm. + */ + var RC4Drop = C_algo.RC4Drop = RC4.extend({ + /** + * Configuration options. + * + * @property {number} drop The number of keystream words to drop. Default 192 + */ + cfg: RC4.cfg.extend({ + drop: 192 + }), + + _doReset: function () { + RC4._doReset.call(this); + + // Drop + for (var i = this.cfg.drop; i > 0; i--) { + generateKeystreamWord.call(this); + } + } + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.RC4Drop.encrypt(message, key, cfg); + * var plaintext = CryptoJS.RC4Drop.decrypt(ciphertext, key, cfg); + */ + C.RC4Drop = StreamCipher._createHelper(RC4Drop); + }()); + + + return CryptoJS.RC4; + +})); +},{"./cipher-core":50,"./core":51,"./enc-base64":52,"./evpkdf":54,"./md5":59}],74:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + /** @preserve + (c) 2012 by Cédric Mesnil. 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. + + 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 HOLDER 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. + */ + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Constants table + var _zl = WordArray.create([ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13]); + var _zr = WordArray.create([ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]); + var _sl = WordArray.create([ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ]); + var _sr = WordArray.create([ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ]); + + var _hl = WordArray.create([ 0x00000000, 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xA953FD4E]); + var _hr = WordArray.create([ 0x50A28BE6, 0x5C4DD124, 0x6D703EF3, 0x7A6D76E9, 0x00000000]); + + /** + * RIPEMD160 hash algorithm. + */ + var RIPEMD160 = C_algo.RIPEMD160 = Hasher.extend({ + _doReset: function () { + this._hash = WordArray.create([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]); + }, + + _doProcessBlock: function (M, offset) { + + // Swap endian + for (var i = 0; i < 16; i++) { + // Shortcuts + var offset_i = offset + i; + var M_offset_i = M[offset_i]; + + // Swap + M[offset_i] = ( + (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) | + (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00) + ); + } + // Shortcut + var H = this._hash.words; + var hl = _hl.words; + var hr = _hr.words; + var zl = _zl.words; + var zr = _zr.words; + var sl = _sl.words; + var sr = _sr.words; + + // Working variables + var al, bl, cl, dl, el; + var ar, br, cr, dr, er; + + ar = al = H[0]; + br = bl = H[1]; + cr = cl = H[2]; + dr = dl = H[3]; + er = el = H[4]; + // Computation + var t; + for (var i = 0; i < 80; i += 1) { + t = (al + M[offset+zl[i]])|0; + if (i<16){ + t += f1(bl,cl,dl) + hl[0]; + } else if (i<32) { + t += f2(bl,cl,dl) + hl[1]; + } else if (i<48) { + t += f3(bl,cl,dl) + hl[2]; + } else if (i<64) { + t += f4(bl,cl,dl) + hl[3]; + } else {// if (i<80) { + t += f5(bl,cl,dl) + hl[4]; + } + t = t|0; + t = rotl(t,sl[i]); + t = (t+el)|0; + al = el; + el = dl; + dl = rotl(cl, 10); + cl = bl; + bl = t; + + t = (ar + M[offset+zr[i]])|0; + if (i<16){ + t += f5(br,cr,dr) + hr[0]; + } else if (i<32) { + t += f4(br,cr,dr) + hr[1]; + } else if (i<48) { + t += f3(br,cr,dr) + hr[2]; + } else if (i<64) { + t += f2(br,cr,dr) + hr[3]; + } else {// if (i<80) { + t += f1(br,cr,dr) + hr[4]; + } + t = t|0; + t = rotl(t,sr[i]) ; + t = (t+er)|0; + ar = er; + er = dr; + dr = rotl(cr, 10); + cr = br; + br = t; + } + // Intermediate hash value + t = (H[1] + cl + dr)|0; + H[1] = (H[2] + dl + er)|0; + H[2] = (H[3] + el + ar)|0; + H[3] = (H[4] + al + br)|0; + H[4] = (H[0] + bl + cr)|0; + H[0] = t; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = ( + (((nBitsTotal << 8) | (nBitsTotal >>> 24)) & 0x00ff00ff) | + (((nBitsTotal << 24) | (nBitsTotal >>> 8)) & 0xff00ff00) + ); + data.sigBytes = (dataWords.length + 1) * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var hash = this._hash; + var H = hash.words; + + // Swap endian + for (var i = 0; i < 5; i++) { + // Shortcut + var H_i = H[i]; + + // Swap + H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) | + (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00); + } + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + + function f1(x, y, z) { + return ((x) ^ (y) ^ (z)); + + } + + function f2(x, y, z) { + return (((x)&(y)) | ((~x)&(z))); + } + + function f3(x, y, z) { + return (((x) | (~(y))) ^ (z)); + } + + function f4(x, y, z) { + return (((x) & (z)) | ((y)&(~(z)))); + } + + function f5(x, y, z) { + return ((x) ^ ((y) |(~(z)))); + + } + + function rotl(x,n) { + return (x<>>(32-n)); + } + + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.RIPEMD160('message'); + * var hash = CryptoJS.RIPEMD160(wordArray); + */ + C.RIPEMD160 = Hasher._createHelper(RIPEMD160); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacRIPEMD160(message, key); + */ + C.HmacRIPEMD160 = Hasher._createHmacHelper(RIPEMD160); + }(Math)); + + + return CryptoJS.RIPEMD160; + +})); +},{"./core":51}],75:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Reusable object + var W = []; + + /** + * SHA-1 hash algorithm. + */ + var SHA1 = C_algo.SHA1 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0x67452301, 0xefcdab89, + 0x98badcfe, 0x10325476, + 0xc3d2e1f0 + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + + // Computation + for (var i = 0; i < 80; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var n = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; + W[i] = (n << 1) | (n >>> 31); + } + + var t = ((a << 5) | (a >>> 27)) + e + W[i]; + if (i < 20) { + t += ((b & c) | (~b & d)) + 0x5a827999; + } else if (i < 40) { + t += (b ^ c ^ d) + 0x6ed9eba1; + } else if (i < 60) { + t += ((b & c) | (b & d) | (c & d)) - 0x70e44324; + } else /* if (i < 80) */ { + t += (b ^ c ^ d) - 0x359d3e2a; + } + + e = d; + d = c; + c = (b << 30) | (b >>> 2); + b = a; + a = t; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA1('message'); + * var hash = CryptoJS.SHA1(wordArray); + */ + C.SHA1 = Hasher._createHelper(SHA1); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA1(message, key); + */ + C.HmacSHA1 = Hasher._createHmacHelper(SHA1); + }()); + + + return CryptoJS.SHA1; + +})); +},{"./core":51}],76:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./sha256")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./sha256"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_algo = C.algo; + var SHA256 = C_algo.SHA256; + + /** + * SHA-224 hash algorithm. + */ + var SHA224 = C_algo.SHA224 = SHA256.extend({ + _doReset: function () { + this._hash = new WordArray.init([ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 + ]); + }, + + _doFinalize: function () { + var hash = SHA256._doFinalize.call(this); + + hash.sigBytes -= 4; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA224('message'); + * var hash = CryptoJS.SHA224(wordArray); + */ + C.SHA224 = SHA256._createHelper(SHA224); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA224(message, key); + */ + C.HmacSHA224 = SHA256._createHmacHelper(SHA224); + }()); + + + return CryptoJS.SHA224; + +})); +},{"./core":51,"./sha256":77}],77:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_algo = C.algo; + + // Initialization and round constants tables + var H = []; + var K = []; + + // Compute constants + (function () { + function isPrime(n) { + var sqrtN = Math.sqrt(n); + for (var factor = 2; factor <= sqrtN; factor++) { + if (!(n % factor)) { + return false; + } + } + + return true; + } + + function getFractionalBits(n) { + return ((n - (n | 0)) * 0x100000000) | 0; + } + + var n = 2; + var nPrime = 0; + while (nPrime < 64) { + if (isPrime(n)) { + if (nPrime < 8) { + H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); + } + K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); + + nPrime++; + } + + n++; + } + }()); + + // Reusable object + var W = []; + + /** + * SHA-256 hash algorithm. + */ + var SHA256 = C_algo.SHA256 = Hasher.extend({ + _doReset: function () { + this._hash = new WordArray.init(H.slice(0)); + }, + + _doProcessBlock: function (M, offset) { + // Shortcut + var H = this._hash.words; + + // Working variables + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + var f = H[5]; + var g = H[6]; + var h = H[7]; + + // Computation + for (var i = 0; i < 64; i++) { + if (i < 16) { + W[i] = M[offset + i] | 0; + } else { + var gamma0x = W[i - 15]; + var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ + ((gamma0x << 14) | (gamma0x >>> 18)) ^ + (gamma0x >>> 3); + + var gamma1x = W[i - 2]; + var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ + ((gamma1x << 13) | (gamma1x >>> 19)) ^ + (gamma1x >>> 10); + + W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; + } + + var ch = (e & f) ^ (~e & g); + var maj = (a & b) ^ (a & c) ^ (b & c); + + var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); + var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); + + var t1 = h + sigma1 + ch + K[i] + W[i]; + var t2 = sigma0 + maj; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } + + // Intermediate hash value + H[0] = (H[0] + a) | 0; + H[1] = (H[1] + b) | 0; + H[2] = (H[2] + c) | 0; + H[3] = (H[3] + d) | 0; + H[4] = (H[4] + e) | 0; + H[5] = (H[5] + f) | 0; + H[6] = (H[6] + g) | 0; + H[7] = (H[7] + h) | 0; + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Return final computed hash + return this._hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA256('message'); + * var hash = CryptoJS.SHA256(wordArray); + */ + C.SHA256 = Hasher._createHelper(SHA256); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA256(message, key); + */ + C.HmacSHA256 = Hasher._createHmacHelper(SHA256); + }(Math)); + + + return CryptoJS.SHA256; + +})); +},{"./core":51}],78:[function(require,module,exports){ ;(function (root, factory, undef) { if (typeof exports === "object") { // CommonJS @@ -7242,7 +11358,1186 @@ module.exports = transfer; return CryptoJS.SHA3; })); -},{"./core":47,"./x64-core":49}],49:[function(require,module,exports){ +},{"./core":51,"./x64-core":82}],79:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core"), require("./sha512")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core", "./sha512"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + var SHA512 = C_algo.SHA512; + + /** + * SHA-384 hash algorithm. + */ + var SHA384 = C_algo.SHA384 = SHA512.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0xcbbb9d5d, 0xc1059ed8), new X64Word.init(0x629a292a, 0x367cd507), + new X64Word.init(0x9159015a, 0x3070dd17), new X64Word.init(0x152fecd8, 0xf70e5939), + new X64Word.init(0x67332667, 0xffc00b31), new X64Word.init(0x8eb44a87, 0x68581511), + new X64Word.init(0xdb0c2e0d, 0x64f98fa7), new X64Word.init(0x47b5481d, 0xbefa4fa4) + ]); + }, + + _doFinalize: function () { + var hash = SHA512._doFinalize.call(this); + + hash.sigBytes -= 16; + + return hash; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA384('message'); + * var hash = CryptoJS.SHA384(wordArray); + */ + C.SHA384 = SHA512._createHelper(SHA384); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA384(message, key); + */ + C.HmacSHA384 = SHA512._createHmacHelper(SHA384); + }()); + + + return CryptoJS.SHA384; + +})); +},{"./core":51,"./sha512":80,"./x64-core":82}],80:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var X64WordArray = C_x64.WordArray; + var C_algo = C.algo; + + function X64Word_create() { + return X64Word.create.apply(X64Word, arguments); + } + + // Constants + var K = [ + X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd), + X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc), + X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019), + X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118), + X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe), + X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2), + X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1), + X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694), + X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3), + X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65), + X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483), + X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5), + X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210), + X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4), + X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725), + X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70), + X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926), + X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df), + X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8), + X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b), + X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001), + X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30), + X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910), + X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8), + X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53), + X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8), + X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb), + X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3), + X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60), + X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec), + X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9), + X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b), + X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207), + X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178), + X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6), + X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b), + X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493), + X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c), + X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a), + X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817) + ]; + + // Reusable objects + var W = []; + (function () { + for (var i = 0; i < 80; i++) { + W[i] = X64Word_create(); + } + }()); + + /** + * SHA-512 hash algorithm. + */ + var SHA512 = C_algo.SHA512 = Hasher.extend({ + _doReset: function () { + this._hash = new X64WordArray.init([ + new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b), + new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1), + new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f), + new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179) + ]); + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var H = this._hash.words; + + var H0 = H[0]; + var H1 = H[1]; + var H2 = H[2]; + var H3 = H[3]; + var H4 = H[4]; + var H5 = H[5]; + var H6 = H[6]; + var H7 = H[7]; + + var H0h = H0.high; + var H0l = H0.low; + var H1h = H1.high; + var H1l = H1.low; + var H2h = H2.high; + var H2l = H2.low; + var H3h = H3.high; + var H3l = H3.low; + var H4h = H4.high; + var H4l = H4.low; + var H5h = H5.high; + var H5l = H5.low; + var H6h = H6.high; + var H6l = H6.low; + var H7h = H7.high; + var H7l = H7.low; + + // Working variables + var ah = H0h; + var al = H0l; + var bh = H1h; + var bl = H1l; + var ch = H2h; + var cl = H2l; + var dh = H3h; + var dl = H3l; + var eh = H4h; + var el = H4l; + var fh = H5h; + var fl = H5l; + var gh = H6h; + var gl = H6l; + var hh = H7h; + var hl = H7l; + + // Rounds + for (var i = 0; i < 80; i++) { + // Shortcut + var Wi = W[i]; + + // Extend message + if (i < 16) { + var Wih = Wi.high = M[offset + i * 2] | 0; + var Wil = Wi.low = M[offset + i * 2 + 1] | 0; + } else { + // Gamma0 + var gamma0x = W[i - 15]; + var gamma0xh = gamma0x.high; + var gamma0xl = gamma0x.low; + var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7); + var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25)); + + // Gamma1 + var gamma1x = W[i - 2]; + var gamma1xh = gamma1x.high; + var gamma1xl = gamma1x.low; + var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6); + var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26)); + + // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16] + var Wi7 = W[i - 7]; + var Wi7h = Wi7.high; + var Wi7l = Wi7.low; + + var Wi16 = W[i - 16]; + var Wi16h = Wi16.high; + var Wi16l = Wi16.low; + + var Wil = gamma0l + Wi7l; + var Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0); + var Wil = Wil + gamma1l; + var Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0); + var Wil = Wil + Wi16l; + var Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0); + + Wi.high = Wih; + Wi.low = Wil; + } + + var chh = (eh & fh) ^ (~eh & gh); + var chl = (el & fl) ^ (~el & gl); + var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch); + var majl = (al & bl) ^ (al & cl) ^ (bl & cl); + + var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7)); + var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7)); + var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9)); + var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9)); + + // t1 = h + sigma1 + ch + K[i] + W[i] + var Ki = K[i]; + var Kih = Ki.high; + var Kil = Ki.low; + + var t1l = hl + sigma1l; + var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0); + var t1l = t1l + chl; + var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0); + var t1l = t1l + Kil; + var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0); + var t1l = t1l + Wil; + var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0); + + // t2 = sigma0 + maj + var t2l = sigma0l + majl; + var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0); + + // Update working variables + hh = gh; + hl = gl; + gh = fh; + gl = fl; + fh = eh; + fl = el; + el = (dl + t1l) | 0; + eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0; + dh = ch; + dl = cl; + ch = bh; + cl = bl; + bh = ah; + bl = al; + al = (t1l + t2l) | 0; + ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0; + } + + // Intermediate hash value + H0l = H0.low = (H0l + al); + H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0)); + H1l = H1.low = (H1l + bl); + H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0)); + H2l = H2.low = (H2l + cl); + H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0)); + H3l = H3.low = (H3l + dl); + H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0)); + H4l = H4.low = (H4l + el); + H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0)); + H5l = H5.low = (H5l + fl); + H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0)); + H6l = H6.low = (H6l + gl); + H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0)); + H7l = H7.low = (H7l + hl); + H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0)); + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000); + dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Convert hash to 32-bit word array before returning + var hash = this._hash.toX32(); + + // Return final computed hash + return hash; + }, + + clone: function () { + var clone = Hasher.clone.call(this); + clone._hash = this._hash.clone(); + + return clone; + }, + + blockSize: 1024/32 + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA512('message'); + * var hash = CryptoJS.SHA512(wordArray); + */ + C.SHA512 = Hasher._createHelper(SHA512); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA512(message, key); + */ + C.HmacSHA512 = Hasher._createHmacHelper(SHA512); + }()); + + + return CryptoJS.SHA512; + +})); +},{"./core":51,"./x64-core":82}],81:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./enc-base64"), require("./md5"), require("./evpkdf"), require("./cipher-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./enc-base64", "./md5", "./evpkdf", "./cipher-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function () { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var BlockCipher = C_lib.BlockCipher; + var C_algo = C.algo; + + // Permuted Choice 1 constants + var PC1 = [ + 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, + 59, 51, 43, 35, 27, 19, 11, 3, + 60, 52, 44, 36, 63, 55, 47, 39, + 31, 23, 15, 7, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, + 29, 21, 13, 5, 28, 20, 12, 4 + ]; + + // Permuted Choice 2 constants + var PC2 = [ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 + ]; + + // Cumulative bit shift constants + var BIT_SHIFTS = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]; + + // SBOXes and round permutation constants + var SBOX_P = [ + { + 0x0: 0x808200, + 0x10000000: 0x8000, + 0x20000000: 0x808002, + 0x30000000: 0x2, + 0x40000000: 0x200, + 0x50000000: 0x808202, + 0x60000000: 0x800202, + 0x70000000: 0x800000, + 0x80000000: 0x202, + 0x90000000: 0x800200, + 0xa0000000: 0x8200, + 0xb0000000: 0x808000, + 0xc0000000: 0x8002, + 0xd0000000: 0x800002, + 0xe0000000: 0x0, + 0xf0000000: 0x8202, + 0x8000000: 0x0, + 0x18000000: 0x808202, + 0x28000000: 0x8202, + 0x38000000: 0x8000, + 0x48000000: 0x808200, + 0x58000000: 0x200, + 0x68000000: 0x808002, + 0x78000000: 0x2, + 0x88000000: 0x800200, + 0x98000000: 0x8200, + 0xa8000000: 0x808000, + 0xb8000000: 0x800202, + 0xc8000000: 0x800002, + 0xd8000000: 0x8002, + 0xe8000000: 0x202, + 0xf8000000: 0x800000, + 0x1: 0x8000, + 0x10000001: 0x2, + 0x20000001: 0x808200, + 0x30000001: 0x800000, + 0x40000001: 0x808002, + 0x50000001: 0x8200, + 0x60000001: 0x200, + 0x70000001: 0x800202, + 0x80000001: 0x808202, + 0x90000001: 0x808000, + 0xa0000001: 0x800002, + 0xb0000001: 0x8202, + 0xc0000001: 0x202, + 0xd0000001: 0x800200, + 0xe0000001: 0x8002, + 0xf0000001: 0x0, + 0x8000001: 0x808202, + 0x18000001: 0x808000, + 0x28000001: 0x800000, + 0x38000001: 0x200, + 0x48000001: 0x8000, + 0x58000001: 0x800002, + 0x68000001: 0x2, + 0x78000001: 0x8202, + 0x88000001: 0x8002, + 0x98000001: 0x800202, + 0xa8000001: 0x202, + 0xb8000001: 0x808200, + 0xc8000001: 0x800200, + 0xd8000001: 0x0, + 0xe8000001: 0x8200, + 0xf8000001: 0x808002 + }, + { + 0x0: 0x40084010, + 0x1000000: 0x4000, + 0x2000000: 0x80000, + 0x3000000: 0x40080010, + 0x4000000: 0x40000010, + 0x5000000: 0x40084000, + 0x6000000: 0x40004000, + 0x7000000: 0x10, + 0x8000000: 0x84000, + 0x9000000: 0x40004010, + 0xa000000: 0x40000000, + 0xb000000: 0x84010, + 0xc000000: 0x80010, + 0xd000000: 0x0, + 0xe000000: 0x4010, + 0xf000000: 0x40080000, + 0x800000: 0x40004000, + 0x1800000: 0x84010, + 0x2800000: 0x10, + 0x3800000: 0x40004010, + 0x4800000: 0x40084010, + 0x5800000: 0x40000000, + 0x6800000: 0x80000, + 0x7800000: 0x40080010, + 0x8800000: 0x80010, + 0x9800000: 0x0, + 0xa800000: 0x4000, + 0xb800000: 0x40080000, + 0xc800000: 0x40000010, + 0xd800000: 0x84000, + 0xe800000: 0x40084000, + 0xf800000: 0x4010, + 0x10000000: 0x0, + 0x11000000: 0x40080010, + 0x12000000: 0x40004010, + 0x13000000: 0x40084000, + 0x14000000: 0x40080000, + 0x15000000: 0x10, + 0x16000000: 0x84010, + 0x17000000: 0x4000, + 0x18000000: 0x4010, + 0x19000000: 0x80000, + 0x1a000000: 0x80010, + 0x1b000000: 0x40000010, + 0x1c000000: 0x84000, + 0x1d000000: 0x40004000, + 0x1e000000: 0x40000000, + 0x1f000000: 0x40084010, + 0x10800000: 0x84010, + 0x11800000: 0x80000, + 0x12800000: 0x40080000, + 0x13800000: 0x4000, + 0x14800000: 0x40004000, + 0x15800000: 0x40084010, + 0x16800000: 0x10, + 0x17800000: 0x40000000, + 0x18800000: 0x40084000, + 0x19800000: 0x40000010, + 0x1a800000: 0x40004010, + 0x1b800000: 0x80010, + 0x1c800000: 0x0, + 0x1d800000: 0x4010, + 0x1e800000: 0x40080010, + 0x1f800000: 0x84000 + }, + { + 0x0: 0x104, + 0x100000: 0x0, + 0x200000: 0x4000100, + 0x300000: 0x10104, + 0x400000: 0x10004, + 0x500000: 0x4000004, + 0x600000: 0x4010104, + 0x700000: 0x4010000, + 0x800000: 0x4000000, + 0x900000: 0x4010100, + 0xa00000: 0x10100, + 0xb00000: 0x4010004, + 0xc00000: 0x4000104, + 0xd00000: 0x10000, + 0xe00000: 0x4, + 0xf00000: 0x100, + 0x80000: 0x4010100, + 0x180000: 0x4010004, + 0x280000: 0x0, + 0x380000: 0x4000100, + 0x480000: 0x4000004, + 0x580000: 0x10000, + 0x680000: 0x10004, + 0x780000: 0x104, + 0x880000: 0x4, + 0x980000: 0x100, + 0xa80000: 0x4010000, + 0xb80000: 0x10104, + 0xc80000: 0x10100, + 0xd80000: 0x4000104, + 0xe80000: 0x4010104, + 0xf80000: 0x4000000, + 0x1000000: 0x4010100, + 0x1100000: 0x10004, + 0x1200000: 0x10000, + 0x1300000: 0x4000100, + 0x1400000: 0x100, + 0x1500000: 0x4010104, + 0x1600000: 0x4000004, + 0x1700000: 0x0, + 0x1800000: 0x4000104, + 0x1900000: 0x4000000, + 0x1a00000: 0x4, + 0x1b00000: 0x10100, + 0x1c00000: 0x4010000, + 0x1d00000: 0x104, + 0x1e00000: 0x10104, + 0x1f00000: 0x4010004, + 0x1080000: 0x4000000, + 0x1180000: 0x104, + 0x1280000: 0x4010100, + 0x1380000: 0x0, + 0x1480000: 0x10004, + 0x1580000: 0x4000100, + 0x1680000: 0x100, + 0x1780000: 0x4010004, + 0x1880000: 0x10000, + 0x1980000: 0x4010104, + 0x1a80000: 0x10104, + 0x1b80000: 0x4000004, + 0x1c80000: 0x4000104, + 0x1d80000: 0x4010000, + 0x1e80000: 0x4, + 0x1f80000: 0x10100 + }, + { + 0x0: 0x80401000, + 0x10000: 0x80001040, + 0x20000: 0x401040, + 0x30000: 0x80400000, + 0x40000: 0x0, + 0x50000: 0x401000, + 0x60000: 0x80000040, + 0x70000: 0x400040, + 0x80000: 0x80000000, + 0x90000: 0x400000, + 0xa0000: 0x40, + 0xb0000: 0x80001000, + 0xc0000: 0x80400040, + 0xd0000: 0x1040, + 0xe0000: 0x1000, + 0xf0000: 0x80401040, + 0x8000: 0x80001040, + 0x18000: 0x40, + 0x28000: 0x80400040, + 0x38000: 0x80001000, + 0x48000: 0x401000, + 0x58000: 0x80401040, + 0x68000: 0x0, + 0x78000: 0x80400000, + 0x88000: 0x1000, + 0x98000: 0x80401000, + 0xa8000: 0x400000, + 0xb8000: 0x1040, + 0xc8000: 0x80000000, + 0xd8000: 0x400040, + 0xe8000: 0x401040, + 0xf8000: 0x80000040, + 0x100000: 0x400040, + 0x110000: 0x401000, + 0x120000: 0x80000040, + 0x130000: 0x0, + 0x140000: 0x1040, + 0x150000: 0x80400040, + 0x160000: 0x80401000, + 0x170000: 0x80001040, + 0x180000: 0x80401040, + 0x190000: 0x80000000, + 0x1a0000: 0x80400000, + 0x1b0000: 0x401040, + 0x1c0000: 0x80001000, + 0x1d0000: 0x400000, + 0x1e0000: 0x40, + 0x1f0000: 0x1000, + 0x108000: 0x80400000, + 0x118000: 0x80401040, + 0x128000: 0x0, + 0x138000: 0x401000, + 0x148000: 0x400040, + 0x158000: 0x80000000, + 0x168000: 0x80001040, + 0x178000: 0x40, + 0x188000: 0x80000040, + 0x198000: 0x1000, + 0x1a8000: 0x80001000, + 0x1b8000: 0x80400040, + 0x1c8000: 0x1040, + 0x1d8000: 0x80401000, + 0x1e8000: 0x400000, + 0x1f8000: 0x401040 + }, + { + 0x0: 0x80, + 0x1000: 0x1040000, + 0x2000: 0x40000, + 0x3000: 0x20000000, + 0x4000: 0x20040080, + 0x5000: 0x1000080, + 0x6000: 0x21000080, + 0x7000: 0x40080, + 0x8000: 0x1000000, + 0x9000: 0x20040000, + 0xa000: 0x20000080, + 0xb000: 0x21040080, + 0xc000: 0x21040000, + 0xd000: 0x0, + 0xe000: 0x1040080, + 0xf000: 0x21000000, + 0x800: 0x1040080, + 0x1800: 0x21000080, + 0x2800: 0x80, + 0x3800: 0x1040000, + 0x4800: 0x40000, + 0x5800: 0x20040080, + 0x6800: 0x21040000, + 0x7800: 0x20000000, + 0x8800: 0x20040000, + 0x9800: 0x0, + 0xa800: 0x21040080, + 0xb800: 0x1000080, + 0xc800: 0x20000080, + 0xd800: 0x21000000, + 0xe800: 0x1000000, + 0xf800: 0x40080, + 0x10000: 0x40000, + 0x11000: 0x80, + 0x12000: 0x20000000, + 0x13000: 0x21000080, + 0x14000: 0x1000080, + 0x15000: 0x21040000, + 0x16000: 0x20040080, + 0x17000: 0x1000000, + 0x18000: 0x21040080, + 0x19000: 0x21000000, + 0x1a000: 0x1040000, + 0x1b000: 0x20040000, + 0x1c000: 0x40080, + 0x1d000: 0x20000080, + 0x1e000: 0x0, + 0x1f000: 0x1040080, + 0x10800: 0x21000080, + 0x11800: 0x1000000, + 0x12800: 0x1040000, + 0x13800: 0x20040080, + 0x14800: 0x20000000, + 0x15800: 0x1040080, + 0x16800: 0x80, + 0x17800: 0x21040000, + 0x18800: 0x40080, + 0x19800: 0x21040080, + 0x1a800: 0x0, + 0x1b800: 0x21000000, + 0x1c800: 0x1000080, + 0x1d800: 0x40000, + 0x1e800: 0x20040000, + 0x1f800: 0x20000080 + }, + { + 0x0: 0x10000008, + 0x100: 0x2000, + 0x200: 0x10200000, + 0x300: 0x10202008, + 0x400: 0x10002000, + 0x500: 0x200000, + 0x600: 0x200008, + 0x700: 0x10000000, + 0x800: 0x0, + 0x900: 0x10002008, + 0xa00: 0x202000, + 0xb00: 0x8, + 0xc00: 0x10200008, + 0xd00: 0x202008, + 0xe00: 0x2008, + 0xf00: 0x10202000, + 0x80: 0x10200000, + 0x180: 0x10202008, + 0x280: 0x8, + 0x380: 0x200000, + 0x480: 0x202008, + 0x580: 0x10000008, + 0x680: 0x10002000, + 0x780: 0x2008, + 0x880: 0x200008, + 0x980: 0x2000, + 0xa80: 0x10002008, + 0xb80: 0x10200008, + 0xc80: 0x0, + 0xd80: 0x10202000, + 0xe80: 0x202000, + 0xf80: 0x10000000, + 0x1000: 0x10002000, + 0x1100: 0x10200008, + 0x1200: 0x10202008, + 0x1300: 0x2008, + 0x1400: 0x200000, + 0x1500: 0x10000000, + 0x1600: 0x10000008, + 0x1700: 0x202000, + 0x1800: 0x202008, + 0x1900: 0x0, + 0x1a00: 0x8, + 0x1b00: 0x10200000, + 0x1c00: 0x2000, + 0x1d00: 0x10002008, + 0x1e00: 0x10202000, + 0x1f00: 0x200008, + 0x1080: 0x8, + 0x1180: 0x202000, + 0x1280: 0x200000, + 0x1380: 0x10000008, + 0x1480: 0x10002000, + 0x1580: 0x2008, + 0x1680: 0x10202008, + 0x1780: 0x10200000, + 0x1880: 0x10202000, + 0x1980: 0x10200008, + 0x1a80: 0x2000, + 0x1b80: 0x202008, + 0x1c80: 0x200008, + 0x1d80: 0x0, + 0x1e80: 0x10000000, + 0x1f80: 0x10002008 + }, + { + 0x0: 0x100000, + 0x10: 0x2000401, + 0x20: 0x400, + 0x30: 0x100401, + 0x40: 0x2100401, + 0x50: 0x0, + 0x60: 0x1, + 0x70: 0x2100001, + 0x80: 0x2000400, + 0x90: 0x100001, + 0xa0: 0x2000001, + 0xb0: 0x2100400, + 0xc0: 0x2100000, + 0xd0: 0x401, + 0xe0: 0x100400, + 0xf0: 0x2000000, + 0x8: 0x2100001, + 0x18: 0x0, + 0x28: 0x2000401, + 0x38: 0x2100400, + 0x48: 0x100000, + 0x58: 0x2000001, + 0x68: 0x2000000, + 0x78: 0x401, + 0x88: 0x100401, + 0x98: 0x2000400, + 0xa8: 0x2100000, + 0xb8: 0x100001, + 0xc8: 0x400, + 0xd8: 0x2100401, + 0xe8: 0x1, + 0xf8: 0x100400, + 0x100: 0x2000000, + 0x110: 0x100000, + 0x120: 0x2000401, + 0x130: 0x2100001, + 0x140: 0x100001, + 0x150: 0x2000400, + 0x160: 0x2100400, + 0x170: 0x100401, + 0x180: 0x401, + 0x190: 0x2100401, + 0x1a0: 0x100400, + 0x1b0: 0x1, + 0x1c0: 0x0, + 0x1d0: 0x2100000, + 0x1e0: 0x2000001, + 0x1f0: 0x400, + 0x108: 0x100400, + 0x118: 0x2000401, + 0x128: 0x2100001, + 0x138: 0x1, + 0x148: 0x2000000, + 0x158: 0x100000, + 0x168: 0x401, + 0x178: 0x2100400, + 0x188: 0x2000001, + 0x198: 0x2100000, + 0x1a8: 0x0, + 0x1b8: 0x2100401, + 0x1c8: 0x100401, + 0x1d8: 0x400, + 0x1e8: 0x2000400, + 0x1f8: 0x100001 + }, + { + 0x0: 0x8000820, + 0x1: 0x20000, + 0x2: 0x8000000, + 0x3: 0x20, + 0x4: 0x20020, + 0x5: 0x8020820, + 0x6: 0x8020800, + 0x7: 0x800, + 0x8: 0x8020000, + 0x9: 0x8000800, + 0xa: 0x20800, + 0xb: 0x8020020, + 0xc: 0x820, + 0xd: 0x0, + 0xe: 0x8000020, + 0xf: 0x20820, + 0x80000000: 0x800, + 0x80000001: 0x8020820, + 0x80000002: 0x8000820, + 0x80000003: 0x8000000, + 0x80000004: 0x8020000, + 0x80000005: 0x20800, + 0x80000006: 0x20820, + 0x80000007: 0x20, + 0x80000008: 0x8000020, + 0x80000009: 0x820, + 0x8000000a: 0x20020, + 0x8000000b: 0x8020800, + 0x8000000c: 0x0, + 0x8000000d: 0x8020020, + 0x8000000e: 0x8000800, + 0x8000000f: 0x20000, + 0x10: 0x20820, + 0x11: 0x8020800, + 0x12: 0x20, + 0x13: 0x800, + 0x14: 0x8000800, + 0x15: 0x8000020, + 0x16: 0x8020020, + 0x17: 0x20000, + 0x18: 0x0, + 0x19: 0x20020, + 0x1a: 0x8020000, + 0x1b: 0x8000820, + 0x1c: 0x8020820, + 0x1d: 0x20800, + 0x1e: 0x820, + 0x1f: 0x8000000, + 0x80000010: 0x20000, + 0x80000011: 0x800, + 0x80000012: 0x8020020, + 0x80000013: 0x20820, + 0x80000014: 0x20, + 0x80000015: 0x8020000, + 0x80000016: 0x8000000, + 0x80000017: 0x8000820, + 0x80000018: 0x8020820, + 0x80000019: 0x8000020, + 0x8000001a: 0x8000800, + 0x8000001b: 0x0, + 0x8000001c: 0x20800, + 0x8000001d: 0x820, + 0x8000001e: 0x20020, + 0x8000001f: 0x8020800 + } + ]; + + // Masks that select the SBOX input + var SBOX_MASK = [ + 0xf8000001, 0x1f800000, 0x01f80000, 0x001f8000, + 0x0001f800, 0x00001f80, 0x000001f8, 0x8000001f + ]; + + /** + * DES block cipher algorithm. + */ + var DES = C_algo.DES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + + // Select 56 bits according to PC1 + var keyBits = []; + for (var i = 0; i < 56; i++) { + var keyBitPos = PC1[i] - 1; + keyBits[i] = (keyWords[keyBitPos >>> 5] >>> (31 - keyBitPos % 32)) & 1; + } + + // Assemble 16 subkeys + var subKeys = this._subKeys = []; + for (var nSubKey = 0; nSubKey < 16; nSubKey++) { + // Create subkey + var subKey = subKeys[nSubKey] = []; + + // Shortcut + var bitShift = BIT_SHIFTS[nSubKey]; + + // Select 48 bits according to PC2 + for (var i = 0; i < 24; i++) { + // Select from the left 28 key bits + subKey[(i / 6) | 0] |= keyBits[((PC2[i] - 1) + bitShift) % 28] << (31 - i % 6); + + // Select from the right 28 key bits + subKey[4 + ((i / 6) | 0)] |= keyBits[28 + (((PC2[i + 24] - 1) + bitShift) % 28)] << (31 - i % 6); + } + + // Since each subkey is applied to an expanded 32-bit input, + // the subkey can be broken into 8 values scaled to 32-bits, + // which allows the key to be used without expansion + subKey[0] = (subKey[0] << 1) | (subKey[0] >>> 31); + for (var i = 1; i < 7; i++) { + subKey[i] = subKey[i] >>> ((i - 1) * 4 + 3); + } + subKey[7] = (subKey[7] << 5) | (subKey[7] >>> 27); + } + + // Compute inverse subkeys + var invSubKeys = this._invSubKeys = []; + for (var i = 0; i < 16; i++) { + invSubKeys[i] = subKeys[15 - i]; + } + }, + + encryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._subKeys); + }, + + decryptBlock: function (M, offset) { + this._doCryptBlock(M, offset, this._invSubKeys); + }, + + _doCryptBlock: function (M, offset, subKeys) { + // Get input + this._lBlock = M[offset]; + this._rBlock = M[offset + 1]; + + // Initial permutation + exchangeLR.call(this, 4, 0x0f0f0f0f); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeRL.call(this, 2, 0x33333333); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeLR.call(this, 1, 0x55555555); + + // Rounds + for (var round = 0; round < 16; round++) { + // Shortcuts + var subKey = subKeys[round]; + var lBlock = this._lBlock; + var rBlock = this._rBlock; + + // Feistel function + var f = 0; + for (var i = 0; i < 8; i++) { + f |= SBOX_P[i][((rBlock ^ subKey[i]) & SBOX_MASK[i]) >>> 0]; + } + this._lBlock = rBlock; + this._rBlock = lBlock ^ f; + } + + // Undo swap from last round + var t = this._lBlock; + this._lBlock = this._rBlock; + this._rBlock = t; + + // Final permutation + exchangeLR.call(this, 1, 0x55555555); + exchangeRL.call(this, 8, 0x00ff00ff); + exchangeRL.call(this, 2, 0x33333333); + exchangeLR.call(this, 16, 0x0000ffff); + exchangeLR.call(this, 4, 0x0f0f0f0f); + + // Set output + M[offset] = this._lBlock; + M[offset + 1] = this._rBlock; + }, + + keySize: 64/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + // Swap bits across the left and right words + function exchangeLR(offset, mask) { + var t = ((this._lBlock >>> offset) ^ this._rBlock) & mask; + this._rBlock ^= t; + this._lBlock ^= t << offset; + } + + function exchangeRL(offset, mask) { + var t = ((this._rBlock >>> offset) ^ this._lBlock) & mask; + this._lBlock ^= t; + this._rBlock ^= t << offset; + } + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.DES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.DES.decrypt(ciphertext, key, cfg); + */ + C.DES = BlockCipher._createHelper(DES); + + /** + * Triple-DES block cipher algorithm. + */ + var TripleDES = C_algo.TripleDES = BlockCipher.extend({ + _doReset: function () { + // Shortcuts + var key = this._key; + var keyWords = key.words; + + // Create DES instances + this._des1 = DES.createEncryptor(WordArray.create(keyWords.slice(0, 2))); + this._des2 = DES.createEncryptor(WordArray.create(keyWords.slice(2, 4))); + this._des3 = DES.createEncryptor(WordArray.create(keyWords.slice(4, 6))); + }, + + encryptBlock: function (M, offset) { + this._des1.encryptBlock(M, offset); + this._des2.decryptBlock(M, offset); + this._des3.encryptBlock(M, offset); + }, + + decryptBlock: function (M, offset) { + this._des3.decryptBlock(M, offset); + this._des2.encryptBlock(M, offset); + this._des1.decryptBlock(M, offset); + }, + + keySize: 192/32, + + ivSize: 64/32, + + blockSize: 64/32 + }); + + /** + * Shortcut functions to the cipher's object interface. + * + * @example + * + * var ciphertext = CryptoJS.TripleDES.encrypt(message, key, cfg); + * var plaintext = CryptoJS.TripleDES.decrypt(ciphertext, key, cfg); + */ + C.TripleDES = BlockCipher._createHelper(TripleDES); + }()); + + + return CryptoJS.TripleDES; + +})); +},{"./cipher-core":50,"./core":51,"./enc-base64":52,"./evpkdf":54,"./md5":59}],82:[function(require,module,exports){ ;(function (root, factory) { if (typeof exports === "object") { // CommonJS @@ -7547,19 +12842,15 @@ module.exports = transfer; return CryptoJS; })); -},{"./core":47}],50:[function(require,module,exports){ +},{"./core":51}],83:[function(require,module,exports){ /*! https://mths.be/utf8js v2.0.0 by @mathias */ ;(function(root) { - // Detect free variables 'exports' var freeExports = typeof exports == 'object' && exports; - // Detect free variable 'module' var freeModule = typeof module == 'object' && module && module.exports == freeExports && module; - // Detect free variable 'global', from Node.js or Browserified code, - // and use it as 'root' var freeGlobal = typeof global == 'object' && global; if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { root = freeGlobal; @@ -7800,26 +13091,15 @@ module.exports = BigNumber; // jshint ignore:line },{}],"web3":[function(require,module,exports){ -var web3 = require('./lib/web3'); -var namereg = require('./lib/web3/namereg'); - -web3.providers.HttpProvider = require('./lib/web3/httpprovider'); -web3.providers.IpcProvider = require('./lib/web3/ipcprovider'); - -web3.eth.contract = require('./lib/web3/contract'); -web3.eth.namereg = namereg.namereg; -web3.eth.ibanNamereg = namereg.ibanNamereg; -web3.eth.sendIBANTransaction = require('./lib/web3/transfer'); -web3.eth.iban = require('./lib/web3/iban'); +var Web3 = require('./lib/web3'); // dont override global variable -if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { - window.web3 = web3; +if (typeof window !== 'undefined' && typeof window.Web3 === 'undefined') { + window.Web3 = Web3; } -module.exports = web3; +module.exports = Web3; - -},{"./lib/web3":22,"./lib/web3/contract":25,"./lib/web3/httpprovider":31,"./lib/web3/iban":32,"./lib/web3/ipcprovider":33,"./lib/web3/namereg":41,"./lib/web3/transfer":45}]},{},["web3"]) +},{"./lib/web3":22}]},{},["web3"]) //# sourceMappingURL=web3-light.js.map ` diff --git a/xeth/xeth.go b/xeth/xeth.go index 19c42a9a32..a45ce688bf 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -644,7 +644,9 @@ func (p *XEth) NewWhisperFilter(to, from string, topics [][]string) int { callback := func(msg WhisperMessage) { p.messagesMu.RLock() // Only read lock to the filter pool defer p.messagesMu.RUnlock() - p.messages[id].insert(msg) + if p.messages[id] != nil { + p.messages[id].insert(msg) + } } // Initialize the core whisper filter and wrap into xeth id = p.Whisper().Watch(to, from, topics, callback) From 9e1d9bff3b18cfa09ba96cd027fa653daae10816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 5 Nov 2015 23:57:57 +0200 Subject: [PATCH 06/27] node: customizable protocol and service stacks --- node/config.go | 171 +++++++++++++ node/config_test.go | 120 +++++++++ node/errors.go | 31 +++ node/node.go | 252 +++++++++++++++++++ node/node_example_test.go | 87 +++++++ node/node_test.go | 492 +++++++++++++++++++++++++++++++++++++ node/service.go | 67 +++++ node/service_test.go | 60 +++++ node/utils.go | 33 +++ p2p/discover/table.go | 7 +- p2p/discover/table_test.go | 8 +- p2p/discover/udp.go | 16 +- p2p/discover/udp_test.go | 2 +- 13 files changed, 1333 insertions(+), 13 deletions(-) create mode 100644 node/config.go create mode 100644 node/config_test.go create mode 100644 node/errors.go create mode 100644 node/node.go create mode 100644 node/node_example_test.go create mode 100644 node/node_test.go create mode 100644 node/service.go create mode 100644 node/service_test.go create mode 100644 node/utils.go diff --git a/node/config.go b/node/config.go new file mode 100644 index 0000000000..93f0ba79d6 --- /dev/null +++ b/node/config.go @@ -0,0 +1,171 @@ +// 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 . + +package node + +import ( + "crypto/ecdsa" + "encoding/json" + "io/ioutil" + "net" + "os" + "path/filepath" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/p2p/discover" + "github.com/ethereum/go-ethereum/p2p/nat" +) + +var ( + datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key + datadirStaticNodes = "static-nodes.json" // Path within the datadir to the static node list + datadirTrustedNodes = "trusted-nodes.json" // Path within the datadir to the trusted node list + datadirNodeDatabase = "nodes" // Path within the datadir to store the node infos +) + +// Config represents a small collection of configuration values to fine tune the +// P2P network layer of a protocol stack. These values can be further extended by +// all registered services. +type Config struct { + // DataDir is the file system folder the node should use for any data storage + // requirements. The configured data directory will not be directly shared with + // registered services, instead those can use utility methods to create/access + // databases or flat files. This enables ephemeral nodes which can fully reside + // in memory. + DataDir string + + // This field should be a valid secp256k1 private key that will be used for both + // remote peer identification as well as network traffic encryption. If no key + // is configured, the preset one is loaded from the data dir, generating it if + // needed. + PrivateKey *ecdsa.PrivateKey + + // Name sets the node name of this server. Use common.MakeName to create a name + // that follows existing conventions. + Name string + + // NoDiscovery specifies whether the peer discovery mechanism should be started + // or not. Disabling is usually useful for protocol debugging (manual topology). + NoDiscovery bool + + // Bootstrap nodes used to establish connectivity with the rest of the network. + BootstrapNodes []*discover.Node + + // Network interface address on which the node should listen for inbound peers. + ListenAddr string + + // If set to a non-nil value, the given NAT port mapper is used to make the + // listening port available to the Internet. + NAT nat.Interface + + // If Dialer is set to a non-nil value, the given Dialer is used to dial outbound + // peer connections. + Dialer *net.Dialer + + // If NoDial is true, the node will not dial any peers. + NoDial bool + + // MaxPeers is the maximum number of peers that can be connected. If this is + // set to zero, then only the configured static and trusted peers can connect. + MaxPeers int + + // MaxPendingPeers is the maximum number of peers that can be pending in the + // handshake phase, counted separately for inbound and outbound connections. + // Zero defaults to preset values. + MaxPendingPeers int +} + +// NodeKey retrieves the currently configured private key of the node, checking +// first any manually set key, falling back to the one found in the configured +// data folder. If no key can be found, a new one is generated. +func (c *Config) NodeKey() *ecdsa.PrivateKey { + // Use any specifically configured key + if c.PrivateKey != nil { + return c.PrivateKey + } + // Generate ephemeral key if no datadir is being used + if c.DataDir == "" { + key, err := crypto.GenerateKey() + if err != nil { + glog.Fatalf("Failed to generate ephemeral node key: %v", err) + } + return key + } + // Fall back to persistent key from the data directory + keyfile := filepath.Join(c.DataDir, datadirPrivateKey) + if key, err := crypto.LoadECDSA(keyfile); err == nil { + return key + } + // No persistent key found, generate and store a new one + key, err := crypto.GenerateKey() + if err != nil { + glog.Fatalf("Failed to generate node key: %v", err) + } + if err := crypto.SaveECDSA(keyfile, key); err != nil { + glog.V(logger.Error).Infof("Failed to persist node key: %v", err) + } + return key +} + +// StaticNodes returns a list of node enode URLs configured as static nodes. +func (c *Config) StaticNodes() []*discover.Node { + return c.parsePersistentNodes(datadirStaticNodes) +} + +// TrusterNodes returns a list of node enode URLs configured as trusted nodes. +func (c *Config) TrusterNodes() []*discover.Node { + return c.parsePersistentNodes(datadirTrustedNodes) +} + +// parsePersistentNodes parses a list of discovery node URLs loaded from a .json +// file from within the data directory. +func (c *Config) parsePersistentNodes(file string) []*discover.Node { + // Short circuit if no node config is present + if c.DataDir == "" { + return nil + } + path := filepath.Join(c.DataDir, file) + if _, err := os.Stat(path); err != nil { + return nil + } + // Load the nodes from the config file + blob, err := ioutil.ReadFile(path) + if err != nil { + glog.V(logger.Error).Infof("Failed to access nodes: %v", err) + return nil + } + nodelist := []string{} + if err := json.Unmarshal(blob, &nodelist); err != nil { + glog.V(logger.Error).Infof("Failed to load nodes: %v", err) + return nil + } + // Interpret the list as a discovery node array + var nodes []*discover.Node + for _, url := range nodelist { + if url == "" { + continue + } + node, err := discover.ParseNode(url) + if err != nil { + glog.V(logger.Error).Infof("Node URL %s: %v\n", url, err) + continue + } + nodes = append(nodes, node) + } + return nodes +} diff --git a/node/config_test.go b/node/config_test.go new file mode 100644 index 0000000000..f59f3c0fe0 --- /dev/null +++ b/node/config_test.go @@ -0,0 +1,120 @@ +// 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 . + +package node + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/ethereum/go-ethereum/crypto" +) + +// Tests that datadirs can be successfully created, be them manually configured +// ones or automatically generated temporary ones. +func TestDatadirCreation(t *testing.T) { + // Create a temporary data dir and check that it can be used by a node + dir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("failed to create manual data dir: %v", err) + } + defer os.RemoveAll(dir) + + if _, err := New(&Config{DataDir: dir}); err != nil { + t.Fatalf("failed to create stack with existing datadir: %v", err) + } + // Generate a long non-existing datadir path and check that it gets created by a node + dir = filepath.Join(dir, "a", "b", "c", "d", "e", "f") + if _, err := New(&Config{DataDir: dir}); err != nil { + t.Fatalf("failed to create stack with creatable datadir: %v", err) + } + if _, err := os.Stat(dir); err != nil { + t.Fatalf("freshly created datadir not accessible: %v", err) + } + // Verify that an impossible datadir fails creation + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("failed to create temporary file: %v", err) + } + defer os.Remove(file.Name()) + + dir = filepath.Join(file.Name(), "invalid/path") + if _, err := New(&Config{DataDir: dir}); err == nil { + t.Fatalf("protocol stack created with an invalid datadir") + } +} + +// Tests that node keys can be correctly created, persisted, loaded and/or made +// ephemeral. +func TestNodeKeyPersistency(t *testing.T) { + // Create a temporary folder and make sure no key is present + dir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("failed to create temporary data directory: %v", err) + } + defer os.RemoveAll(dir) + + if _, err := os.Stat(filepath.Join(dir, datadirPrivateKey)); err == nil { + t.Fatalf("non-created node key already exists") + } + // Configure a node with a preset key and ensure it's not persisted + key, err := crypto.GenerateKey() + if err != nil { + t.Fatalf("failed to generate one-shot node key: %v", err) + } + if _, err := New(&Config{DataDir: dir, PrivateKey: key}); err != nil { + t.Fatalf("failed to create empty stack: %v", err) + } + if _, err := os.Stat(filepath.Join(dir, datadirPrivateKey)); err == nil { + t.Fatalf("one-shot node key persisted to data directory") + } + // Configure a node with no preset key and ensure it is persisted this time + if _, err := New(&Config{DataDir: dir}); err != nil { + t.Fatalf("failed to create newly keyed stack: %v", err) + } + if _, err := os.Stat(filepath.Join(dir, datadirPrivateKey)); err != nil { + t.Fatalf("node key not persisted to data directory: %v", err) + } + key, err = crypto.LoadECDSA(filepath.Join(dir, datadirPrivateKey)) + if err != nil { + t.Fatalf("failed to load freshly persisted node key: %v", err) + } + blob1, err := ioutil.ReadFile(filepath.Join(dir, datadirPrivateKey)) + if err != nil { + t.Fatalf("failed to read freshly persisted node key: %v", err) + } + // Configure a new node and ensure the previously persisted key is loaded + if _, err := New(&Config{DataDir: dir}); err != nil { + t.Fatalf("failed to create previously keyed stack: %v", err) + } + blob2, err := ioutil.ReadFile(filepath.Join(dir, datadirPrivateKey)) + if err != nil { + t.Fatalf("failed to read previously persisted node key: %v", err) + } + if bytes.Compare(blob1, blob2) != 0 { + t.Fatalf("persisted node key mismatch: have %x, want %x", blob2, blob1) + } + // Configure ephemeral node and ensure no key is dumped locally + if _, err := New(&Config{DataDir: ""}); err != nil { + t.Fatalf("failed to create ephemeral stack: %v", err) + } + if _, err := os.Stat(filepath.Join(".", datadirPrivateKey)); err == nil { + t.Fatalf("ephemeral node key persisted to disk") + } +} diff --git a/node/errors.go b/node/errors.go new file mode 100644 index 0000000000..f8eece06d1 --- /dev/null +++ b/node/errors.go @@ -0,0 +1,31 @@ +// 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 . + +package node + +import "fmt" + +// StopError is returned if a node fails to stop either any of its registered +// services or itself. +type StopError struct { + Server error + Services map[string]error +} + +// Error generates a textual representation of the stop error. +func (e *StopError) Error() string { + return fmt.Sprintf("server: %v, services: %v", e.Server, e.Services) +} diff --git a/node/node.go b/node/node.go new file mode 100644 index 0000000000..ad4e69414c --- /dev/null +++ b/node/node.go @@ -0,0 +1,252 @@ +// 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 . + +// Package node represents the Ethereum protocol stack container. +package node + +import ( + "errors" + "os" + "path/filepath" + "sync" + "syscall" + + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/p2p" +) + +var ( + ErrDatadirUsed = errors.New("datadir already used") + ErrNodeStopped = errors.New("node not started") + ErrNodeRunning = errors.New("node already running") + ErrServiceUnknown = errors.New("service not registered") + ErrServiceRegistered = errors.New("service already registered") + + datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} +) + +// Node represents a P2P node into which arbitrary services might be registered. +type Node struct { + datadir string // Path to the currently used data directory + config *p2p.Server // Configuration of the underlying P2P networking layer + stack map[string]ServiceConstructor // Protocol stack registered into this node + emux *event.TypeMux // Event multiplexer used between the services of a stack + + running *p2p.Server // Currently running P2P networking layer + services map[string]Service // Currently running services + + lock sync.RWMutex +} + +// New creates a new P2P node, ready for protocol registration. +func New(conf *Config) (*Node, error) { + // Ensure the data directory exists, failing if it cannot be created + if conf.DataDir != "" { + if err := os.MkdirAll(conf.DataDir, 0700); err != nil { + return nil, err + } + } + // Assemble the networking layer and the node itself + nodeDbPath := "" + if conf.DataDir != "" { + nodeDbPath = filepath.Join(conf.DataDir, datadirNodeDatabase) + } + return &Node{ + datadir: conf.DataDir, + config: &p2p.Server{ + PrivateKey: conf.NodeKey(), + Name: conf.Name, + Discovery: !conf.NoDiscovery, + BootstrapNodes: conf.BootstrapNodes, + StaticNodes: conf.StaticNodes(), + TrustedNodes: conf.TrusterNodes(), + NodeDatabase: nodeDbPath, + ListenAddr: conf.ListenAddr, + NAT: conf.NAT, + Dialer: conf.Dialer, + NoDial: conf.NoDial, + MaxPeers: conf.MaxPeers, + MaxPendingPeers: conf.MaxPendingPeers, + }, + stack: make(map[string]ServiceConstructor), + emux: new(event.TypeMux), + }, nil +} + +// Register injects a new service into the node's stack. +func (n *Node) Register(id string, constructor ServiceConstructor) error { + n.lock.Lock() + defer n.lock.Unlock() + + // Short circuit if the node is running or if the id is taken + if n.running != nil { + return ErrNodeRunning + } + if _, ok := n.stack[id]; ok { + return ErrServiceRegistered + } + // Otherwise register the service and return + n.stack[id] = constructor + + return nil +} + +// Unregister removes a service from a node's stack. If the node is currently +// running, an error will be returned. +func (n *Node) Unregister(id string) error { + n.lock.Lock() + defer n.lock.Unlock() + + // Short circuit if the node is running, or if the service is unknown + if n.running != nil { + return ErrNodeRunning + } + if _, ok := n.stack[id]; !ok { + return ErrServiceUnknown + } + // Otherwise drop the service and return + delete(n.stack, id) + return nil +} + +// Start create a live P2P node and starts running it. +func (n *Node) Start() error { + n.lock.Lock() + defer n.lock.Unlock() + + // Short circuit if the node's already running + if n.running != nil { + return ErrNodeRunning + } + // Otherwise copy and specialize the P2P configuration + running := new(p2p.Server) + *running = *n.config + + ctx := &ServiceContext{ + dataDir: n.datadir, + EventMux: n.emux, + } + services := make(map[string]Service) + for id, constructor := range n.stack { + service, err := constructor(ctx) + if err != nil { + return err + } + services[id] = service + } + // Gather the protocols and start the freshly assembled P2P server + for _, service := range services { + running.Protocols = append(running.Protocols, service.Protocols()...) + } + if err := running.Start(); err != nil { + if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { + return ErrDatadirUsed + } + return err + } + // Start each of the services + started := []string{} + for id, service := range services { + // Start the next service, stopping all previous upon failure + if err := service.Start(); err != nil { + for _, id := range started { + services[id].Stop() + } + return err + } + // Mark the service started for potential cleanup + started = append(started, id) + } + // Finish initializing the startup + n.services = services + n.running = running + + return nil +} + +// Stop terminates a running node along with all it's services. In the node was +// not started, an error is returned. +func (n *Node) Stop() error { + n.lock.Lock() + defer n.lock.Unlock() + + // Short circuit if the node's not running + if n.running == nil { + return ErrNodeStopped + } + // Otherwise terminate all the services and the P2P server too + failure := &StopError{ + Services: make(map[string]error), + } + for id, service := range n.services { + if err := service.Stop(); err != nil { + failure.Services[id] = err + } + } + n.running.Stop() + + n.services = nil + n.running = nil + + if len(failure.Services) > 0 { + return failure + } + return nil +} + +// Restart terminates a running node and boots up a new one in its place. If the +// node isn't running, an error is returned. +func (n *Node) Restart() error { + if err := n.Stop(); err != nil { + return err + } + if err := n.Start(); err != nil { + return err + } + return nil +} + +// Server retrieves the currently running P2P network layer. This method is meant +// only to inspect fields of the currently running server, life cycle management +// should be left to this Node entity. +func (n *Node) Server() *p2p.Server { + n.lock.RLock() + defer n.lock.RUnlock() + + return n.running +} + +// Service retrieves a currently running services registered under a given id. +func (n *Node) Service(id string) Service { + n.lock.RLock() + defer n.lock.RUnlock() + + if n.services == nil { + return nil + } + return n.services[id] +} + +// DataDir retrieves the current datadir used by the protocol stack. +func (n *Node) DataDir() string { + return n.datadir +} + +// EventMux retrieves the event multiplexer used by all the network services in +// the current protocol stack. +func (n *Node) EventMux() *event.TypeMux { + return n.emux +} diff --git a/node/node_example_test.go b/node/node_example_test.go new file mode 100644 index 0000000000..f2bd014b06 --- /dev/null +++ b/node/node_example_test.go @@ -0,0 +1,87 @@ +// 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 . + +package node_test + +import ( + "fmt" + "log" + + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/discover" +) + +// SampleService is a trivial network service that can be attached to a node for +// life cycle management. +// +// The following methods are needed to implement a node.Service: +// - Protocols() []p2p.Protocol - devp2p protocols the service can communicate on +// - Start() error - method invoked when the node is ready to start the service +// - Stop() error - method invoked when the node terminates the service +type SampleService struct{} + +func (s *SampleService) Protocols() []p2p.Protocol { return nil } +func (s *SampleService) Start() error { fmt.Println("Sample service starting..."); return nil } +func (s *SampleService) Stop() error { fmt.Println("Sample service stopping..."); return nil } + +func ExampleUsage() { + // Create a network node to run protocols with the default values. The below list + // is only used to display each of the configuration options. All of these could + // have been ommited if the default behavior is desired. + nodeConfig := &node.Config{ + DataDir: "", // Empty uses ephemeral storage + PrivateKey: nil, // Nil generates a node key on the fly + Name: "", // Any textual node name is allowed + NoDiscovery: false, // Can disable discovering remote nodes + BootstrapNodes: []*discover.Node{}, // List of bootstrap nodes to use + ListenAddr: ":0", // Network interface to listen on + NAT: nil, // UPnP port mapper to use for crossing firewalls + Dialer: nil, // Custom dialer to use for establishing peer connections + NoDial: false, // Can prevent this node from dialing out + MaxPeers: 0, // Number of peers to allow + MaxPendingPeers: 0, // Number of peers allowed to handshake concurrently + } + stack, err := node.New(nodeConfig) + if err != nil { + log.Fatalf("Failed to create network node: %v", err) + } + // Create and register a simple network service. This is done through the definition + // of a node.ServiceConstructor that will instantiate a node.Service. The reason for + // the factory method approach is to support service restarts without relying on the + // individual implementations' support for such operations. + constructor := func(context *node.ServiceContext) (node.Service, error) { + return new(SampleService), nil + } + if err := stack.Register("my sample service", constructor); err != nil { + log.Fatalf("Failed to register service: %v", err) + } + // Boot up the entire protocol stack, do a restart and terminate + if err := stack.Start(); err != nil { + log.Fatalf("Failed to start the protocol stack: %v", err) + } + if err := stack.Restart(); err != nil { + log.Fatalf("Failed to restart the protocol stack: %v", err) + } + if err := stack.Stop(); err != nil { + log.Fatalf("Failed to stop the protocol stack: %v", err) + } + // Output: + // Sample service starting... + // Sample service stopping... + // Sample service starting... + // Sample service stopping... +} diff --git a/node/node_test.go b/node/node_test.go new file mode 100644 index 0000000000..7201276b59 --- /dev/null +++ b/node/node_test.go @@ -0,0 +1,492 @@ +// 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 . + +package node + +import ( + "errors" + "io/ioutil" + "os" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/p2p" +) + +var ( + testNodeKey, _ = crypto.GenerateKey() + + testNodeConfig = &Config{ + PrivateKey: testNodeKey, + Name: "test node", + } +) + +// Tests that an empty protocol stack can be started, restarted and stopped. +func TestNodeLifeCycle(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Ensure that a stopped node can be stopped again + for i := 0; i < 3; i++ { + if err := stack.Stop(); err != ErrNodeStopped { + t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped) + } + } + // Ensure that a node can be successfully started, but only once + if err := stack.Start(); err != nil { + t.Fatalf("failed to start node: %v", err) + } + if err := stack.Start(); err != ErrNodeRunning { + t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning) + } + // Ensure that a node can be restarted arbitrarily many times + for i := 0; i < 3; i++ { + if err := stack.Restart(); err != nil { + t.Fatalf("iter %d: failed to restart node: %v", i, err) + } + } + // Ensure that a node can be stopped, but only once + if err := stack.Stop(); err != nil { + t.Fatalf("failed to stop node: %v", err) + } + if err := stack.Stop(); err != ErrNodeStopped { + t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped) + } +} + +// Tests that if the data dir is already in use, an appropriate error is returned. +func TestNodeUsedDataDir(t *testing.T) { + // Create a temporary folder to use as the data directory + dir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("failed to create temporary data directory: %v", err) + } + defer os.RemoveAll(dir) + + // Create a new node based on the data directory + original, err := New(&Config{DataDir: dir}) + if err != nil { + t.Fatalf("failed to create original protocol stack: %v", err) + } + if err := original.Start(); err != nil { + t.Fatalf("failed to start original protocol stack: %v", err) + } + defer original.Stop() + + // Create a second node based on the same data directory and ensure failure + duplicate, err := New(&Config{DataDir: dir}) + if err != nil { + t.Fatalf("failed to create duplicate protocol stack: %v", err) + } + if err := duplicate.Start(); err != ErrDatadirUsed { + t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed) + } +} + +// NoopService is a trivial implementation of the Service interface. +type NoopService struct{} + +func (s *NoopService) Protocols() []p2p.Protocol { return nil } +func (s *NoopService) Start() error { return nil } +func (s *NoopService) Stop() error { return nil } + +func NewNoopService(*ServiceContext) (Service, error) { return new(NoopService), nil } + +// Tests whether services can be registered and unregistered. +func TestServiceRegistry(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Create a batch of dummy services and ensure they don't exist + ids := []string{"A", "B", "C"} + for i, id := range ids { + if err := stack.Unregister(id); err != ErrServiceUnknown { + t.Fatalf("service %d: pre-unregistration failure mismatch: have %v, want %v", i, err, ErrServiceUnknown) + } + } + // Register the services, checking that the operation succeeds only once + for i, id := range ids { + if err := stack.Register(id, NewNoopService); err != nil { + t.Fatalf("service %d: registration failed: %v", i, err) + } + if err := stack.Register(id, NewNoopService); err != ErrServiceRegistered { + t.Fatalf("service %d: registration failure mismatch: have %v, want %v", i, err, ErrServiceRegistered) + } + } + // Unregister the services, checking that the operation succeeds only once + for i, id := range ids { + if err := stack.Unregister(id); err != nil { + t.Fatalf("service %d: unregistration failed: %v", i, err) + } + if err := stack.Unregister(id); err != ErrServiceUnknown { + t.Fatalf("service %d: unregistration failure mismatch: have %v, want %v", i, err, ErrServiceUnknown) + } + } +} + +// InstrumentedService is an implementation of Service for which all interface +// methods can be instrumented both return value as well as event hook wise. +type InstrumentedService struct { + protocols []p2p.Protocol + start error + stop error + + protocolsHook func() + startHook func() + stopHook func() +} + +func (s *InstrumentedService) Protocols() []p2p.Protocol { + if s.protocolsHook != nil { + s.protocolsHook() + } + return s.protocols +} + +func (s *InstrumentedService) Start() error { + if s.startHook != nil { + s.startHook() + } + return s.start +} + +func (s *InstrumentedService) Stop() error { + if s.stopHook != nil { + s.stopHook() + } + return s.stop +} + +// Tests that registered services get started and stopped correctly. +func TestServiceLifeCycle(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Register a batch of life-cycle instrumented services + ids := []string{"A", "B", "C"} + + started := make(map[string]bool) + stopped := make(map[string]bool) + + for i, id := range ids { + id := id // Closure for the constructor + constructor := func(*ServiceContext) (Service, error) { + return &InstrumentedService{ + startHook: func() { started[id] = true }, + stopHook: func() { stopped[id] = true }, + }, nil + } + if err := stack.Register(id, constructor); err != nil { + t.Fatalf("service %d: registration failed: %v", i, err) + } + } + // Start the node and check that all services are running + if err := stack.Start(); err != nil { + t.Fatalf("failed to start protocol stack: %v", err) + } + for i, id := range ids { + if !started[id] { + t.Fatalf("service %d: freshly started service not running", i) + } + if stopped[id] { + t.Fatalf("service %d: freshly started service already stopped", i) + } + if stack.Service(id) == nil { + t.Fatalf("service %d: freshly started service unaccessible", i) + } + } + // Stop the node and check that all services have been stopped + if err := stack.Stop(); err != nil { + t.Fatalf("failed to stop protocol stack: %v", err) + } + for i, id := range ids { + if !stopped[id] { + t.Fatalf("service %d: freshly terminated service still running", i) + } + if service := stack.Service(id); service != nil { + t.Fatalf("service %d: freshly terminated service still accessible: %v", i, service) + } + } +} + +// Tests that services are restarted cleanly as new instances. +func TestServiceRestarts(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Define a service that does not support restarts + var ( + running bool + started int + ) + constructor := func(*ServiceContext) (Service, error) { + running = false + + return &InstrumentedService{ + startHook: func() { + if running { + panic("already running") + } + running = true + started++ + }, + }, nil + } + // Register the service and start the protocol stack + if err := stack.Register("service", constructor); err != nil { + t.Fatalf("failed to register the service: %v", err) + } + if err := stack.Start(); err != nil { + t.Fatalf("failed to start protocol stack: %v", err) + } + defer stack.Stop() + + if running != true || started != 1 { + t.Fatalf("running/started mismatch: have %v/%d, want true/1", running, started) + } + // Restart the stack a few times and check successful service restarts + for i := 0; i < 3; i++ { + if err := stack.Restart(); err != nil { + t.Fatalf("iter %d: failed to restart stack: %v", i, err) + } + } + if running != true || started != 4 { + t.Fatalf("running/started mismatch: have %v/%d, want true/4", running, started) + } +} + +// Tests that if a service fails to initialize itself, none of the other services +// will be allowed to even start. +func TestServiceConstructionAbortion(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Define a batch of good services + ids := []string{"A", "B", "C", "D", "E", "F"} + + started := make(map[string]bool) + for i, id := range ids { + id := id // Closure for the constructor + constructor := func(*ServiceContext) (Service, error) { + return &InstrumentedService{ + startHook: func() { started[id] = true }, + }, nil + } + if err := stack.Register(id, constructor); err != nil { + t.Fatalf("service %d: registration failed: %v", i, err) + } + } + // Register a service that fails to construct itself + failure := errors.New("fail") + failer := func(*ServiceContext) (Service, error) { + return nil, failure + } + if err := stack.Register("failer", failer); err != nil { + t.Fatalf("failer registration failed: %v", err) + } + // Start the protocol stack and ensure none of the services get started + for i := 0; i < 100; i++ { + if err := stack.Start(); err != failure { + t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) + } + for i, id := range ids { + if started[id] { + t.Fatalf("service %d: started should not have", i) + } + delete(started, id) + } + } +} + +// Tests that if a service fails to start, all others started before it will be +// shut down. +func TestServiceStartupAbortion(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Register a batch of good services + ids := []string{"A", "B", "C", "D", "E", "F"} + + started := make(map[string]bool) + stopped := make(map[string]bool) + + for i, id := range ids { + id := id // Closure for the constructor + constructor := func(*ServiceContext) (Service, error) { + return &InstrumentedService{ + startHook: func() { started[id] = true }, + stopHook: func() { stopped[id] = true }, + }, nil + } + if err := stack.Register(id, constructor); err != nil { + t.Fatalf("service %d: registration failed: %v", i, err) + } + } + // Register a service that fails to start + failure := errors.New("fail") + failer := func(*ServiceContext) (Service, error) { + return &InstrumentedService{ + start: failure, + }, nil + } + if err := stack.Register("failer", failer); err != nil { + t.Fatalf("failer registration failed: %v", err) + } + // Start the protocol stack and ensure all started services stop + for i := 0; i < 100; i++ { + if err := stack.Start(); err != failure { + t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) + } + for i, id := range ids { + if started[id] && !stopped[id] { + t.Fatalf("service %d: started but not stopped", i) + } + delete(started, id) + delete(stopped, id) + } + } +} + +// Tests that even if a registered service fails to shut down cleanly, it does +// not influece the rest of the shutdown invocations. +func TestServiceTerminationGuarantee(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Register a batch of good services + ids := []string{"A", "B", "C", "D", "E", "F"} + + started := make(map[string]bool) + stopped := make(map[string]bool) + + for i, id := range ids { + id := id // Closure for the constructor + constructor := func(*ServiceContext) (Service, error) { + return &InstrumentedService{ + startHook: func() { started[id] = true }, + stopHook: func() { stopped[id] = true }, + }, nil + } + if err := stack.Register(id, constructor); err != nil { + t.Fatalf("service %d: registration failed: %v", i, err) + } + } + // Register a service that fails to shot down cleanly + failure := errors.New("fail") + failer := func(*ServiceContext) (Service, error) { + return &InstrumentedService{ + stop: failure, + }, nil + } + if err := stack.Register("failer", failer); err != nil { + t.Fatalf("failer registration failed: %v", err) + } + // Start the protocol stack, and ensure that a failing shut down terminates all + for i := 0; i < 100; i++ { + // Start the stack and make sure all is online + if err := stack.Start(); err != nil { + t.Fatalf("iter %d: failed to start protocol stack: %v", i, err) + } + for j, id := range ids { + if !started[id] { + t.Fatalf("iter %d, service %d: service not running", i, j) + } + if stopped[id] { + t.Fatalf("iter %d, service %d: service already stopped", i, j) + } + } + // Stop the stack, verify failure and check all terminations + err := stack.Stop() + if err, ok := err.(*StopError); !ok { + t.Fatalf("iter %d: termination failure mismatch: have %v, want StopError", i, err) + } else { + if err.Services["failer"] != failure { + t.Fatalf("iter %d: failer termination failure mismatch: have %v, want %v", i, err.Services["failer"], failure) + } + if len(err.Services) != 1 { + t.Fatalf("iter %d: failure count mismatch: have %d, want %d", i, len(err.Services), 1) + } + } + for j, id := range ids { + if !stopped[id] { + t.Fatalf("iter %d, service %d: service not terminated", i, j) + } + delete(started, id) + delete(stopped, id) + } + } +} + +// Tests that all protocols defined by individual services get launched. +func TestProtocolGather(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Register a batch of services with some configured number of protocols + services := map[string]int{ + "Zero Protocols": 0, + "Single Protocol": 1, + "Many Protocols": 25, + } + for id, count := range services { + protocols := make([]p2p.Protocol, count) + for i := 0; i < len(protocols); i++ { + protocols[i].Name = id + protocols[i].Version = uint(i) + } + constructor := func(*ServiceContext) (Service, error) { + return &InstrumentedService{ + protocols: protocols, + }, nil + } + if err := stack.Register(id, constructor); err != nil { + t.Fatalf("service %s: registration failed: %v", id, err) + } + } + // Start the services and ensure all protocols start successfully + if err := stack.Start(); err != nil { + t.Fatalf("failed to start protocol stack: %v", err) + } + defer stack.Stop() + + protocols := stack.Server().Protocols + if len(protocols) != 26 { + t.Fatalf("mismatching number of protocols launched: have %d, want %d", len(protocols), 26) + } + for id, count := range services { + for ver := 0; ver < count; ver++ { + launched := false + for i := 0; i < len(protocols); i++ { + if protocols[i].Name == id && protocols[i].Version == uint(ver) { + launched = true + break + } + } + if !launched { + t.Errorf("configured protocol not launched: %s v%d", id, ver) + } + } + } +} diff --git a/node/service.go b/node/service.go new file mode 100644 index 0000000000..ec838dbe8e --- /dev/null +++ b/node/service.go @@ -0,0 +1,67 @@ +// 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 . + +package node + +import ( + "path/filepath" + + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/p2p" +) + +// ServiceContext is a collection of service independent options inherited from +// the protocol stack, that is passed to all constructors to be optionally used; +// as well as utility methods to operate on the service environment. +type ServiceContext struct { + dataDir string // Data directory for protocol persistence + EventMux *event.TypeMux // Event multiplexer used for decoupled notifications +} + +// Database opens an existing database with the given name (or creates one if no +// previous can be found) from within the node's data directory. If the node is +// an ephemeral one, a memory database is returned. +func (ctx *ServiceContext) Database(name string, cache int) (ethdb.Database, error) { + if ctx.dataDir == "" { + return ethdb.NewMemDatabase() + } + return ethdb.NewLDBDatabase(filepath.Join(ctx.dataDir, name), cache) +} + +// ServiceConstructor is the function signature of the constructors needed to be +// registered for service instantiation. +type ServiceConstructor func(ctx *ServiceContext) (Service, error) + +// Service is an individual protocol that can be registered into a node. +// +// Notes: +// - Service life-cycle management is delegated to the node. The service is +// allowed to initialize itself upon creation, but no goroutines should be +// spun up outside of the Start method. +// - Restart logic is not required as the node will create a fresh instance +// every time a service is started. +type Service interface { + // Protocol retrieves the P2P protocols the service wishes to start. + Protocols() []p2p.Protocol + + // Start spawns any goroutines required by the service. + Start() error + + // Stop terminates all goroutines belonging to the service, blocking until they + // are all terminated. + Stop() error +} diff --git a/node/service_test.go b/node/service_test.go new file mode 100644 index 0000000000..50a4f9715b --- /dev/null +++ b/node/service_test.go @@ -0,0 +1,60 @@ +// 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 . + +package node + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +// Tests that service context methods work properly. +func TestServiceContext(t *testing.T) { + // Create a temporary folder and ensure no database is contained within + dir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("failed to create temporary data directory: %v", err) + } + defer os.RemoveAll(dir) + + if _, err := os.Stat(filepath.Join(dir, "database")); err == nil { + t.Fatalf("non-created database already exists") + } + // Request the opening/creation of a database and ensure it persists to disk + ctx := &ServiceContext{dataDir: dir} + db, err := ctx.Database("persistent", 0) + if err != nil { + t.Fatalf("failed to open persistent database: %v", err) + } + db.Close() + + if _, err := os.Stat(filepath.Join(dir, "persistent")); err != nil { + t.Fatalf("persistent database doesn't exists: %v", err) + } + // Request th opening/creation of an ephemeral database and ensure it's not persisted + ctx = &ServiceContext{dataDir: ""} + db, err = ctx.Database("ephemeral", 0) + if err != nil { + t.Fatalf("failed to open ephemeral database: %v", err) + } + db.Close() + + if _, err := os.Stat(filepath.Join(dir, "ephemeral")); err == nil { + t.Fatalf("ephemeral database exists") + } +} diff --git a/node/utils.go b/node/utils.go new file mode 100644 index 0000000000..deaa6c5fbf --- /dev/null +++ b/node/utils.go @@ -0,0 +1,33 @@ +// 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 . + +package node + +import ( + "path/filepath" + + "github.com/ethereum/go-ethereum/ethdb" +) + +// openDatabase opens an existing database with the given name from within the +// specified data directory, creating one if none exists. If the data directory +// is empty, an ephemeral memory database is returned. +func openDatabase(dataDir string, name string, cache int) (ethdb.Database, error) { + if dataDir == "" { + return ethdb.NewMemDatabase() + } + return ethdb.NewLDBDatabase(filepath.Join(dataDir, name), cache) +} diff --git a/p2p/discover/table.go b/p2p/discover/table.go index c128c2ed16..298ba3fa6a 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -90,12 +90,11 @@ type transport interface { // that was most recently active is the first element in entries. type bucket struct{ entries []*Node } -func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string) *Table { +func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string) (*Table, error) { // If no node database was given, use an in-memory one db, err := newNodeDB(nodeDBPath, Version, ourID) if err != nil { - glog.V(logger.Warn).Infoln("Failed to open node database:", err) - db, _ = newNodeDB("", Version, ourID) + return nil, err } tab := &Table{ net: t, @@ -114,7 +113,7 @@ func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string tab.buckets[i] = new(bucket) } go tab.refreshLoop() - return tab + return tab, nil } // Self returns the local node. diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 84962a1a5e..13effaed62 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -34,7 +34,7 @@ import ( func TestTable_pingReplace(t *testing.T) { doit := func(newNodeIsResponding, lastInBucketIsResponding bool) { transport := newPingRecorder() - tab := newTable(transport, NodeID{}, &net.UDPAddr{}, "") + tab, _ := newTable(transport, NodeID{}, &net.UDPAddr{}, "") defer tab.Close() pingSender := newNode(MustHexID("a502af0f59b2aab7746995408c79e9ca312d2793cc997e44fc55eda62f0150bbb8c59a6f9269ba3a081518b62699ee807c7c19c20125ddfccca872608af9e370"), net.IP{}, 99, 99) @@ -177,7 +177,7 @@ func TestTable_closest(t *testing.T) { test := func(test *closeTest) bool { // for any node table, Target and N - tab := newTable(nil, test.Self, &net.UDPAddr{}, "") + tab, _ := newTable(nil, test.Self, &net.UDPAddr{}, "") defer tab.Close() tab.stuff(test.All) @@ -236,7 +236,7 @@ func TestTable_ReadRandomNodesGetAll(t *testing.T) { }, } test := func(buf []*Node) bool { - tab := newTable(nil, NodeID{}, &net.UDPAddr{}, "") + tab, _ := newTable(nil, NodeID{}, &net.UDPAddr{}, "") defer tab.Close() for i := 0; i < len(buf); i++ { ld := cfg.Rand.Intn(len(tab.buckets)) @@ -279,7 +279,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { func TestTable_Lookup(t *testing.T) { self := nodeAtDistance(common.Hash{}, 0) - tab := newTable(lookupTestnet, self.ID, &net.UDPAddr{}, "") + tab, _ := newTable(lookupTestnet, self.ID, &net.UDPAddr{}, "") defer tab.Close() // lookup on empty table returns no nodes diff --git a/p2p/discover/udp.go b/p2p/discover/udp.go index 20f69cf084..fc7fa737c3 100644 --- a/p2p/discover/udp.go +++ b/p2p/discover/udp.go @@ -200,12 +200,15 @@ func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, nodeDBP if err != nil { return nil, err } - tab, _ := newUDP(priv, conn, natm, nodeDBPath) + tab, _, err := newUDP(priv, conn, natm, nodeDBPath) + if err != nil { + return nil, err + } glog.V(logger.Info).Infoln("Listening,", tab.self) return tab, nil } -func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath string) (*Table, *udp) { +func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath string) (*Table, *udp, error) { udp := &udp{ conn: c, priv: priv, @@ -225,10 +228,15 @@ func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath strin } // TODO: separate TCP port udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port)) - udp.Table = newTable(udp, PubkeyID(&priv.PublicKey), realaddr, nodeDBPath) + tab, err := newTable(udp, PubkeyID(&priv.PublicKey), realaddr, nodeDBPath) + if err != nil { + return nil, nil, err + } + udp.Table = tab + go udp.loop() go udp.readLoop() - return udp.Table, udp + return udp.Table, udp, nil } func (t *udp) close() { diff --git a/p2p/discover/udp_test.go b/p2p/discover/udp_test.go index 913199c268..944e73d6ed 100644 --- a/p2p/discover/udp_test.go +++ b/p2p/discover/udp_test.go @@ -69,7 +69,7 @@ func newUDPTest(t *testing.T) *udpTest { remotekey: newkey(), remoteaddr: &net.UDPAddr{IP: net.IP{1, 2, 3, 4}, Port: 30303}, } - test.table, test.udp = newUDP(test.localkey, test.pipe, nil, "") + test.table, test.udp, _ = newUDP(test.localkey, test.pipe, nil, "") return test } From 8a44451edfa36ea40da564a2fa7ea905d45440a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 17 Nov 2015 13:39:18 +0200 Subject: [PATCH 07/27] cmd: drop blocktest command, create gethrpctest program --- cmd/geth/blocktestcmd.go | 135 ----------------------------- cmd/gethrpctest/main.go | 182 +++++++++++++++++++++++++++++++++++++++ node/utils.go | 33 ------- 3 files changed, 182 insertions(+), 168 deletions(-) delete mode 100644 cmd/geth/blocktestcmd.go create mode 100644 cmd/gethrpctest/main.go delete mode 100644 node/utils.go diff --git a/cmd/geth/blocktestcmd.go b/cmd/geth/blocktestcmd.go deleted file mode 100644 index e4d97aa531..0000000000 --- a/cmd/geth/blocktestcmd.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -package main - -import ( - "fmt" - "os" - - "github.com/codegangsta/cli" - "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/tests" -) - -var blocktestCommand = cli.Command{ - Action: runBlockTest, - Name: "blocktest", - Usage: `loads a block test file`, - Description: ` -The first argument should be a block test file. -The second argument is the name of a block test from the file. - -The block test will be loaded into an in-memory database. -If loading succeeds, the RPC server is started. Clients will -be able to interact with the chain defined by the test. -`, -} - -func runBlockTest(ctx *cli.Context) { - var ( - file, testname string - rpc bool - ) - args := ctx.Args() - switch { - case len(args) == 1: - file = args[0] - case len(args) == 2: - file, testname = args[0], args[1] - case len(args) == 3: - file, testname = args[0], args[1] - rpc = true - default: - utils.Fatalf(`Usage: ethereum blocktest [ [ "rpc" ] ]`) - } - bt, err := tests.LoadBlockTests(file) - if err != nil { - utils.Fatalf("%v", err) - } - - // run all tests if no test name is specified - if testname == "" { - ecode := 0 - for name, test := range bt { - fmt.Printf("----------------- Running Block Test %q\n", name) - ethereum, err := runOneBlockTest(ctx, test) - if err != nil { - fmt.Println(err) - fmt.Println("FAIL") - ecode = 1 - } - if ethereum != nil { - ethereum.Stop() - ethereum.WaitForShutdown() - } - } - os.Exit(ecode) - return - } - // otherwise, run the given test - test, ok := bt[testname] - if !ok { - utils.Fatalf("Test file does not contain test named %q", testname) - } - ethereum, err := runOneBlockTest(ctx, test) - if err != nil { - utils.Fatalf("%v", err) - } - if rpc { - fmt.Println("Block Test post state validated, starting RPC interface.") - startEth(ctx, ethereum) - utils.StartRPC(ethereum, ctx) - ethereum.WaitForShutdown() - } -} - -func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, error) { - cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) - db, _ := ethdb.NewMemDatabase() - cfg.NewDB = func(path string) (ethdb.Database, error) { return db, nil } - cfg.MaxPeers = 0 // disable network - cfg.Shh = false // disable whisper - cfg.NAT = nil // disable port mapping - ethereum, err := eth.New(cfg) - if err != nil { - return nil, err - } - - // import the genesis block - ethereum.ResetWithGenesisBlock(test.Genesis) - // import pre accounts - _, err = test.InsertPreState(db, cfg.AccountManager) - if err != nil { - return ethereum, fmt.Errorf("InsertPreState: %v", err) - } - - cm := ethereum.BlockChain() - validBlocks, err := test.TryBlocksInsert(cm) - if err != nil { - return ethereum, fmt.Errorf("Block Test load error: %v", err) - } - newDB, err := cm.State() - if err != nil { - return ethereum, fmt.Errorf("Block Test get state error: %v", err) - } - if err := test.ValidatePostState(newDB); err != nil { - return ethereum, fmt.Errorf("post state validation failed: %v", err) - } - return ethereum, test.ValidateImportedHeaders(cm, validBlocks) -} diff --git a/cmd/gethrpctest/main.go b/cmd/gethrpctest/main.go new file mode 100644 index 0000000000..5419ccc46b --- /dev/null +++ b/cmd/gethrpctest/main.go @@ -0,0 +1,182 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +// gethrpctest is a command to run the external RPC tests. +package main + +import ( + "flag" + "io/ioutil" + "log" + "os" + "os/signal" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/node" + "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/tests" + "github.com/ethereum/go-ethereum/whisper" + "github.com/ethereum/go-ethereum/xeth" +) + +const defaultTestKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" + +var ( + testFile = flag.String("json", "", "Path to the .json test file to load") + testName = flag.String("test", "", "Name of the test from the .json file to run") + testKey = flag.String("key", defaultTestKey, "Private key of a test account to inject") +) + +var ( + ethereumServiceId = "ethereum" + whisperServiceId = "whisper" +) + +func main() { + flag.Parse() + + // Load the test suite to run the RPC against + tests, err := tests.LoadBlockTests(*testFile) + if err != nil { + log.Fatalf("Failed to load test suite: %v", err) + } + test, found := tests[*testName] + if !found { + log.Fatalf("Requested test (%s) not found within suite", *testName) + } + // Create the protocol stack to run the test with + keydir, err := ioutil.TempDir("", "") + if err != nil { + log.Fatalf("Failed to create temporary keystore directory: %v", err) + } + defer os.RemoveAll(keydir) + + stack, err := MakeSystemNode(keydir, *testKey, test) + if err != nil { + log.Fatalf("Failed to assemble test stack: %v", err) + } + if err := stack.Start(); err != nil { + log.Fatalf("Failed to start test node: %v", err) + } + defer stack.Stop() + + log.Println("Test node started...") + + // Make sure the tests contained within the suite pass + if err := RunTest(stack, test); err != nil { + log.Fatalf("Failed to run the pre-configured test: %v", err) + } + log.Println("Initial test suite passed...") + + // Start the RPC interface and wait until terminated + if err := StartRPC(stack); err != nil { + log.Fatalf("Failed to start RPC instarface: %v", err) + } + log.Println("RPC Interface started, accepting requests...") + + quit := make(chan os.Signal, 1) + signal.Notify(quit, os.Interrupt) + <-quit +} + +// MakeSystemNode configures a protocol stack for the RPC tests based on a given +// keystore path and initial pre-state. +func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node.Node, error) { + // Create a networkless protocol stack + stack, err := node.New(&node.Config{NoDiscovery: true}) + if err != nil { + return nil, err + } + // Create the keystore and inject an unlocked account if requested + keystore := crypto.NewKeyStorePassphrase(keydir, crypto.StandardScryptN, crypto.StandardScryptP) + accman := accounts.NewManager(keystore) + + if len(privkey) > 0 { + key, err := crypto.HexToECDSA(privkey) + if err != nil { + return nil, err + } + if err := keystore.StoreKey(crypto.NewKeyFromECDSA(key), ""); err != nil { + return nil, err + } + if err := accman.Unlock(crypto.NewKeyFromECDSA(key).Address, ""); err != nil { + return nil, err + } + } + // Initialize and register the Ethereum protocol + db, _ := ethdb.NewMemDatabase() + if _, err := test.InsertPreState(db, accman); err != nil { + return nil, err + } + ethConf := ð.Config{ + TestGenesisState: db, + TestGenesisBlock: test.Genesis, + AccountManager: accman, + } + if err := stack.Register(ethereumServiceId, func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { + return nil, err + } + // Initialize and register the Whisper protocol + if err := stack.Register(whisperServiceId, func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { + return nil, err + } + return stack, nil +} + +// RunTest executes the specified test against an already pre-configured protocol +// stack to ensure basic checks pass before running RPC tests. +func RunTest(stack *node.Node, test *tests.BlockTest) error { + blockchain := stack.Service(ethereumServiceId).(*eth.Ethereum).BlockChain() + + // Process the blocks and verify the imported headers + blocks, err := test.TryBlocksInsert(blockchain) + if err != nil { + return err + } + if err := test.ValidateImportedHeaders(blockchain, blocks); err != nil { + return err + } + // Retrieve the assembled state and validate it + stateDb, err := blockchain.State() + if err != nil { + return err + } + if err := test.ValidatePostState(stateDb); err != nil { + return err + } + return nil +} + +// StartRPC initializes an RPC interface to the given protocol stack. +func StartRPC(stack *node.Node) error { + config := comms.HttpConfig{ + ListenAddress: "127.0.0.1", + ListenPort: 8545, + } + xeth := xeth.New(stack, nil) + codec := codec.JSON + + apis, err := api.ParseApiString(comms.DefaultHttpRpcApis, codec, xeth, stack) + if err != nil { + return err + } + return comms.StartHttp(config, codec, api.Merge(apis...)) +} diff --git a/node/utils.go b/node/utils.go deleted file mode 100644 index deaa6c5fbf..0000000000 --- a/node/utils.go +++ /dev/null @@ -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 . - -package node - -import ( - "path/filepath" - - "github.com/ethereum/go-ethereum/ethdb" -) - -// openDatabase opens an existing database with the given name from within the -// specified data directory, creating one if none exists. If the data directory -// is empty, an ephemeral memory database is returned. -func openDatabase(dataDir string, name string, cache int) (ethdb.Database, error) { - if dataDir == "" { - return ethdb.NewMemDatabase() - } - return ethdb.NewLDBDatabase(filepath.Join(dataDir, name), cache) -} From 1e806c4c775bd98b224eb0249007502d348e737b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 17 Nov 2015 18:33:25 +0200 Subject: [PATCH 08/27] cmd, common, core, eth, node, rpc, tests, whisper, xeth: use protocol stacks --- cmd/geth/js.go | 33 ++- cmd/geth/js_test.go | 128 +++++---- cmd/geth/main.go | 309 ++++++++------------- cmd/gethrpctest/main.go | 13 +- cmd/utils/bootnodes.go | 41 +++ cmd/utils/cmd.go | 11 +- cmd/utils/flags.go | 419 ++++++++++++++++++++--------- common/natspec/natspec_e2e_test.go | 12 +- common/types.go | 28 +- core/block_validator_test.go | 2 +- core/blockchain.go | 6 +- core/blockchain_test.go | 8 +- core/chain_makers.go | 2 +- core/default_genesis.go | 13 +- core/genesis.go | 116 +++++--- eth/backend.go | 345 ++++-------------------- node/node.go | 124 ++++++--- node/node_example_test.go | 12 +- node/node_test.go | 54 +++- node/service.go | 35 ++- node/service_test.go | 54 +++- rpc/api/admin.go | 37 +-- rpc/api/api_test.go | 2 +- rpc/api/utils.go | 12 +- tests/block_test_util.go | 25 +- whisper/peer_test.go | 2 +- whisper/whisper.go | 16 +- whisper/whisper_test.go | 2 +- xeth/state.go | 4 +- xeth/xeth.go | 135 ++++++---- 30 files changed, 1051 insertions(+), 949 deletions(-) create mode 100644 cmd/utils/bootnodes.go diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 4d5462539b..a0e8bdb21c 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/common/registrar" "github.com/ethereum/go-ethereum/eth" re "github.com/ethereum/go-ethereum/jsre" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc/api" "github.com/ethereum/go-ethereum/rpc/codec" @@ -77,7 +78,7 @@ func (r dumbterm) AppendHistory(string) {} type jsre struct { re *re.JSRE - ethereum *eth.Ethereum + stack *node.Node xeth *xeth.XEth wait chan *big.Int ps1 string @@ -176,18 +177,18 @@ func newLightweightJSRE(docRoot string, client comms.EthereumClient, datadir str return js } -func newJSRE(ethereum *eth.Ethereum, docRoot, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre { - js := &jsre{ethereum: ethereum, ps1: "> "} +func newJSRE(stack *node.Node, docRoot, corsDomain string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre { + js := &jsre{stack: stack, ps1: "> "} // set default cors domain used by startRpc from CLI flag js.corsDomain = corsDomain if f == nil { f = js } - js.xeth = xeth.New(ethereum, f) + js.xeth = xeth.New(stack, f) js.wait = js.xeth.UpdateState() js.client = client if clt, ok := js.client.(*comms.InProcClient); ok { - if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, ethereum); err == nil { + if offeredApis, err := api.ParseApiString(shared.AllApis, codec.JSON, js.xeth, stack); err == nil { clt.Initialize(api.Merge(offeredApis...)) } } @@ -202,14 +203,14 @@ func newJSRE(ethereum *eth.Ethereum, docRoot, corsDomain string, client comms.Et js.prompter = dumbterm{bufio.NewReader(os.Stdin)} } else { lr := liner.NewLiner() - js.withHistory(ethereum.DataDir, func(hist *os.File) { lr.ReadHistory(hist) }) + js.withHistory(stack.DataDir(), func(hist *os.File) { lr.ReadHistory(hist) }) lr.SetCtrlCAborts(true) js.loadAutoCompletion() lr.SetWordCompleter(apiWordCompleter) lr.SetTabCompletionStyle(liner.TabPrints) js.prompter = lr js.atexit = func() { - js.withHistory(ethereum.DataDir, func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) + js.withHistory(stack.DataDir(), func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) lr.Close() close(js.wait) } @@ -276,7 +277,7 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { apiNames = append(apiNames, a) } - apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.ethereum) + apiImpl, err := api.ParseApiString(strings.Join(apiNames, ","), codec.JSON, js.xeth, js.stack) if err != nil { utils.Fatalf("Unable to determine supported api's: %v", err) } @@ -342,8 +343,14 @@ func (self *jsre) AskPassword() (string, bool) { } func (self *jsre) ConfirmTransaction(tx string) bool { - if self.ethereum.NatSpec { - notice := natspec.GetNotice(self.xeth, tx, self.ethereum.HTTPClient()) + // Retrieve the Ethereum instance from the node + var ethereum *eth.Ethereum + if _, err := self.stack.SingletonService(ðereum); err != nil { + return false + } + // If natspec is enabled, ask for permission + if ethereum.NatSpec { + notice := natspec.GetNotice(self.xeth, tx, ethereum.HTTPClient()) fmt.Println(notice) answer, _ := self.Prompt("Confirm Transaction [y/n]") return strings.HasPrefix(strings.Trim(answer, " "), "y") @@ -359,7 +366,11 @@ func (self *jsre) UnlockAccount(addr []byte) bool { return false } // TODO: allow retry - if err := self.ethereum.AccountManager().Unlock(common.BytesToAddress(addr), pass); err != nil { + var ethereum *eth.Ethereum + if _, err := self.stack.SingletonService(ðereum); err != nil { + return false + } + if err := ethereum.AccountManager().Unlock(common.BytesToAddress(addr), pass); err != nil { return false } else { fmt.Println("Account is now unlocked for this session.") diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index 4770797062..ed4d04b483 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc/codec" "github.com/ethereum/go-ethereum/rpc/comms" ) @@ -66,7 +67,10 @@ type testjethre struct { } func (self *testjethre) UnlockAccount(acc []byte) bool { - err := self.ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "") + var ethereum *eth.Ethereum + self.stack.SingletonService(ðereum) + + err := ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "") if err != nil { panic("unable to unlock") } @@ -74,67 +78,74 @@ func (self *testjethre) UnlockAccount(acc []byte) bool { } func (self *testjethre) ConfirmTransaction(tx string) bool { - if self.ethereum.NatSpec { + var ethereum *eth.Ethereum + self.stack.SingletonService(ðereum) + + if ethereum.NatSpec { self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.client) } return true } -func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) { +func testJEthRE(t *testing.T) (string, *testjethre, *node.Node) { return testREPL(t, nil) } -func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *eth.Ethereum) { +func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *node.Node) { tmp, err := ioutil.TempDir("", "geth-test") if err != nil { t.Fatal(err) } + // Create a networkless protocol stack + stack, err := node.New(&node.Config{PrivateKey: testNodeKey, Name: "test", NoDiscovery: true}) + if err != nil { + t.Fatalf("failed to create node: %v", err) + } + // Initialize and register the Ethereum protocol + keystore := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore")) + accman := accounts.NewManager(keystore) db, _ := ethdb.NewMemDatabase() - core.WriteGenesisBlockForTesting(db, core.GenesisAccount{common.HexToAddress(testAddress), common.String2Big(testBalance)}) - ks := crypto.NewKeyStorePlain(filepath.Join(tmp, "keystore")) - am := accounts.NewManager(ks) - conf := ð.Config{ - NodeKey: testNodeKey, - DataDir: tmp, - AccountManager: am, - MaxPeers: 0, - Name: "test", - DocRoot: "/", - SolcPath: testSolcPath, - PowTest: true, - NewDB: func(path string) (ethdb.Database, error) { return db, nil }, + + ethConf := ð.Config{ + TestGenesisState: db, + AccountManager: accman, + DocRoot: "/", + SolcPath: testSolcPath, + PowTest: true, } if config != nil { - config(conf) + config(ethConf) } - ethereum, err := eth.New(conf) - if err != nil { - t.Fatal("%v", err) + if err := stack.Register("ethereum", func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { + t.Fatalf("failed to register ethereum protocol: %v", err) } - + // Initialize all the keys for testing keyb, err := crypto.HexToECDSA(testKey) if err != nil { t.Fatal(err) } key := crypto.NewKeyFromECDSA(keyb) - err = ks.StoreKey(key, "") - if err != nil { + if err := keystore.StoreKey(key, ""); err != nil { t.Fatal(err) } - - err = am.Unlock(key.Address, "") - if err != nil { + if err := accman.Unlock(key.Address, ""); err != nil { t.Fatal(err) } + // Start the node and assemble the REPL tester + if err := stack.Start(); err != nil { + t.Fatalf("failed to start test stack: %v", err) + } + var ethereum *eth.Ethereum + stack.SingletonService(ðereum) assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") client := comms.NewInProcClient(codec.JSON) tf := &testjethre{client: ethereum.HTTPClient()} - repl := newJSRE(ethereum, assetPath, "", client, false, tf) + repl := newJSRE(stack, assetPath, "", client, false, tf) tf.jsre = repl - return tmp, tf, ethereum + return tmp, tf, stack } func TestNodeInfo(t *testing.T) { @@ -151,11 +162,8 @@ func TestNodeInfo(t *testing.T) { } func TestAccounts(t *testing.T) { - tmp, repl, ethereum := testJEthRE(t) - if err := ethereum.Start(); err != nil { - t.Fatalf("error starting ethereum: %v", err) - } - defer ethereum.Stop() + tmp, repl, node := testJEthRE(t) + defer node.Stop() defer os.RemoveAll(tmp) checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`) @@ -174,11 +182,8 @@ func TestAccounts(t *testing.T) { } func TestBlockChain(t *testing.T) { - tmp, repl, ethereum := testJEthRE(t) - if err := ethereum.Start(); err != nil { - t.Fatalf("error starting ethereum: %v", err) - } - defer ethereum.Stop() + tmp, repl, node := testJEthRE(t) + defer node.Stop() defer os.RemoveAll(tmp) // get current block dump before export/import. val, err := repl.re.Run("JSON.stringify(debug.dumpBlock(eth.blockNumber))") @@ -196,6 +201,8 @@ func TestBlockChain(t *testing.T) { tmpfile := filepath.Join(extmp, "export.chain") tmpfileq := strconv.Quote(tmpfile) + var ethereum *eth.Ethereum + node.SingletonService(ðereum) ethereum.BlockChain().Reset() checkEvalJSON(t, repl, `admin.exportChain(`+tmpfileq+`)`, `true`) @@ -209,22 +216,15 @@ func TestBlockChain(t *testing.T) { } func TestMining(t *testing.T) { - tmp, repl, ethereum := testJEthRE(t) - if err := ethereum.Start(); err != nil { - t.Fatalf("error starting ethereum: %v", err) - } - defer ethereum.Stop() + tmp, repl, node := testJEthRE(t) + defer node.Stop() defer os.RemoveAll(tmp) checkEvalJSON(t, repl, `eth.mining`, `false`) } func TestRPC(t *testing.T) { - tmp, repl, ethereum := testJEthRE(t) - if err := ethereum.Start(); err != nil { - t.Errorf("error starting ethereum: %v", err) - return - } - defer ethereum.Stop() + tmp, repl, node := testJEthRE(t) + defer node.Stop() defer os.RemoveAll(tmp) checkEvalJSON(t, repl, `admin.startRPC("127.0.0.1", 5004, "*", "web3,eth,net")`, `true`) @@ -234,12 +234,8 @@ func TestCheckTestAccountBalance(t *testing.T) { t.Skip() // i don't think it tests the correct behaviour here. it's actually testing // internals which shouldn't be tested. This now fails because of a change in the core // and i have no means to fix this, sorry - @obscuren - tmp, repl, ethereum := testJEthRE(t) - if err := ethereum.Start(); err != nil { - t.Errorf("error starting ethereum: %v", err) - return - } - defer ethereum.Stop() + tmp, repl, node := testJEthRE(t) + defer node.Stop() defer os.RemoveAll(tmp) repl.re.Run(`primary = "` + testAddress + `"`) @@ -247,12 +243,8 @@ func TestCheckTestAccountBalance(t *testing.T) { } func TestSignature(t *testing.T) { - tmp, repl, ethereum := testJEthRE(t) - if err := ethereum.Start(); err != nil { - t.Errorf("error starting ethereum: %v", err) - return - } - defer ethereum.Stop() + tmp, repl, node := testJEthRE(t) + defer node.Stop() defer os.RemoveAll(tmp) val, err := repl.re.Run(`eth.sign("` + testAddress + `", "` + testHash + `")`) @@ -443,7 +435,10 @@ multiply7 = Multiply7.at(contractaddress); } func pendingTransactions(repl *testjethre, t *testing.T) (txc int64, err error) { - txs := repl.ethereum.TxPool().GetTransactions() + var ethereum *eth.Ethereum + repl.stack.SingletonService(ðereum) + + txs := ethereum.TxPool().GetTransactions() return int64(len(txs)), nil } @@ -468,12 +463,15 @@ func processTxs(repl *testjethre, t *testing.T, expTxc int) bool { t.Errorf("incorrect number of pending transactions, expected %v, got %v", expTxc, txc) return false } - err = repl.ethereum.StartMining(runtime.NumCPU(), "") + var ethereum *eth.Ethereum + repl.stack.SingletonService(ðereum) + + err = ethereum.StartMining(runtime.NumCPU(), "") if err != nil { t.Errorf("unexpected error mining: %v", err) return false } - defer repl.ethereum.StopMining() + defer ethereum.StopMining() timer := time.NewTimer(100 * time.Second) height := new(big.Int).Add(repl.xeth.CurrentBlock().Number(), big.NewInt(1)) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 82bc21ab05..6fac4f4582 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -33,13 +33,11 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc/codec" @@ -68,22 +66,9 @@ func init() { } app = utils.NewApp(Version, "the go-ethereum command line interface") - app.Action = run + app.Action = geth app.HideVersion = true // we have a command to print the version app.Commands = []cli.Command{ - { - Action: blockRecovery, - Name: "recover", - Usage: "Attempts to recover a corrupted database by setting a new block by number or hash", - Description: ` -The recover commands will attempt to read out the last -block based on that. - -recover #number recovers by number -recover recovers by hash -`, - }, - blocktestCommand, importCommand, exportCommand, upgradedbCommand, @@ -285,7 +270,7 @@ This command allows to open a console on a running geth node. `, }, { - Action: execJSFiles, + Action: execScripts, Name: "js", Usage: `executes the given JavaScript files in the Geth JavaScript VM`, Description: ` @@ -376,14 +361,6 @@ func main() { } } -// makeExtra resolves extradata for the miner from a flag or returns a default. -func makeExtra(ctx *cli.Context) []byte { - if ctx.GlobalIsSet(utils.ExtraDataFlag.Name) { - return []byte(ctx.GlobalString(utils.ExtraDataFlag.Name)) - } - return makeDefaultExtra() -} - func makeDefaultExtra() []byte { var clientInfo = struct { Version uint @@ -404,18 +381,13 @@ func makeDefaultExtra() []byte { return extra } -func run(ctx *cli.Context) { - cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) - cfg.ExtraData = makeExtra(ctx) - - ethereum, err := eth.New(cfg) - if err != nil { - utils.Fatalf("%v", err) - } - - startEth(ctx, ethereum) - // this blocks the thread - ethereum.WaitForShutdown() +// geth is the main entry point into the system if no special subcommand is ran. +// It creates a default node based on the command line arguments and runs it in +// blocking mode, waiting for it to be shut down. +func geth(ctx *cli.Context) { + node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx) + startNode(ctx, node) + node.Wait() } func attach(ctx *cli.Context) { @@ -449,156 +421,107 @@ func attach(ctx *cli.Context) { } } +// console starts a new geth node, attaching a JavaScript console to it at the +// same time. func console(ctx *cli.Context) { - cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) - cfg.ExtraData = makeExtra(ctx) - - ethereum, err := eth.New(cfg) - if err != nil { - utils.Fatalf("%v", err) - } + // Create and start the node based on the CLI flags + node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx) + startNode(ctx, node) + // Attach to the newly started node, and either execute script or become interactive client := comms.NewInProcClient(codec.JSON) - - startEth(ctx, ethereum) - repl := newJSRE( - ethereum, + repl := newJSRE(node, ctx.GlobalString(utils.JSpathFlag.Name), ctx.GlobalString(utils.RPCCORSDomainFlag.Name), - client, - true, - nil, - ) + client, true, nil) - if ctx.GlobalString(utils.ExecFlag.Name) != "" { - repl.batch(ctx.GlobalString(utils.ExecFlag.Name)) + if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { + repl.batch(script) } else { repl.welcome() repl.interactive() } - - ethereum.Stop() - ethereum.WaitForShutdown() + node.Stop() } -func execJSFiles(ctx *cli.Context) { - cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) - ethereum, err := eth.New(cfg) - if err != nil { - utils.Fatalf("%v", err) - } +// execScripts starts a new geth node based on the CLI flags, and executes each +// of the JavaScript files specified as command arguments. +func execScripts(ctx *cli.Context) { + // Create and start the node based on the CLI flags + node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx) + startNode(ctx, node) + // Attach to the newly started node and execute the given scripts client := comms.NewInProcClient(codec.JSON) - startEth(ctx, ethereum) - repl := newJSRE( - ethereum, + repl := newJSRE(node, ctx.GlobalString(utils.JSpathFlag.Name), ctx.GlobalString(utils.RPCCORSDomainFlag.Name), - client, - false, - nil, - ) + client, false, nil) + for _, file := range ctx.Args() { repl.exec(file) } - - ethereum.Stop() - ethereum.WaitForShutdown() + node.Stop() } -func unlockAccount(ctx *cli.Context, am *accounts.Manager, addr string, i int, inputpassphrases []string) (addrHex, auth string, passphrases []string) { - var err error - passphrases = inputpassphrases - addrHex, err = utils.ParamToAddress(addr, am) - if err == nil { - // Attempt to unlock the account 3 times - attempts := 3 - for tries := 0; tries < attempts; tries++ { - msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", addr, tries+1, attempts) - auth, passphrases = getPassPhrase(ctx, msg, false, i, passphrases) - err = am.Unlock(common.HexToAddress(addrHex), auth) - if err == nil || passphrases != nil { - break - } +func unlockAccount(ctx *cli.Context, accman *accounts.Manager, address string, i int, passwords []string) (common.Address, string) { + // Try to unlock the specified account a few times + account := utils.MakeAddress(accman, address) + + for trials := 0; trials < 3; trials++ { + prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) + password := getPassPhrase(prompt, false, i, passwords) + if err := accman.Unlock(account, password); err == nil { + return account, password } } - - if err != nil { - utils.Fatalf("Unlock account '%s' (%v) failed: %v", addr, addrHex, err) - } - fmt.Printf("Account '%s' (%v) unlocked.\n", addr, addrHex) - return + // All trials expended to unlock account, bail out + utils.Fatalf("Failed to unlock account: %s", address) + return common.Address{}, "" } -func blockRecovery(ctx *cli.Context) { - if len(ctx.Args()) < 1 { - glog.Fatal("recover requires block number or hash") +// startNode boots up the system node and all registered protocols, after which +// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the +// miner. +func startNode(ctx *cli.Context, stack *node.Node) { + // Start up the node itself + utils.StartNode(stack) + + // Unlock any account specifically requested + var ethereum *eth.Ethereum + if _, err := stack.SingletonService(ðereum); err != nil { + utils.Fatalf("ethereum service not running: %v", err) } - arg := ctx.Args().First() + accman := ethereum.AccountManager() + passwords := utils.MakePasswordList(ctx) - cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) - blockDb, err := ethdb.NewLDBDatabase(filepath.Join(cfg.DataDir, "blockchain"), cfg.DatabaseCache) - if err != nil { - glog.Fatalln("could not open db:", err) - } - - var block *types.Block - if arg[0] == '#' { - block = core.GetBlock(blockDb, core.GetCanonicalHash(blockDb, common.String2Big(arg[1:]).Uint64())) - } else { - block = core.GetBlock(blockDb, common.HexToHash(arg)) - } - - if block == nil { - glog.Fatalln("block not found. Recovery failed") - } - - if err = core.WriteHeadBlockHash(blockDb, block.Hash()); err != nil { - glog.Fatalln("block write err", err) - } - glog.Infof("Recovery succesful. New HEAD %x\n", block.Hash()) -} - -func startEth(ctx *cli.Context, eth *eth.Ethereum) { - // Start Ethereum itself - utils.StartEthereum(eth) - - am := eth.AccountManager() - account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) - accounts := strings.Split(account, " ") - var passphrases []string + accounts := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") for i, account := range accounts { - if len(account) > 0 { - if account == "primary" { - utils.Fatalf("the 'primary' keyword is deprecated. You can use integer indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.") - } - _, _, passphrases = unlockAccount(ctx, am, account, i, passphrases) + if trimmed := strings.TrimSpace(account); trimmed != "" { + unlockAccount(ctx, accman, trimmed, i, passwords) } } // Start auxiliary services if enabled. if !ctx.GlobalBool(utils.IPCDisabledFlag.Name) { - if err := utils.StartIPC(eth, ctx); err != nil { - utils.Fatalf("Error string IPC: %v", err) + if err := utils.StartIPC(stack, ctx); err != nil { + utils.Fatalf("Failed to start IPC: %v", err) } } if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { - if err := utils.StartRPC(eth, ctx); err != nil { - utils.Fatalf("Error starting RPC: %v", err) + if err := utils.StartRPC(stack, ctx); err != nil { + utils.Fatalf("Failed to start RPC: %v", err) } } if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { - err := eth.StartMining( - ctx.GlobalInt(utils.MinerThreadsFlag.Name), - ctx.GlobalString(utils.MiningGPUFlag.Name)) - if err != nil { - utils.Fatalf("%v", err) + if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil { + utils.Fatalf("Failed to start mining: %v", err) } } } func accountList(ctx *cli.Context) { - am := utils.MakeAccountManager(ctx) - accts, err := am.Accounts() + accman := utils.MakeAccountManager(ctx) + accts, err := accman.Accounts() if err != nil { utils.Fatalf("Could not list accounts: %v", err) } @@ -607,67 +530,57 @@ func accountList(ctx *cli.Context) { } } -func getPassPhrase(ctx *cli.Context, desc string, confirmation bool, i int, inputpassphrases []string) (passphrase string, passphrases []string) { - passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) - if len(passfile) == 0 { - fmt.Println(desc) - auth, err := utils.PromptPassword("Passphrase: ", true) +// getPassPhrase retrieves the passwor associated with an account, either fetched +// from a list of preloaded passphrases, or requested interactively from the user. +func getPassPhrase(prompt string, confirmation bool, i int, passwords []string) string { + // If a list of passwords was supplied, retrieve from them + if len(passwords) > 0 { + if i < len(passwords) { + return passwords[i] + } + return passwords[len(passwords)-1] + } + // Otherwise prompt the user for the password + fmt.Println(prompt) + password, err := utils.PromptPassword("Passphrase: ", true) + if err != nil { + utils.Fatalf("Failed to read passphrase: %v", err) + } + if confirmation { + confirm, err := utils.PromptPassword("Repeat passphrase: ", false) if err != nil { - utils.Fatalf("%v", err) + utils.Fatalf("Failed to read passphrase confirmation: %v", err) } - if confirmation { - confirm, err := utils.PromptPassword("Repeat Passphrase: ", false) - if err != nil { - utils.Fatalf("%v", err) - } - if auth != confirm { - utils.Fatalf("Passphrases did not match.") - } - } - passphrase = auth - - } else { - passphrases = inputpassphrases - if passphrases == nil { - passbytes, err := ioutil.ReadFile(passfile) - if err != nil { - utils.Fatalf("Unable to read password file '%s': %v", passfile, err) - } - // this is backwards compatible if the same password unlocks several accounts - // it also has the consequence that trailing newlines will not count as part - // of the password, so --password <(echo -n 'pass') will now work without -n - passphrases = strings.Split(string(passbytes), "\n") - } - if i >= len(passphrases) { - passphrase = passphrases[len(passphrases)-1] - } else { - passphrase = passphrases[i] + if password != confirm { + utils.Fatalf("Passphrases do not match") } } - return + return password } +// accountCreate creates a new account into the keystore defined by the CLI flags. func accountCreate(ctx *cli.Context) { - am := utils.MakeAccountManager(ctx) - passphrase, _ := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, nil) - acct, err := am.NewAccount(passphrase) + accman := utils.MakeAccountManager(ctx) + password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) + + account, err := accman.NewAccount(password) if err != nil { - utils.Fatalf("Could not create the account: %v", err) + utils.Fatalf("Failed to create account: %v", err) } - fmt.Printf("Address: %x\n", acct) + fmt.Printf("Address: %x\n", account) } +// accountUpdate transitions an account from a previous format to the current +// one, also providing the possibility to change the pass-phrase. func accountUpdate(ctx *cli.Context) { - am := utils.MakeAccountManager(ctx) - arg := ctx.Args().First() - if len(arg) == 0 { - utils.Fatalf("account address or index must be given as argument") + if len(ctx.Args()) == 0 { + utils.Fatalf("No accounts specified to update") } + accman := utils.MakeAccountManager(ctx) - addr, authFrom, passphrases := unlockAccount(ctx, am, arg, 0, nil) - authTo, _ := getPassPhrase(ctx, "Please give a new password. Do not forget this password.", true, 0, passphrases) - err := am.Update(common.HexToAddress(addr), authFrom, authTo) - if err != nil { + account, oldPassword := unlockAccount(ctx, accman, ctx.Args().First(), 0, nil) + newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil) + if err := accman.Update(account, oldPassword, newPassword); err != nil { utils.Fatalf("Could not update the account: %v", err) } } @@ -682,10 +595,10 @@ func importWallet(ctx *cli.Context) { utils.Fatalf("Could not read wallet file: %v", err) } - am := utils.MakeAccountManager(ctx) - passphrase, _ := getPassPhrase(ctx, "", false, 0, nil) + accman := utils.MakeAccountManager(ctx) + passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx)) - acct, err := am.ImportPreSaleKey(keyJson, passphrase) + acct, err := accman.ImportPreSaleKey(keyJson, passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) } @@ -697,9 +610,9 @@ func accountImport(ctx *cli.Context) { if len(keyfile) == 0 { utils.Fatalf("keyfile must be given as argument") } - am := utils.MakeAccountManager(ctx) - passphrase, _ := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, nil) - acct, err := am.Import(keyfile, passphrase) + accman := utils.MakeAccountManager(ctx) + passphrase := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) + acct, err := accman.Import(keyfile, passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) } diff --git a/cmd/gethrpctest/main.go b/cmd/gethrpctest/main.go index 5419ccc46b..cb4c7aece2 100644 --- a/cmd/gethrpctest/main.go +++ b/cmd/gethrpctest/main.go @@ -45,11 +45,6 @@ var ( testKey = flag.String("key", defaultTestKey, "Private key of a test account to inject") ) -var ( - ethereumServiceId = "ethereum" - whisperServiceId = "whisper" -) - func main() { flag.Parse() @@ -131,11 +126,11 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node TestGenesisBlock: test.Genesis, AccountManager: accman, } - if err := stack.Register(ethereumServiceId, func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { + if err := stack.Register("ethereum", func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { return nil, err } // Initialize and register the Whisper protocol - if err := stack.Register(whisperServiceId, func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { + if err := stack.Register("whisper", func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { return nil, err } return stack, nil @@ -144,7 +139,9 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node // RunTest executes the specified test against an already pre-configured protocol // stack to ensure basic checks pass before running RPC tests. func RunTest(stack *node.Node, test *tests.BlockTest) error { - blockchain := stack.Service(ethereumServiceId).(*eth.Ethereum).BlockChain() + var ethereum *eth.Ethereum + stack.SingletonService(ðereum) + blockchain := ethereum.BlockChain() // Process the blocks and verify the imported headers blocks, err := test.TryBlocksInsert(blockchain) diff --git a/cmd/utils/bootnodes.go b/cmd/utils/bootnodes.go new file mode 100644 index 0000000000..fbbaa1f227 --- /dev/null +++ b/cmd/utils/bootnodes.go @@ -0,0 +1,41 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package utils + +import "github.com/ethereum/go-ethereum/p2p/discover" + +// FrontierBootNodes are the enode URLs of the P2P bootstrap nodes running on +// the Frontier network. +var FrontierBootNodes = []*discover.Node{ + // ETH/DEV Go Bootnodes + discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE + discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR + discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG + + // ETH/DEV Cpp Bootnodes + discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"), +} + +// TestNetBootNodes are the enode URLs of the P2P bootstrap nodes running on the +// Morden test network. +var TestNetBootNodes = []*discover.Node{ + // ETH/DEV Go Bootnodes + discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"), + discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"), + + // ETH/DEV Cpp Bootnodes +} diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 5cbb581244..a0d60a583d 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -29,9 +29,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" - "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/rlp" "github.com/peterh/liner" ) @@ -110,10 +110,9 @@ func Fatalf(format string, args ...interface{}) { os.Exit(1) } -func StartEthereum(ethereum *eth.Ethereum) { - glog.V(logger.Info).Infoln("Starting", ethereum.Name()) - if err := ethereum.Start(); err != nil { - Fatalf("Error starting Ethereum: %v", err) +func StartNode(stack *node.Node) { + if err := stack.Start(); err != nil { + Fatalf("Error starting protocol stack: %v", err) } go func() { sigc := make(chan os.Signal, 1) @@ -121,7 +120,7 @@ func StartEthereum(ethereum *eth.Ethereum) { defer signal.Stop(sigc) <-sigc glog.V(logger.Info).Infoln("Got interrupt, shutting down...") - go ethereum.Stop() + go stack.Stop() logger.Flush() for i := 10; i > 0; i-- { <-sigc diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3792dc1e0d..30570d930b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -19,6 +19,7 @@ package utils import ( "crypto/ecdsa" "fmt" + "io/ioutil" "log" "math" "math/big" @@ -28,12 +29,14 @@ import ( "path/filepath" "runtime" "strconv" + "strings" "github.com/codegangsta/cli" "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" "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/crypto" "github.com/ethereum/go-ethereum/eth" @@ -42,6 +45,8 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc/api" @@ -49,6 +54,7 @@ import ( "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/whisper" "github.com/ethereum/go-ethereum/xeth" ) @@ -192,12 +198,12 @@ var ( // Account settings UnlockedAccountFlag = cli.StringFlag{ Name: "unlock", - Usage: "Unlock an account (may be creation index) until this program exits (prompts for password)", + Usage: "Comma separated list of accounts to unlock", Value: "", } PasswordFileFlag = cli.StringFlag{ Name: "password", - Usage: "Password file to use with options/subcommands needing a pass phrase", + Usage: "Password file to use for non-inteactive password input", Value: "", } @@ -316,7 +322,7 @@ var ( } BootnodesFlag = cli.StringFlag{ Name: "bootnodes", - Usage: "Space-separated enode URLs for P2P discovery bootstrap", + Usage: "Comma separated enode URLs for P2P discovery bootstrap", Value: "", } NodeKeyFileFlag = cli.StringFlag{ @@ -385,6 +391,90 @@ var ( } ) +// MustMakeDataDir retrieves the currently requested data directory, terminating +// if none (or the empty string) is specified. If the node is starting a testnet, +// the a subdirectory of the specified datadir will be used. +func MustMakeDataDir(ctx *cli.Context) string { + if path := ctx.GlobalString(DataDirFlag.Name); path != "" { + if ctx.GlobalBool(TestNetFlag.Name) { + return filepath.Join(path, "/testnet") + } + return path + } + Fatalf("Cannot determine default data directory, please set manually (--datadir)") + return "" +} + +// MakeNodeKey creates a node key from set command line flags, either loading it +// from a file or as a specified hex value. If neither flags were provided, this +// method returns nil and an emphemeral key is to be generated. +func MakeNodeKey(ctx *cli.Context) *ecdsa.PrivateKey { + var ( + hex = ctx.GlobalString(NodeKeyHexFlag.Name) + file = ctx.GlobalString(NodeKeyFileFlag.Name) + + key *ecdsa.PrivateKey + err error + ) + switch { + case file != "" && hex != "": + Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) + + case file != "": + if key, err = crypto.LoadECDSA(file); err != nil { + Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) + } + + case hex != "": + if key, err = crypto.HexToECDSA(hex); err != nil { + Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) + } + } + return key +} + +// MakeNodeName creates a node name from a base set and the command line flags. +func MakeNodeName(client, version string, ctx *cli.Context) string { + name := common.MakeName(client, version) + if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { + name += "/" + identity + } + if ctx.GlobalBool(VMEnableJitFlag.Name) { + name += "/JIT" + } + return name +} + +// MakeBootstrapNodes creates a list of bootstrap nodes from the command line +// flags, reverting to pre-configured ones if none have been specified. +func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node { + // Return pre-configured nodes if none were manually requested + if !ctx.GlobalIsSet(BootnodesFlag.Name) { + if ctx.GlobalBool(TestNetFlag.Name) { + return TestNetBootNodes + } + return FrontierBootNodes + } + // Otherwise parse and use the CLI bootstrap nodes + bootnodes := []*discover.Node{} + + for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") { + node, err := discover.ParseNode(url) + if err != nil { + glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err) + continue + } + bootnodes = append(bootnodes, node) + } + return bootnodes +} + +// MakeListenAddress creates a TCP listening address string from set command +// line flags. +func MakeListenAddress(ctx *cli.Context) string { + return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) +} + // MakeNAT creates a port mapper from set command line flags. func MakeNAT(ctx *cli.Context) nat.Interface { natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) @@ -394,64 +484,145 @@ func MakeNAT(ctx *cli.Context) nat.Interface { return natif } -// MakeNodeKey creates a node key from set command line flags. -func MakeNodeKey(ctx *cli.Context) (key *ecdsa.PrivateKey) { - hex, file := ctx.GlobalString(NodeKeyHexFlag.Name), ctx.GlobalString(NodeKeyFileFlag.Name) - var err error - switch { - case file != "" && hex != "": - Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) - case file != "": - if key, err = crypto.LoadECDSA(file); err != nil { - Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) - } - case hex != "": - if key, err = crypto.HexToECDSA(hex); err != nil { - Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) - } +// MakeGenesisBlock loads up a genesis block from an input file specified in the +// command line, or returns the empty string if none set. +func MakeGenesisBlock(ctx *cli.Context) string { + genesis := ctx.GlobalString(GenesisFileFlag.Name) + if genesis == "" { + return "" } - return key + data, err := ioutil.ReadFile(genesis) + if err != nil { + Fatalf("Failed to load custom genesis file: %v", err) + } + return string(data) } -// MakeEthConfig creates ethereum options from set command line flags. -func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config { - customName := ctx.GlobalString(IdentityFlag.Name) - if len(customName) > 0 { - clientID += "/" + customName +// MakeAccountManager creates an account manager from set command line flags. +func MakeAccountManager(ctx *cli.Context) *accounts.Manager { + // Create the keystore crypto primitive, light if requested + scryptN := crypto.StandardScryptN + scryptP := crypto.StandardScryptP + + if ctx.GlobalBool(LightKDFFlag.Name) { + scryptN = crypto.LightScryptN + scryptP = crypto.LightScryptP } - am := MakeAccountManager(ctx) - etherbase, err := ParamToAddress(ctx.GlobalString(EtherbaseFlag.Name), am) + // Assemble an account manager using the configured datadir + var ( + datadir = MustMakeDataDir(ctx) + keystore = crypto.NewKeyStorePassphrase(filepath.Join(datadir, "keystore"), scryptN, scryptP) + ) + return accounts.NewManager(keystore) +} + +// MakeAddress converts an account specified directly as a hex encoded string or +// a key index in the key store to an internal account representation. +func MakeAddress(accman *accounts.Manager, account string) common.Address { + // If the specified account is a valid address, return it + if common.IsHexAddress(account) { + return common.HexToAddress(account) + } + // Otherwise try to interpret the account as a keystore index + index, err := strconv.Atoi(account) if err != nil { - glog.V(logger.Error).Infoln("WARNING: No etherbase set and no accounts found as default") + Fatalf("Invalid account address or index: '%s'", account) } - // Assemble the entire eth configuration and return - cfg := ð.Config{ - Name: common.MakeName(clientID, version), - DataDir: MustDataDir(ctx), - GenesisFile: ctx.GlobalString(GenesisFileFlag.Name), + hex, err := accman.AddressByIndex(index) + if err != nil { + Fatalf("Failed to retrieve requested account #%d: %v", index, err) + } + return common.HexToAddress(hex) +} + +// MakeEtherbase retrieves the etherbase either from the directly specified +// command line flags or from the keystore if CLI indexed. +func MakeEtherbase(accman *accounts.Manager, ctx *cli.Context) common.Address { + // If the specified etherbase is a valid address, return it + etherbase := ctx.GlobalString(EtherbaseFlag.Name) + if common.IsHexAddress(etherbase) { + return common.HexToAddress(etherbase) + } + // If no etherbase was specified and no accounts are known, bail out + accounts, _ := accman.Accounts() + if etherbase == "" && len(accounts) == 0 { + glog.V(logger.Error).Infoln("WARNING: No etherbase set and no accounts found as default") + return common.Address{} + } + // Otherwise try to interpret the parameter as a keystore index + index, err := strconv.Atoi(etherbase) + if err != nil { + Fatalf("Invalid account address or index: '%s'", etherbase) + } + hex, err := accman.AddressByIndex(index) + if err != nil { + Fatalf("Failed to set requested account #%d as etherbase: %v", index, err) + } + return common.HexToAddress(hex) +} + +// MakeMinerExtra resolves extradata for the miner from the set command line flags +// or returns a default one composed on the client, runtime and OS metadata. +func MakeMinerExtra(extra []byte, ctx *cli.Context) []byte { + if ctx.GlobalIsSet(ExtraDataFlag.Name) { + return []byte(ctx.GlobalString(ExtraDataFlag.Name)) + } + return extra +} + +// MakePasswordList loads up a list of password from a file specified by the +// command line flags. +func MakePasswordList(ctx *cli.Context) []string { + if path := ctx.GlobalString(PasswordFileFlag.Name); path != "" { + blob, err := ioutil.ReadFile(path) + if err != nil { + Fatalf("Failed to read password file: %v", err) + } + return strings.Split(string(blob), "\n") + } + return nil +} + +// MakeSystemNode sets up a local node, configures the services to launch and +// assembles the P2P protocol stack. +func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node.Node { + // Avoid conflicting network flags + networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag} + for _, flag := range netFlags { + if ctx.GlobalBool(flag.Name) { + networks++ + } + } + if networks > 1 { + Fatalf("The %v flags are mutually exclusive", netFlags) + } + // Configure the node's service container + stackConf := &node.Config{ + DataDir: MustMakeDataDir(ctx), + PrivateKey: MakeNodeKey(ctx), + Name: MakeNodeName(name, version, ctx), + NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name), + BootstrapNodes: MakeBootstrapNodes(ctx), + ListenAddr: MakeListenAddress(ctx), + NAT: MakeNAT(ctx), + MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name), + MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name), + } + // Configure the Ethereum service + accman := MakeAccountManager(ctx) + + ethConf := ð.Config{ + Genesis: MakeGenesisBlock(ctx), FastSync: ctx.GlobalBool(FastSyncFlag.Name), BlockChainVersion: ctx.GlobalInt(BlockchainVersionFlag.Name), DatabaseCache: ctx.GlobalInt(CacheFlag.Name), - SkipBcVersionCheck: false, NetworkId: ctx.GlobalInt(NetworkIdFlag.Name), - LogFile: ctx.GlobalString(LogFileFlag.Name), - Verbosity: ctx.GlobalInt(VerbosityFlag.Name), - Etherbase: common.HexToAddress(etherbase), + AccountManager: accman, + Etherbase: MakeEtherbase(accman, ctx), MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name), - AccountManager: am, - VmDebug: ctx.GlobalBool(VMDebugFlag.Name), - MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name), - MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name), - Port: ctx.GlobalString(ListenPortFlag.Name), - Olympic: ctx.GlobalBool(OlympicFlag.Name), - NAT: MakeNAT(ctx), + ExtraData: MakeMinerExtra(extra, ctx), NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name), DocRoot: ctx.GlobalString(DocRootFlag.Name), - Discovery: !ctx.GlobalBool(NoDiscoverFlag.Name), - NodeKey: MakeNodeKey(ctx), - Shh: ctx.GlobalBool(WhisperEnabledFlag.Name), - Dial: true, - BootNodes: ctx.GlobalString(BootnodesFlag.Name), GasPrice: common.String2Big(ctx.GlobalString(GasPriceFlag.Name)), GpoMinGasPrice: common.String2Big(ctx.GlobalString(GpoMinGasPriceFlag.Name)), GpoMaxGasPrice: common.String2Big(ctx.GlobalString(GpoMaxGasPriceFlag.Name)), @@ -462,46 +633,70 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config { SolcPath: ctx.GlobalString(SolcPathFlag.Name), AutoDAG: ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name), } + // Configure the Whisper service + shhEnable := ctx.GlobalBool(WhisperEnabledFlag.Name) - if ctx.GlobalBool(DevModeFlag.Name) && ctx.GlobalBool(TestNetFlag.Name) { - glog.Fatalf("%s and %s are mutually exclusive\n", DevModeFlag.Name, TestNetFlag.Name) - } + // Override any default configs in dev mode or the test net + switch { + case ctx.GlobalBool(OlympicFlag.Name): + if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + ethConf.NetworkId = 1 + } + if !ctx.GlobalIsSet(GenesisFileFlag.Name) { + ethConf.Genesis = core.OlympicGenesisBlock() + } - if ctx.GlobalBool(TestNetFlag.Name) { - // testnet is always stored in the testnet folder - cfg.DataDir += "/testnet" - cfg.NetworkId = 2 - cfg.TestNet = true - } + case ctx.GlobalBool(TestNetFlag.Name): + if !ctx.GlobalIsSet(NetworkIdFlag.Name) { + ethConf.NetworkId = 2 + } + if !ctx.GlobalIsSet(GenesisFileFlag.Name) { + ethConf.Genesis = core.TestNetGenesisBlock() + } + state.StartingNonce = 1048576 // (2**20) - if ctx.GlobalBool(VMEnableJitFlag.Name) { - cfg.Name += "/JIT" - } - if ctx.GlobalBool(DevModeFlag.Name) { - if !ctx.GlobalIsSet(VMDebugFlag.Name) { - cfg.VmDebug = true + case ctx.GlobalBool(DevModeFlag.Name): + // Override the base network stack configs + if !ctx.GlobalIsSet(DataDirFlag.Name) { + stackConf.DataDir = filepath.Join(os.TempDir(), "/ethereum_dev_mode") } if !ctx.GlobalIsSet(MaxPeersFlag.Name) { - cfg.MaxPeers = 0 - } - if !ctx.GlobalIsSet(GasPriceFlag.Name) { - cfg.GasPrice = new(big.Int) + stackConf.MaxPeers = 0 } if !ctx.GlobalIsSet(ListenPortFlag.Name) { - cfg.Port = "0" // auto port + stackConf.ListenAddr = ":0" + } + // Override the Ethereum protocol configs + if !ctx.GlobalIsSet(GenesisFileFlag.Name) { + ethConf.Genesis = core.OlympicGenesisBlock() + } + if !ctx.GlobalIsSet(GasPriceFlag.Name) { + ethConf.GasPrice = new(big.Int) } if !ctx.GlobalIsSet(WhisperEnabledFlag.Name) { - cfg.Shh = true + shhEnable = true } - if !ctx.GlobalIsSet(DataDirFlag.Name) { - cfg.DataDir = os.TempDir() + "/ethereum_dev_mode" + if !ctx.GlobalIsSet(VMDebugFlag.Name) { + vm.Debug = true } - cfg.PowTest = true - cfg.DevMode = true - - glog.V(logger.Info).Infoln("dev mode enabled") + ethConf.PowTest = true } - return cfg + // Assemble and return the protocol stack + stack, err := node.New(stackConf) + if err != nil { + Fatalf("Failed to create the protocol stack: %v", err) + } + if err := stack.Register("eth", func(ctx *node.ServiceContext) (node.Service, error) { + return eth.New(ctx, ethConf) + }); err != nil { + Fatalf("Failed to register the Ethereum service: %v", err) + } + if shhEnable { + if err := stack.Register("shh", func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { + Fatalf("Failed to register the Whisper service: %v", err) + } + } + return stack } // SetupLogger configures glog from the logging-related command line flags. @@ -509,7 +704,12 @@ func SetupLogger(ctx *cli.Context) { glog.SetV(ctx.GlobalInt(VerbosityFlag.Name)) glog.CopyStandardLogTo("INFO") glog.SetToStderr(true) - glog.SetLogDir(ctx.GlobalString(LogFileFlag.Name)) + if ctx.GlobalIsSet(LogFileFlag.Name) { + logger.New("", ctx.GlobalString(LogFileFlag.Name), ctx.GlobalInt(VerbosityFlag.Name)) + } + if ctx.GlobalIsSet(VMDebugFlag.Name) { + vm.Debug = ctx.GlobalBool(VMDebugFlag.Name) + } } // SetupNetwork configures the system for either the main net or some test network. @@ -535,7 +735,7 @@ func SetupVM(ctx *cli.Context) { // MakeChain creates a chain manager from set command line flags. func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database) { - datadir := MustDataDir(ctx) + datadir := MustMakeDataDir(ctx) cache := ctx.GlobalInt(CacheFlag.Name) var err error @@ -543,7 +743,7 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database Fatalf("Could not open database: %v", err) } if ctx.GlobalBool(OlympicFlag.Name) { - _, err := core.WriteTestNetGenesisBlock(chainDb, 42) + _, err := core.WriteTestNetGenesisBlock(chainDb) if err != nil { glog.Fatalln(err) } @@ -560,32 +760,6 @@ func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database return chain, chainDb } -// MakeChain creates an account manager from set command line flags. -func MakeAccountManager(ctx *cli.Context) *accounts.Manager { - dataDir := MustDataDir(ctx) - if ctx.GlobalBool(TestNetFlag.Name) { - dataDir += "/testnet" - } - scryptN := crypto.StandardScryptN - scryptP := crypto.StandardScryptP - if ctx.GlobalBool(LightKDFFlag.Name) { - scryptN = crypto.LightScryptN - scryptP = crypto.LightScryptP - } - ks := crypto.NewKeyStorePassphrase(filepath.Join(dataDir, "keystore"), scryptN, scryptP) - return accounts.NewManager(ks) -} - -// MustDataDir retrieves the currently requested data directory, terminating if -// none (or the empty string) is specified. -func MustDataDir(ctx *cli.Context) string { - if path := ctx.GlobalString(DataDirFlag.Name); path != "" { - return path - } - Fatalf("Cannot determine default data directory, please set manually (--datadir)") - return "" -} - func IpcSocketPath(ctx *cli.Context) (ipcpath string) { if runtime.GOOS == "windows" { ipcpath = common.DefaultIpcPath() @@ -605,39 +779,39 @@ func IpcSocketPath(ctx *cli.Context) (ipcpath string) { return } -func StartIPC(eth *eth.Ethereum, ctx *cli.Context) error { +// StartIPC starts a IPC JSON-RPC API server. +func StartIPC(stack *node.Node, ctx *cli.Context) error { config := comms.IpcConfig{ Endpoint: IpcSocketPath(ctx), } initializer := func(conn net.Conn) (comms.Stopper, shared.EthereumApi, error) { - fe := useragent.NewRemoteFrontend(conn, eth.AccountManager()) - xeth := xeth.New(eth, fe) - apis, err := api.ParseApiString(ctx.GlobalString(IPCApiFlag.Name), codec.JSON, xeth, eth) + fe := useragent.NewRemoteFrontend(conn, stack.Service("eth").(*eth.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) } -func StartRPC(eth *eth.Ethereum, ctx *cli.Context) error { +// StartRPC starts a HTTP JSON-RPC API server. +func StartRPC(stack *node.Node, ctx *cli.Context) error { config := comms.HttpConfig{ ListenAddress: ctx.GlobalString(RPCListenAddrFlag.Name), ListenPort: uint(ctx.GlobalInt(RPCPortFlag.Name)), CorsDomain: ctx.GlobalString(RPCCORSDomainFlag.Name), } - xeth := xeth.New(eth, nil) + xeth := xeth.New(stack, nil) codec := codec.JSON - apis, err := api.ParseApiString(ctx.GlobalString(RpcApiFlag.Name), codec, xeth, eth) + apis, err := api.ParseApiString(ctx.GlobalString(RpcApiFlag.Name), codec, xeth, stack) if err != nil { return err } - return comms.StartHttp(config, codec, api.Merge(apis...)) } @@ -647,20 +821,3 @@ func StartPProf(ctx *cli.Context) { log.Println(http.ListenAndServe(address, nil)) }() } - -func ParamToAddress(addr string, am *accounts.Manager) (addrHex string, err error) { - if !((len(addr) == 40) || (len(addr) == 42)) { // with or without 0x - index, err := strconv.Atoi(addr) - if err != nil { - Fatalf("Invalid account address '%s'", addr) - } - - addrHex, err = am.AddressByIndex(index) - if err != nil { - return "", err - } - } else { - addrHex = addr - } - return -} diff --git a/common/natspec/natspec_e2e_test.go b/common/natspec/natspec_e2e_test.go index 5c0d43091c..95109ec07a 100644 --- a/common/natspec/natspec_e2e_test.go +++ b/common/natspec/natspec_e2e_test.go @@ -34,6 +34,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/node" xe "github.com/ethereum/go-ethereum/xeth" ) @@ -146,13 +148,11 @@ func testEth(t *testing.T) (ethereum *eth.Ethereum, err error) { } // only use minimalistic stack with no networking - return eth.New(ð.Config{ - DataDir: tmp, + return eth.New(&node.ServiceContext{EventMux: new(event.TypeMux)}, ð.Config{ AccountManager: am, Etherbase: common.HexToAddress(testAddress), - MaxPeers: 0, PowTest: true, - NewDB: func(path string) (ethdb.Database, error) { return db, nil }, + TestGenesisState: db, GpoMinGasPrice: common.Big1, GpobaseCorrectionFactor: 1, GpoMaxGasPrice: common.Big1, @@ -166,7 +166,7 @@ func testInit(t *testing.T) (self *testFrontend) { t.Errorf("error creating ethereum: %v", err) return } - err = ethereum.Start() + err = ethereum.Start(nil) if err != nil { t.Errorf("error starting ethereum: %v", err) return @@ -174,7 +174,7 @@ func testInit(t *testing.T) (self *testFrontend) { // mock frontend self = &testFrontend{t: t, ethereum: ethereum} - self.xeth = xe.New(ethereum, self) + self.xeth = xe.New(nil, self) self.wait = self.xeth.UpdateState() addr, _ := self.ethereum.Etherbase() diff --git a/common/types.go b/common/types.go index 624f4b8265..ea58381886 100644 --- a/common/types.go +++ b/common/types.go @@ -24,13 +24,13 @@ import ( ) const ( - hashLength = 32 - addressLength = 20 + HashLength = 32 + AddressLength = 20 ) type ( - Hash [hashLength]byte - Address [addressLength]byte + Hash [HashLength]byte + Address [AddressLength]byte ) func BytesToHash(b []byte) Hash { @@ -53,10 +53,10 @@ func (h Hash) Hex() string { return "0x" + Bytes2Hex(h[:]) } // Sets the hash to the value of b. If b is larger than len(h) it will panic func (h *Hash) SetBytes(b []byte) { if len(b) > len(h) { - b = b[len(b)-hashLength:] + b = b[len(b)-HashLength:] } - copy(h[hashLength-len(b):], b) + copy(h[HashLength-len(b):], b) } // Set string `s` to h. If s is larger than len(h) it will panic @@ -92,6 +92,18 @@ func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } +// IsHexAddress verifies whether a string can represent a valid hex-encoded +// Ethereum address or not. +func IsHexAddress(s string) bool { + if len(s) == 2+2*AddressLength && IsHex(s[2:]) { + return true + } + if len(s) == 2*AddressLength && IsHex(s) { + return true + } + return false +} + // Get the string representation of the underlying address func (a Address) Str() string { return string(a[:]) } func (a Address) Bytes() []byte { return a[:] } @@ -102,9 +114,9 @@ func (a Address) Hex() string { return "0x" + Bytes2Hex(a[:]) } // Sets the address to the value of b. If b is larger than len(a) it will panic func (a *Address) SetBytes(b []byte) { if len(b) > len(a) { - b = b[len(b)-addressLength:] + b = b[len(b)-AddressLength:] } - copy(a[addressLength-len(b):], b) + copy(a[AddressLength-len(b):], b) } // Set string `s` to a. If s is larger than len(a) it will panic diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 70953d76d0..2c4a97b457 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -34,7 +34,7 @@ func proc() (Validator, *BlockChain) { db, _ := ethdb.NewMemDatabase() var mux event.TypeMux - WriteTestNetGenesisBlock(db, 0) + WriteTestNetGenesisBlock(db) blockchain, err := NewBlockChain(db, thePow(), &mux) if err != nil { fmt.Println(err) diff --git a/core/blockchain.go b/core/blockchain.go index 5e1fc9424c..5a6795b3ec 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -149,11 +149,7 @@ func NewBlockChain(chainDb ethdb.Database, pow pow.PoW, mux *event.TypeMux) (*Bl bc.genesisBlock = bc.GetBlockByNumber(0) if bc.genesisBlock == nil { - reader, err := NewDefaultGenesisReader() - if err != nil { - return nil, err - } - bc.genesisBlock, err = WriteGenesisBlock(chainDb, reader) + bc.genesisBlock, err = WriteDefaultGenesisBlock(chainDb) if err != nil { return nil, err } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index f18b5d084a..6e1c5fdc76 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -51,7 +51,7 @@ func thePow() pow.PoW { func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain { var eventMux event.TypeMux - WriteTestNetGenesisBlock(db, 0) + WriteTestNetGenesisBlock(db) blockchain, err := NewBlockChain(db, thePow(), &eventMux) if err != nil { t.Error("failed creating blockchain:", err) @@ -506,7 +506,7 @@ func testReorgShort(t *testing.T, full bool) { func testReorg(t *testing.T, first, second []int, td int64, full bool) { // Create a pristine block chain db, _ := ethdb.NewMemDatabase() - genesis, _ := WriteTestNetGenesisBlock(db, 0) + genesis, _ := WriteTestNetGenesisBlock(db) bc := chm(genesis, db) // Insert an easy and a difficult chain afterwards @@ -553,7 +553,7 @@ func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } func testBadHashes(t *testing.T, full bool) { // Create a pristine block chain db, _ := ethdb.NewMemDatabase() - genesis, _ := WriteTestNetGenesisBlock(db, 0) + genesis, _ := WriteTestNetGenesisBlock(db) bc := chm(genesis, db) // Create a chain, ban a hash and try to import @@ -580,7 +580,7 @@ func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } func testReorgBadHashes(t *testing.T, full bool) { // Create a pristine block chain db, _ := ethdb.NewMemDatabase() - genesis, _ := WriteTestNetGenesisBlock(db, 0) + genesis, _ := WriteTestNetGenesisBlock(db) bc := chm(genesis, db) // Create a chain, import and ban aferwards diff --git a/core/chain_makers.go b/core/chain_makers.go index f1ada487f2..6d3152d977 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -220,7 +220,7 @@ func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) { evmux := &event.TypeMux{} // Initialize a fresh chain with only a genesis block - genesis, _ := WriteTestNetGenesisBlock(db, 0) + genesis, _ := WriteTestNetGenesisBlock(db) blockchain, _ := NewBlockChain(db, FakePow{}, evmux) // Create and inject the requested chain diff --git a/core/default_genesis.go b/core/default_genesis.go index f8acda9fb6..b418bfdfe0 100644 --- a/core/default_genesis.go +++ b/core/default_genesis.go @@ -16,15 +16,6 @@ package core -import ( - "compress/gzip" - "encoding/base64" - "io" - "strings" -) - -func NewDefaultGenesisReader() (io.Reader, error) { - return gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultGenesisBlock))) -} - +// defaultGenesisBlock is a gzip compressed dump of the official default Ethereum +// genesis block. const defaultGenesisBlock = "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" diff --git a/core/genesis.go b/core/genesis.go index 3fd8f42b0b..d8c6e9cea3 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -17,6 +17,8 @@ package core import ( + "compress/gzip" + "encoding/base64" "encoding/json" "fmt" "io" @@ -158,46 +160,80 @@ func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) return block } -func WriteTestNetGenesisBlock(chainDb ethdb.Database, nonce uint64) (*types.Block, error) { - testGenesis := fmt.Sprintf(`{ - "nonce": "0x%x", - "difficulty": "0x20000", - "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", - "coinbase": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x", - "gasLimit": "0x2FEFD8", - "alloc": { - "0000000000000000000000000000000000000001": { "balance": "1" }, - "0000000000000000000000000000000000000002": { "balance": "1" }, - "0000000000000000000000000000000000000003": { "balance": "1" }, - "0000000000000000000000000000000000000004": { "balance": "1" }, - "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376" } - } -}`, types.EncodeNonce(nonce)) - return WriteGenesisBlock(chainDb, strings.NewReader(testGenesis)) +// WriteDefaultGenesisBlock assembles the official Ethereum genesis block and +// writes it - along with all associated state - into a chain database. +func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) { + return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock())) } -func WriteOlympicGenesisBlock(chainDb ethdb.Database, nonce uint64) (*types.Block, error) { - testGenesis := fmt.Sprintf(`{ - "nonce":"0x%x", - "gasLimit":"0x%x", - "difficulty":"0x%x", - "alloc": { - "0000000000000000000000000000000000000001": {"balance": "1"}, - "0000000000000000000000000000000000000002": {"balance": "1"}, - "0000000000000000000000000000000000000003": {"balance": "1"}, - "0000000000000000000000000000000000000004": {"balance": "1"}, - "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"} - } -}`, types.EncodeNonce(nonce), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes()) - return WriteGenesisBlock(chainDb, strings.NewReader(testGenesis)) +// WriteTestNetGenesisBlock assembles the Morden test network genesis block and +// writes it - along with all associated state - into a chain database. +func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) { + return WriteGenesisBlock(chainDb, strings.NewReader(TestNetGenesisBlock())) +} + +// WriteOlympicGenesisBlock assembles the Olympic genesis block and writes it +// along with all associated state into a chain database. +func WriteOlympicGenesisBlock(db ethdb.Database) (*types.Block, error) { + return WriteGenesisBlock(db, strings.NewReader(OlympicGenesisBlock())) +} + +// DefaultGenesisBlock assembles a JSON string representing the default Ethereum +// genesis block. +func DefaultGenesisBlock() string { + reader, err := gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultGenesisBlock))) + if err != nil { + panic(fmt.Sprintf("failed to access default genesis: %v", err)) + } + blob, err := ioutil.ReadAll(reader) + if err != nil { + panic(fmt.Sprintf("failed to load default genesis: %v", err)) + } + return string(blob) +} + +// OlympicGenesisBlock assembles a JSON string representing the Olympic genesis +// block. +func OlympicGenesisBlock() string { + return fmt.Sprintf(`{ + "nonce":"0x%x", + "gasLimit":"0x%x", + "difficulty":"0x%x", + "alloc": { + "0000000000000000000000000000000000000001": {"balance": "1"}, + "0000000000000000000000000000000000000002": {"balance": "1"}, + "0000000000000000000000000000000000000003": {"balance": "1"}, + "0000000000000000000000000000000000000004": {"balance": "1"}, + "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}, + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"} + } + }`, types.EncodeNonce(42), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes()) +} + +// TestNetGenesisBlock assembles a JSON string representing the Morden test net +// genenis block. +func TestNetGenesisBlock() string { + return fmt.Sprintf(`{ + "nonce": "0x%x", + "difficulty": "0x20000", + "mixhash": "0x00000000000000000000000000000000000000647572616c65787365646c6578", + "coinbase": "0x0000000000000000000000000000000000000000", + "timestamp": "0x00", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x", + "gasLimit": "0x2FEFD8", + "alloc": { + "0000000000000000000000000000000000000001": { "balance": "1" }, + "0000000000000000000000000000000000000002": { "balance": "1" }, + "0000000000000000000000000000000000000003": { "balance": "1" }, + "0000000000000000000000000000000000000004": { "balance": "1" }, + "102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c": { "balance": "1606938044258990275541962092341162602522202993782792835301376" } + } + }`, types.EncodeNonce(0x6d6f7264656e)) } diff --git a/eth/backend.go b/eth/backend.go index 5bd6ac55da..5a8cf6a734 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -19,16 +19,12 @@ package eth import ( "bytes" - "crypto/ecdsa" - "encoding/json" "fmt" - "io/ioutil" "math/big" "os" "path/filepath" "regexp" "strings" - "syscall" "time" "github.com/ethereum/ethash" @@ -37,21 +33,16 @@ import ( "github.com/ethereum/go-ethereum/common/compiler" "github.com/ethereum/go-ethereum/common/httpclient" "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/core/vm" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/miner" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/discover" - "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/whisper" ) const ( @@ -63,74 +54,29 @@ const ( ) var ( - jsonlogger = logger.NewJsonLogger() - datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} portInUseErrRE = regexp.MustCompile("address already in use") - - defaultBootNodes = []*discover.Node{ - // ETH/DEV Go Bootnodes - discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE - discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR - discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG - // ETH/DEV cpp-ethereum (poc-9.ethdev.com) - discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"), - } - - defaultTestNetBootNodes = []*discover.Node{ - discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"), - discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"), - } - - staticNodes = "static-nodes.json" // Path within to search for the static node list - trustedNodes = "trusted-nodes.json" // Path within to search for the trusted node list ) type Config struct { - DevMode bool - TestNet bool - - Name string - NetworkId int - GenesisFile string - GenesisBlock *types.Block // used by block tests - FastSync bool - Olympic bool + NetworkId int // Network ID to use for selecting peers to connect to + Genesis string // Genesis JSON to seed the chain database with + FastSync bool // Enables the state download based fast synchronisation algorithm BlockChainVersion int SkipBcVersionCheck bool // e.g. blockchain export DatabaseCache int - DataDir string - LogFile string - Verbosity int - VmDebug bool NatSpec bool DocRoot string AutoDAG bool PowTest bool ExtraData []byte - MaxPeers int - MaxPendingPeers int - Discovery bool - Port string - - // Space-separated list of discovery node URLs - BootNodes string - - // This key is used to identify the node on the network. - // If nil, an ephemeral key is used. - NodeKey *ecdsa.PrivateKey - - NAT nat.Interface - Shh bool - Dial bool - + AccountManager *accounts.Manager Etherbase common.Address GasPrice *big.Int MinerThreads int - AccountManager *accounts.Manager SolcPath string GpoMinGasPrice *big.Int @@ -140,87 +86,8 @@ type Config struct { GpobaseStepUp int GpobaseCorrectionFactor int - // NewDB is used to create databases. - // If nil, the default is to create leveldb databases on disk. - NewDB func(path string) (ethdb.Database, error) -} - -func (cfg *Config) parseBootNodes() []*discover.Node { - if cfg.BootNodes == "" { - if cfg.TestNet { - return defaultTestNetBootNodes - } - - return defaultBootNodes - } - var ns []*discover.Node - for _, url := range strings.Split(cfg.BootNodes, " ") { - if url == "" { - continue - } - n, err := discover.ParseNode(url) - if err != nil { - glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err) - continue - } - ns = append(ns, n) - } - return ns -} - -// parseNodes parses a list of discovery node URLs loaded from a .json file. -func (cfg *Config) parseNodes(file string) []*discover.Node { - // Short circuit if no node config is present - path := filepath.Join(cfg.DataDir, file) - if _, err := os.Stat(path); err != nil { - return nil - } - // Load the nodes from the config file - blob, err := ioutil.ReadFile(path) - if err != nil { - glog.V(logger.Error).Infof("Failed to access nodes: %v", err) - return nil - } - nodelist := []string{} - if err := json.Unmarshal(blob, &nodelist); err != nil { - glog.V(logger.Error).Infof("Failed to load nodes: %v", err) - return nil - } - // Interpret the list as a discovery node array - var nodes []*discover.Node - for _, url := range nodelist { - if url == "" { - continue - } - node, err := discover.ParseNode(url) - if err != nil { - glog.V(logger.Error).Infof("Node URL %s: %v\n", url, err) - continue - } - nodes = append(nodes, node) - } - return nodes -} - -func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) { - // use explicit key from command line args if set - if cfg.NodeKey != nil { - return cfg.NodeKey, nil - } - // use persistent key if present - keyfile := filepath.Join(cfg.DataDir, "nodekey") - key, err := crypto.LoadECDSA(keyfile) - if err == nil { - return key, nil - } - // no persistent key, generate and store a new one - if key, err = crypto.GenerateKey(); err != nil { - return nil, fmt.Errorf("could not generate server key: %v", err) - } - if err := crypto.SaveECDSA(keyfile, key); err != nil { - glog.V(logger.Error).Infoln("could not persist nodekey: ", err) - } - return key, nil + TestGenesisBlock *types.Block // Genesis block to seed the chain database with (testing only!) + TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!) } type Ethereum struct { @@ -235,7 +102,6 @@ type Ethereum struct { txPool *core.TxPool blockchain *core.BlockChain accountManager *accounts.Manager - whisper *whisper.Whisper pow *ethash.Ethash protocolManager *ProtocolManager SolcPath string @@ -250,44 +116,28 @@ type Ethereum struct { httpclient *httpclient.HTTPClient - net *p2p.Server eventMux *event.TypeMux miner *miner.Miner - // logger logger.LogSystem - - Mining bool - MinerThreads int - NatSpec bool - DataDir string - AutoDAG bool - PowTest bool - autodagquit chan bool - etherbase common.Address - clientVersion string - netVersionId int - shhVersionId int + Mining bool + MinerThreads int + NatSpec bool + AutoDAG bool + PowTest bool + autodagquit chan bool + etherbase common.Address + netVersionId int } -func New(config *Config) (*Ethereum, error) { - logger.New(config.DataDir, config.LogFile, config.Verbosity) - +func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Let the database take 3/4 of the max open files (TODO figure out a way to get the actual limit of the open files) const dbCount = 3 ethdb.OpenFileLimit = 128 / (dbCount + 1) - newdb := config.NewDB - if newdb == nil { - newdb = func(path string) (ethdb.Database, error) { return ethdb.NewLDBDatabase(path, config.DatabaseCache) } - } - // Open the chain database and perform any upgrades needed - chainDb, err := newdb(filepath.Join(config.DataDir, "chaindata")) + chainDb, err := ctx.Database("chaindata", config.DatabaseCache) if err != nil { - if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { - err = fmt.Errorf("%v (check if another instance of geth is already running with the same data directory '%s')", err, config.DataDir) - } - return nil, fmt.Errorf("blockchain db err: %v", err) + return nil, err } if db, ok := chainDb.(*ethdb.LDBDatabase); ok { db.Meter("eth/db/chaindata/") @@ -299,56 +149,32 @@ func New(config *Config) (*Ethereum, error) { return nil, err } - dappDb, err := newdb(filepath.Join(config.DataDir, "dapp")) + dappDb, err := ctx.Database("dapp", config.DatabaseCache) if err != nil { - if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { - err = fmt.Errorf("%v (check if another instance of geth is already running with the same data directory '%s')", err, config.DataDir) - } - return nil, fmt.Errorf("dapp db err: %v", err) + return nil, err } if db, ok := dappDb.(*ethdb.LDBDatabase); ok { db.Meter("eth/db/dapp/") } - - nodeDb := filepath.Join(config.DataDir, "nodes") glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId) - if len(config.GenesisFile) > 0 { - fr, err := os.Open(config.GenesisFile) + // Load up any custom genesis block if requested + if len(config.Genesis) > 0 { + block, err := core.WriteGenesisBlock(chainDb, strings.NewReader(config.Genesis)) if err != nil { return nil, err } - - block, err := core.WriteGenesisBlock(chainDb, fr) - if err != nil { - return nil, err - } - glog.V(logger.Info).Infof("Successfully wrote genesis block. New genesis hash = %x\n", block.Hash()) + glog.V(logger.Info).Infof("Successfully wrote custom genesis block: %x", block.Hash()) } - - // different modes - switch { - case config.Olympic: - glog.V(logger.Error).Infoln("Starting Olympic network") - fallthrough - case config.DevMode: - _, err := core.WriteOlympicGenesisBlock(chainDb, 42) - if err != nil { - return nil, err - } - case config.TestNet: - state.StartingNonce = 1048576 // (2**20) - _, err := core.WriteTestNetGenesisBlock(chainDb, 0x6d6f7264656e) - if err != nil { - return nil, err - } + // Load up a test setup if directly injected + if config.TestGenesisState != nil { + chainDb = config.TestGenesisState } - // This is for testing only. - if config.GenesisBlock != nil { - core.WriteTd(chainDb, config.GenesisBlock.Hash(), config.GenesisBlock.Difficulty()) - core.WriteBlock(chainDb, config.GenesisBlock) - core.WriteCanonicalHash(chainDb, config.GenesisBlock.Hash(), config.GenesisBlock.NumberU64()) - core.WriteHeadBlockHash(chainDb, config.GenesisBlock.Hash()) + if config.TestGenesisBlock != nil { + core.WriteTd(chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.Difficulty()) + core.WriteBlock(chainDb, config.TestGenesisBlock) + core.WriteCanonicalHash(chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64()) + core.WriteHeadBlockHash(chainDb, config.TestGenesisBlock.Hash()) } if !config.SkipBcVersionCheck { @@ -367,9 +193,7 @@ func New(config *Config) (*Ethereum, error) { dappDb: dappDb, eventMux: &event.TypeMux{}, accountManager: config.AccountManager, - DataDir: config.DataDir, etherbase: config.Etherbase, - clientVersion: config.Name, // TODO should separate from Name netVersionId: config.NetworkId, NatSpec: config.NatSpec, MinerThreads: config.MinerThreads, @@ -412,48 +236,9 @@ func New(config *Config) (*Ethereum, error) { eth.miner.SetGasPrice(config.GasPrice) eth.miner.SetExtra(config.ExtraData) - if config.Shh { - eth.whisper = whisper.New() - eth.shhVersionId = int(eth.whisper.Version()) - } - - netprv, err := config.nodeKey() - if err != nil { - return nil, err - } - protocols := append([]p2p.Protocol{}, eth.protocolManager.SubProtocols...) - if config.Shh { - protocols = append(protocols, eth.whisper.Protocol()) - } - eth.net = &p2p.Server{ - PrivateKey: netprv, - Name: config.Name, - MaxPeers: config.MaxPeers, - MaxPendingPeers: config.MaxPendingPeers, - Discovery: config.Discovery, - Protocols: protocols, - NAT: config.NAT, - NoDial: !config.Dial, - BootstrapNodes: config.parseBootNodes(), - StaticNodes: config.parseNodes(staticNodes), - TrustedNodes: config.parseNodes(trustedNodes), - NodeDatabase: nodeDb, - } - if len(config.Port) > 0 { - eth.net.ListenAddr = ":" + config.Port - } - - vm.Debug = config.VmDebug - return eth, nil } -// Network retrieves the underlying P2P network server. This should eventually -// be moved out into a protocol independent package, but for now use an accessor. -func (s *Ethereum) Network() *p2p.Server { - return s.net -} - func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { s.blockchain.ResetWithGenesisBlock(gb) } @@ -480,86 +265,48 @@ func (s *Ethereum) StopMining() { s.miner.Stop() } func (s *Ethereum) IsMining() bool { return s.miner.Mining() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } -// func (s *Ethereum) Logger() logger.LogSystem { return s.logger } -func (s *Ethereum) Name() string { return s.net.Name } func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } -func (s *Ethereum) Whisper() *whisper.Whisper { return s.whisper } func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } func (s *Ethereum) DappDb() ethdb.Database { return s.dappDb } func (s *Ethereum) IsListening() bool { return true } // Always listening -func (s *Ethereum) PeerCount() int { return s.net.PeerCount() } -func (s *Ethereum) Peers() []*p2p.Peer { return s.net.Peers() } -func (s *Ethereum) MaxPeers() int { return s.net.MaxPeers } -func (s *Ethereum) ClientVersion() string { return s.clientVersion } func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } func (s *Ethereum) NetVersion() int { return s.netVersionId } -func (s *Ethereum) ShhVersion() int { return s.shhVersionId } func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } -// Start the ethereum -func (s *Ethereum) Start() error { - jsonlogger.LogJson(&logger.LogStarting{ - ClientString: s.net.Name, - ProtocolVersion: s.EthVersion(), - }) - err := s.net.Start() - if err != nil { - if portInUseErrRE.MatchString(err.Error()) { - err = fmt.Errorf("%v (possibly another instance of geth is using the same port)", err) - } - return err - } +// Protocols implements node.Service, returning all the currently configured +// network protocols to start. +func (s *Ethereum) Protocols() []p2p.Protocol { + return s.protocolManager.SubProtocols +} +// Start implements node.Service, starting all internal goroutines needed by the +// Ethereum protocol implementation. +func (s *Ethereum) Start(*p2p.Server) error { if s.AutoDAG { s.StartAutoDAG() } - s.protocolManager.Start() - - if s.whisper != nil { - s.whisper.Start() - } - - glog.V(logger.Info).Infoln("Server started") return nil } -func (s *Ethereum) StartForTest() { - jsonlogger.LogJson(&logger.LogStarting{ - ClientString: s.net.Name, - ProtocolVersion: s.EthVersion(), - }) -} - -// AddPeer connects to the given node and maintains the connection until the -// server is shut down. If the connection fails for any reason, the server will -// attempt to reconnect the peer. -func (self *Ethereum) AddPeer(nodeURL string) error { - n, err := discover.ParseNode(nodeURL) - if err != nil { - return fmt.Errorf("invalid node URL: %v", err) - } - self.net.AddPeer(n) - return nil -} - -func (s *Ethereum) Stop() { - s.net.Stop() +// Stop implements node.Service, terminating all internal goroutines used by the +// Ethereum protocol. +func (s *Ethereum) Stop() error { s.blockchain.Stop() s.protocolManager.Stop() s.txPool.Stop() s.eventMux.Stop() - if s.whisper != nil { - s.whisper.Stop() - } + s.StopAutoDAG() s.chainDb.Close() s.dappDb.Close() close(s.shutdownChan) + + return nil } // This function will wait for a shutdown and resumes main thread execution diff --git a/node/node.go b/node/node.go index ad4e69414c..023f774034 100644 --- a/node/node.go +++ b/node/node.go @@ -21,6 +21,7 @@ import ( "errors" "os" "path/filepath" + "reflect" "sync" "syscall" @@ -40,14 +41,17 @@ var ( // Node represents a P2P node into which arbitrary services might be registered. type Node struct { - datadir string // Path to the currently used data directory - config *p2p.Server // Configuration of the underlying P2P networking layer - stack map[string]ServiceConstructor // Protocol stack registered into this node - emux *event.TypeMux // Event multiplexer used between the services of a stack + datadir string // Path to the currently used data directory + eventmux *event.TypeMux // Event multiplexer used between the services of a stack - running *p2p.Server // Currently running P2P networking layer - services map[string]Service // Currently running services + serverConfig *p2p.Server // Configuration of the underlying P2P networking layer + server *p2p.Server // Currently running P2P networking layer + serviceIndex map[string]ServiceConstructor // Set of services currently registered in the node + serviceOrder []string // Service construction order to handle dependencies + services map[string]Service // Currently running services + + stop chan struct{} // Channel to wait for termination notifications lock sync.RWMutex } @@ -66,7 +70,7 @@ func New(conf *Config) (*Node, error) { } return &Node{ datadir: conf.DataDir, - config: &p2p.Server{ + serverConfig: &p2p.Server{ PrivateKey: conf.NodeKey(), Name: conf.Name, Discovery: !conf.NoDiscovery, @@ -81,8 +85,9 @@ func New(conf *Config) (*Node, error) { MaxPeers: conf.MaxPeers, MaxPendingPeers: conf.MaxPendingPeers, }, - stack: make(map[string]ServiceConstructor), - emux: new(event.TypeMux), + serviceIndex: make(map[string]ServiceConstructor), + serviceOrder: []string{}, + eventmux: new(event.TypeMux), }, nil } @@ -92,14 +97,15 @@ func (n *Node) Register(id string, constructor ServiceConstructor) error { defer n.lock.Unlock() // Short circuit if the node is running or if the id is taken - if n.running != nil { + if n.server != nil { return ErrNodeRunning } - if _, ok := n.stack[id]; ok { + if _, ok := n.serviceIndex[id]; ok { return ErrServiceRegistered } // Otherwise register the service and return - n.stack[id] = constructor + n.serviceOrder = append(n.serviceOrder, id) + n.serviceIndex[id] = constructor return nil } @@ -111,14 +117,20 @@ func (n *Node) Unregister(id string) error { defer n.lock.Unlock() // Short circuit if the node is running, or if the service is unknown - if n.running != nil { + if n.server != nil { return ErrNodeRunning } - if _, ok := n.stack[id]; !ok { + if _, ok := n.serviceIndex[id]; !ok { return ErrServiceUnknown } // Otherwise drop the service and return - delete(n.stack, id) + delete(n.serviceIndex, id) + for i, service := range n.serviceOrder { + if service == id { + n.serviceOrder = append(n.serviceOrder[:i], n.serviceOrder[i+1:]...) + break + } + } return nil } @@ -128,19 +140,27 @@ func (n *Node) Start() error { defer n.lock.Unlock() // Short circuit if the node's already running - if n.running != nil { + if n.server != nil { return ErrNodeRunning } // Otherwise copy and specialize the P2P configuration running := new(p2p.Server) - *running = *n.config + *running = *n.serverConfig - ctx := &ServiceContext{ - dataDir: n.datadir, - EventMux: n.emux, - } services := make(map[string]Service) - for id, constructor := range n.stack { + for _, id := range n.serviceOrder { + constructor := n.serviceIndex[id] + + // Create a new context for the particular service + ctx := &ServiceContext{ + datadir: n.datadir, + services: make(map[string]Service), + EventMux: n.eventmux, + } + for id, s := range services { // copy needed for threaded access + ctx.services[id] = s + } + // Construct and save the service service, err := constructor(ctx) if err != nil { return err @@ -161,10 +181,12 @@ func (n *Node) Start() error { started := []string{} for id, service := range services { // Start the next service, stopping all previous upon failure - if err := service.Start(); err != nil { + if err := service.Start(running); err != nil { for _, id := range started { services[id].Stop() } + running.Stop() + return err } // Mark the service started for potential cleanup @@ -172,7 +194,8 @@ func (n *Node) Start() error { } // Finish initializing the startup n.services = services - n.running = running + n.server = running + n.stop = make(chan struct{}) return nil } @@ -184,7 +207,7 @@ func (n *Node) Stop() error { defer n.lock.Unlock() // Short circuit if the node's not running - if n.running == nil { + if n.server == nil { return ErrNodeStopped } // Otherwise terminate all the services and the P2P server too @@ -196,10 +219,11 @@ func (n *Node) Stop() error { failure.Services[id] = err } } - n.running.Stop() + n.server.Stop() n.services = nil - n.running = nil + n.server = nil + close(n.stop) if len(failure.Services) > 0 { return failure @@ -207,6 +231,19 @@ func (n *Node) Stop() error { return nil } +// Wait blocks the thread until the node is stopped. If the node is not running +// at the time of invocation, the method immediately returns. +func (n *Node) Wait() { + n.lock.RLock() + if n.server == nil { + return + } + stop := n.stop + n.lock.RUnlock() + + <-stop +} + // Restart terminates a running node and boots up a new one in its place. If the // node isn't running, an error is returned. func (n *Node) Restart() error { @@ -226,20 +263,45 @@ func (n *Node) Server() *p2p.Server { n.lock.RLock() defer n.lock.RUnlock() - return n.running + return n.server } -// Service retrieves a currently running services registered under a given id. +// Service retrieves a currently running service registered under a given id. func (n *Node) Service(id string) Service { n.lock.RLock() defer n.lock.RUnlock() - if n.services == nil { + // Short circuit if the node's not running + if n.server == nil { return nil } return n.services[id] } +// SingletonService retrieves a currently running service using a specific type +// implementing the Service interface. This is a utility function for scenarios +// where it is known that only one instance of a given service type is running, +// allowing to access services without needing to know their specific id with +// which they were registered. Note, this method uses reflection, so do not run +// in a tight loop. +func (n *Node) SingletonService(service interface{}) (string, error) { + n.lock.RLock() + defer n.lock.RUnlock() + + // Short circuit if the node's not running + if n.server == nil { + return "", ErrServiceUnknown + } + // Otherwise try to find the service to return + for id, running := range n.services { + if reflect.TypeOf(running) == reflect.ValueOf(service).Elem().Type() { + reflect.ValueOf(service).Elem().Set(reflect.ValueOf(running)) + return id, nil + } + } + return "", ErrServiceUnknown +} + // DataDir retrieves the current datadir used by the protocol stack. func (n *Node) DataDir() string { return n.datadir @@ -248,5 +310,5 @@ func (n *Node) DataDir() string { // EventMux retrieves the event multiplexer used by all the network services in // the current protocol stack. func (n *Node) EventMux() *event.TypeMux { - return n.emux + return n.eventmux } diff --git a/node/node_example_test.go b/node/node_example_test.go index f2bd014b06..898d4f5bc2 100644 --- a/node/node_example_test.go +++ b/node/node_example_test.go @@ -35,8 +35,8 @@ import ( type SampleService struct{} func (s *SampleService) Protocols() []p2p.Protocol { return nil } -func (s *SampleService) Start() error { fmt.Println("Sample service starting..."); return nil } -func (s *SampleService) Stop() error { fmt.Println("Sample service stopping..."); return nil } +func (s *SampleService) Start(*p2p.Server) error { fmt.Println("Service starting..."); return nil } +func (s *SampleService) Stop() error { fmt.Println("Service stopping..."); return nil } func ExampleUsage() { // Create a network node to run protocols with the default values. The below list @@ -80,8 +80,8 @@ func ExampleUsage() { log.Fatalf("Failed to stop the protocol stack: %v", err) } // Output: - // Sample service starting... - // Sample service stopping... - // Sample service starting... - // Sample service stopping... + // Service starting... + // Service stopping... + // Service starting... + // Service stopping... } diff --git a/node/node_test.go b/node/node_test.go index 7201276b59..1d5570e426 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -102,7 +102,7 @@ func TestNodeUsedDataDir(t *testing.T) { type NoopService struct{} func (s *NoopService) Protocols() []p2p.Protocol { return nil } -func (s *NoopService) Start() error { return nil } +func (s *NoopService) Start(*p2p.Server) error { return nil } func (s *NoopService) Stop() error { return nil } func NewNoopService(*ServiceContext) (Service, error) { return new(NoopService), nil } @@ -148,7 +148,7 @@ type InstrumentedService struct { stop error protocolsHook func() - startHook func() + startHook func(*p2p.Server) stopHook func() } @@ -159,9 +159,9 @@ func (s *InstrumentedService) Protocols() []p2p.Protocol { return s.protocols } -func (s *InstrumentedService) Start() error { +func (s *InstrumentedService) Start(server *p2p.Server) error { if s.startHook != nil { - s.startHook() + s.startHook(server) } return s.start } @@ -189,7 +189,7 @@ func TestServiceLifeCycle(t *testing.T) { id := id // Closure for the constructor constructor := func(*ServiceContext) (Service, error) { return &InstrumentedService{ - startHook: func() { started[id] = true }, + startHook: func(*p2p.Server) { started[id] = true }, stopHook: func() { stopped[id] = true }, }, nil } @@ -241,7 +241,7 @@ func TestServiceRestarts(t *testing.T) { running = false return &InstrumentedService{ - startHook: func() { + startHook: func(*p2p.Server) { if running { panic("already running") } @@ -288,7 +288,7 @@ func TestServiceConstructionAbortion(t *testing.T) { id := id // Closure for the constructor constructor := func(*ServiceContext) (Service, error) { return &InstrumentedService{ - startHook: func() { started[id] = true }, + startHook: func(*p2p.Server) { started[id] = true }, }, nil } if err := stack.Register(id, constructor); err != nil { @@ -334,7 +334,7 @@ func TestServiceStartupAbortion(t *testing.T) { id := id // Closure for the constructor constructor := func(*ServiceContext) (Service, error) { return &InstrumentedService{ - startHook: func() { started[id] = true }, + startHook: func(*p2p.Server) { started[id] = true }, stopHook: func() { stopped[id] = true }, }, nil } @@ -384,7 +384,7 @@ func TestServiceTerminationGuarantee(t *testing.T) { id := id // Closure for the constructor constructor := func(*ServiceContext) (Service, error) { return &InstrumentedService{ - startHook: func() { started[id] = true }, + startHook: func(*p2p.Server) { started[id] = true }, stopHook: func() { stopped[id] = true }, }, nil } @@ -438,6 +438,42 @@ func TestServiceTerminationGuarantee(t *testing.T) { } } +// TestSingletonServiceRetrieval tests that singleton services can be retrieved. +func TestSingletonServiceRetrieval(t *testing.T) { + // Create a simple stack and register two service types + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + if err := stack.Register("noop", func(*ServiceContext) (Service, error) { return new(NoopService), nil }); err != nil { + t.Fatalf("noop service registration failed: %v", err) + } + if err := stack.Register("instrumented", func(*ServiceContext) (Service, error) { return new(InstrumentedService), nil }); err != nil { + t.Fatalf("instrumented service registration failed: %v", err) + } + // Make sure none of the services can be retrieved until started + var noopServ *NoopService + if id, err := stack.SingletonService(&noopServ); id != "" || err != ErrServiceUnknown { + t.Fatalf("noop service retrieval mismatch: have %v/%v, want %v/%v", id, err, "", ErrServiceUnknown) + } + var instServ *InstrumentedService + if id, err := stack.SingletonService(&instServ); id != "" || err != ErrServiceUnknown { + t.Fatalf("instrumented service retrieval mismatch: have %v/%v, want %v/%v", id, err, "", ErrServiceUnknown) + } + // Start the stack and ensure everything is retrievable now + if err := stack.Start(); err != nil { + t.Fatalf("failed to start stack: %v", err) + } + defer stack.Stop() + + if id, err := stack.SingletonService(&noopServ); id != "noop" || err != nil { + t.Fatalf("noop service retrieval mismatch: have %v/%v, want %v/%v", id, err, "noop", nil) + } + if id, err := stack.SingletonService(&instServ); id != "instrumented" || err != nil { + t.Fatalf("instrumented service retrieval mismatch: have %v/%v, want %v/%v", id, err, "instrumented", nil) + } +} + // Tests that all protocols defined by individual services get launched. func TestProtocolGather(t *testing.T) { stack, err := New(testNodeConfig) diff --git a/node/service.go b/node/service.go index ec838dbe8e..28fc34764b 100644 --- a/node/service.go +++ b/node/service.go @@ -18,6 +18,7 @@ package node import ( "path/filepath" + "reflect" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -28,18 +29,39 @@ import ( // the protocol stack, that is passed to all constructors to be optionally used; // as well as utility methods to operate on the service environment. type ServiceContext struct { - dataDir string // Data directory for protocol persistence - EventMux *event.TypeMux // Event multiplexer used for decoupled notifications + datadir string // Data directory for protocol persistence + services map[string]Service // Index of the already constructed services + EventMux *event.TypeMux // Event multiplexer used for decoupled notifications } // Database opens an existing database with the given name (or creates one if no // previous can be found) from within the node's data directory. If the node is // an ephemeral one, a memory database is returned. func (ctx *ServiceContext) Database(name string, cache int) (ethdb.Database, error) { - if ctx.dataDir == "" { + if ctx.datadir == "" { return ethdb.NewMemDatabase() } - return ethdb.NewLDBDatabase(filepath.Join(ctx.dataDir, name), cache) + return ethdb.NewLDBDatabase(filepath.Join(ctx.datadir, name), cache) +} + +// Service retrieves an already constructed service registered under a given id. +func (ctx *ServiceContext) Service(id string) Service { + return ctx.services[id] +} + +// SingletonService retrieves an already constructed service using a specific type +// implementing the Service interface. This is a utility function for scenarios +// where it is known that only one instance of a given service type is running, +// allowing to access services without needing to know their specific id with +// which they were registered. +func (ctx *ServiceContext) SingletonService(service interface{}) (string, error) { + for id, running := range ctx.services { + if reflect.TypeOf(running) == reflect.ValueOf(service).Elem().Type() { + reflect.ValueOf(service).Elem().Set(reflect.ValueOf(running)) + return id, nil + } + } + return "", ErrServiceUnknown } // ServiceConstructor is the function signature of the constructors needed to be @@ -58,8 +80,9 @@ type Service interface { // Protocol retrieves the P2P protocols the service wishes to start. Protocols() []p2p.Protocol - // Start spawns any goroutines required by the service. - Start() error + // Start is called after all services have been constructed and the networking + // layer was also initialized to spawn any goroutines required by the service. + Start(server *p2p.Server) error // Stop terminates all goroutines belonging to the service, blocking until they // are all terminated. diff --git a/node/service_test.go b/node/service_test.go index 50a4f9715b..921a1a0126 100644 --- a/node/service_test.go +++ b/node/service_test.go @@ -17,14 +17,16 @@ package node import ( + "fmt" "io/ioutil" "os" "path/filepath" "testing" ) -// Tests that service context methods work properly. -func TestServiceContext(t *testing.T) { +// Tests that databases are correctly created persistent or ephemeral based on +// the configured service context. +func TestContextDatabases(t *testing.T) { // Create a temporary folder and ensure no database is contained within dir, err := ioutil.TempDir("", "") if err != nil { @@ -36,7 +38,7 @@ func TestServiceContext(t *testing.T) { t.Fatalf("non-created database already exists") } // Request the opening/creation of a database and ensure it persists to disk - ctx := &ServiceContext{dataDir: dir} + ctx := &ServiceContext{datadir: dir} db, err := ctx.Database("persistent", 0) if err != nil { t.Fatalf("failed to open persistent database: %v", err) @@ -47,7 +49,7 @@ func TestServiceContext(t *testing.T) { t.Fatalf("persistent database doesn't exists: %v", err) } // Request th opening/creation of an ephemeral database and ensure it's not persisted - ctx = &ServiceContext{dataDir: ""} + ctx = &ServiceContext{datadir: ""} db, err = ctx.Database("ephemeral", 0) if err != nil { t.Fatalf("failed to open ephemeral database: %v", err) @@ -58,3 +60,47 @@ func TestServiceContext(t *testing.T) { t.Fatalf("ephemeral database exists") } } + +// Tests that already constructed services can be retrieves by later ones. +func TestContextServices(t *testing.T) { + stack, err := New(testNodeConfig) + if err != nil { + t.Fatalf("failed to create protocol stack: %v", err) + } + // Define a set of services, constructed before/after a verifier + formers := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"} + latters := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} + + verifier := func(ctx *ServiceContext) (Service, error) { + for i, id := range formers { + if ctx.Service(id) == nil { + return nil, fmt.Errorf("former %d: service not found", i) + } + } + for i, id := range latters { + if ctx.Service(id) != nil { + return nil, fmt.Errorf("latters %d: service found", i) + } + } + return new(NoopService), nil + } + // Register the collection of services + for i, id := range formers { + if err := stack.Register(id, NewNoopService); err != nil { + t.Fatalf("former #%d: failed to register service: %v", i, err) + } + } + if err := stack.Register("verifier", verifier); err != nil { + t.Fatalf("failed to register service verifier: %v", err) + } + for i, id := range latters { + if err := stack.Register(id, NewNoopService); err != nil { + t.Fatalf("latter #%d: failed to register service: %v", i, err) + } + } + // Start the protocol stack and ensure services are constructed in order + if err := stack.Start(); err != nil { + t.Fatalf("failed to start stack: %v", err) + } + defer stack.Stop() +} diff --git a/rpc/api/admin.go b/rpc/api/admin.go index c11662577a..4682062e0a 100644 --- a/rpc/api/admin.go +++ b/rpc/api/admin.go @@ -32,6 +32,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/logger/glog" + "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" @@ -80,19 +82,24 @@ 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, ethereum *eth.Ethereum, codec codec.Codec) *adminApi { - return &adminApi{ - xeth: xeth, - ethereum: ethereum, - codec: codec, - coder: codec.New(nil), +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.SingletonService(&api.ethereum) + } + return api } // collection with supported methods @@ -128,24 +135,24 @@ func (self *adminApi) AddPeer(req *shared.Request) (interface{}, error) { if err := self.coder.Decode(req.Params, &args); err != nil { return nil, shared.NewDecodeParamError(err.Error()) } - - err := self.ethereum.AddPeer(args.Url) - if err == nil { - return true, nil + node, err := discover.ParseNode(args.Url) + if err != nil { + return nil, fmt.Errorf("invalid node URL: %v", err) } - return false, err + self.stack.Server().AddPeer(node) + return true, nil } func (self *adminApi) Peers(req *shared.Request) (interface{}, error) { - return self.ethereum.Network().PeersInfo(), nil + return self.stack.Server().PeersInfo(), nil } func (self *adminApi) NodeInfo(req *shared.Request) (interface{}, error) { - return self.ethereum.Network().NodeInfo(), nil + return self.stack.Server().NodeInfo(), nil } func (self *adminApi) DataDir(req *shared.Request) (interface{}, error) { - return self.ethereum.DataDir, nil + return self.stack.DataDir(), nil } func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { @@ -253,7 +260,7 @@ func (self *adminApi) StartRPC(req *shared.Request) (interface{}, error) { CorsDomain: args.CorsDomain, } - apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.ethereum) + apis, err := ParseApiString(args.Apis, self.codec, self.xeth, self.stack) if err != nil { return false, err } diff --git a/rpc/api/api_test.go b/rpc/api/api_test.go index 131ef68f81..eb63e81510 100644 --- a/rpc/api/api_test.go +++ b/rpc/api/api_test.go @@ -93,7 +93,7 @@ func TestCompileSolidity(t *testing.T) { expSource := source eth := ð.Ethereum{} - xeth := xeth.NewTest(eth, nil) + xeth := xeth.NewTest(nil, nil) api := NewEthApi(xeth, eth, codec.JSON) var rpcRequest shared.Request diff --git a/rpc/api/utils.go b/rpc/api/utils.go index 8351e88d39..6e372c0613 100644 --- a/rpc/api/utils.go +++ b/rpc/api/utils.go @@ -22,6 +22,7 @@ import ( "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" @@ -154,7 +155,7 @@ var ( ) // Parse a comma separated API string to individual api's -func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.Ethereum) ([]shared.EthereumApi, error) { +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") } @@ -162,10 +163,16 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth. names := strings.Split(apistr, ",") apis := make([]shared.EthereumApi, len(names)) + var eth *eth.Ethereum + if stack != nil { + if _, err := stack.SingletonService(ð); err != nil { + return nil, err + } + } for i, name := range names { switch strings.ToLower(strings.TrimSpace(name)) { case shared.AdminApiName: - apis[i] = NewAdminApi(xeth, eth, codec) + apis[i] = NewAdminApi(xeth, stack, codec) case shared.DebugApiName: apis[i] = NewDebugApi(xeth, eth, codec) case shared.DbApiName: @@ -188,7 +195,6 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth. return nil, fmt.Errorf("Unknown API '%s'", name) } } - return apis, nil } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 6a2eb96a42..473bc3419f 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -36,7 +36,9 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rlp" ) @@ -165,15 +167,6 @@ func runBlockTest(test *BlockTest) error { ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore"), crypto.StandardScryptN, crypto.StandardScryptP) am := accounts.NewManager(ks) db, _ := ethdb.NewMemDatabase() - cfg := ð.Config{ - DataDir: common.DefaultDataDir(), - Verbosity: 5, - Etherbase: common.Address{}, - AccountManager: am, - NewDB: func(path string) (ethdb.Database, error) { return db, nil }, - } - - cfg.GenesisBlock = test.Genesis // import pre accounts & construct test genesis block & state root _, err := test.InsertPreState(db, am) @@ -181,16 +174,16 @@ func runBlockTest(test *BlockTest) error { return fmt.Errorf("InsertPreState: %v", err) } - ethereum, err := eth.New(cfg) + cfg := ð.Config{ + TestGenesisState: db, + TestGenesisBlock: test.Genesis, + Etherbase: common.Address{}, + AccountManager: am, + } + ethereum, err := eth.New(&node.ServiceContext{EventMux: new(event.TypeMux)}, cfg) if err != nil { return err } - - err = ethereum.Start() - if err != nil { - return err - } - cm := ethereum.BlockChain() validBlocks, err := test.TryBlocksInsert(cm) if err != nil { diff --git a/whisper/peer_test.go b/whisper/peer_test.go index b3d2031c19..636bd8ca1f 100644 --- a/whisper/peer_test.go +++ b/whisper/peer_test.go @@ -37,7 +37,7 @@ func startTestPeer() *testPeer { // Create a whisper client and connect with it to the tester peer client := New() - client.Start() + client.Start(nil) termed := make(chan struct{}) go func() { diff --git a/whisper/whisper.go b/whisper/whisper.go index a341f23e48..7201062b81 100644 --- a/whisper/whisper.go +++ b/whisper/whisper.go @@ -98,9 +98,9 @@ func New() *Whisper { return whisper } -// Protocol returns the whisper sub-protocol handler for this particular client. -func (self *Whisper) Protocol() p2p.Protocol { - return self.protocol +// Protocols returns the whisper sub-protocols ran by this particular client. +func (self *Whisper) Protocols() []p2p.Protocol { + return []p2p.Protocol{self.protocol} } // Version returns the whisper sub-protocols version number. @@ -156,14 +156,20 @@ func (self *Whisper) Send(envelope *Envelope) error { return self.add(envelope) } -func (self *Whisper) Start() { +// Start implements node.Service, starting the background data propagation thread +// of the Whisper protocol. +func (self *Whisper) Start(*p2p.Server) error { glog.V(logger.Info).Infoln("Whisper started") go self.update() + return nil } -func (self *Whisper) Stop() { +// Stop implements node.Service, stopping the background data propagation thread +// of the Whisper protocol. +func (self *Whisper) Stop() error { close(self.quit) glog.V(logger.Info).Infoln("Whisper stopped") + return nil } // Messages retrieves all the currently pooled messages matching a filter id. diff --git a/whisper/whisper_test.go b/whisper/whisper_test.go index b83ce0fe70..9cc235e7a5 100644 --- a/whisper/whisper_test.go +++ b/whisper/whisper_test.go @@ -33,7 +33,7 @@ func startTestCluster(n int) []*Whisper { whispers := make([]*Whisper, n) for i := 0; i < n; i++ { whispers[i] = New() - whispers[i].Start() + whispers[i].Start(nil) } // Wire all the peers to the root one for i := 1; i < n; i++ { diff --git a/xeth/state.go b/xeth/state.go index 981fe63b7e..e67dc4b5f9 100644 --- a/xeth/state.go +++ b/xeth/state.go @@ -19,6 +19,7 @@ package xeth import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/eth" ) type State struct { @@ -45,8 +46,7 @@ func (self *State) SafeGet(addr string) *Object { func (self *State) safeGet(addr string) *state.StateObject { object := self.state.GetStateObject(common.HexToAddress(addr)) if object == nil { - object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.ChainDb()) + object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.Service("eth").(*eth.Ethereum).ChainDb()) } - return object } diff --git a/xeth/xeth.go b/xeth/xeth.go index 19c42a9a32..6bc94273ee 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -40,7 +40,9 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/miner" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/whisper" ) var ( @@ -77,7 +79,7 @@ type XEth struct { transactMu sync.Mutex // read-only fields - backend *eth.Ethereum + backend *node.Node frontend Frontend agent *miner.RemoteAgent gpo *eth.GasPriceOracle @@ -86,19 +88,26 @@ type XEth struct { filterManager *filters.FilterSystem } -func NewTest(eth *eth.Ethereum, frontend Frontend) *XEth { - return &XEth{backend: eth, frontend: frontend} +func NewTest(stack *node.Node, frontend Frontend) *XEth { + return &XEth{backend: stack, frontend: frontend} } // New creates an XEth that uses the given frontend. // If a nil Frontend is provided, a default frontend which // confirms all transactions will be used. -func New(ethereum *eth.Ethereum, frontend Frontend) *XEth { +func New(stack *node.Node, frontend Frontend) *XEth { + var ( + ethereum *eth.Ethereum + whisper *whisper.Whisper + ) + stack.SingletonService(ðereum) + stack.SingletonService(&whisper) + xeth := &XEth{ - backend: ethereum, + backend: stack, frontend: frontend, quit: make(chan struct{}), - filterManager: filters.NewFilterSystem(ethereum.EventMux()), + filterManager: filters.NewFilterSystem(stack.EventMux()), logQueue: make(map[int]*logQueue), blockQueue: make(map[int]*hashQueue), transactionQueue: make(map[int]*hashQueue), @@ -106,19 +115,35 @@ func New(ethereum *eth.Ethereum, frontend Frontend) *XEth { agent: miner.NewRemoteAgent(), gpo: eth.NewGasPriceOracle(ethereum), } - if ethereum.Whisper() != nil { - xeth.whisper = NewWhisper(ethereum.Whisper()) + if whisper != nil { + xeth.whisper = NewWhisper(whisper) } ethereum.Miner().Register(xeth.agent) if frontend == nil { xeth.frontend = dummyFrontend{} } - state, _ := xeth.backend.BlockChain().State() + state, _ := ethereum.BlockChain().State() xeth.state = NewState(xeth, state) go xeth.start() return xeth } +func (self *XEth) EthereumService() *eth.Ethereum { + var ethereum *eth.Ethereum + if _, err := self.backend.SingletonService(ðereum); err != nil { + return nil + } + return ethereum +} + +func (self *XEth) WhisperService() *whisper.Whisper { + var whisper *whisper.Whisper + if _, err := self.backend.SingletonService(&whisper); err != nil { + return nil + } + return whisper +} + func (self *XEth) start() { timer := time.NewTicker(2 * time.Second) defer timer.Stop() @@ -172,7 +197,7 @@ done: func (self *XEth) Stop() { close(self.quit) self.filterManager.Stop() - self.backend.Miner().Unregister(self.agent) + self.EthereumService().Miner().Unregister(self.agent) } func cAddress(a []string) []common.Address { @@ -207,21 +232,20 @@ func (self *XEth) AtStateNum(num int64) *XEth { var err error switch num { case -2: - st = self.backend.Miner().PendingState().Copy() + st = self.EthereumService().Miner().PendingState().Copy() default: if block := self.getBlockByHeight(num); block != nil { - st, err = state.New(block.Root(), self.backend.ChainDb()) + st, err = state.New(block.Root(), self.EthereumService().ChainDb()) if err != nil { return nil } } else { - st, err = state.New(self.backend.BlockChain().GetBlockByNumber(0).Root(), self.backend.ChainDb()) + st, err = state.New(self.EthereumService().BlockChain().GetBlockByNumber(0).Root(), self.EthereumService().ChainDb()) if err != nil { return nil } } } - return self.WithState(st) } @@ -270,7 +294,7 @@ func (self *XEth) UpdateState() (wait chan *big.Int) { wait <- n n = nil } - statedb, err := state.New(event.Block.Root(), self.backend.ChainDb()) + statedb, err := state.New(event.Block.Root(), self.EthereumService().ChainDb()) if err != nil { glog.V(logger.Error).Infoln("Could not create new state: %v", err) return @@ -294,7 +318,7 @@ func (self *XEth) getBlockByHeight(height int64) *types.Block { switch height { case -2: - return self.backend.Miner().PendingBlock() + return self.EthereumService().Miner().PendingBlock() case -1: return self.CurrentBlock() default: @@ -305,28 +329,29 @@ func (self *XEth) getBlockByHeight(height int64) *types.Block { num = uint64(height) } - return self.backend.BlockChain().GetBlockByNumber(num) + return self.EthereumService().BlockChain().GetBlockByNumber(num) } func (self *XEth) BlockByHash(strHash string) *Block { hash := common.HexToHash(strHash) - block := self.backend.BlockChain().GetBlock(hash) + block := self.EthereumService().BlockChain().GetBlock(hash) return NewBlock(block) } func (self *XEth) EthBlockByHash(strHash string) *types.Block { hash := common.HexToHash(strHash) - block := self.backend.BlockChain().GetBlock(hash) + block := self.EthereumService().BlockChain().GetBlock(hash) return block } func (self *XEth) EthTransactionByHash(hash string) (*types.Transaction, common.Hash, uint64, uint64) { - if tx, hash, number, index := core.GetTransaction(self.backend.ChainDb(), common.HexToHash(hash)); tx != nil { + ethereum := self.EthereumService() + if tx, hash, number, index := core.GetTransaction(ethereum.ChainDb(), common.HexToHash(hash)); tx != nil { return tx, hash, number, index } - return self.backend.TxPool().GetTransaction(common.HexToHash(hash)), common.Hash{}, 0, 0 + return ethereum.TxPool().GetTransaction(common.HexToHash(hash)), common.Hash{}, 0, 0 } func (self *XEth) BlockByNumber(num int64) *Block { @@ -338,23 +363,23 @@ func (self *XEth) EthBlockByNumber(num int64) *types.Block { } func (self *XEth) Td(hash common.Hash) *big.Int { - return self.backend.BlockChain().GetTd(hash) + return self.EthereumService().BlockChain().GetTd(hash) } func (self *XEth) CurrentBlock() *types.Block { - return self.backend.BlockChain().CurrentBlock() + return self.EthereumService().BlockChain().CurrentBlock() } func (self *XEth) GetBlockReceipts(bhash common.Hash) types.Receipts { - return core.GetBlockReceipts(self.backend.ChainDb(), bhash) + return core.GetBlockReceipts(self.EthereumService().ChainDb(), bhash) } func (self *XEth) GetTxReceipt(txhash common.Hash) *types.Receipt { - return core.GetReceipt(self.backend.ChainDb(), txhash) + return core.GetReceipt(self.EthereumService().ChainDb(), txhash) } func (self *XEth) GasLimit() *big.Int { - return self.backend.BlockChain().GasLimit() + return self.EthereumService().BlockChain().GasLimit() } func (self *XEth) Block(v interface{}) *Block { @@ -371,7 +396,7 @@ func (self *XEth) Block(v interface{}) *Block { func (self *XEth) Accounts() []string { // TODO: check err? - accounts, _ := self.backend.AccountManager().Accounts() + accounts, _ := self.EthereumService().AccountManager().Accounts() accountAddresses := make([]string, len(accounts)) for i, ac := range accounts { accountAddresses[i] = ac.Address.Hex() @@ -382,73 +407,73 @@ func (self *XEth) Accounts() []string { // accessor for solidity compiler. // memoized if available, retried on-demand if not func (self *XEth) Solc() (*compiler.Solidity, error) { - return self.backend.Solc() + return self.EthereumService().Solc() } // set in js console via admin interface or wrapper from cli flags func (self *XEth) SetSolc(solcPath string) (*compiler.Solidity, error) { - self.backend.SetSolc(solcPath) + self.EthereumService().SetSolc(solcPath) return self.Solc() } // store DApp value in extra database func (self *XEth) DbPut(key, val []byte) bool { - self.backend.DappDb().Put(append(dappStorePre, key...), val) + self.EthereumService().DappDb().Put(append(dappStorePre, key...), val) return true } // retrieve DApp value from extra database func (self *XEth) DbGet(key []byte) ([]byte, error) { - val, err := self.backend.DappDb().Get(append(dappStorePre, key...)) + val, err := self.EthereumService().DappDb().Get(append(dappStorePre, key...)) return val, err } func (self *XEth) PeerCount() int { - return self.backend.PeerCount() + return self.backend.Server().PeerCount() } func (self *XEth) IsMining() bool { - return self.backend.IsMining() + return self.EthereumService().IsMining() } func (self *XEth) HashRate() int64 { - return self.backend.Miner().HashRate() + return self.EthereumService().Miner().HashRate() } func (self *XEth) EthVersion() string { - return fmt.Sprintf("%d", self.backend.EthVersion()) + return fmt.Sprintf("%d", self.EthereumService().EthVersion()) } func (self *XEth) NetworkVersion() string { - return fmt.Sprintf("%d", self.backend.NetVersion()) + return fmt.Sprintf("%d", self.EthereumService().NetVersion()) } func (self *XEth) WhisperVersion() string { - return fmt.Sprintf("%d", self.backend.ShhVersion()) + return fmt.Sprintf("%d", self.WhisperService().Version()) } func (self *XEth) ClientVersion() string { - return self.backend.ClientVersion() + return self.backend.Server().Name } func (self *XEth) SetMining(shouldmine bool, threads int) bool { - ismining := self.backend.IsMining() + ismining := self.EthereumService().IsMining() if shouldmine && !ismining { - err := self.backend.StartMining(threads, "") + err := self.EthereumService().StartMining(threads, "") return err == nil } if ismining && !shouldmine { - self.backend.StopMining() + self.EthereumService().StopMining() } - return self.backend.IsMining() + return self.EthereumService().IsMining() } func (self *XEth) IsListening() bool { - return self.backend.IsListening() + return true } func (self *XEth) Coinbase() string { - eb, err := self.backend.Etherbase() + eb, err := self.EthereumService().Etherbase() if err != nil { return "0x0" } @@ -514,7 +539,7 @@ func (self *XEth) NewLogFilter(earliest, latest int64, skip, max int, address [] self.logMu.Lock() defer self.logMu.Unlock() - filter := filters.New(self.backend.ChainDb()) + filter := filters.New(self.EthereumService().ChainDb()) id := self.filterManager.Add(filter) self.logQueue[id] = &logQueue{timeout: time.Now()} @@ -538,7 +563,7 @@ func (self *XEth) NewTransactionFilter() int { self.transactionMu.Lock() defer self.transactionMu.Unlock() - filter := filters.New(self.backend.ChainDb()) + filter := filters.New(self.EthereumService().ChainDb()) id := self.filterManager.Add(filter) self.transactionQueue[id] = &hashQueue{timeout: time.Now()} @@ -557,7 +582,7 @@ func (self *XEth) NewBlockFilter() int { self.blockMu.Lock() defer self.blockMu.Unlock() - filter := filters.New(self.backend.ChainDb()) + filter := filters.New(self.EthereumService().ChainDb()) id := self.filterManager.Add(filter) self.blockQueue[id] = &hashQueue{timeout: time.Now()} @@ -624,7 +649,7 @@ func (self *XEth) Logs(id int) vm.Logs { } func (self *XEth) AllLogs(earliest, latest int64, skip, max int, address []string, topics [][]string) vm.Logs { - filter := filters.New(self.backend.ChainDb()) + filter := filters.New(self.EthereumService().ChainDb()) filter.SetBeginBlock(earliest) filter.SetEndBlock(latest) filter.SetAddresses(cAddress(address)) @@ -775,7 +800,7 @@ func (self *XEth) PushTx(encodedTx string) (string, error) { return "", err } - err = self.backend.TxPool().Add(tx) + err = self.EthereumService().TxPool().Add(tx) if err != nil { return "", err } @@ -799,7 +824,7 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st statedb := self.State().State().Copy() var from *state.StateObject if len(fromStr) == 0 { - accounts, err := self.backend.AccountManager().Accounts() + accounts, err := self.EthereumService().AccountManager().Accounts() if err != nil || len(accounts) == 0 { from = statedb.GetOrNewStateObject(common.Address{}) } else { @@ -832,7 +857,7 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st } header := self.CurrentBlock().Header() - vmenv := core.NewEnv(statedb, self.backend.BlockChain(), msg, header) + vmenv := core.NewEnv(statedb, self.EthereumService().BlockChain(), msg, header) gp := new(core.GasPool).AddGas(common.MaxBig) res, gas, err := core.ApplyMessage(vmenv, msg, gp) return common.ToHex(res), gas.String(), err @@ -843,7 +868,7 @@ func (self *XEth) ConfirmTransaction(tx string) bool { } func (self *XEth) doSign(from common.Address, hash common.Hash, didUnlock bool) ([]byte, error) { - sig, err := self.backend.AccountManager().Sign(accounts.Account{Address: from}, hash.Bytes()) + sig, err := self.EthereumService().AccountManager().Sign(accounts.Account{Address: from}, hash.Bytes()) if err == accounts.ErrLocked { if didUnlock { return nil, fmt.Errorf("signer account still locked after successful unlock") @@ -915,7 +940,7 @@ func (self *XEth) SignTransaction(fromStr, toStr, nonceStr, valueStr, gasStr, ga if len(nonceStr) != 0 { nonce = common.Big(nonceStr).Uint64() } else { - state := self.backend.TxPool().State() + state := self.EthereumService().TxPool().State() nonce = state.GetNonce(from) } var tx *types.Transaction @@ -1003,7 +1028,7 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS if len(nonceStr) != 0 { nonce = common.Big(nonceStr).Uint64() } else { - state := self.backend.TxPool().State() + state := self.EthereumService().TxPool().State() nonce = state.GetNonce(from) } var tx *types.Transaction @@ -1017,7 +1042,7 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS if err != nil { return "", err } - if err = self.backend.TxPool().Add(signed); err != nil { + if err = self.EthereumService().TxPool().Add(signed); err != nil { return "", err } From 3e1000fda3424d880bc43ebbb16d8a33447d4182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 26 Nov 2015 18:35:44 +0200 Subject: [PATCH 09/27] cmd, eth, node, rpc, xeth: use single-instance services --- cmd/geth/js.go | 4 +- cmd/geth/js_test.go | 14 +-- cmd/geth/main.go | 2 +- cmd/gethrpctest/main.go | 6 +- cmd/utils/flags.go | 10 +- eth/backend.go | 4 +- node/errors.go | 20 +++- node/node.go | 126 +++++++-------------- node/node_example_test.go | 2 +- node/node_test.go | 230 ++++++++++++++++---------------------- node/service.go | 38 +++---- node/service_test.go | 37 +++--- node/utils_test.go | 117 +++++++++++++++++++ rpc/api/admin.go | 2 +- rpc/api/utils.go | 2 +- xeth/state.go | 3 +- xeth/xeth.go | 8 +- 17 files changed, 330 insertions(+), 295 deletions(-) create mode 100644 node/utils_test.go diff --git a/cmd/geth/js.go b/cmd/geth/js.go index a0e8bdb21c..f1845d94f5 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -345,7 +345,7 @@ func (self *jsre) AskPassword() (string, bool) { func (self *jsre) ConfirmTransaction(tx string) bool { // Retrieve the Ethereum instance from the node var ethereum *eth.Ethereum - if _, err := self.stack.SingletonService(ðereum); err != nil { + if err := self.stack.Service(ðereum); err != nil { return false } // If natspec is enabled, ask for permission @@ -367,7 +367,7 @@ func (self *jsre) UnlockAccount(addr []byte) bool { } // TODO: allow retry var ethereum *eth.Ethereum - if _, err := self.stack.SingletonService(ðereum); err != nil { + if err := self.stack.Service(ðereum); err != nil { return false } if err := ethereum.AccountManager().Unlock(common.BytesToAddress(addr), pass); err != nil { diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index ed4d04b483..a0f3f2fb76 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -68,7 +68,7 @@ type testjethre struct { func (self *testjethre) UnlockAccount(acc []byte) bool { var ethereum *eth.Ethereum - self.stack.SingletonService(ðereum) + self.stack.Service(ðereum) err := ethereum.AccountManager().Unlock(common.BytesToAddress(acc), "") if err != nil { @@ -79,7 +79,7 @@ func (self *testjethre) UnlockAccount(acc []byte) bool { func (self *testjethre) ConfirmTransaction(tx string) bool { var ethereum *eth.Ethereum - self.stack.SingletonService(ðereum) + self.stack.Service(ðereum) if ethereum.NatSpec { self.lastConfirm = natspec.GetNotice(self.xeth, tx, self.client) @@ -118,7 +118,7 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod if config != nil { config(ethConf) } - if err := stack.Register("ethereum", 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) } // Initialize all the keys for testing @@ -138,7 +138,7 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod t.Fatalf("failed to start test stack: %v", err) } var ethereum *eth.Ethereum - stack.SingletonService(ðereum) + stack.Service(ðereum) assetPath := filepath.Join(os.Getenv("GOPATH"), "src", "github.com", "ethereum", "go-ethereum", "cmd", "mist", "assets", "ext") client := comms.NewInProcClient(codec.JSON) @@ -202,7 +202,7 @@ func TestBlockChain(t *testing.T) { tmpfileq := strconv.Quote(tmpfile) var ethereum *eth.Ethereum - node.SingletonService(ðereum) + node.Service(ðereum) ethereum.BlockChain().Reset() checkEvalJSON(t, repl, `admin.exportChain(`+tmpfileq+`)`, `true`) @@ -436,7 +436,7 @@ multiply7 = Multiply7.at(contractaddress); func pendingTransactions(repl *testjethre, t *testing.T) (txc int64, err error) { var ethereum *eth.Ethereum - repl.stack.SingletonService(ðereum) + repl.stack.Service(ðereum) txs := ethereum.TxPool().GetTransactions() return int64(len(txs)), nil @@ -464,7 +464,7 @@ func processTxs(repl *testjethre, t *testing.T, expTxc int) bool { return false } var ethereum *eth.Ethereum - repl.stack.SingletonService(ðereum) + repl.stack.Service(ðereum) err = ethereum.StartMining(runtime.NumCPU(), "") if err != nil { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 6fac4f4582..3a54718456 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -489,7 +489,7 @@ func startNode(ctx *cli.Context, stack *node.Node) { // Unlock any account specifically requested var ethereum *eth.Ethereum - if _, err := stack.SingletonService(ðereum); err != nil { + if err := stack.Service(ðereum); err != nil { utils.Fatalf("ethereum service not running: %v", err) } accman := ethereum.AccountManager() diff --git a/cmd/gethrpctest/main.go b/cmd/gethrpctest/main.go index cb4c7aece2..7130980ac3 100644 --- a/cmd/gethrpctest/main.go +++ b/cmd/gethrpctest/main.go @@ -126,11 +126,11 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node TestGenesisBlock: test.Genesis, AccountManager: accman, } - if err := stack.Register("ethereum", 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 { return nil, err } // Initialize and register the Whisper protocol - if err := stack.Register("whisper", func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { + if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { return nil, err } return stack, nil @@ -140,7 +140,7 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node // stack to ensure basic checks pass before running RPC tests. func RunTest(stack *node.Node, test *tests.BlockTest) error { var ethereum *eth.Ethereum - stack.SingletonService(ðereum) + stack.Service(ðereum) blockchain := ethereum.BlockChain() // Process the blocks and verify the imported headers diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 30570d930b..53126f9e5d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -686,13 +686,13 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. if err != nil { Fatalf("Failed to create the protocol stack: %v", err) } - if err := stack.Register("eth", func(ctx *node.ServiceContext) (node.Service, error) { + if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { Fatalf("Failed to register the Ethereum service: %v", err) } if shhEnable { - if err := stack.Register("shh", func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { + if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { Fatalf("Failed to register the Whisper service: %v", err) } } @@ -786,7 +786,11 @@ func StartIPC(stack *node.Node, ctx *cli.Context) error { } initializer := func(conn net.Conn) (comms.Stopper, shared.EthereumApi, error) { - fe := useragent.NewRemoteFrontend(conn, stack.Service("eth").(*eth.Ethereum).AccountManager()) + var ethereum *eth.Ethereum + if err := stack.Service(ðereum); err != nil { + return nil, nil, err + } + 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 { diff --git a/eth/backend.go b/eth/backend.go index 5a8cf6a734..0369f6afd2 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -135,7 +135,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { ethdb.OpenFileLimit = 128 / (dbCount + 1) // Open the chain database and perform any upgrades needed - chainDb, err := ctx.Database("chaindata", config.DatabaseCache) + chainDb, err := ctx.OpenDatabase("chaindata", config.DatabaseCache) if err != nil { return nil, err } @@ -149,7 +149,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return nil, err } - dappDb, err := ctx.Database("dapp", config.DatabaseCache) + dappDb, err := ctx.OpenDatabase("dapp", config.DatabaseCache) if err != nil { return nil, err } diff --git a/node/errors.go b/node/errors.go index f8eece06d1..bd5ddeb5de 100644 --- a/node/errors.go +++ b/node/errors.go @@ -16,13 +16,27 @@ package node -import "fmt" +import ( + "fmt" + "reflect" +) -// StopError is returned if a node fails to stop either any of its registered +// DuplicateServiceError is returned during Node startup if a registered service +// constructor returns a service of the same type that was already started. +type DuplicateServiceError struct { + Kind reflect.Type +} + +// Error generates a textual representation of the duplicate service error. +func (e *DuplicateServiceError) Error() string { + return fmt.Sprintf("duplicate service: %v", e.Kind) +} + +// StopError is returned if a Node fails to stop either any of its registered // services or itself. type StopError struct { Server error - Services map[string]error + Services map[reflect.Type]error } // Error generates a textual representation of the stop error. diff --git a/node/node.go b/node/node.go index 023f774034..5566bc44bf 100644 --- a/node/node.go +++ b/node/node.go @@ -30,16 +30,16 @@ import ( ) var ( - ErrDatadirUsed = errors.New("datadir already used") - ErrNodeStopped = errors.New("node not started") - ErrNodeRunning = errors.New("node already running") - ErrServiceUnknown = errors.New("service not registered") - ErrServiceRegistered = errors.New("service already registered") + ErrDatadirUsed = errors.New("datadir already used") + ErrNodeStopped = errors.New("node not started") + ErrNodeRunning = errors.New("node already running") + ErrServiceUnknown = errors.New("unknown service") datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true} ) -// Node represents a P2P node into which arbitrary services might be registered. +// Node represents a P2P node into which arbitrary (uniquely typed) services might +// be registered. type Node struct { datadir string // Path to the currently used data directory eventmux *event.TypeMux // Event multiplexer used between the services of a stack @@ -47,9 +47,8 @@ type Node struct { serverConfig *p2p.Server // Configuration of the underlying P2P networking layer server *p2p.Server // Currently running P2P networking layer - serviceIndex map[string]ServiceConstructor // Set of services currently registered in the node - serviceOrder []string // Service construction order to handle dependencies - services map[string]Service // Currently running services + serviceFuncs []ServiceConstructor // Service constructors (in dependency order) + services map[reflect.Type]Service // Currently running services stop chan struct{} // Channel to wait for termination notifications lock sync.RWMutex @@ -85,52 +84,21 @@ func New(conf *Config) (*Node, error) { MaxPeers: conf.MaxPeers, MaxPendingPeers: conf.MaxPendingPeers, }, - serviceIndex: make(map[string]ServiceConstructor), - serviceOrder: []string{}, + serviceFuncs: []ServiceConstructor{}, eventmux: new(event.TypeMux), }, nil } -// Register injects a new service into the node's stack. -func (n *Node) Register(id string, constructor ServiceConstructor) error { +// Register injects a new service into the node's stack. The service created by +// the passed constructor must be unique in its type with regard to sibling ones. +func (n *Node) Register(constructor ServiceConstructor) error { n.lock.Lock() defer n.lock.Unlock() - // Short circuit if the node is running or if the id is taken if n.server != nil { return ErrNodeRunning } - if _, ok := n.serviceIndex[id]; ok { - return ErrServiceRegistered - } - // Otherwise register the service and return - n.serviceOrder = append(n.serviceOrder, id) - n.serviceIndex[id] = constructor - - return nil -} - -// Unregister removes a service from a node's stack. If the node is currently -// running, an error will be returned. -func (n *Node) Unregister(id string) error { - n.lock.Lock() - defer n.lock.Unlock() - - // Short circuit if the node is running, or if the service is unknown - if n.server != nil { - return ErrNodeRunning - } - if _, ok := n.serviceIndex[id]; !ok { - return ErrServiceUnknown - } - // Otherwise drop the service and return - delete(n.serviceIndex, id) - for i, service := range n.serviceOrder { - if service == id { - n.serviceOrder = append(n.serviceOrder[:i], n.serviceOrder[i+1:]...) - break - } - } + n.serviceFuncs = append(n.serviceFuncs, constructor) return nil } @@ -147,25 +115,27 @@ func (n *Node) Start() error { running := new(p2p.Server) *running = *n.serverConfig - services := make(map[string]Service) - for _, id := range n.serviceOrder { - constructor := n.serviceIndex[id] - + services := make(map[reflect.Type]Service) + for _, constructor := range n.serviceFuncs { // Create a new context for the particular service ctx := &ServiceContext{ datadir: n.datadir, - services: make(map[string]Service), + services: make(map[reflect.Type]Service), EventMux: n.eventmux, } - for id, s := range services { // copy needed for threaded access - ctx.services[id] = s + for kind, s := range services { // copy needed for threaded access + ctx.services[kind] = s } // Construct and save the service service, err := constructor(ctx) if err != nil { return err } - services[id] = service + kind := reflect.TypeOf(service) + if _, exists := services[kind]; exists { + return &DuplicateServiceError{Kind: kind} + } + services[kind] = service } // Gather the protocols and start the freshly assembled P2P server for _, service := range services { @@ -178,19 +148,19 @@ func (n *Node) Start() error { return err } // Start each of the services - started := []string{} - for id, service := range services { + started := []reflect.Type{} + for kind, service := range services { // Start the next service, stopping all previous upon failure if err := service.Start(running); err != nil { - for _, id := range started { - services[id].Stop() + for _, kind := range started { + services[kind].Stop() } running.Stop() return err } // Mark the service started for potential cleanup - started = append(started, id) + started = append(started, kind) } // Finish initializing the startup n.services = services @@ -212,11 +182,11 @@ func (n *Node) Stop() error { } // Otherwise terminate all the services and the P2P server too failure := &StopError{ - Services: make(map[string]error), + Services: make(map[reflect.Type]error), } - for id, service := range n.services { + for kind, service := range n.services { if err := service.Stop(); err != nil { - failure.Services[id] = err + failure.Services[kind] = err } } n.server.Stop() @@ -266,40 +236,22 @@ func (n *Node) Server() *p2p.Server { return n.server } -// Service retrieves a currently running service registered under a given id. -func (n *Node) Service(id string) Service { +// Service retrieves a currently running service registered of a specific type. +func (n *Node) Service(service interface{}) error { n.lock.RLock() defer n.lock.RUnlock() // Short circuit if the node's not running if n.server == nil { - return nil - } - return n.services[id] -} - -// SingletonService retrieves a currently running service using a specific type -// implementing the Service interface. This is a utility function for scenarios -// where it is known that only one instance of a given service type is running, -// allowing to access services without needing to know their specific id with -// which they were registered. Note, this method uses reflection, so do not run -// in a tight loop. -func (n *Node) SingletonService(service interface{}) (string, error) { - n.lock.RLock() - defer n.lock.RUnlock() - - // Short circuit if the node's not running - if n.server == nil { - return "", ErrServiceUnknown + return ErrNodeStopped } // Otherwise try to find the service to return - for id, running := range n.services { - if reflect.TypeOf(running) == reflect.ValueOf(service).Elem().Type() { - reflect.ValueOf(service).Elem().Set(reflect.ValueOf(running)) - return id, nil - } + element := reflect.ValueOf(service).Elem() + if running, ok := n.services[element.Type()]; ok { + element.Set(reflect.ValueOf(running)) + return nil } - return "", ErrServiceUnknown + return ErrServiceUnknown } // DataDir retrieves the current datadir used by the protocol stack. diff --git a/node/node_example_test.go b/node/node_example_test.go index 898d4f5bc2..2f9b49a56d 100644 --- a/node/node_example_test.go +++ b/node/node_example_test.go @@ -66,7 +66,7 @@ func ExampleUsage() { constructor := func(context *node.ServiceContext) (node.Service, error) { return new(SampleService), nil } - if err := stack.Register("my sample service", constructor); err != nil { + if err := stack.Register(constructor); err != nil { log.Fatalf("Failed to register service: %v", err) } // Boot up the entire protocol stack, do a restart and terminate diff --git a/node/node_test.go b/node/node_test.go index 1d5570e426..ef096fc917 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -20,6 +20,7 @@ import ( "errors" "io/ioutil" "os" + "reflect" "testing" "github.com/ethereum/go-ethereum/crypto" @@ -98,79 +99,36 @@ func TestNodeUsedDataDir(t *testing.T) { } } -// NoopService is a trivial implementation of the Service interface. -type NoopService struct{} - -func (s *NoopService) Protocols() []p2p.Protocol { return nil } -func (s *NoopService) Start(*p2p.Server) error { return nil } -func (s *NoopService) Stop() error { return nil } - -func NewNoopService(*ServiceContext) (Service, error) { return new(NoopService), nil } - -// Tests whether services can be registered and unregistered. +// Tests whether services can be registered and duplicates caught. func TestServiceRegistry(t *testing.T) { stack, err := New(testNodeConfig) if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } - // Create a batch of dummy services and ensure they don't exist - ids := []string{"A", "B", "C"} - for i, id := range ids { - if err := stack.Unregister(id); err != ErrServiceUnknown { - t.Fatalf("service %d: pre-unregistration failure mismatch: have %v, want %v", i, err, ErrServiceUnknown) + // Register a batch of unique services and ensure they start successfully + services := []ServiceConstructor{NewNoopServiceA, NewNoopServiceB, NewNoopServiceC} + for i, constructor := range services { + if err := stack.Register(constructor); err != nil { + t.Fatalf("service #%d: registration failed: %v", i, err) } } - // Register the services, checking that the operation succeeds only once - for i, id := range ids { - if err := stack.Register(id, NewNoopService); err != nil { - t.Fatalf("service %d: registration failed: %v", i, err) - } - if err := stack.Register(id, NewNoopService); err != ErrServiceRegistered { - t.Fatalf("service %d: registration failure mismatch: have %v, want %v", i, err, ErrServiceRegistered) + if err := stack.Start(); err != nil { + t.Fatalf("failed to start original service stack: %v", err) + } + if err := stack.Stop(); err != nil { + t.Fatalf("failed to stop original service stack: %v", err) + } + // Duplicate one of the services and retry starting the node + if err := stack.Register(NewNoopServiceB); err != nil { + t.Fatalf("duplicate registration failed: %v", err) + } + if err := stack.Start(); err == nil { + t.Fatalf("duplicate service started") + } else { + if _, ok := err.(*DuplicateServiceError); !ok { + t.Fatalf("duplicate error mismatch: have %v, want %v", err, DuplicateServiceError{}) } } - // Unregister the services, checking that the operation succeeds only once - for i, id := range ids { - if err := stack.Unregister(id); err != nil { - t.Fatalf("service %d: unregistration failed: %v", i, err) - } - if err := stack.Unregister(id); err != ErrServiceUnknown { - t.Fatalf("service %d: unregistration failure mismatch: have %v, want %v", i, err, ErrServiceUnknown) - } - } -} - -// InstrumentedService is an implementation of Service for which all interface -// methods can be instrumented both return value as well as event hook wise. -type InstrumentedService struct { - protocols []p2p.Protocol - start error - stop error - - protocolsHook func() - startHook func(*p2p.Server) - stopHook func() -} - -func (s *InstrumentedService) Protocols() []p2p.Protocol { - if s.protocolsHook != nil { - s.protocolsHook() - } - return s.protocols -} - -func (s *InstrumentedService) Start(server *p2p.Server) error { - if s.startHook != nil { - s.startHook(server) - } - return s.start -} - -func (s *InstrumentedService) Stop() error { - if s.stopHook != nil { - s.stopHook() - } - return s.stop } // Tests that registered services get started and stopped correctly. @@ -180,12 +138,15 @@ func TestServiceLifeCycle(t *testing.T) { t.Fatalf("failed to create protocol stack: %v", err) } // Register a batch of life-cycle instrumented services - ids := []string{"A", "B", "C"} - + services := map[string]InstrumentingWrapper{ + "A": InstrumentedServiceMakerA, + "B": InstrumentedServiceMakerB, + "C": InstrumentedServiceMakerC, + } started := make(map[string]bool) stopped := make(map[string]bool) - for i, id := range ids { + for id, maker := range services { id := id // Closure for the constructor constructor := func(*ServiceContext) (Service, error) { return &InstrumentedService{ @@ -193,35 +154,29 @@ func TestServiceLifeCycle(t *testing.T) { stopHook: func() { stopped[id] = true }, }, nil } - if err := stack.Register(id, constructor); err != nil { - t.Fatalf("service %d: registration failed: %v", i, err) + if err := stack.Register(maker(constructor)); err != nil { + t.Fatalf("service %s: registration failed: %v", id, err) } } // Start the node and check that all services are running if err := stack.Start(); err != nil { t.Fatalf("failed to start protocol stack: %v", err) } - for i, id := range ids { + for id, _ := range services { if !started[id] { - t.Fatalf("service %d: freshly started service not running", i) + t.Fatalf("service %s: freshly started service not running", id) } if stopped[id] { - t.Fatalf("service %d: freshly started service already stopped", i) - } - if stack.Service(id) == nil { - t.Fatalf("service %d: freshly started service unaccessible", i) + t.Fatalf("service %s: freshly started service already stopped", id) } } // Stop the node and check that all services have been stopped if err := stack.Stop(); err != nil { t.Fatalf("failed to stop protocol stack: %v", err) } - for i, id := range ids { + for id, _ := range services { if !stopped[id] { - t.Fatalf("service %d: freshly terminated service still running", i) - } - if service := stack.Service(id); service != nil { - t.Fatalf("service %d: freshly terminated service still accessible: %v", i, service) + t.Fatalf("service %s: freshly terminated service still running", id) } } } @@ -251,7 +206,7 @@ func TestServiceRestarts(t *testing.T) { }, nil } // Register the service and start the protocol stack - if err := stack.Register("service", constructor); err != nil { + if err := stack.Register(constructor); err != nil { t.Fatalf("failed to register the service: %v", err) } if err := stack.Start(); err != nil { @@ -281,18 +236,21 @@ func TestServiceConstructionAbortion(t *testing.T) { t.Fatalf("failed to create protocol stack: %v", err) } // Define a batch of good services - ids := []string{"A", "B", "C", "D", "E", "F"} - + services := map[string]InstrumentingWrapper{ + "A": InstrumentedServiceMakerA, + "B": InstrumentedServiceMakerB, + "C": InstrumentedServiceMakerC, + } started := make(map[string]bool) - for i, id := range ids { + for id, maker := range services { id := id // Closure for the constructor constructor := func(*ServiceContext) (Service, error) { return &InstrumentedService{ startHook: func(*p2p.Server) { started[id] = true }, }, nil } - if err := stack.Register(id, constructor); err != nil { - t.Fatalf("service %d: registration failed: %v", i, err) + if err := stack.Register(maker(constructor)); err != nil { + t.Fatalf("service %s: registration failed: %v", id, err) } } // Register a service that fails to construct itself @@ -300,7 +258,7 @@ func TestServiceConstructionAbortion(t *testing.T) { failer := func(*ServiceContext) (Service, error) { return nil, failure } - if err := stack.Register("failer", failer); err != nil { + if err := stack.Register(failer); err != nil { t.Fatalf("failer registration failed: %v", err) } // Start the protocol stack and ensure none of the services get started @@ -308,9 +266,9 @@ func TestServiceConstructionAbortion(t *testing.T) { if err := stack.Start(); err != failure { t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) } - for i, id := range ids { + for id, _ := range services { if started[id] { - t.Fatalf("service %d: started should not have", i) + t.Fatalf("service %s: started should not have", id) } delete(started, id) } @@ -325,12 +283,15 @@ func TestServiceStartupAbortion(t *testing.T) { t.Fatalf("failed to create protocol stack: %v", err) } // Register a batch of good services - ids := []string{"A", "B", "C", "D", "E", "F"} - + services := map[string]InstrumentingWrapper{ + "A": InstrumentedServiceMakerA, + "B": InstrumentedServiceMakerB, + "C": InstrumentedServiceMakerC, + } started := make(map[string]bool) stopped := make(map[string]bool) - for i, id := range ids { + for id, maker := range services { id := id // Closure for the constructor constructor := func(*ServiceContext) (Service, error) { return &InstrumentedService{ @@ -338,8 +299,8 @@ func TestServiceStartupAbortion(t *testing.T) { stopHook: func() { stopped[id] = true }, }, nil } - if err := stack.Register(id, constructor); err != nil { - t.Fatalf("service %d: registration failed: %v", i, err) + if err := stack.Register(maker(constructor)); err != nil { + t.Fatalf("service %s: registration failed: %v", id, err) } } // Register a service that fails to start @@ -349,7 +310,7 @@ func TestServiceStartupAbortion(t *testing.T) { start: failure, }, nil } - if err := stack.Register("failer", failer); err != nil { + if err := stack.Register(failer); err != nil { t.Fatalf("failer registration failed: %v", err) } // Start the protocol stack and ensure all started services stop @@ -357,9 +318,9 @@ func TestServiceStartupAbortion(t *testing.T) { if err := stack.Start(); err != failure { t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) } - for i, id := range ids { + for id, _ := range services { if started[id] && !stopped[id] { - t.Fatalf("service %d: started but not stopped", i) + t.Fatalf("service %s: started but not stopped", id) } delete(started, id) delete(stopped, id) @@ -375,12 +336,15 @@ func TestServiceTerminationGuarantee(t *testing.T) { t.Fatalf("failed to create protocol stack: %v", err) } // Register a batch of good services - ids := []string{"A", "B", "C", "D", "E", "F"} - + services := map[string]InstrumentingWrapper{ + "A": InstrumentedServiceMakerA, + "B": InstrumentedServiceMakerB, + "C": InstrumentedServiceMakerC, + } started := make(map[string]bool) stopped := make(map[string]bool) - for i, id := range ids { + for id, maker := range services { id := id // Closure for the constructor constructor := func(*ServiceContext) (Service, error) { return &InstrumentedService{ @@ -388,8 +352,8 @@ func TestServiceTerminationGuarantee(t *testing.T) { stopHook: func() { stopped[id] = true }, }, nil } - if err := stack.Register(id, constructor); err != nil { - t.Fatalf("service %d: registration failed: %v", i, err) + if err := stack.Register(maker(constructor)); err != nil { + t.Fatalf("service %s: registration failed: %v", id, err) } } // Register a service that fails to shot down cleanly @@ -399,7 +363,7 @@ func TestServiceTerminationGuarantee(t *testing.T) { stop: failure, }, nil } - if err := stack.Register("failer", failer); err != nil { + if err := stack.Register(failer); err != nil { t.Fatalf("failer registration failed: %v", err) } // Start the protocol stack, and ensure that a failing shut down terminates all @@ -408,12 +372,12 @@ func TestServiceTerminationGuarantee(t *testing.T) { if err := stack.Start(); err != nil { t.Fatalf("iter %d: failed to start protocol stack: %v", i, err) } - for j, id := range ids { + for id, _ := range services { if !started[id] { - t.Fatalf("iter %d, service %d: service not running", i, j) + t.Fatalf("iter %d, service %s: service not running", i, id) } if stopped[id] { - t.Fatalf("iter %d, service %d: service already stopped", i, j) + t.Fatalf("iter %d, service %s: service already stopped", i, id) } } // Stop the stack, verify failure and check all terminations @@ -421,16 +385,17 @@ func TestServiceTerminationGuarantee(t *testing.T) { if err, ok := err.(*StopError); !ok { t.Fatalf("iter %d: termination failure mismatch: have %v, want StopError", i, err) } else { - if err.Services["failer"] != failure { - t.Fatalf("iter %d: failer termination failure mismatch: have %v, want %v", i, err.Services["failer"], failure) + failer := reflect.TypeOf(&InstrumentedService{}) + if err.Services[failer] != failure { + t.Fatalf("iter %d: failer termination failure mismatch: have %v, want %v", i, err.Services[failer], failure) } if len(err.Services) != 1 { t.Fatalf("iter %d: failure count mismatch: have %d, want %d", i, len(err.Services), 1) } } - for j, id := range ids { + for id, _ := range services { if !stopped[id] { - t.Fatalf("iter %d, service %d: service not terminated", i, j) + t.Fatalf("iter %d, service %s: service not terminated", i, id) } delete(started, id) delete(stopped, id) @@ -438,27 +403,27 @@ func TestServiceTerminationGuarantee(t *testing.T) { } } -// TestSingletonServiceRetrieval tests that singleton services can be retrieved. -func TestSingletonServiceRetrieval(t *testing.T) { +// TestServiceRetrieval tests that individual services can be retrieved. +func TestServiceRetrieval(t *testing.T) { // Create a simple stack and register two service types stack, err := New(testNodeConfig) if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } - if err := stack.Register("noop", func(*ServiceContext) (Service, error) { return new(NoopService), nil }); err != nil { + if err := stack.Register(NewNoopService); err != nil { t.Fatalf("noop service registration failed: %v", err) } - if err := stack.Register("instrumented", func(*ServiceContext) (Service, error) { return new(InstrumentedService), nil }); err != nil { + if err := stack.Register(NewInstrumentedService); err != nil { t.Fatalf("instrumented service registration failed: %v", err) } // Make sure none of the services can be retrieved until started var noopServ *NoopService - if id, err := stack.SingletonService(&noopServ); id != "" || err != ErrServiceUnknown { - t.Fatalf("noop service retrieval mismatch: have %v/%v, want %v/%v", id, err, "", ErrServiceUnknown) + if err := stack.Service(&noopServ); err != ErrNodeStopped { + t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, ErrNodeStopped) } var instServ *InstrumentedService - if id, err := stack.SingletonService(&instServ); id != "" || err != ErrServiceUnknown { - t.Fatalf("instrumented service retrieval mismatch: have %v/%v, want %v/%v", id, err, "", ErrServiceUnknown) + if err := stack.Service(&instServ); err != ErrNodeStopped { + t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, ErrNodeStopped) } // Start the stack and ensure everything is retrievable now if err := stack.Start(); err != nil { @@ -466,11 +431,11 @@ func TestSingletonServiceRetrieval(t *testing.T) { } defer stack.Stop() - if id, err := stack.SingletonService(&noopServ); id != "noop" || err != nil { - t.Fatalf("noop service retrieval mismatch: have %v/%v, want %v/%v", id, err, "noop", nil) + if err := stack.Service(&noopServ); err != nil { + t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, nil) } - if id, err := stack.SingletonService(&instServ); id != "instrumented" || err != nil { - t.Fatalf("instrumented service retrieval mismatch: have %v/%v, want %v/%v", id, err, "instrumented", nil) + if err := stack.Service(&instServ); err != nil { + t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, nil) } } @@ -481,13 +446,16 @@ func TestProtocolGather(t *testing.T) { t.Fatalf("failed to create protocol stack: %v", err) } // Register a batch of services with some configured number of protocols - services := map[string]int{ - "Zero Protocols": 0, - "Single Protocol": 1, - "Many Protocols": 25, + services := map[string]struct { + Count int + Maker InstrumentingWrapper + }{ + "Zero Protocols": {0, InstrumentedServiceMakerA}, + "Single Protocol": {1, InstrumentedServiceMakerB}, + "Many Protocols": {25, InstrumentedServiceMakerC}, } - for id, count := range services { - protocols := make([]p2p.Protocol, count) + for id, config := range services { + protocols := make([]p2p.Protocol, config.Count) for i := 0; i < len(protocols); i++ { protocols[i].Name = id protocols[i].Version = uint(i) @@ -497,7 +465,7 @@ func TestProtocolGather(t *testing.T) { protocols: protocols, }, nil } - if err := stack.Register(id, constructor); err != nil { + if err := stack.Register(config.Maker(constructor)); err != nil { t.Fatalf("service %s: registration failed: %v", id, err) } } @@ -511,8 +479,8 @@ func TestProtocolGather(t *testing.T) { if len(protocols) != 26 { t.Fatalf("mismatching number of protocols launched: have %d, want %d", len(protocols), 26) } - for id, count := range services { - for ver := 0; ver < count; ver++ { + for id, config := range services { + for ver := 0; ver < config.Count; ver++ { launched := false for i := 0; i < len(protocols); i++ { if protocols[i].Name == id && protocols[i].Version == uint(ver) { diff --git a/node/service.go b/node/service.go index 28fc34764b..bfeeb7ab98 100644 --- a/node/service.go +++ b/node/service.go @@ -29,39 +29,29 @@ import ( // the protocol stack, that is passed to all constructors to be optionally used; // as well as utility methods to operate on the service environment. type ServiceContext struct { - datadir string // Data directory for protocol persistence - services map[string]Service // Index of the already constructed services - EventMux *event.TypeMux // Event multiplexer used for decoupled notifications + datadir string // Data directory for protocol persistence + services map[reflect.Type]Service // Index of the already constructed services + EventMux *event.TypeMux // Event multiplexer used for decoupled notifications } -// Database opens an existing database with the given name (or creates one if no -// previous can be found) from within the node's data directory. If the node is -// an ephemeral one, a memory database is returned. -func (ctx *ServiceContext) Database(name string, cache int) (ethdb.Database, error) { +// OpenDatabase opens an existing database with the given name (or creates one +// if no previous can be found) from within the node's data directory. If the +// node is an ephemeral one, a memory database is returned. +func (ctx *ServiceContext) OpenDatabase(name string, cache int) (ethdb.Database, error) { if ctx.datadir == "" { return ethdb.NewMemDatabase() } return ethdb.NewLDBDatabase(filepath.Join(ctx.datadir, name), cache) } -// Service retrieves an already constructed service registered under a given id. -func (ctx *ServiceContext) Service(id string) Service { - return ctx.services[id] -} - -// SingletonService retrieves an already constructed service using a specific type -// implementing the Service interface. This is a utility function for scenarios -// where it is known that only one instance of a given service type is running, -// allowing to access services without needing to know their specific id with -// which they were registered. -func (ctx *ServiceContext) SingletonService(service interface{}) (string, error) { - for id, running := range ctx.services { - if reflect.TypeOf(running) == reflect.ValueOf(service).Elem().Type() { - reflect.ValueOf(service).Elem().Set(reflect.ValueOf(running)) - return id, nil - } +// Service retrieves a currently running service registered of a specific type. +func (ctx *ServiceContext) Service(service interface{}) error { + element := reflect.ValueOf(service).Elem() + if running, ok := ctx.services[element.Type()]; ok { + element.Set(reflect.ValueOf(running)) + return nil } - return "", ErrServiceUnknown + return ErrServiceUnknown } // ServiceConstructor is the function signature of the constructors needed to be diff --git a/node/service_test.go b/node/service_test.go index 921a1a0126..1dfb61f73a 100644 --- a/node/service_test.go +++ b/node/service_test.go @@ -39,7 +39,7 @@ func TestContextDatabases(t *testing.T) { } // Request the opening/creation of a database and ensure it persists to disk ctx := &ServiceContext{datadir: dir} - db, err := ctx.Database("persistent", 0) + db, err := ctx.OpenDatabase("persistent", 0) if err != nil { t.Fatalf("failed to open persistent database: %v", err) } @@ -50,7 +50,7 @@ func TestContextDatabases(t *testing.T) { } // Request th opening/creation of an ephemeral database and ensure it's not persisted ctx = &ServiceContext{datadir: ""} - db, err = ctx.Database("ephemeral", 0) + db, err = ctx.OpenDatabase("ephemeral", 0) if err != nil { t.Fatalf("failed to open ephemeral database: %v", err) } @@ -67,36 +67,27 @@ func TestContextServices(t *testing.T) { if err != nil { t.Fatalf("failed to create protocol stack: %v", err) } - // Define a set of services, constructed before/after a verifier - formers := []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"} - latters := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} - + // Define a verifier that ensures a NoopA is before it and NoopB after verifier := func(ctx *ServiceContext) (Service, error) { - for i, id := range formers { - if ctx.Service(id) == nil { - return nil, fmt.Errorf("former %d: service not found", i) - } + var objA *NoopServiceA + if ctx.Service(&objA) != nil { + return nil, fmt.Errorf("former service not found") } - for i, id := range latters { - if ctx.Service(id) != nil { - return nil, fmt.Errorf("latters %d: service found", i) - } + var objB *NoopServiceB + if err := ctx.Service(&objB); err != ErrServiceUnknown { + return nil, fmt.Errorf("latters lookup error mismatch: have %v, want %v", err, ErrServiceUnknown) } return new(NoopService), nil } // Register the collection of services - for i, id := range formers { - if err := stack.Register(id, NewNoopService); err != nil { - t.Fatalf("former #%d: failed to register service: %v", i, err) - } + if err := stack.Register(NewNoopServiceA); err != nil { + t.Fatalf("former failed to register service: %v", err) } - if err := stack.Register("verifier", verifier); err != nil { + if err := stack.Register(verifier); err != nil { t.Fatalf("failed to register service verifier: %v", err) } - for i, id := range latters { - if err := stack.Register(id, NewNoopService); err != nil { - t.Fatalf("latter #%d: failed to register service: %v", i, err) - } + if err := stack.Register(NewNoopServiceB); err != nil { + t.Fatalf("latter failed to register service: %v", err) } // Start the protocol stack and ensure services are constructed in order if err := stack.Start(); err != nil { diff --git a/node/utils_test.go b/node/utils_test.go new file mode 100644 index 0000000000..756622c863 --- /dev/null +++ b/node/utils_test.go @@ -0,0 +1,117 @@ +// 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 . + +// Contains a batch of utility type declarations used by the tests. As the node +// operates on unique types, a lot of them are needed to check various features. + +package node + +import ( + "reflect" + + "github.com/ethereum/go-ethereum/p2p" +) + +// NoopService is a trivial implementation of the Service interface. +type NoopService struct{} + +func (s *NoopService) Protocols() []p2p.Protocol { return nil } +func (s *NoopService) Start(*p2p.Server) error { return nil } +func (s *NoopService) Stop() error { return nil } + +func NewNoopService(*ServiceContext) (Service, error) { return new(NoopService), nil } + +// Set of services all wrapping the base NoopService resulting in the same method +// signatures but different outer types. +type NoopServiceA struct{ NoopService } +type NoopServiceB struct{ NoopService } +type NoopServiceC struct{ NoopService } +type NoopServiceD struct{ NoopService } + +func NewNoopServiceA(*ServiceContext) (Service, error) { return new(NoopServiceA), nil } +func NewNoopServiceB(*ServiceContext) (Service, error) { return new(NoopServiceB), nil } +func NewNoopServiceC(*ServiceContext) (Service, error) { return new(NoopServiceC), nil } +func NewNoopServiceD(*ServiceContext) (Service, error) { return new(NoopServiceD), nil } + +// InstrumentedService is an implementation of Service for which all interface +// methods can be instrumented both return value as well as event hook wise. +type InstrumentedService struct { + protocols []p2p.Protocol + start error + stop error + + protocolsHook func() + startHook func(*p2p.Server) + stopHook func() +} + +func NewInstrumentedService(*ServiceContext) (Service, error) { return new(InstrumentedService), nil } + +func (s *InstrumentedService) Protocols() []p2p.Protocol { + if s.protocolsHook != nil { + s.protocolsHook() + } + return s.protocols +} + +func (s *InstrumentedService) Start(server *p2p.Server) error { + if s.startHook != nil { + s.startHook(server) + } + return s.start +} + +func (s *InstrumentedService) Stop() error { + if s.stopHook != nil { + s.stopHook() + } + return s.stop +} + +// InstrumentingWrapper is a method to specialize a service constructor returning +// a generic InstrumentedService into one returning a wrapping specific one. +type InstrumentingWrapper func(base ServiceConstructor) ServiceConstructor + +func InstrumentingWrapperMaker(base ServiceConstructor, kind reflect.Type) ServiceConstructor { + return func(ctx *ServiceContext) (Service, error) { + obj, err := base(ctx) + if err != nil { + return nil, err + } + wrapper := reflect.New(kind) + wrapper.Elem().Field(0).Set(reflect.ValueOf(obj).Elem()) + + return wrapper.Interface().(Service), nil + } +} + +// Set of services all wrapping the base InstrumentedService resulting in the +// same method signatures but different outer types. +type InstrumentedServiceA struct{ InstrumentedService } +type InstrumentedServiceB struct{ InstrumentedService } +type InstrumentedServiceC struct{ InstrumentedService } + +func InstrumentedServiceMakerA(base ServiceConstructor) ServiceConstructor { + return InstrumentingWrapperMaker(base, reflect.TypeOf(InstrumentedServiceA{})) +} + +func InstrumentedServiceMakerB(base ServiceConstructor) ServiceConstructor { + return InstrumentingWrapperMaker(base, reflect.TypeOf(InstrumentedServiceB{})) +} + +func InstrumentedServiceMakerC(base ServiceConstructor) ServiceConstructor { + return InstrumentingWrapperMaker(base, reflect.TypeOf(InstrumentedServiceC{})) +} diff --git a/rpc/api/admin.go b/rpc/api/admin.go index 4682062e0a..1133c9bca3 100644 --- a/rpc/api/admin.go +++ b/rpc/api/admin.go @@ -97,7 +97,7 @@ func NewAdminApi(xeth *xeth.XEth, stack *node.Node, codec codec.Codec) *adminApi coder: codec.New(nil), } if stack != nil { - stack.SingletonService(&api.ethereum) + stack.Service(&api.ethereum) } return api } diff --git a/rpc/api/utils.go b/rpc/api/utils.go index 6e372c0613..d6820cd2ef 100644 --- a/rpc/api/utils.go +++ b/rpc/api/utils.go @@ -165,7 +165,7 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, stack *no var eth *eth.Ethereum if stack != nil { - if _, err := stack.SingletonService(ð); err != nil { + if err := stack.Service(ð); err != nil { return nil, err } } diff --git a/xeth/state.go b/xeth/state.go index e67dc4b5f9..7daccb5255 100644 --- a/xeth/state.go +++ b/xeth/state.go @@ -19,7 +19,6 @@ package xeth import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/eth" ) type State struct { @@ -46,7 +45,7 @@ func (self *State) SafeGet(addr string) *Object { func (self *State) safeGet(addr string) *state.StateObject { object := self.state.GetStateObject(common.HexToAddress(addr)) if object == nil { - object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.Service("eth").(*eth.Ethereum).ChainDb()) + object = state.NewStateObject(common.HexToAddress(addr), self.xeth.EthereumService().ChainDb()) } return object } diff --git a/xeth/xeth.go b/xeth/xeth.go index 6bc94273ee..5e773d1c96 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -100,8 +100,8 @@ func New(stack *node.Node, frontend Frontend) *XEth { ethereum *eth.Ethereum whisper *whisper.Whisper ) - stack.SingletonService(ðereum) - stack.SingletonService(&whisper) + stack.Service(ðereum) + stack.Service(&whisper) xeth := &XEth{ backend: stack, @@ -130,7 +130,7 @@ func New(stack *node.Node, frontend Frontend) *XEth { func (self *XEth) EthereumService() *eth.Ethereum { var ethereum *eth.Ethereum - if _, err := self.backend.SingletonService(ðereum); err != nil { + if err := self.backend.Service(ðereum); err != nil { return nil } return ethereum @@ -138,7 +138,7 @@ func (self *XEth) EthereumService() *eth.Ethereum { func (self *XEth) WhisperService() *whisper.Whisper { var whisper *whisper.Whisper - if _, err := self.backend.SingletonService(&whisper); err != nil { + if err := self.backend.Service(&whisper); err != nil { return nil } return whisper From 18ea468cf8c2a82d3c1310c81a6389cd7c019fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 27 Nov 2015 19:32:46 +0200 Subject: [PATCH 10/27] common: fix #2008, wrong hex prefix check --- common/types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/types.go b/common/types.go index ea58381886..acbd5b28da 100644 --- a/common/types.go +++ b/common/types.go @@ -95,10 +95,10 @@ func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } // IsHexAddress verifies whether a string can represent a valid hex-encoded // Ethereum address or not. func IsHexAddress(s string) bool { - if len(s) == 2+2*AddressLength && IsHex(s[2:]) { + if len(s) == 2+2*AddressLength && IsHex(s) { return true } - if len(s) == 2*AddressLength && IsHex(s) { + if len(s) == 2*AddressLength && IsHex("0x"+s) { return true } return false From 9af4065243cecad8aaa297ee396ebbc17b280733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Sun, 29 Nov 2015 17:52:52 +0200 Subject: [PATCH 11/27] Makefile: enable iOS experimental builds (fix prev omission) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5fc5e9a9de..1f9bf0db85 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ geth: @echo "Done building." @echo "Run \"$(GOBIN)/geth\" to launch geth." -geth-cross: geth-linux geth-darwin geth-windows geth-android +geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios @echo "Full cross compilation done:" @ls -l $(GOBIN)/geth-* From 1ead43c88cfacc0d30e186cc3782d31b4e9f5764 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Mon, 30 Nov 2015 09:49:10 +0100 Subject: [PATCH 12/27] console: fix instance name printed incorrect on start --- cmd/geth/js.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 196f3af593..843c9a5b57 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -245,7 +245,7 @@ func (self *jsre) batch(statement string) { func (self *jsre) welcome() { self.re.Run(` (function () { - console.log('instance: ' + web3.version.client); + console.log('instance: ' + web3.version.node); console.log(' datadir: ' + admin.datadir); console.log("coinbase: " + eth.coinbase); var ts = 1000 * eth.getBlock(eth.blockNumber).timestamp; From 52904ae32f0a591e7dccad7827ff1c2a73c27026 Mon Sep 17 00:00:00 2001 From: zsfelfoldi Date: Wed, 25 Nov 2015 18:28:21 +0100 Subject: [PATCH 13/27] trie: added error handling Created alternate versions of Trie and SecureTrie functions that can return a MissingNodeError (used by ODR services) --- trie/arc.go | 12 +++ trie/errors.go | 41 +++++++++ trie/iterator.go | 19 +++- trie/proof.go | 11 ++- trie/secure_trie.go | 49 +++++++++-- trie/trie.go | 210 +++++++++++++++++++++++++++++++------------- trie/trie_test.go | 75 +++++++++++++++- 7 files changed, 346 insertions(+), 71 deletions(-) create mode 100644 trie/errors.go diff --git a/trie/arc.go b/trie/arc.go index 9da012e168..fc7a3259f0 100644 --- a/trie/arc.go +++ b/trie/arc.go @@ -62,6 +62,18 @@ func newARC(c int) *arc { } } +// Clear clears the cache +func (a *arc) Clear() { + a.mutex.Lock() + defer a.mutex.Unlock() + a.p = 0 + a.t1 = list.New() + a.b1 = list.New() + a.t2 = list.New() + a.b2 = list.New() + a.cache = make(map[string]*entry, a.c) +} + // Put inserts a new key-value pair into the cache. // This optimizes future access to this entry (side effect). func (a *arc) Put(key hashNode, value node) bool { diff --git a/trie/errors.go b/trie/errors.go new file mode 100644 index 0000000000..a0f58f28fc --- /dev/null +++ b/trie/errors.go @@ -0,0 +1,41 @@ +// Copyright 2014 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 . + +package trie + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" +) + +// MissingNodeError is returned by the trie functions (TryGet, TryUpdate, TryDelete) +// in the case where a trie node is not present in the local database. Contains +// information necessary for retrieving the missing node through an ODR service. +// +// NodeHash is the hash of the missing node +// RootHash is the original root of the trie that contains the node +// KeyPrefix is the prefix that leads from the root to the missing node (hex encoded) +// KeySuffix (optional) contains the rest of the key we were looking for, gives a +// hint on which further nodes should also be retrieved (hex encoded) +type MissingNodeError struct { + RootHash, NodeHash common.Hash + KeyPrefix, KeySuffix []byte +} + +func (err *MissingNodeError) Error() string { + return fmt.Sprintf("Missing trie node %064x", err.NodeHash) +} diff --git a/trie/iterator.go b/trie/iterator.go index 38555fe08d..5f205e0817 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -16,7 +16,12 @@ package trie -import "bytes" +import ( + "bytes" + + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) type Iterator struct { trie *Trie @@ -100,7 +105,11 @@ func (self *Iterator) next(node interface{}, key []byte, isIterStart bool) []byt } case hashNode: - return self.next(self.trie.resolveHash(node), key, isIterStart) + rn, err := self.trie.resolveHash(node, nil, nil) + if err != nil && glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) + } + return self.next(rn, key, isIterStart) } return nil } @@ -127,7 +136,11 @@ func (self *Iterator) key(node interface{}) []byte { } } case hashNode: - return self.key(self.trie.resolveHash(node)) + rn, err := self.trie.resolveHash(node, nil, nil) + if err != nil && glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) + } + return self.key(rn) } return nil diff --git a/trie/proof.go b/trie/proof.go index a705c49db0..2e88bb50bc 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -7,6 +7,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/rlp" ) @@ -39,7 +41,14 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue { case nil: return nil case hashNode: - tn = t.resolveHash(n) + var err error + tn, err = t.resolveHash(n, nil, nil) + if err != nil { + if glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) + } + return nil + } default: panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 47d1934d05..caeef3c3a3 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -21,6 +21,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" ) var secureKeyPrefix = []byte("secure-key-") @@ -46,8 +48,8 @@ type SecureTrie struct { // NewSecure creates a trie with an existing root node from db. // // If root is the zero hash or the sha3 hash of an empty string, the -// trie is initially empty. Otherwise, New will panics if db is nil -// and returns ErrMissingRoot if the root node cannpt be found. +// trie is initially empty. Otherwise, New will panic if db is nil +// and returns MissingNodeError if the root node cannot be found. // Accessing the trie loads nodes from db on demand. func NewSecure(root common.Hash, db Database) (*SecureTrie, error) { if db == nil { @@ -63,7 +65,18 @@ func NewSecure(root common.Hash, db Database) (*SecureTrie, error) { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. func (t *SecureTrie) Get(key []byte) []byte { - return t.Trie.Get(t.hashKey(key)) + res, err := t.TryGet(key) + if err != nil && glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) + } + return res +} + +// TryGet returns the value for key stored in the trie. +// The value bytes must not be modified by the caller. +// If a node was not found in the database, a MissingNodeError is returned. +func (t *SecureTrie) TryGet(key []byte) ([]byte, error) { + return t.Trie.TryGet(t.hashKey(key)) } // Update associates key with value in the trie. Subsequent calls to @@ -73,14 +86,40 @@ func (t *SecureTrie) Get(key []byte) []byte { // The value bytes must not be modified by the caller while they are // stored in the trie. func (t *SecureTrie) Update(key, value []byte) { + if err := t.TryUpdate(key, value); err != nil && glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) + } +} + +// TryUpdate associates key with value in the trie. Subsequent calls to +// Get will return value. If value has length zero, any existing value +// is deleted from the trie and calls to Get will return nil. +// +// The value bytes must not be modified by the caller while they are +// stored in the trie. +// +// If a node was not found in the database, a MissingNodeError is returned. +func (t *SecureTrie) TryUpdate(key, value []byte) error { hk := t.hashKey(key) - t.Trie.Update(hk, value) + err := t.Trie.TryUpdate(hk, value) + if err != nil { + return err + } t.Trie.db.Put(t.secKey(hk), key) + return nil } // Delete removes any existing value for key from the trie. func (t *SecureTrie) Delete(key []byte) { - t.Trie.Delete(t.hashKey(key)) + if err := t.TryDelete(key); err != nil && glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) + } +} + +// TryDelete removes any existing value for key from the trie. +// If a node was not found in the database, a MissingNodeError is returned. +func (t *SecureTrie) TryDelete(key []byte) error { + return t.Trie.TryDelete(t.hashKey(key)) } // GetKey returns the sha3 preimage of a hashed key that was diff --git a/trie/trie.go b/trie/trie.go index a3a383fb58..717296e27d 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -19,7 +19,6 @@ package trie import ( "bytes" - "errors" "fmt" "hash" @@ -44,7 +43,10 @@ var ( emptyState = crypto.Sha3Hash(nil) ) -var ErrMissingRoot = errors.New("missing root node") +// ClearGlobalCache clears the global trie cache +func ClearGlobalCache() { + globalCache.Clear() +} // Database must be implemented by backing stores for the trie. type Database interface { @@ -67,8 +69,9 @@ type DatabaseWriter interface { // // Trie is not safe for concurrent use. type Trie struct { - root node - db Database + root node + db Database + originalRoot common.Hash *hasher } @@ -76,16 +79,19 @@ type Trie struct { // // If root is the zero hash or the sha3 hash of an empty string, the // trie is initially empty and does not require a database. Otherwise, -// New will panics if db is nil or root does not exist in the -// database. Accessing the trie loads nodes from db on demand. +// New will panic if db is nil and returns a MissingNodeError if root does +// not exist in the database. Accessing the trie loads nodes from db on demand. func New(root common.Hash, db Database) (*Trie, error) { - trie := &Trie{db: db} + trie := &Trie{db: db, originalRoot: root} if (root != common.Hash{}) && root != emptyRoot { if db == nil { panic("trie.New: cannot use existing root without a database") } if v, _ := trie.db.Get(root[:]); len(v) == 0 { - return nil, ErrMissingRoot + return nil, &MissingNodeError{ + RootHash: root, + NodeHash: root, + } } trie.root = hashNode(root.Bytes()) } @@ -100,28 +106,44 @@ func (t *Trie) Iterator() *Iterator { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. func (t *Trie) Get(key []byte) []byte { + res, err := t.TryGet(key) + if err != nil && glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) + } + return res +} + +// TryGet returns the value for key stored in the trie. +// The value bytes must not be modified by the caller. +// If a node was not found in the database, a MissingNodeError is returned. +func (t *Trie) TryGet(key []byte) ([]byte, error) { key = compactHexDecode(key) + pos := 0 tn := t.root - for len(key) > 0 { + for pos < len(key) { switch n := tn.(type) { case shortNode: - if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { - return nil + if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) { + return nil, nil } tn = n.Val - key = key[len(n.Key):] + pos += len(n.Key) case fullNode: - tn = n[key[0]] - key = key[1:] + tn = n[key[pos]] + pos++ case nil: - return nil + return nil, nil case hashNode: - tn = t.resolveHash(n) + var err error + tn, err = t.resolveHash(n, key[:pos], key[pos:]) + if err != nil { + return nil, err + } default: panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) } } - return tn.(valueNode) + return tn.(valueNode), nil } // Update associates key with value in the trie. Subsequent calls to @@ -131,17 +153,40 @@ func (t *Trie) Get(key []byte) []byte { // The value bytes must not be modified by the caller while they are // stored in the trie. func (t *Trie) Update(key, value []byte) { - k := compactHexDecode(key) - if len(value) != 0 { - t.root = t.insert(t.root, k, valueNode(value)) - } else { - t.root = t.delete(t.root, k) + if err := t.TryUpdate(key, value); err != nil && glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) } } -func (t *Trie) insert(n node, key []byte, value node) node { +// TryUpdate associates key with value in the trie. Subsequent calls to +// Get will return value. If value has length zero, any existing value +// is deleted from the trie and calls to Get will return nil. +// +// The value bytes must not be modified by the caller while they are +// stored in the trie. +// +// If a node was not found in the database, a MissingNodeError is returned. +func (t *Trie) TryUpdate(key, value []byte) error { + k := compactHexDecode(key) + if len(value) != 0 { + n, err := t.insert(t.root, nil, k, valueNode(value)) + if err != nil { + return err + } + t.root = n + } else { + n, err := t.delete(t.root, nil, k) + if err != nil { + return err + } + t.root = n + } + return nil +} + +func (t *Trie) insert(n node, prefix, key []byte, value node) (node, error) { if len(key) == 0 { - return value + return value, nil } switch n := n.(type) { case shortNode: @@ -149,25 +194,40 @@ func (t *Trie) insert(n node, key []byte, value node) node { // If the whole key matches, keep this short node as is // and only update the value. if matchlen == len(n.Key) { - return shortNode{n.Key, t.insert(n.Val, key[matchlen:], value)} + nn, err := t.insert(n.Val, append(prefix, key[:matchlen]...), key[matchlen:], value) + if err != nil { + return nil, err + } + return shortNode{n.Key, nn}, nil } // Otherwise branch out at the index where they differ. var branch fullNode - branch[n.Key[matchlen]] = t.insert(nil, n.Key[matchlen+1:], n.Val) - branch[key[matchlen]] = t.insert(nil, key[matchlen+1:], value) + var err error + branch[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val) + if err != nil { + return nil, err + } + branch[key[matchlen]], err = t.insert(nil, append(prefix, key[:matchlen+1]...), key[matchlen+1:], value) + if err != nil { + return nil, err + } // Replace this shortNode with the branch if it occurs at index 0. if matchlen == 0 { - return branch + return branch, nil } // Otherwise, replace it with a short node leading up to the branch. - return shortNode{key[:matchlen], branch} + return shortNode{key[:matchlen], branch}, nil case fullNode: - n[key[0]] = t.insert(n[key[0]], key[1:], value) - return n + nn, err := t.insert(n[key[0]], append(prefix, key[0]), key[1:], value) + if err != nil { + return nil, err + } + n[key[0]] = nn + return n, nil case nil: - return shortNode{key, value} + return shortNode{key, value}, nil case hashNode: // We've hit a part of the trie that isn't loaded yet. Load @@ -176,7 +236,11 @@ func (t *Trie) insert(n node, key []byte, value node) node { // // TODO: track whether insertion changed the value and keep // n as a hash node if it didn't. - return t.insert(t.resolveHash(n), key, value) + rn, err := t.resolveHash(n, prefix, key) + if err != nil { + return nil, err + } + return t.insert(rn, prefix, key, value) default: panic(fmt.Sprintf("%T: invalid node: %v", n, n)) @@ -185,28 +249,44 @@ func (t *Trie) insert(n node, key []byte, value node) node { // Delete removes any existing value for key from the trie. func (t *Trie) Delete(key []byte) { + if err := t.TryDelete(key); err != nil && glog.V(logger.Error) { + glog.Errorf("Unhandled trie error: %v", err) + } +} + +// TryDelete removes any existing value for key from the trie. +// If a node was not found in the database, a MissingNodeError is returned. +func (t *Trie) TryDelete(key []byte) error { k := compactHexDecode(key) - t.root = t.delete(t.root, k) + n, err := t.delete(t.root, nil, k) + if err != nil { + return err + } + t.root = n + return nil } // delete returns the new root of the trie with key deleted. // It reduces the trie to minimal form by simplifying // nodes on the way up after deleting recursively. -func (t *Trie) delete(n node, key []byte) node { +func (t *Trie) delete(n node, prefix, key []byte) (node, error) { switch n := n.(type) { case shortNode: matchlen := prefixLen(key, n.Key) if matchlen < len(n.Key) { - return n // don't replace n on mismatch + return n, nil // don't replace n on mismatch } if matchlen == len(key) { - return nil // remove n entirely for whole matches + return nil, nil // remove n entirely for whole matches } // The key is longer than n.Key. Remove the remaining suffix // from the subtrie. Child can never be nil here since the // subtrie must contain at least two other values with keys // longer than n.Key. - child := t.delete(n.Val, key[len(n.Key):]) + child, err := t.delete(n.Val, append(prefix, key[:len(n.Key)]...), key[len(n.Key):]) + if err != nil { + return nil, err + } switch child := child.(type) { case shortNode: // Deleting from the subtrie reduced it to another @@ -215,13 +295,17 @@ func (t *Trie) delete(n node, key []byte) node { // always creates a new slice) instead of append to // avoid modifying n.Key since it might be shared with // other nodes. - return shortNode{concat(n.Key, child.Key...), child.Val} + return shortNode{concat(n.Key, child.Key...), child.Val}, nil default: - return shortNode{n.Key, child} + return shortNode{n.Key, child}, nil } case fullNode: - n[key[0]] = t.delete(n[key[0]], key[1:]) + nn, err := t.delete(n[key[0]], append(prefix, key[0]), key[1:]) + if err != nil { + return nil, err + } + n[key[0]] = nn // Check how many non-nil entries are left after deleting and // reduce the full node to a short node if only one entry is // left. Since n must've contained at least two children @@ -250,21 +334,24 @@ func (t *Trie) delete(n node, key []byte) node { // shortNode{..., shortNode{...}}. Since the entry // might not be loaded yet, resolve it just for this // check. - cnode := t.resolve(n[pos]) + cnode, err := t.resolve(n[pos], prefix, []byte{byte(pos)}) + if err != nil { + return nil, err + } if cnode, ok := cnode.(shortNode); ok { k := append([]byte{byte(pos)}, cnode.Key...) - return shortNode{k, cnode.Val} + return shortNode{k, cnode.Val}, nil } } // Otherwise, n is replaced by a one-nibble short node // containing the child. - return shortNode{[]byte{byte(pos)}, n[pos]} + return shortNode{[]byte{byte(pos)}, n[pos]}, nil } // n still contains at least two values and cannot be reduced. - return n + return n, nil case nil: - return nil + return nil, nil case hashNode: // We've hit a part of the trie that isn't loaded yet. Load @@ -273,7 +360,11 @@ func (t *Trie) delete(n node, key []byte) node { // // TODO: track whether deletion actually hit a key and keep // n as a hash node if it didn't. - return t.delete(t.resolveHash(n), key) + rn, err := t.resolveHash(n, prefix, key) + if err != nil { + return nil, err + } + return t.delete(rn, prefix, key) default: panic(fmt.Sprintf("%T: invalid node: %v (%v)", n, n, key)) @@ -287,34 +378,31 @@ func concat(s1 []byte, s2 ...byte) []byte { return r } -func (t *Trie) resolve(n node) node { +func (t *Trie) resolve(n node, prefix, suffix []byte) (node, error) { if n, ok := n.(hashNode); ok { - return t.resolveHash(n) + return t.resolveHash(n, prefix, suffix) } - return n + return n, nil } -func (t *Trie) resolveHash(n hashNode) node { +func (t *Trie) resolveHash(n hashNode, prefix, suffix []byte) (node, error) { if v, ok := globalCache.Get(n); ok { - return v + return v, nil } enc, err := t.db.Get(n) if err != nil || enc == nil { - // TODO: This needs to be improved to properly distinguish errors. - // Disk I/O errors shouldn't produce nil (and cause a - // consensus failure or weird crash), but it is unclear how - // they could be handled because the entire stack above the trie isn't - // prepared to cope with missing state nodes. - if glog.V(logger.Error) { - glog.Errorf("Dangling hash node ref %x: %v", n, err) + return nil, &MissingNodeError{ + RootHash: t.originalRoot, + NodeHash: common.BytesToHash(n), + KeyPrefix: prefix, + KeySuffix: suffix, } - return nil } dec := mustDecodeNode(n, enc) if dec != nil { globalCache.Put(n, dec) } - return dec + return dec, nil } // Root returns the root hash of the trie. diff --git a/trie/trie_test.go b/trie/trie_test.go index c96861bedb..35d043cdf1 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -64,11 +64,84 @@ func TestMissingRoot(t *testing.T) { if trie != nil { t.Error("New returned non-nil trie for invalid root") } - if err != ErrMissingRoot { + if _, ok := err.(*MissingNodeError); !ok { t.Error("New returned wrong error: %v", err) } } +func TestMissingNode(t *testing.T) { + db, _ := ethdb.NewMemDatabase() + trie, _ := New(common.Hash{}, db) + updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") + updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") + root, _ := trie.Commit() + + ClearGlobalCache() + + trie, _ = New(root, db) + _, err := trie.TryGet([]byte("120000")) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + trie, _ = New(root, db) + _, err = trie.TryGet([]byte("120099")) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + trie, _ = New(root, db) + _, err = trie.TryGet([]byte("123456")) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + trie, _ = New(root, db) + err = trie.TryUpdate([]byte("120099"), []byte("zxcvzxcvzxcvzxcvzxcvzxcvzxcvzxcv")) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + trie, _ = New(root, db) + err = trie.TryDelete([]byte("123456")) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + db.Delete(common.FromHex("e1d943cc8f061a0c0b98162830b970395ac9315654824bf21b73b891365262f9")) + ClearGlobalCache() + + trie, _ = New(root, db) + _, err = trie.TryGet([]byte("120000")) + if _, ok := err.(*MissingNodeError); !ok { + t.Errorf("Wrong error: %v", err) + } + + trie, _ = New(root, db) + _, err = trie.TryGet([]byte("120099")) + if _, ok := err.(*MissingNodeError); !ok { + t.Errorf("Wrong error: %v", err) + } + + trie, _ = New(root, db) + _, err = trie.TryGet([]byte("123456")) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + trie, _ = New(root, db) + err = trie.TryUpdate([]byte("120099"), []byte("zxcv")) + if _, ok := err.(*MissingNodeError); !ok { + t.Errorf("Wrong error: %v", err) + } + + trie, _ = New(root, db) + err = trie.TryDelete([]byte("123456")) + if _, ok := err.(*MissingNodeError); !ok { + t.Errorf("Wrong error: %v", err) + } +} + func TestInsert(t *testing.T) { trie := newEmpty() From 61ca14bc44dce04a125c9f633b047b8bbe7b3a83 Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Tue, 1 Dec 2015 11:01:40 +0100 Subject: [PATCH 14/27] eth: use global event mux instead --- eth/backend.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/backend.go b/eth/backend.go index 0369f6afd2..91f02db72a 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -191,7 +191,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { shutdownChan: make(chan bool), chainDb: chainDb, dappDb: dappDb, - eventMux: &event.TypeMux{}, + eventMux: ctx.EventMux, accountManager: config.AccountManager, etherbase: config.Etherbase, netVersionId: config.NetworkId, From 391ca61678418a15f14909b611458fdc0894bbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 1 Dec 2015 12:40:55 +0200 Subject: [PATCH 15/27] Makefile: build ARM v5/v6/v7, drop high API mobile clients --- Makefile | 61 ++++++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 1f9bf0db85..12802647e3 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,10 @@ # don't need to bother with make. .PHONY: geth geth-cross evm all test travis-test-with-coverage xgo clean -.PHONY: geth-linux geth-linux-arm geth-linux-386 geth-linux-amd64 +.PHONY: geth-linux geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-386 geth-linux-amd64 .PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64 .PHONY: geth-windows geth-windows-386 geth-windows-amd64 -.PHONY: geth-android geth-android-16 geth-android-21 -.PHONY: geth-ios geth-ios-5.0 geth-ios-8.1 +.PHONY: geth-android geth-ios GOBIN = build/bin @@ -24,15 +23,10 @@ geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios @echo "Full cross compilation done:" @ls -l $(GOBIN)/geth-* -geth-linux: xgo geth-linux-arm geth-linux-386 geth-linux-amd64 +geth-linux: geth-linux-386 geth-linux-amd64 geth-linux-arm @echo "Linux cross compilation done:" @ls -l $(GOBIN)/geth-linux-* -geth-linux-arm: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm -v $(shell build/flags.sh) ./cmd/geth - @echo "Linux ARM cross compilation done:" - @ls -l $(GOBIN)/geth-linux-* | grep arm - geth-linux-386: xgo build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/386 -v $(shell build/flags.sh) ./cmd/geth @echo "Linux 386 cross compilation done:" @@ -43,7 +37,26 @@ geth-linux-amd64: xgo @echo "Linux amd64 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep amd64 -geth-darwin: xgo geth-darwin-386 geth-darwin-amd64 +geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 + @echo "Linux ARM cross compilation done:" + @ls -l $(GOBIN)/geth-linux-* | grep arm + +geth-linux-arm-5: xgo + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-5 -v $(shell build/flags.sh) ./cmd/geth + @echo "Linux ARMv5 cross compilation done:" + @ls -l $(GOBIN)/geth-linux-* | grep arm-5 + +geth-linux-arm-6: xgo + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-6 -v $(shell build/flags.sh) ./cmd/geth + @echo "Linux ARMv6 cross compilation done:" + @ls -l $(GOBIN)/geth-linux-* | grep arm-6 + +geth-linux-arm-7: xgo + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm-7 -v $(shell build/flags.sh) ./cmd/geth + @echo "Linux ARMv7 cross compilation done:" + @ls -l $(GOBIN)/geth-linux-* | grep arm-7 + +geth-darwin: geth-darwin-386 geth-darwin-amd64 @echo "Darwin cross compilation done:" @ls -l $(GOBIN)/geth-darwin-* @@ -57,7 +70,7 @@ geth-darwin-amd64: xgo @echo "Darwin amd64 cross compilation done:" @ls -l $(GOBIN)/geth-darwin-* | grep amd64 -geth-windows: xgo geth-windows-386 geth-windows-amd64 +geth-windows: geth-windows-386 geth-windows-amd64 @echo "Windows cross compilation done:" @ls -l $(GOBIN)/geth-windows-* @@ -71,34 +84,16 @@ geth-windows-amd64: xgo @echo "Windows amd64 cross compilation done:" @ls -l $(GOBIN)/geth-windows-* | grep amd64 -geth-android: xgo geth-android-16 geth-android-21 +geth-android: xgo + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android/* -v $(shell build/flags.sh) ./cmd/geth @echo "Android cross compilation done:" @ls -l $(GOBIN)/geth-android-* -geth-android-16: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android-16/* -v $(shell build/flags.sh) ./cmd/geth - @echo "Android 16 cross compilation done:" - @ls -l $(GOBIN)/geth-android-16-* - -geth-android-21: xgo - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=android-21/* -v $(shell build/flags.sh) ./cmd/geth - @echo "Android 21 cross compilation done:" - @ls -l $(GOBIN)/geth-android-21-* - -geth-ios: xgo geth-ios-5.0 geth-ios-8.1 +geth-ios: xgo + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios/* -v $(shell build/flags.sh) ./cmd/geth @echo "iOS cross compilation done:" @ls -l $(GOBIN)/geth-ios-* -geth-ios-5.0: - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios-5.0/* -v $(shell build/flags.sh) ./cmd/geth - @echo "iOS 5.0 cross compilation done:" - @ls -l $(GOBIN)/geth-ios-5.0-* - -geth-ios-8.1: - build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --depsargs=--disable-assembly --targets=ios-8.1/* -v $(shell build/flags.sh) ./cmd/geth - @echo "iOS 8.1 cross compilation done:" - @ls -l $(GOBIN)/geth-ios-8.1-* - evm: build/env.sh $(GOROOT)/bin/go install -v $(shell build/flags.sh) ./cmd/evm @echo "Done building." From d648e96b3d2c52074b6085ceb26e5f2755257791 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 1 Dec 2015 11:20:49 +0100 Subject: [PATCH 16/27] cmd/utils: restore starting geth without any accounts and etherbase Also remove some duplication around address/index parsing. --- cmd/geth/main.go | 7 +++++-- cmd/utils/flags.go | 32 +++++++++++++------------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 3a54718456..6ec30cebcf 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -464,9 +464,12 @@ func execScripts(ctx *cli.Context) { node.Stop() } +// tries unlocking the specified account a few times. func unlockAccount(ctx *cli.Context, accman *accounts.Manager, address string, i int, passwords []string) (common.Address, string) { - // Try to unlock the specified account a few times - account := utils.MakeAddress(accman, address) + account, err := utils.MakeAddress(accman, address) + if err != nil { + utils.Fatalf("Unlock error: %v", err) + } for trials := 0; trials < 3; trials++ { prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 53126f9e5d..839ec3f027 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -518,47 +518,41 @@ func MakeAccountManager(ctx *cli.Context) *accounts.Manager { // MakeAddress converts an account specified directly as a hex encoded string or // a key index in the key store to an internal account representation. -func MakeAddress(accman *accounts.Manager, account string) common.Address { +func MakeAddress(accman *accounts.Manager, account string) (a common.Address, err error) { // If the specified account is a valid address, return it if common.IsHexAddress(account) { - return common.HexToAddress(account) + return common.HexToAddress(account), nil } // Otherwise try to interpret the account as a keystore index index, err := strconv.Atoi(account) if err != nil { - Fatalf("Invalid account address or index: '%s'", account) + return a, fmt.Errorf("invalid account address or index %q", account) } hex, err := accman.AddressByIndex(index) if err != nil { - Fatalf("Failed to retrieve requested account #%d: %v", index, err) + return a, fmt.Errorf("can't get account #%d (%v)", index, err) } - return common.HexToAddress(hex) + return common.HexToAddress(hex), nil } // MakeEtherbase retrieves the etherbase either from the directly specified // command line flags or from the keystore if CLI indexed. func MakeEtherbase(accman *accounts.Manager, ctx *cli.Context) common.Address { - // If the specified etherbase is a valid address, return it - etherbase := ctx.GlobalString(EtherbaseFlag.Name) - if common.IsHexAddress(etherbase) { - return common.HexToAddress(etherbase) - } - // If no etherbase was specified and no accounts are known, bail out accounts, _ := accman.Accounts() - if etherbase == "" && len(accounts) == 0 { + if !ctx.GlobalIsSet(EtherbaseFlag.Name) && len(accounts) == 0 { glog.V(logger.Error).Infoln("WARNING: No etherbase set and no accounts found as default") return common.Address{} } - // Otherwise try to interpret the parameter as a keystore index - index, err := strconv.Atoi(etherbase) - if err != nil { - Fatalf("Invalid account address or index: '%s'", etherbase) + etherbase := ctx.GlobalString(EtherbaseFlag.Name) + if etherbase == "" { + return common.Address{} } - hex, err := accman.AddressByIndex(index) + // If the specified etherbase is a valid address, return it + addr, err := MakeAddress(accman, etherbase) if err != nil { - Fatalf("Failed to set requested account #%d as etherbase: %v", index, err) + Fatalf("Option %q: %v", EtherbaseFlag.Name, err) } - return common.HexToAddress(hex) + return addr } // MakeMinerExtra resolves extradata for the miner from the set command line flags From 2e43414c7931322f9eac114b253e6fbdcdc5b678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 1 Dec 2015 13:20:43 +0200 Subject: [PATCH 17/27] accounts: increase re-lock timeout to account for slow CI servers --- accounts/accounts_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go index d7a8a2b85f..55ddecdea3 100644 --- a/accounts/accounts_test.go +++ b/accounts/accounts_test.go @@ -68,7 +68,7 @@ func TestTimedUnlock(t *testing.T) { } // Signing fails again after automatic locking - time.Sleep(150 * time.Millisecond) + time.Sleep(350 * time.Millisecond) _, err = am.Sign(a1, testSigData) if err != ErrLocked { t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err) From 4b28705df4d6a53bfa9028de611a8410a93e08be Mon Sep 17 00:00:00 2001 From: Bas van Kervel Date: Thu, 15 Oct 2015 16:07:19 +0200 Subject: [PATCH 18/27] rpc: new RPC implementation with pub/sub support --- accounts/account_manager.go | 15 + cmd/geth/js.go | 22 +- cmd/geth/js_test.go | 2 +- cmd/geth/main.go | 1 + cmd/geth/usage.go | 1 + cmd/gethrpctest/main.go | 65 ++- cmd/utils/api.go | 74 +++ cmd/utils/flags.go | 52 +- common/types.go | 49 ++ core/api.go | 974 ++++++++++++++++++++++++++++++++++++ core/types/block.go | 4 + core/types/bloom9.go | 4 + core/vm/log.go | 17 + eth/api.go | 266 ++++++++++ eth/backend.go | 60 +++ eth/downloader/api.go | 64 +++ eth/filters/api.go | 575 +++++++++++++++++++++ miner/miner_rpc.go | 72 +++ miner/worker.go | 1 + node/node.go | 10 + node/node_example_test.go | 2 + node/service.go | 4 + node/utils_test.go | 6 + rpc/api/mergedapi.go | 8 +- rpc/api/personal_js.go | 5 + rpc/api/utils.go | 2 + rpc/comms/ipc.go | 22 +- rpc/jeth.go | 72 +++ rpc/v2/doc.go | 102 ++++ rpc/v2/errors.go | 85 ++++ rpc/v2/json.go | 336 +++++++++++++ rpc/v2/json_test.go | 73 +++ rpc/v2/server.go | 459 +++++++++++++++++ rpc/v2/server_test.go | 218 ++++++++ rpc/v2/types.go | 352 +++++++++++++ rpc/v2/types_test.go | 57 +++ rpc/v2/utils.go | 205 ++++++++ whisper/api.go | 413 +++++++++++++++ whisper/whisper.go | 14 + 39 files changed, 4749 insertions(+), 14 deletions(-) create mode 100644 cmd/utils/api.go create mode 100644 core/api.go create mode 100644 eth/api.go create mode 100644 eth/downloader/api.go create mode 100644 eth/filters/api.go create mode 100644 miner/miner_rpc.go create mode 100644 rpc/v2/doc.go create mode 100644 rpc/v2/errors.go create mode 100644 rpc/v2/json.go create mode 100644 rpc/v2/json_test.go create mode 100644 rpc/v2/server.go create mode 100644 rpc/v2/server_test.go create mode 100644 rpc/v2/types.go create mode 100644 rpc/v2/types_test.go create mode 100644 rpc/v2/utils.go create mode 100644 whisper/api.go diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 2781be656f..74006395cd 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -44,6 +44,10 @@ type Account struct { Address common.Address } +func (acc *Account) MarshalJSON() ([]byte, error) { + return []byte(`"` + acc.Address.Hex() + `"`), nil +} + type Manager struct { keyStore crypto.KeyStore unlocked map[common.Address]*unlocked @@ -92,6 +96,17 @@ func (am *Manager) Unlock(addr common.Address, keyAuth string) error { return am.TimedUnlock(addr, keyAuth, 0) } +func (am *Manager) Lock(addr common.Address) error { + am.mutex.Lock() + if unl, found := am.unlocked[addr]; found { + am.mutex.Unlock() + am.expire(addr, unl, time.Duration(0) * time.Nanosecond) + } else { + am.mutex.Unlock() + } + return nil +} + // TimedUnlock unlocks the account with the given address. The account // stays unlocked for the duration of timeout. A timeout of 0 unlocks the account // until the program exits. diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 843c9a5b57..56b7a8b001 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -246,10 +246,10 @@ func (self *jsre) welcome() { self.re.Run(` (function () { console.log('instance: ' + web3.version.node); - console.log(' datadir: ' + admin.datadir); console.log("coinbase: " + eth.coinbase); var ts = 1000 * eth.getBlock(eth.blockNumber).timestamp; console.log("at block: " + eth.blockNumber + " (" + new Date(ts) + ")"); + console.log(' datadir: ' + admin.datadir); })(); `) if modules, err := self.supportedApis(); err == nil { @@ -258,7 +258,7 @@ func (self *jsre) welcome() { loadedModules = append(loadedModules, fmt.Sprintf("%s:%s", api, version)) } sort.Strings(loadedModules) - fmt.Println("modules:", strings.Join(loadedModules, " ")) + } } @@ -325,12 +325,28 @@ func (js *jsre) apiBindings(f xeth.Frontend) error { } _, err = js.re.Run(shortcuts) - if err != nil { utils.Fatalf("Error setting namespaces: %v", err) } js.re.Run(`var GlobalRegistrar = eth.contract(` + registrar.GlobalRegistrarAbi + `); registrar = GlobalRegistrar.at("` + registrar.GlobalRegistrarAddr + `");`) + + // overrule some of the methods that require password as input and ask for it interactively + p, err := js.re.Get("personal") + if err != nil { + fmt.Println("Unable to overrule sensitive methods in personal module") + return nil + } + + // Override the unlockAccount and newAccount methods on the personal object since these require user interaction. + // Assign the jeth.unlockAccount and jeth.newAccount in the jsre the original web3 callbacks. These will be called + // by the jeth.* methods after they got the password from the user and send the original web3 request to the backend. + persObj := p.Object() + js.re.Run(`jeth.unlockAccount = personal.unlockAccount;`) + persObj.Set("unlockAccount", jeth.UnlockAccount) + js.re.Run(`jeth.newAccount = personal.newAccount;`) + persObj.Set("newAccount", jeth.NewAccount) + return nil } diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index a0f3f2fb76..ca636188f4 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -168,7 +168,7 @@ func TestAccounts(t *testing.T) { checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`) checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`) - val, err := repl.re.Run(`personal.newAccount("password")`) + val, err := repl.re.Run(`jeth.newAccount("password")`) if err != nil { t.Errorf("expected no error, got %v", err) } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 6ec30cebcf..bb291ccde2 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -313,6 +313,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.IPCDisabledFlag, utils.IPCApiFlag, utils.IPCPathFlag, + utils.IPCExperimental, utils.ExecFlag, utils.WhisperEnabledFlag, utils.DevModeFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 5c09e29ce4..7a6ff704c4 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -158,6 +158,7 @@ var AppHelpFlagGroups = []flagGroup{ Flags: []cli.Flag{ utils.WhisperEnabledFlag, utils.NatspecEnabledFlag, + utils.IPCExperimental, }, }, { diff --git a/cmd/gethrpctest/main.go b/cmd/gethrpctest/main.go index 7130980ac3..5e79bd7395 100644 --- a/cmd/gethrpctest/main.go +++ b/cmd/gethrpctest/main.go @@ -23,6 +23,8 @@ import ( "log" "os" "os/signal" + "path/filepath" + "runtime" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/crypto" @@ -35,6 +37,11 @@ import ( "github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/whisper" "github.com/ethereum/go-ethereum/xeth" + rpc "github.com/ethereum/go-ethereum/rpc/v2" + "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/cmd/utils" ) const defaultTestKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" @@ -81,9 +88,14 @@ func main() { } log.Println("Initial test suite passed...") + if err := StartIPC(stack); err != nil { + log.Fatalf("Failed to start IPC interface: %v\n", err) + } + log.Println("IPC Interface started, accepting requests...") + // Start the RPC interface and wait until terminated if err := StartRPC(stack); err != nil { - log.Fatalf("Failed to start RPC instarface: %v", err) + log.Fatalf("Failed to start RPC interface: %v", err) } log.Println("RPC Interface started, accepting requests...") @@ -177,3 +189,54 @@ func StartRPC(stack *node.Node) error { } return comms.StartHttp(config, codec, api.Merge(apis...)) } + +// StartRPC initializes an IPC interface to the given protocol stack. +func StartIPC(stack *node.Node) error { + var ethereum *eth.Ethereum + if err := stack.Service(ðereum); err != nil { + return err + } + + endpoint := `\\.\pipe\geth.ipc` + if runtime.GOOS != "windows" { + endpoint = filepath.Join(common.DefaultDataDir(), "geth.ipc") + } + + config := comms.IpcConfig{ + Endpoint: endpoint, + } + + listener, err := comms.CreateListener(config) + if err != nil { + return err + } + + server := rpc.NewServer() + + // register package API's this node provides + offered := stack.RPCApis() + for _, api := range offered { + server.RegisterName(api.Namespace, api.Service) + glog.V(logger.Debug).Infof("Register %T@%s for IPC service\n", api.Service, api.Namespace) + } + + web3 := utils.NewPublicWeb3Api(stack) + server.RegisterName("web3", web3) + net := utils.NewPublicNetApi(stack.Server(), ethereum.NetVersion()) + server.RegisterName("net", net) + + go func() { + 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 +} diff --git a/cmd/utils/api.go b/cmd/utils/api.go new file mode 100644 index 0000000000..83c7d5eaa4 --- /dev/null +++ b/cmd/utils/api.go @@ -0,0 +1,74 @@ +// 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 . + +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))) +} + +// NetService 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) +} \ No newline at end of file diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 839ec3f027..abee6210f3 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -54,6 +54,7 @@ import ( "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/xeth" ) @@ -300,6 +301,10 @@ var ( Usage: "Filename for IPC socket/pipe", Value: DirectoryString{common.DefaultIpcPath()}, } + IPCExperimental = cli.BoolFlag{ + Name: "ipcexp", + Usage: "Enable the new RPC implementation", + } ExecFlag = cli.StringFlag{ Name: "exec", Usage: "Execute JavaScript statement (only in combination with console/attach)", @@ -690,6 +695,7 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. Fatalf("Failed to register the Whisper service: %v", err) } } + return stack } @@ -773,17 +779,53 @@ func IpcSocketPath(ctx *cli.Context) (ipcpath string) { return } -// StartIPC starts a IPC JSON-RPC API server. func StartIPC(stack *node.Node, ctx *cli.Context) error { config := comms.IpcConfig{ Endpoint: IpcSocketPath(ctx), } - initializer := func(conn net.Conn) (comms.Stopper, shared.EthereumApi, error) { - var ethereum *eth.Ethereum - if err := stack.Service(ðereum); err != nil { - return nil, nil, err + var ethereum *eth.Ethereum + if err := stack.Service(ðereum); err != nil { + return err + } + + if ctx.GlobalIsSet(IPCExperimental.Name) { + listener, err := comms.CreateListener(config) + if err != nil { + return err } + + server := rpc.NewServer() + + // register package API's this node provides + offered := stack.RPCApis() + for _, api := range offered { + server.RegisterName(api.Namespace, api.Service) + glog.V(logger.Debug).Infof("Register %T under namespace '%s' for IPC service\n", api.Service, api.Namespace) + } + + web3 := NewPublicWeb3Api(stack) + server.RegisterName("web3", web3) + net := NewPublicNetApi(stack.Server(), ethereum.NetVersion()) + server.RegisterName("net", net) + + go func() { + 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 + } + + 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) diff --git a/common/types.go b/common/types.go index acbd5b28da..b1666d7338 100644 --- a/common/types.go +++ b/common/types.go @@ -17,6 +17,8 @@ package common import ( + "encoding/hex" + "encoding/json" "fmt" "math/big" "math/rand" @@ -50,6 +52,21 @@ func (h Hash) Bytes() []byte { return h[:] } func (h Hash) Big() *big.Int { return Bytes2Big(h[:]) } func (h Hash) Hex() string { return "0x" + Bytes2Hex(h[:]) } +// UnmarshalJSON parses a hash in its hex from to a hash. +func (h *Hash) UnmarshalJSON(input []byte) error { + length := len(input) + if length >= 2 && input[0] == '"' && input[length-1] == '"' { + input = input[1 : length-1] + } + h.SetBytes(FromHex(string(input))) + return nil +} + +// Serialize given hash to JSON +func (h Hash) MarshalJSON() ([]byte, error) { + return json.Marshal(h.Hex()) +} + // Sets the hash to the value of b. If b is larger than len(h) it will panic func (h *Hash) SetBytes(b []byte) { if len(b) > len(h) { @@ -129,6 +146,38 @@ func (a *Address) Set(other Address) { } } +// Serialize given address to JSON +func (a Address) MarshalJSON() ([]byte, error) { + return json.Marshal(a.Hex()) +} + +// Parse address from raw json data +func (a *Address) UnmarshalJSON(data []byte) error { + if len(data) > 2 && data[0] == '"' && data[len(data)-1] == '"' { + data = data[:len(data)-1][1:] + } + + if len(data) > 2 && data[0] == '0' && data[1] == 'x' { + data = data[2:] + } + + if len(data) != 2*AddressLength { + return fmt.Errorf("Invalid address length, expected %d got %d bytes", 2*AddressLength, len(data)) + } + + n, err := hex.Decode(a[:], data) + if err != nil { + return err + } + + if n != AddressLength { + return fmt.Errorf("Invalid address") + } + + a.Set(HexToAddress(string(data))) + return nil +} + // PP Pretty Prints a byte slice in the following format: // hex(value[:4])...(hex[len(value)-4:]) func PP(value []byte) string { diff --git a/core/api.go b/core/api.go new file mode 100644 index 0000000000..8c1fb67c84 --- /dev/null +++ b/core/api.go @@ -0,0 +1,974 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package core + +import ( + "bytes" + "encoding/json" + "fmt" + "math/big" + "time" + + "sync" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/rlp" + rpc "github.com/ethereum/go-ethereum/rpc/v2" + "gopkg.in/fatih/set.v0" +) + +const ( + FilterTimeout = 300 * time.Second // Remove filter after FilterTimeout + + defaultGasPrice = uint64(10000000000000) + defaultGas = uint64(90000) +) + +// PublicBlockChainApi provides an API to access the Ethereum blockchain. +// It offers only methods that operate on public data that is freely available to anyone. +type PublicBlockChainApi struct { + bc *BlockChain + am *accounts.Manager +} + +// NewPublicBlockChainApi creates a new Etheruem blockchain API. +func NewPublicBlockChainApi(bc *BlockChain, am *accounts.Manager) *PublicBlockChainApi { + return &PublicBlockChainApi{bc: bc, am: am} +} + +// BlockNumber returns the block number of the chain head. +func (s *PublicBlockChainApi) BlockNumber() *big.Int { + return s.bc.CurrentHeader().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. +func (s *PublicBlockChainApi) GetBalance(address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) { + block := blockByNumber(s.bc, blockNr) + if block == nil { + return nil, nil + } + + state, err := state.New(block.Root(), s.bc.chainDb) + if err != nil { + return nil, err + } + 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 *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 +// 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) { + if block := blockByNumber(s.bc, blockNr); block != nil { + return s.rpcOutputBlock(block, true, fullTx) + } + return nil, nil +} + +// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full +// detail, otherwise only the transaction hash is returned. +func (s *PublicBlockChainApi) GetBlockByHash(blockHash common.Hash, fullTx bool) (map[string]interface{}, error) { + if block := s.bc.GetBlock(blockHash); block != nil { + return s.rpcOutputBlock(block, true, fullTx) + } + return nil, nil +} + +// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true +// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned. +func (s *PublicBlockChainApi) GetUncleByBlockNumberAndIndex(blockNr rpc.BlockNumber, index rpc.HexNumber) (map[string]interface{}, error) { + if blockNr == rpc.PendingBlockNumber { + return nil, nil + } + + if block := blockByNumber(s.bc, blockNr); block != nil { + uncles := block.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) + return nil, nil + } + block = types.NewBlockWithHeader(uncles[index.Int()]) + return s.rpcOutputBlock(block, false, false) + } + return nil, nil +} + +// GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. When fullTx is true +// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned. +func (s *PublicBlockChainApi) GetUncleByBlockHashAndIndex(blockHash common.Hash, index rpc.HexNumber) (map[string]interface{}, error) { + if block := s.bc.GetBlock(blockHash); block != nil { + uncles := block.Uncles() + if index.Int() < 0 || index.Int() >= len(uncles) { + glog.V(logger.Debug).Infof("uncle block on index %d not found for block %s", index.Int(), blockHash.Hex()) + return nil, nil + } + block = types.NewBlockWithHeader(uncles[index.Int()]) + return s.rpcOutputBlock(block, false, false) + } + return nil, nil +} + +// GetUncleCountByBlockNumber returns number of uncles in the block for the given block number +func (s *PublicBlockChainApi) GetUncleCountByBlockNumber(blockNr rpc.BlockNumber) *rpc.HexNumber { + if blockNr == rpc.PendingBlockNumber { + return rpc.NewHexNumber(0) + } + + if block := blockByNumber(s.bc, blockNr); block != nil { + return rpc.NewHexNumber(len(block.Uncles())) + } + return nil +} + +// GetUncleCountByBlockHash returns number of uncles in the block for the given block hash +func (s *PublicBlockChainApi) GetUncleCountByBlockHash(blockHash common.Hash) *rpc.HexNumber { + if block := s.bc.GetBlock(blockHash); block != nil { + return rpc.NewHexNumber(len(block.Uncles())) + } + return nil +} + +// NewBlocksArgs allows the user to specify if the returned block should include transactions and in which format. +type NewBlocksArgs struct { + IncludeTransactions bool `json:"includeTransactions"` + TransactionDetails bool `json:"transactionDetails"` +} + +// NewBlocks triggers a new block event each time a block is appended to the chain. It accepts an argument which allows +// the caller to specify whether the output should contain transactions and in what format. +func (s *PublicBlockChainApi) NewBlocks(args NewBlocksArgs) (rpc.Subscription, error) { + sub := s.bc.eventMux.Subscribe(ChainEvent{}) + + output := func(rawBlock interface{}) interface{} { + if event, ok := rawBlock.(ChainEvent); ok { + notification, err := s.rpcOutputBlock(event.Block, args.IncludeTransactions, args.TransactionDetails) + if err == nil { + return notification + } + } + return rawBlock + } + + return rpc.NewSubscriptionWithOutputFormat(sub, output), nil +} + +// GetCode returns the code stored at the given address in the state for the given block number. +func (s *PublicBlockChainApi) GetCode(address common.Address, blockNr rpc.BlockNumber) (string, error) { + return s.GetData(address, blockNr) +} + +// 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) { + if block := blockByNumber(s.bc, blockNr); block != nil { + state, err := state.New(block.Root(), s.bc.chainDb) + if err != nil { + return "", err + } + res := state.GetCode(address) + if len(res) == 0 { // backwards compatibility + return "0x", nil + } + return common.ToHex(res), nil + } + + return "0x", nil +} + +// 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) { + if block := blockByNumber(s.bc, blockNr); block != nil { + state, err := state.New(block.Root(), s.bc.chainDb) + if err != nil { + return "", err + } + + return state.GetState(address, common.HexToHash(key)).Hex(), nil + } + + return "0x", nil +} + +// 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 } + +type CallArgs struct { + From common.Address `json:"from"` + To common.Address `json:"to"` + Gas rpc.HexNumber `json:"gas"` + GasPrice rpc.HexNumber `json:"gasPrice"` + Value rpc.HexNumber `json:"value"` + Data string `json:"data"` +} + +func (s *PublicBlockChainApi) doCall(args CallArgs, blockNr rpc.BlockNumber) (string, *big.Int, error) { + if block := blockByNumber(s.bc, blockNr); block != nil { + stateDb, err := state.New(block.Root(), s.bc.chainDb) + if err != nil { + return "0x", nil, err + } + + stateDb = stateDb.Copy() + var from *state.StateObject + if args.From == (common.Address{}) { + accounts, err := s.am.Accounts() + if err != nil || len(accounts) == 0 { + from = stateDb.GetOrNewStateObject(common.Address{}) + } else { + from = stateDb.GetOrNewStateObject(accounts[0].Address) + } + } else { + from = stateDb.GetOrNewStateObject(args.From) + } + + from.SetBalance(common.MaxBig) + + msg := callmsg{ + from: from, + to: &args.To, + gas: args.Gas.BigInt(), + gasPrice: args.GasPrice.BigInt(), + value: args.Value.BigInt(), + data: common.FromHex(args.Data), + } + + if msg.gas.Cmp(common.Big0) == 0 { + msg.gas = big.NewInt(50000000) + } + + if msg.gasPrice.Cmp(common.Big0) == 0 { + msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon) + } + + header := s.bc.CurrentBlock().Header() + vmenv := NewEnv(stateDb, s.bc, msg, header) + gp := new(GasPool).AddGas(common.MaxBig) + res, gas, err := ApplyMessage(vmenv, msg, gp) + if len(res) == 0 { // backwards compatability + return "0x", gas, err + } + return common.ToHex(res), gas, err + } + + return "0x", common.Big0, nil +} + +func (s *PublicBlockChainApi) Call(args CallArgs, blockNr rpc.BlockNumber) (string, error) { + result, _, err := s.doCall(args, blockNr) + return result, err +} + +func (s *PublicBlockChainApi) EstimateGas(args CallArgs) (*rpc.HexNumber, error) { + _, gas, err := s.doCall(args, rpc.LatestBlockNumber) + return rpc.NewHexNumber(gas), err +} + +// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are +// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain +// transaction hashes. +func (s *PublicBlockChainApi) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields := map[string]interface{}{ + "number": rpc.NewHexNumber(b.Number()), + "hash": b.Hash(), + "parentHash": b.ParentHash(), + "nonce": b.Header().Nonce, + "sha3Uncles": b.UncleHash(), + "logsBloom": b.Bloom(), + "stateRoot": b.Root(), + "miner": b.Coinbase(), + "difficulty": rpc.NewHexNumber(b.Difficulty()), + "totalDifficulty": rpc.NewHexNumber(s.bc.GetTd(b.Hash())), + "extraData": fmt.Sprintf("0x%x", b.Extra()), + "size": rpc.NewHexNumber(b.Size().Int64()), + "gasLimit": rpc.NewHexNumber(b.GasLimit()), + "gasUsed": rpc.NewHexNumber(b.GasUsed()), + "timestamp": rpc.NewHexNumber(b.Time()), + "transactionsRoot": b.TxHash(), + "receiptRoot": b.ReceiptHash(), + } + + if inclTx { + formatTx := func(tx *types.Transaction) (interface{}, error) { + return tx.Hash(), nil + } + + if fullTx { + formatTx = func(tx *types.Transaction) (interface{}, error) { + return newRPCTransaction(b, tx.Hash()) + } + } + + txs := b.Transactions() + transactions := make([]interface{}, len(txs)) + var err error + for i, tx := range b.Transactions() { + if transactions[i], err = formatTx(tx); err != nil { + return nil, err + } + } + fields["transactions"] = transactions + } + + uncles := b.Uncles() + uncleHashes := make([]common.Hash, len(uncles)) + for i, uncle := range uncles { + uncleHashes[i] = uncle.Hash() + } + fields["uncles"] = uncleHashes + + return fields, nil +} + +// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction +type RPCTransaction struct { + BlockHash common.Hash `json:"blockHash"` + BlockNumber *rpc.HexNumber `json:"blockNumber"` + From common.Address `json:"from"` + Gas *rpc.HexNumber `json:"gas"` + GasPrice *rpc.HexNumber `json:"gasPrice"` + Hash common.Hash `json:"hash"` + Input string `json:"input"` + Nonce *rpc.HexNumber `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *rpc.HexNumber `json:"transactionIndex"` + Value *rpc.HexNumber `json:"value"` +} + +// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation +func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { + from, _ := tx.From() + + return &RPCTransaction{ + From: from, + Gas: rpc.NewHexNumber(tx.Gas()), + GasPrice: rpc.NewHexNumber(tx.GasPrice()), + Hash: tx.Hash(), + Input: fmt.Sprintf("0x%x", tx.Data()), + Nonce: rpc.NewHexNumber(tx.Nonce()), + To: tx.To(), + Value: rpc.NewHexNumber(tx.Value()), + } +} + +// newRPCTransaction returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) { + if txIndex >= 0 && txIndex < len(b.Transactions()) { + tx := b.Transactions()[txIndex] + from, err := tx.From() + if err != nil { + return nil, err + } + + return &RPCTransaction{ + BlockHash: b.Hash(), + BlockNumber: rpc.NewHexNumber(b.Number()), + From: from, + Gas: rpc.NewHexNumber(tx.Gas()), + GasPrice: rpc.NewHexNumber(tx.GasPrice()), + Hash: tx.Hash(), + Input: fmt.Sprintf("0x%x", tx.Data()), + Nonce: rpc.NewHexNumber(tx.Nonce()), + To: tx.To(), + TransactionIndex: rpc.NewHexNumber(txIndex), + Value: rpc.NewHexNumber(tx.Value()), + }, nil + } + + return nil, nil +} + +// newRPCTransaction returns a transaction that will serialize to the RPC representation. +func newRPCTransaction(b *types.Block, txHash common.Hash) (*RPCTransaction, error) { + for idx, tx := range b.Transactions() { + if tx.Hash() == txHash { + return newRPCTransactionFromBlockIndex(b, idx) + } + } + + return nil, nil +} + +// PublicTransactionPoolApi exposes methods for the RPC interface +type PublicTransactionPoolApi struct { + eventMux *event.TypeMux + chainDb ethdb.Database + bc *BlockChain + am *accounts.Manager + txPool *TxPool + txMu sync.Mutex +} + +// NewPublicTransactionPoolApi creates a new RPC service with methods specific for the transaction pool. +func NewPublicTransactionPoolApi(txPool *TxPool, chainDb ethdb.Database, bc *BlockChain, am *accounts.Manager) *PublicTransactionPoolApi { + return &PublicTransactionPoolApi{ + eventMux: txPool.eventMux, + chainDb: chainDb, + bc: bc, + am: am, + txPool: txPool, + } +} + +func getTransaction(chainDb ethdb.Database, txPool *TxPool, txHash common.Hash) (*types.Transaction, bool, error) { + txData, err := chainDb.Get(txHash.Bytes()) + isPending := false + tx := new(types.Transaction) + + if err == nil && len(txData) > 0 { + if err := rlp.DecodeBytes(txData, tx); err != nil { + return nil, isPending, err + } + } else { + // pending transaction? + tx = txPool.GetTransaction(txHash) + isPending = true + } + + return tx, isPending, nil +} + +// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. +func (s *PublicTransactionPoolApi) GetBlockTransactionCountByNumber(blockNr rpc.BlockNumber) *rpc.HexNumber { + if blockNr == rpc.PendingBlockNumber { + return rpc.NewHexNumber(0) + } + + if block := blockByNumber(s.bc, blockNr); block != nil { + return rpc.NewHexNumber(len(block.Transactions())) + } + + return nil +} + +// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. +func (s *PublicTransactionPoolApi) GetBlockTransactionCountByHash(blockHash common.Hash) *rpc.HexNumber { + if block := s.bc.GetBlock(blockHash); block != nil { + return rpc.NewHexNumber(len(block.Transactions())) + } + return nil +} + +// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. +func (s *PublicTransactionPoolApi) GetTransactionByBlockNumberAndIndex(blockNr rpc.BlockNumber, index rpc.HexNumber) (*RPCTransaction, error) { + if block := blockByNumber(s.bc, blockNr); block != nil { + return newRPCTransactionFromBlockIndex(block, index.Int()) + } + return nil, nil +} + +// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. +func (s *PublicTransactionPoolApi) GetTransactionByBlockHashAndIndex(blockHash common.Hash, index rpc.HexNumber) (*RPCTransaction, error) { + if block := s.bc.GetBlock(blockHash); block != nil { + return newRPCTransactionFromBlockIndex(block, index.Int()) + } + return nil, nil +} + +// 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) { + block := blockByNumber(s.bc, blockNr) + if block == nil { + return nil, nil + } + + state, err := state.New(block.Root(), s.chainDb) + if err != nil { + return nil, err + } + return rpc.NewHexNumber(state.GetNonce(address)), nil +} + +// getTransactionBlockData fetches the meta data for the given transaction from the chain database. This is useful to +// retrieve block information for a hash. It returns the block hash, block index and transaction index. +func getTransactionBlockData(chainDb ethdb.Database, txHash common.Hash) (common.Hash, uint64, uint64, error) { + var txBlock struct { + BlockHash common.Hash + BlockIndex uint64 + Index uint64 + } + + blockData, err := chainDb.Get(append(txHash.Bytes(), 0x0001)) + if err != nil { + return common.Hash{}, uint64(0), uint64(0), err + } + + reader := bytes.NewReader(blockData) + if err = rlp.Decode(reader, &txBlock); err != nil { + return common.Hash{}, uint64(0), uint64(0), err + } + + return txBlock.BlockHash, txBlock.BlockIndex, txBlock.Index, nil +} + +// GetTransactionByHash returns the transaction for the given hash +func (s *PublicTransactionPoolApi) GetTransactionByHash(txHash common.Hash) (*RPCTransaction, error) { + var tx *types.Transaction + var isPending bool + var err error + + if tx, isPending, err = getTransaction(s.chainDb, s.txPool, txHash); err != nil { + glog.V(logger.Debug).Infof("%v\n", err) + return nil, nil + } else if tx == nil { + return nil, nil + } + + if isPending { + return newRPCPendingTransaction(tx), nil + } + + blockHash, _, _, err := getTransactionBlockData(s.chainDb, txHash) + if err != nil { + glog.V(logger.Debug).Infof("%v\n", err) + return nil, nil + } + + if block := s.bc.GetBlock(blockHash); block != nil { + return newRPCTransaction(block, txHash) + } + + return nil, nil +} + +// GetTransactionReceipt returns the transaction receipt for the given transaction hash. +func (s *PublicTransactionPoolApi) GetTransactionReceipt(txHash common.Hash) (map[string]interface{}, error) { + receipt := GetReceipt(s.chainDb, txHash) + if receipt == nil { + glog.V(logger.Debug).Infof("receipt not found for transaction %s", txHash.Hex()) + return nil, nil + } + + tx, _, err := getTransaction(s.chainDb, s.txPool, txHash) + if err != nil { + glog.V(logger.Debug).Infof("%v\n", err) + return nil, nil + } + + txBlock, blockIndex, index, err := getTransactionBlockData(s.chainDb, txHash) + if err != nil { + glog.V(logger.Debug).Infof("%v\n", err) + return nil, nil + } + + from, err := tx.From() + if err != nil { + glog.V(logger.Debug).Infof("%v\n", err) + return nil, nil + } + + fields := map[string]interface{}{ + "blockHash": txBlock, + "blockNumber": rpc.NewHexNumber(blockIndex), + "transactionHash": txHash, + "transactionIndex": rpc.NewHexNumber(index), + "from": from, + "to": tx.To(), + "gasUsed": rpc.NewHexNumber(receipt.GasUsed), + "cumulativeGasUsed": rpc.NewHexNumber(receipt.CumulativeGasUsed), + "contractAddress": nil, + "logs": receipt.Logs, + } + + if receipt.Logs == nil { + fields["logs"] = []vm.Logs{} + } + + // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation + if bytes.Compare(receipt.ContractAddress.Bytes(), bytes.Repeat([]byte{0}, 20)) != 0 { + fields["contractAddress"] = receipt.ContractAddress + } + + return fields, nil +} + +// sign is a helper function that signs a transaction with the private key of the given address. +func (s *PublicTransactionPoolApi) sign(address common.Address, tx *types.Transaction) (*types.Transaction, error) { + acc := accounts.Account{address} + signature, err := s.am.Sign(acc, tx.SigHash().Bytes()) + if err != nil { + return nil, err + } + return tx.WithSignature(signature) +} + +type SendTxArgs struct { + From common.Address `json:"from"` + To common.Address `json:"to"` + Gas *rpc.HexNumber `json:"gas"` + GasPrice *rpc.HexNumber `json:"gasPrice"` + Value *rpc.HexNumber `json:"value"` + Data string `json:"data"` + Nonce *rpc.HexNumber `json:"nonce"` +} + +// SendTransaction will create a transaction for the given transaction argument, sign it and submit it to the +// transaction pool. +func (s *PublicTransactionPoolApi) SendTransaction(args SendTxArgs) (common.Hash, error) { + if args.Gas == nil { + args.Gas = rpc.NewHexNumber(defaultGas) + } + if args.GasPrice == nil { + args.GasPrice = rpc.NewHexNumber(defaultGasPrice) + } + if args.Value == nil { + args.Value = rpc.NewHexNumber(0) + } + + s.txMu.Lock() + defer s.txMu.Unlock() + + if args.Nonce == nil { + args.Nonce = rpc.NewHexNumber(s.txPool.State().GetNonce(args.From)) + } + + var tx *types.Transaction + contractCreation := (args.To == common.Address{}) + + if contractCreation { + tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) + } else { + tx = types.NewTransaction(args.Nonce.Uint64(), args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) + } + + signedTx, err := s.sign(args.From, tx) + if err != nil { + return common.Hash{}, err + } + + if err := s.txPool.Add(signedTx); err != nil { + return common.Hash{}, nil + } + + if contractCreation { + addr := crypto.CreateAddress(args.From, args.Nonce.Uint64()) + 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(), nil +} + +// SendRawTransaction will add the signed transaction to the transaction pool. +// The sender is responsible for signing the transaction and using the correct nonce. +func (s *PublicTransactionPoolApi) SendRawTransaction(encodedTx string) (string, error) { + tx := new(types.Transaction) + if err := rlp.DecodeBytes(common.FromHex(encodedTx), tx); err != nil { + return "", err + } + + if err := s.txPool.Add(tx); err != nil { + return "", err + } + + if tx.To() == nil { + from, err := tx.From() + if err != nil { + return "", err + } + addr := crypto.CreateAddress(from, tx.Nonce()) + glog.V(logger.Info).Infof("Tx(%x) created: %x\n", tx.Hash(), addr) + } else { + glog.V(logger.Info).Infof("Tx(%x) to: %x\n", tx.Hash(), tx.To()) + } + + return tx.Hash().Hex(), nil +} + +// Sign will sign the given data string with the given address. The account corresponding with the address needs to +// be unlocked. +func (s *PublicTransactionPoolApi) Sign(address common.Address, data string) (string, error) { + signature, error := s.am.Sign(accounts.Account{Address: address}, common.HexToHash(data).Bytes()) + return common.ToHex(signature), error +} + +type SignTransactionArgs struct { + From common.Address + To common.Address + Nonce *rpc.HexNumber + Value *rpc.HexNumber + Gas *rpc.HexNumber + GasPrice *rpc.HexNumber + Data string + + BlockNumber int64 +} + +// Tx is a helper object for argument and return values +type Tx struct { + tx *types.Transaction + + To *common.Address `json:"to"` + From common.Address `json:"from"` + Nonce *rpc.HexNumber `json:"nonce"` + Value *rpc.HexNumber `json:"value"` + Data string `json:"data"` + GasLimit *rpc.HexNumber `json:"gas"` + GasPrice *rpc.HexNumber `json:"gasPrice"` + Hash common.Hash `json:"hash"` +} + +func (tx *Tx) UnmarshalJSON(b []byte) (err error) { + req := struct { + To common.Address `json:"to"` + From common.Address `json:"from"` + Nonce *rpc.HexNumber `json:"nonce"` + Value *rpc.HexNumber `json:"value"` + Data string `json:"data"` + GasLimit *rpc.HexNumber `json:"gas"` + GasPrice *rpc.HexNumber `json:"gasPrice"` + Hash common.Hash `json:"hash"` + }{} + + if err := json.Unmarshal(b, &req); err != nil { + return err + } + + contractCreation := (req.To == (common.Address{})) + + tx.To = &req.To + tx.From = req.From + tx.Nonce = req.Nonce + tx.Value = req.Value + tx.Data = req.Data + tx.GasLimit = req.GasLimit + tx.GasPrice = req.GasPrice + tx.Hash = req.Hash + + data := common.Hex2Bytes(tx.Data) + + if tx.Nonce == nil { + return fmt.Errorf("need nonce") + } + if tx.Value == nil { + tx.Value = rpc.NewHexNumber(0) + } + if tx.GasLimit == nil { + tx.GasLimit = rpc.NewHexNumber(0) + } + if tx.GasPrice == nil { + tx.GasPrice = rpc.NewHexNumber(defaultGasPrice) + } + + if contractCreation { + tx.tx = types.NewContractCreation(tx.Nonce.Uint64(), tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data) + } else { + if tx.To == nil { + return fmt.Errorf("need to address") + } + tx.tx = types.NewTransaction(tx.Nonce.Uint64(), *tx.To, tx.Value.BigInt(), tx.GasLimit.BigInt(), tx.GasPrice.BigInt(), data) + } + + return nil +} + +type SignTransactionResult struct { + Raw string `json:"raw"` + Tx *Tx `json:"tx"` +} + +func newTx(t *types.Transaction) *Tx { + from, _ := t.From() + return &Tx{ + tx: t, + To: t.To(), + From: from, + Value: rpc.NewHexNumber(t.Value()), + Nonce: rpc.NewHexNumber(t.Nonce()), + Data: "0x" + common.Bytes2Hex(t.Data()), + GasLimit: rpc.NewHexNumber(t.Gas()), + GasPrice: rpc.NewHexNumber(t.GasPrice()), + Hash: t.Hash(), + } +} + +// SignTransaction will sign the given transaction with the from account. +// The node needs to have the private key of the account corresponding with +// the given from address and it needs to be unlocked. +func (s *PublicTransactionPoolApi) SignTransaction(args *SignTransactionArgs) (*SignTransactionResult, error) { + if args.Gas == nil { + args.Gas = rpc.NewHexNumber(defaultGas) + } + if args.GasPrice == nil { + args.GasPrice = rpc.NewHexNumber(defaultGasPrice) + } + if args.Value == nil { + args.Value = rpc.NewHexNumber(0) + } + + s.txMu.Lock() + defer s.txMu.Unlock() + + if args.Nonce == nil { + args.Nonce = rpc.NewHexNumber(s.txPool.State().GetNonce(args.From)) + } + + var tx *types.Transaction + contractCreation := (args.To == common.Address{}) + + if contractCreation { + tx = types.NewContractCreation(args.Nonce.Uint64(), args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) + } else { + tx = types.NewTransaction(args.Nonce.Uint64(), args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data)) + } + + signedTx, err := s.sign(args.From, tx) + if err != nil { + return nil, err + } + + data, err := rlp.EncodeToBytes(signedTx) + if err != nil { + return nil, err + } + + return &SignTransactionResult{"0x" + common.Bytes2Hex(data), newTx(tx)}, nil +} + +// PendingTransactions returns the transactions that are in the transaction pool and have a from address that is one of +// the accounts this node manages. +func (s *PublicTransactionPoolApi) PendingTransactions() ([]*RPCTransaction, error) { + accounts, err := s.am.Accounts() + if err != nil { + return nil, err + } + + accountSet := set.New() + for _, account := range accounts { + accountSet.Add(account.Address) + } + + pending := s.txPool.GetTransactions() + transactions := make([]*RPCTransaction, 0) + for _, tx := range pending { + if from, _ := tx.From(); accountSet.Has(from) { + transactions = append(transactions, newRPCPendingTransaction(tx)) + } + } + + return transactions, nil +} + +// NewPendingTransaction creates a subscription that is triggered each time a transaction enters the transaction pool +// and is send from one of the transactions this nodes manages. +func (s *PublicTransactionPoolApi) NewPendingTransactions() (rpc.Subscription, error) { + sub := s.eventMux.Subscribe(TxPreEvent{}) + + accounts, err := s.am.Accounts() + if err != nil { + return rpc.Subscription{}, err + } + accountSet := set.New() + for _, account := range accounts { + accountSet.Add(account.Address) + } + accountSetLastUpdates := time.Now() + + output := func(transaction interface{}) interface{} { + if time.Since(accountSetLastUpdates) > (time.Duration(2) * time.Second) { + if accounts, err = s.am.Accounts(); err != nil { + accountSet.Clear() + for _, account := range accounts { + accountSet.Add(account.Address) + } + accountSetLastUpdates = time.Now() + } + } + + tx := transaction.(TxPreEvent) + if from, err := tx.Tx.From(); err == nil { + if accountSet.Has(from) { + return tx.Tx.Hash() + } + } + return nil + } + + return rpc.NewSubscriptionWithOutputFormat(sub, output), nil +} + +// Resend accepts an existing transaction and a new gas price and limit. It will remove the given transaction from the +// pool and reinsert it with the new gas price and limit. +func (s *PublicTransactionPoolApi) Resend(tx *Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) { + + pending := s.txPool.GetTransactions() + for _, p := range pending { + if pFrom, err := p.From(); err == nil && pFrom == tx.From && p.SigHash() == tx.tx.SigHash() { + if gasPrice == nil { + gasPrice = rpc.NewHexNumber(tx.tx.GasPrice()) + } + if gasLimit == nil { + gasLimit = rpc.NewHexNumber(tx.tx.Gas()) + } + + var newTx *types.Transaction + contractCreation := (*tx.tx.To() == common.Address{}) + if contractCreation { + newTx = types.NewContractCreation(tx.tx.Nonce(), tx.tx.Value(), gasPrice.BigInt(), gasLimit.BigInt(), tx.tx.Data()) + } else { + newTx = types.NewTransaction(tx.tx.Nonce(), *tx.tx.To(), tx.tx.Value(), gasPrice.BigInt(), gasLimit.BigInt(), tx.tx.Data()) + } + + signedTx, err := s.sign(tx.From, newTx) + if err != nil { + return common.Hash{}, err + } + + s.txPool.RemoveTx(tx.Hash) + if err = s.txPool.Add(signedTx); err != nil { + return common.Hash{}, err + } + + return signedTx.Hash(), nil + } + } + + return common.Hash{}, fmt.Errorf("Transaction %#x not found", tx.Hash) +} diff --git a/core/types/block.go b/core/types/block.go index 1d1cfa5151..5536e0ea86 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -48,6 +48,10 @@ func (n BlockNonce) Uint64() uint64 { return binary.BigEndian.Uint64(n[:]) } +func (n BlockNonce) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"0x%x"`, n)), nil +} + type Header struct { ParentHash common.Hash // Hash to the previous block UncleHash common.Hash // Uncles of this block diff --git a/core/types/bloom9.go b/core/types/bloom9.go index cd90fd9716..372045ab21 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -69,6 +69,10 @@ func (b Bloom) TestBytes(test []byte) bool { return b.Test(common.BytesToBig(test)) } +func (b Bloom) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"%#x"`, b.Bytes())), nil +} + func CreateBloom(receipts Receipts) Bloom { bin := new(big.Int) for _, receipt := range receipts { diff --git a/core/vm/log.go b/core/vm/log.go index 191e3a2539..a8e73e17b8 100644 --- a/core/vm/log.go +++ b/core/vm/log.go @@ -17,11 +17,13 @@ package vm import ( + "encoding/json" "fmt" "io" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rlp" + rpc "github.com/ethereum/go-ethereum/rpc/v2" ) type Log struct { @@ -63,6 +65,21 @@ func (l *Log) String() string { return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, l.Address, l.Topics, l.Data, l.TxHash, l.TxIndex, l.BlockHash, l.Index) } +func (r *Log) MarshalJSON() ([]byte, error) { + fields := map[string]interface{}{ + "address": r.Address, + "data": fmt.Sprintf("%#x", r.Data), + "blockNumber": rpc.NewHexNumber(r.BlockNumber), + "logIndex": rpc.NewHexNumber(r.Index), + "blockHash": r.BlockHash, + "transactionHash": r.TxHash, + "transactionIndex": rpc.NewHexNumber(r.TxIndex), + "topics": r.Topics, + } + + return json.Marshal(fields) +} + type Logs []*Log // LogForStorage is a wrapper around a Log that flattens and parses the entire diff --git a/eth/api.go b/eth/api.go new file mode 100644 index 0000000000..67f3e3df7d --- /dev/null +++ b/eth/api.go @@ -0,0 +1,266 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package eth + +import ( + "errors" + "math/big" + "time" + + "github.com/ethereum/ethash" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/compiler" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + rpc "github.com/ethereum/go-ethereum/rpc/v2" +) + +// PublicEthereumApi provides an API to access Ethereum related information. +// It offers only methods that operate on public data that is freely available to anyone. +type PublicEthereumApi struct { + e *Ethereum + gpo *GasPriceOracle +} + +// NewPublicEthereumApi creates a new Etheruem protocol API. +func NewPublicEthereumApi(e *Ethereum) *PublicEthereumApi { + return &PublicEthereumApi{e, NewGasPriceOracle(e)} +} + +// GasPrice returns a suggestion for a gas price. +func (s *PublicEthereumApi) GasPrice() *big.Int { + return s.gpo.SuggestPrice() +} + +// GetCompilers returns the collection of available smart contract compilers +func (s *PublicEthereumApi) GetCompilers() ([]string, error) { + solc, err := s.e.Solc() + if err != nil { + return nil, err + } + + if solc != nil { + return []string{"Solidity"}, nil + } + + return nil, nil +} + +// CompileSolidity compiles the given solidity source +func (s *PublicEthereumApi) CompileSolidity(source string) (map[string]*compiler.Contract, error) { + solc, err := s.e.Solc() + if err != nil { + return nil, err + } + + if solc == nil { + return nil, errors.New("solc (solidity compiler) not found") + } + + return solc.Compile(source) +} + +// Etherbase is the address that mining rewards will be send to +func (s *PublicEthereumApi) Etherbase() (common.Address, error) { + return s.e.Etherbase() +} + +// see Etherbase +func (s *PublicEthereumApi) Coinbase() (common.Address, error) { + return s.Etherbase() +} + +// ProtocolVersion returns the current Ethereum protocol version this node supports +func (s *PublicEthereumApi) ProtocolVersion() *rpc.HexNumber { + return rpc.NewHexNumber(s.e.EthVersion()) +} + +// Hashrate returns the POW hashrate +func (s *PublicEthereumApi) Hashrate() *rpc.HexNumber { + return rpc.NewHexNumber(s.e.Miner().HashRate()) +} + +// Syncing returns false in case the node is currently not synching with the network. It can be up to date or has not +// yet received the latest block headers from its pears. In case it is synchronizing an object with 3 properties is +// returned: +// - startingBlock: block number this node started to synchronise from +// - currentBlock: block number this node is currently importing +// - highestBlock: block number of the highest block header this node has received from peers +func (s *PublicEthereumApi) Syncing() (interface{}, error) { + origin, current, height := s.e.Downloader().Progress() + if current < height { + return map[string]interface{}{ + "startingBlock": rpc.NewHexNumber(origin), + "currentBlock": rpc.NewHexNumber(current), + "highestBlock": rpc.NewHexNumber(height), + }, nil + } + return false, nil +} + +// PrivateMinerApi provides private RPC methods to control the miner. +// These methods can be abused by external users and must be considered insecure for use by untrusted users. +type PrivateMinerApi struct { + e *Ethereum +} + +// NewPrivateMinerApi create a new RPC service which controls the miner of this node. +func NewPrivateMinerApi(e *Ethereum) *PrivateMinerApi { + return &PrivateMinerApi{e: e} +} + +// Start the miner with the given number of threads +func (s *PrivateMinerApi) Start(threads rpc.HexNumber) (bool, error) { + s.e.StartAutoDAG() + err := s.e.StartMining(threads.Int(), "") + if err == nil { + return true, nil + } + return false, err +} + +// Stop the miner +func (s *PrivateMinerApi) Stop() bool { + s.e.StopMining() + return true +} + +// SetExtra sets the extra data string that is included when this miner mines a block. +func (s *PrivateMinerApi) SetExtra(extra string) (bool, error) { + if err := s.e.Miner().SetExtra([]byte(extra)); err != nil { + return false, err + } + return true, nil +} + +// SetGasPrice sets the minimum accepted gas price for the miner. +func (s *PrivateMinerApi) SetGasPrice(gasPrice rpc.Number) bool { + s.e.Miner().SetGasPrice(gasPrice.BigInt()) + return true +} + +// SetEtherbase sets the etherbase of the miner +func (s *PrivateMinerApi) SetEtherbase(etherbase common.Address) bool { + s.e.SetEtherbase(etherbase) + return true +} + +// StartAutoDAG starts auto DAG generation. This will prevent the DAG generating on epoch change +// which will cause the node to stop mining during the generation process. +func (s *PrivateMinerApi) StartAutoDAG() bool { + s.e.StartAutoDAG() + return true +} + +// StopAutoDAG stops auto DAG generation +func (s *PrivateMinerApi) StopAutoDAG() bool { + s.e.StopAutoDAG() + return true +} + +// MakeDAG creates the new DAG for the given block number +func (s *PrivateMinerApi) MakeDAG(blockNr rpc.BlockNumber) (bool, error) { + if err := ethash.MakeDAG(uint64(blockNr.Int64()), ""); err != nil { + return false, err + } + return true, nil +} + +// PublicTxPoolApi offers and API for the transaction pool. It only operates on data that is non confidential. +type PublicTxPoolApi struct { + e *Ethereum +} + +// NewPublicTxPoolApi creates a new tx pool service that gives information about the transaction pool. +func NewPublicTxPoolApi(e *Ethereum) *PublicTxPoolApi { + return &PublicTxPoolApi{e} +} + +// Status returns the number of pending and queued transaction in the pool. +func (s *PublicTxPoolApi) Status() map[string]*rpc.HexNumber { + pending, queue := s.e.TxPool().Stats() + return map[string]*rpc.HexNumber{ + "pending": rpc.NewHexNumber(pending), + "queued": rpc.NewHexNumber(queue), + } +} + +// PublicAccountApi provides an API to access accounts managed by this node. +// It offers only methods that can retrieve accounts. +type PublicAccountApi struct { + am *accounts.Manager +} + +// NewPublicAccountApi creates a new PublicAccountApi. +func NewPublicAccountApi(am *accounts.Manager) *PublicAccountApi { + return &PublicAccountApi{am: am} +} + +// Accounts returns the collection of accounts this node manages +func (s *PublicAccountApi) Accounts() ([]accounts.Account, error) { + return s.am.Accounts() +} + +// PrivateAccountApi provides an API to access accounts managed by this node. +// It offers methods to create, (un)lock en list accounts. +type PrivateAccountApi struct { + am *accounts.Manager +} + +// NewPrivateAccountApi create a new PrivateAccountApi. +func NewPrivateAccountApi(am *accounts.Manager) *PrivateAccountApi { + return &PrivateAccountApi{am} +} + +// ListAccounts will return a list of addresses for accounts this node manages. +func (s *PrivateAccountApi) ListAccounts() ([]common.Address, error) { + accounts, err := s.am.Accounts() + if err != nil { + return nil, err + } + + addresses := make([]common.Address, len(accounts)) + for i, acc := range accounts { + addresses[i] = acc.Address + } + return addresses, nil +} + +// NewAccount will create a new account and returns the address for the new account. +func (s *PrivateAccountApi) NewAccount(password string) (common.Address, error) { + acc, err := s.am.NewAccount(password) + if err == nil { + return acc.Address, nil + } + return common.Address{}, err +} + +// UnlockAccount will unlock the account associated with the given address with the given password for duration seconds. +// It returns an indication if the action was successful. +func (s *PrivateAccountApi) UnlockAccount(addr common.Address, password string, duration int) bool { + if err := s.am.TimedUnlock(addr, password, time.Duration(duration)*time.Second); err != nil { + glog.V(logger.Info).Infof("%v\n", err) + return false + } + return true +} + +// LockAccount will lock the account associated with the given address when it's unlocked. +func (s *PrivateAccountApi) LockAccount(addr common.Address) bool { + return s.am.Lock(addr) == nil +} diff --git a/eth/backend.go b/eth/backend.go index 91f02db72a..5755253fae 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/logger" @@ -43,6 +44,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rlp" + rpc "github.com/ethereum/go-ethereum/rpc/v2" ) const ( @@ -239,6 +241,64 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return eth, nil } +// Apis returns the collection of RPC services the ethereum package offers. +// NOTE, some of these services probably need to be moved to somewhere else. +func (s *Ethereum) Apis() []rpc.API { + return []rpc.API{ + rpc.API{ + Namespace: "eth", + Version: "1.0", + Service: NewPublicEthereumApi(s), + Public: true, + }, rpc.API{ + Namespace: "eth", + Version: "1.0", + Service: NewPublicAccountApi(s.AccountManager()), + Public: true, + }, rpc.API{ + Namespace: "personal", + Version: "1.0", + Service: NewPrivateAccountApi(s.AccountManager()), + Public: false, + }, rpc.API{ + Namespace: "eth", + Version: "1.0", + Service: core.NewPublicBlockChainApi(s.BlockChain(), s.AccountManager()), + Public: true, + }, rpc.API{ + Namespace: "eth", + Version: "1.0", + Service: core.NewPublicTransactionPoolApi(s.TxPool(), s.ChainDb(), s.BlockChain(), s.AccountManager()), + Public: true, + }, rpc.API{ + Namespace: "eth", + Version: "1.0", + Service: miner.NewPublicMinerApi(s.Miner()), + Public: true, + }, rpc.API{ + Namespace: "eth", + Version: "1.0", + Service: downloader.NewPublicDownloaderApi(s.Downloader()), + Public: true, + }, rpc.API{ + Namespace: "miner", + Version: "1.0", + Service: NewPrivateMinerApi(s), + Public: false, + }, rpc.API{ + Namespace: "txpool", + Version: "1.0", + Service: NewPublicTxPoolApi(s), + Public: true, + }, rpc.API{ + Namespace: "eth", + Version: "1.0", + Service: filters.NewPublicFilterApi(s.ChainDb(), s.EventMux()), + Public: true, + }, + } +} + func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { s.blockchain.ResetWithGenesisBlock(gb) } diff --git a/eth/downloader/api.go b/eth/downloader/api.go new file mode 100644 index 0000000000..a0064fc2a1 --- /dev/null +++ b/eth/downloader/api.go @@ -0,0 +1,64 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package downloader + +import ( + rpc "github.com/ethereum/go-ethereum/rpc/v2" +) + +// PublicDownloaderApi provides an API which gives informatoin about the current synchronisation status. +// It offers only methods that operates on data that can be available to anyone without security risks. +type PublicDownloaderApi struct { + d *Downloader +} + +// NewPublicDownloaderApi create a new PublicDownloaderApi. +func NewPublicDownloaderApi(d *Downloader) *PublicDownloaderApi { + return &PublicDownloaderApi{d} +} + +// Progress gives progress indications when the node is synchronising with the Ethereum network. +type Progress struct { + Origin uint64 `json:"startingBlock"` + Current uint64 `json:"currentBlock"` + Height uint64 `json:"highestBlock"` +} + +// SyncingResult provides information about the current synchronisation status for this node. +type SyncingResult struct { + Syncing bool `json:"syncing"` + Status Progress `json:"status"` +} + +// Syncing provides information when this nodes starts synchronising with the Ethereumn network and when it's finished. +func (s *PublicDownloaderApi) Syncing() (rpc.Subscription, error) { + sub := s.d.mux.Subscribe(StartEvent{}, DoneEvent{}, FailedEvent{}) + + output := func(event interface{}) interface{} { + switch event.(type) { + case StartEvent: + result := &SyncingResult{Syncing: true} + result.Status.Origin, result.Status.Current, result.Status.Height = s.d.Progress() + return result + case DoneEvent, FailedEvent: + return false + } + return nil + } + + return rpc.NewSubscriptionWithOutputFormat(sub, output), nil +} diff --git a/eth/filters/api.go b/eth/filters/api.go new file mode 100644 index 0000000000..4baa984ca3 --- /dev/null +++ b/eth/filters/api.go @@ -0,0 +1,575 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package filters + +import ( + "sync" + "time" + + "crypto/rand" + "encoding/hex" + "errors" + + "encoding/json" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/event" + rpc "github.com/ethereum/go-ethereum/rpc/v2" +) + +var ( + filterTickerTime = 5 * time.Minute +) + +// byte will be inferred +const ( + unknownFilterTy = iota + blockFilterTy + transactionFilterTy + logFilterTy +) + +// PublicFilterApi offers support to create and manage filters. This will allow externa clients to retrieve various +// information related to the Ethereum protocol such als blocks, transactions and logs. +type PublicFilterApi struct { + mux *event.TypeMux + + quit chan struct{} + chainDb ethdb.Database + + filterManager *FilterSystem + + filterMapMu sync.RWMutex + filterMapping map[string]int // maps between filter internal filter identifiers and external filter identifiers + + logMu sync.RWMutex + logQueue map[int]*logQueue + + blockMu sync.RWMutex + blockQueue map[int]*hashQueue + + transactionMu sync.RWMutex + transactionQueue map[int]*hashQueue + + transactMu sync.Mutex +} + +// NewPublicFilterApi returns a new PublicFilterApi instance. +func NewPublicFilterApi(chainDb ethdb.Database, mux *event.TypeMux) *PublicFilterApi { + svc := &PublicFilterApi{ + mux: mux, + chainDb: chainDb, + filterManager: NewFilterSystem(mux), + filterMapping: make(map[string]int), + logQueue: make(map[int]*logQueue), + blockQueue: make(map[int]*hashQueue), + transactionQueue: make(map[int]*hashQueue), + } + go svc.start() + return svc +} + +// Stop quits the work loop. +func (s *PublicFilterApi) Stop() { + close(s.quit) +} + +// start the work loop, wait and process events. +func (s *PublicFilterApi) start() { + timer := time.NewTicker(2 * time.Second) + defer timer.Stop() +done: + for { + select { + case <-timer.C: + s.logMu.Lock() + for id, filter := range s.logQueue { + if time.Since(filter.timeout) > filterTickerTime { + s.filterManager.Remove(id) + delete(s.logQueue, id) + } + } + s.logMu.Unlock() + + s.blockMu.Lock() + for id, filter := range s.blockQueue { + if time.Since(filter.timeout) > filterTickerTime { + s.filterManager.Remove(id) + delete(s.blockQueue, id) + } + } + s.blockMu.Unlock() + + s.transactionMu.Lock() + for id, filter := range s.transactionQueue { + if time.Since(filter.timeout) > filterTickerTime { + s.filterManager.Remove(id) + delete(s.transactionQueue, id) + } + } + s.transactionMu.Unlock() + case <-s.quit: + break done + } + } + +} + +// NewBlockFilter create a new filter that returns blocks that are included into the canonical chain. +func (s *PublicFilterApi) NewBlockFilter() (string, error) { + externalId, err := newFilterId() + if err != nil { + return "", err + } + + s.blockMu.Lock() + filter := New(s.chainDb) + id := s.filterManager.Add(filter) + s.blockQueue[id] = &hashQueue{timeout: time.Now()} + + filter.BlockCallback = func(block *types.Block, logs vm.Logs) { + s.blockMu.Lock() + defer s.blockMu.Unlock() + + if queue := s.blockQueue[id]; queue != nil { + queue.add(block.Hash()) + } + } + + defer s.blockMu.Unlock() + + s.filterMapMu.Lock() + s.filterMapping[externalId] = id + s.filterMapMu.Unlock() + + return externalId, nil +} + +// NewPendingTransactionFilter creates a filter that returns new pending transactions. +func (s *PublicFilterApi) NewPendingTransactionFilter() (string, error) { + externalId, err := newFilterId() + if err != nil { + return "", err + } + + s.transactionMu.Lock() + defer s.transactionMu.Unlock() + + filter := New(s.chainDb) + id := s.filterManager.Add(filter) + s.transactionQueue[id] = &hashQueue{timeout: time.Now()} + + filter.TransactionCallback = func(tx *types.Transaction) { + s.transactionMu.Lock() + defer s.transactionMu.Unlock() + + if queue := s.transactionQueue[id]; queue != nil { + queue.add(tx.Hash()) + } + } + + s.filterMapMu.Lock() + s.filterMapping[externalId] = id + s.filterMapMu.Unlock() + + return externalId, nil +} + +// newLogFilter creates a new log filter. +func (s *PublicFilterApi) newLogFilter(earliest, latest int64, addresses []common.Address, topics [][]common.Hash) int { + s.logMu.Lock() + defer s.logMu.Unlock() + + filter := New(s.chainDb) + id := s.filterManager.Add(filter) + s.logQueue[id] = &logQueue{timeout: time.Now()} + + filter.SetBeginBlock(earliest) + filter.SetEndBlock(latest) + filter.SetAddresses(addresses) + filter.SetTopics(topics) + filter.LogsCallback = func(logs vm.Logs) { + s.logMu.Lock() + defer s.logMu.Unlock() + + if queue := s.logQueue[id]; queue != nil { + queue.add(logs...) + } + } + + return id +} + +// NewFilterArgs represents a request to create a new filter. +type NewFilterArgs struct { + FromBlock rpc.BlockNumber + ToBlock rpc.BlockNumber + Addresses []common.Address + Topics [][]common.Hash +} + +func (args *NewFilterArgs) UnmarshalJSON(data []byte) error { + type input struct { + From *rpc.BlockNumber `json:"fromBlock"` + ToBlock *rpc.BlockNumber `json:"toBlock"` + Addresses interface{} `json:"address"` + Topics interface{} `json:"topics"` + } + + var raw input + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + + if raw.From == nil { + args.FromBlock = rpc.LatestBlockNumber + } else { + args.FromBlock = *raw.From + } + + if raw.ToBlock == nil { + args.ToBlock = rpc.LatestBlockNumber + } else { + args.ToBlock = *raw.ToBlock + } + + args.Addresses = []common.Address{} + + if raw.Addresses != nil { + // raw.Address can contain a single address or an array of addresses + var addresses []common.Address + + if strAddrs, ok := raw.Addresses.([]interface{}); ok { + for i, addr := range strAddrs { + if strAddr, ok := addr.(string); ok { + if len(strAddr) >= 2 && strAddr[0] == '0' && (strAddr[1] == 'x' || strAddr[1] == 'X') { + strAddr = strAddr[2:] + } + if decAddr, err := hex.DecodeString(strAddr); err == nil { + addresses = append(addresses, common.BytesToAddress(decAddr)) + } else { + fmt.Errorf("invalid address given") + } + } else { + return fmt.Errorf("invalid address on index %d", i) + } + } + } else if singleAddr, ok := raw.Addresses.(string); ok { + if len(singleAddr) >= 2 && singleAddr[0] == '0' && (singleAddr[1] == 'x' || singleAddr[1] == 'X') { + singleAddr = singleAddr[2:] + } + if decAddr, err := hex.DecodeString(singleAddr); err == nil { + addresses = append(addresses, common.BytesToAddress(decAddr)) + } else { + fmt.Errorf("invalid address given") + } + } else { + errors.New("invalid address(es) given") + } + args.Addresses = addresses + } + + topicConverter := func(raw string) (common.Hash, error) { + if len(raw) == 0 { + return common.Hash{}, nil + } + + if len(raw) >= 2 && raw[0] == '0' && (raw[1] == 'x' || raw[1] == 'X') { + raw = raw[2:] + } + + if decAddr, err := hex.DecodeString(raw); err == nil { + return common.BytesToHash(decAddr), nil + } + + return common.Hash{}, errors.New("invalid topic given") + } + + // topics is an array consisting of strings or arrays of strings + if raw.Topics != nil { + topics, ok := raw.Topics.([]interface{}) + if ok { + parsedTopics := make([][]common.Hash, len(topics)) + for i, topic := range topics { + if topic == nil { + parsedTopics[i] = []common.Hash{common.StringToHash("")} + } else if strTopic, ok := topic.(string); ok { + if t, err := topicConverter(strTopic); err != nil { + return fmt.Errorf("invalid topic on index %d", i) + } else { + parsedTopics[i] = []common.Hash{t} + } + } else if arrTopic, ok := topic.([]interface{}); ok { + parsedTopics[i] = make([]common.Hash, len(arrTopic)) + for j := 0; j < len(parsedTopics[i]); i++ { + if arrTopic[j] == nil { + parsedTopics[i][j] = common.StringToHash("") + } else if str, ok := arrTopic[j].(string); ok { + if t, err := topicConverter(str); err != nil { + return fmt.Errorf("invalid topic on index %d", i) + } else { + parsedTopics[i] = []common.Hash{t} + } + } else { + fmt.Errorf("topic[%d][%d] not a string", i, j) + } + } + } else { + return fmt.Errorf("topic[%d] invalid", i) + } + } + args.Topics = parsedTopics + } + } + + return nil +} + +// NewFilter creates a new filter and returns the filter id. It can be uses to retrieve logs. +func (s *PublicFilterApi) NewFilter(args NewFilterArgs) (string, error) { + externalId, err := newFilterId() + if err != nil { + return "", err + } + + var id int + if len(args.Addresses) > 0 { + id = s.newLogFilter(args.FromBlock.Int64(), args.ToBlock.Int64(), args.Addresses, args.Topics) + } else { + id = s.newLogFilter(args.FromBlock.Int64(), args.ToBlock.Int64(), nil, args.Topics) + } + + s.filterMapMu.Lock() + s.filterMapping[externalId] = id + s.filterMapMu.Unlock() + + return externalId, nil +} + +// GetLogs returns the logs matching the given argument. +func (s *PublicFilterApi) GetLogs(args NewFilterArgs) vm.Logs { + filter := New(s.chainDb) + filter.SetBeginBlock(args.FromBlock.Int64()) + filter.SetEndBlock(args.ToBlock.Int64()) + filter.SetAddresses(args.Addresses) + filter.SetTopics(args.Topics) + + return returnLogs(filter.Find()) +} + +// UninstallFilter removes the filter with the given filter id. +func (s *PublicFilterApi) UninstallFilter(filterId string) bool { + s.filterMapMu.Lock() + defer s.filterMapMu.Unlock() + + id, ok := s.filterMapping[filterId] + if !ok { + return false + } + + defer s.filterManager.Remove(id) + delete(s.filterMapping, filterId) + + if _, ok := s.logQueue[id]; ok { + s.logMu.Lock() + defer s.logMu.Unlock() + delete(s.logQueue, id) + return true + } + if _, ok := s.blockQueue[id]; ok { + s.blockMu.Lock() + defer s.blockMu.Unlock() + delete(s.blockQueue, id) + return true + } + if _, ok := s.transactionQueue[id]; ok { + s.transactionMu.Lock() + defer s.transactionMu.Unlock() + delete(s.transactionQueue, id) + return true + } + + return false +} + +// getFilterType is a helper utility that determine the type of filter for the given filter id. +func (s *PublicFilterApi) getFilterType(id int) byte { + if _, ok := s.blockQueue[id]; ok { + return blockFilterTy + } else if _, ok := s.transactionQueue[id]; ok { + return transactionFilterTy + } else if _, ok := s.logQueue[id]; ok { + return logFilterTy + } + + return unknownFilterTy +} + +// blockFilterChanged returns a collection of block hashes for the block filter with the given id. +func (s *PublicFilterApi) blockFilterChanged(id int) []common.Hash { + s.blockMu.Lock() + defer s.blockMu.Unlock() + + if s.blockQueue[id] != nil { + return s.blockQueue[id].get() + } + return nil +} + +// transactionFilterChanged returns a collection of transaction hashes for the pending +// transaction filter with the given id. +func (s *PublicFilterApi) transactionFilterChanged(id int) []common.Hash { + s.blockMu.Lock() + defer s.blockMu.Unlock() + + if s.transactionQueue[id] != nil { + return s.transactionQueue[id].get() + } + return nil +} + +// logFilterChanged returns a collection of logs for the log filter with the given id. +func (s *PublicFilterApi) logFilterChanged(id int) vm.Logs { + s.logMu.Lock() + defer s.logMu.Unlock() + + if s.logQueue[id] != nil { + return s.logQueue[id].get() + } + return nil +} + +// GetFilterLogs returns the logs for the filter with the given id. +func (s *PublicFilterApi) GetFilterLogs(filterId string) vm.Logs { + id, ok := s.filterMapping[filterId] + if !ok { + return returnLogs(nil) + } + + if filter := s.filterManager.Get(id); filter != nil { + return returnLogs(filter.Find()) + } + + return returnLogs(nil) +} + +// GetFilterChanges returns the logs for the filter with the given id since last time is was called. +// This can be used for polling. +func (s *PublicFilterApi) GetFilterChanges(filterId string) interface{} { + s.filterMapMu.Lock() + id, ok := s.filterMapping[filterId] + s.filterMapMu.Unlock() + + if !ok { // filter not found + return []interface{}{} + } + + switch s.getFilterType(id) { + case blockFilterTy: + return returnHashes(s.blockFilterChanged(id)) + case transactionFilterTy: + return returnHashes(s.transactionFilterChanged(id)) + case logFilterTy: + return returnLogs(s.logFilterChanged(id)) + } + + return []interface{}{} +} + +type logQueue struct { + mu sync.Mutex + + logs vm.Logs + timeout time.Time + id int +} + +func (l *logQueue) add(logs ...*vm.Log) { + l.mu.Lock() + defer l.mu.Unlock() + + l.logs = append(l.logs, logs...) +} + +func (l *logQueue) get() vm.Logs { + l.mu.Lock() + defer l.mu.Unlock() + + l.timeout = time.Now() + tmp := l.logs + l.logs = nil + return tmp +} + +type hashQueue struct { + mu sync.Mutex + + hashes []common.Hash + timeout time.Time + id int +} + +func (l *hashQueue) add(hashes ...common.Hash) { + l.mu.Lock() + defer l.mu.Unlock() + + l.hashes = append(l.hashes, hashes...) +} + +func (l *hashQueue) get() []common.Hash { + l.mu.Lock() + defer l.mu.Unlock() + + l.timeout = time.Now() + tmp := l.hashes + l.hashes = nil + return tmp +} + +// newFilterId generates a new random filter identifier that can be exposed to the outer world. By publishing random +// identifiers it is not feasible for DApp's to guess filter id's for other DApp's and uninstall or poll for them +// causing the affected DApp to miss data. +func newFilterId() (string, error) { + var subid [16]byte + n, _ := rand.Read(subid[:]) + if n != 16 { + return "", errors.New("Unable to generate filter id") + } + return "0x" + hex.EncodeToString(subid[:]), nil +} + +// returnLogs is a helper that will return an empty logs array case the given logs is nil, otherwise is will return the +// given logs. The RPC interfaces defines that always an array is returned. +func returnLogs(logs vm.Logs) vm.Logs { + if logs == nil { + return vm.Logs{} + } + return logs +} + +// returnHashes is a helper that will return an empty hash array case the given hash array is nil, otherwise is will +// return the given hashes. The RPC interfaces defines that always an array is returned. +func returnHashes(hashes []common.Hash) []common.Hash { + if hashes == nil { + return []common.Hash{} + } + return hashes +} diff --git a/miner/miner_rpc.go b/miner/miner_rpc.go new file mode 100644 index 0000000000..37b3ea5e42 --- /dev/null +++ b/miner/miner_rpc.go @@ -0,0 +1,72 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package miner + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/logger/glog" + rpc "github.com/ethereum/go-ethereum/rpc/v2" +) + +// PublicMinerApi provides an API to control the miner. +// It offers only methods that operate on data that pose no security risk when it is publicly accessible. +type PublicMinerApi struct { + miner *Miner + agent *RemoteAgent +} + +// NewPublicMinerApi create a new PublicMinerApi instance. +func NewPublicMinerApi(miner *Miner) *PublicMinerApi { + return &PublicMinerApi{miner, NewRemoteAgent()} +} + +// Mining returns an indication if this node is currently mining. +func (s *PublicMinerApi) Mining() bool { + return s.miner.Mining() +} + +// SubmitWork can be used by external miner to submit their POW solution. It returns an indication if the work was +// accepted. Note, this is not an indication if the provided work was valid! +func (s *PublicMinerApi) SubmitWork(nonce rpc.HexNumber, solution, digest common.Hash) bool { + return s.agent.SubmitWork(nonce.Uint64(), digest, solution) +} + +// GetWork returns a work package for external miner. The work package consists of 3 strings +// result[0], 32 bytes hex encoded current block header pow-hash +// result[1], 32 bytes hex encoded seed hash used for DAG +// result[2], 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty +func (s *PublicMinerApi) GetWork() ([]string, error) { + if !s.Mining() { + s.miner.Start(s.miner.coinbase, 0) + } + if work, err := s.agent.GetWork(); err == nil { + return work[:], nil + } else { + glog.Infof("%v\n", err) + } + return nil, fmt.Errorf("mining not ready") +} + +// SubmitHashrate can be used for remote miners to submit their hash rate. This enables the node to report the combined +// hash rate of all miners which submit work through this node. It accepts the miner hash rate and an identifier which +// must be unique between nodes. +func (s *PublicMinerApi) SubmitHashrate(hashrate rpc.HexNumber, id common.Hash) bool { + s.agent.SubmitHashrate(id, hashrate.Uint64()) + return true +} diff --git a/miner/worker.go b/miner/worker.go index 754a6fc483..1a411ae20b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -327,6 +327,7 @@ func (self *worker) wait() { go func(block *types.Block, logs vm.Logs, receipts []*types.Receipt) { self.mux.Post(core.NewMinedBlockEvent{block}) self.mux.Post(core.ChainEvent{block, block.Hash(), logs}) + if stat == core.CanonStatTy { self.mux.Post(core.ChainHeadEvent{block}) self.mux.Post(logs) diff --git a/node/node.go b/node/node.go index 5566bc44bf..da37982730 100644 --- a/node/node.go +++ b/node/node.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/p2p" + rpc "github.com/ethereum/go-ethereum/rpc/v2" ) var ( @@ -264,3 +265,12 @@ func (n *Node) DataDir() string { func (n *Node) EventMux() *event.TypeMux { return n.eventmux } + +// RPCApis returns the collection of RPC descriptor this node offers +func (n *Node) RPCApis() []rpc.API { + var apis []rpc.API + for _, api := range n.services { + apis = append(apis, api.Apis()...) + } + return apis +} diff --git a/node/node_example_test.go b/node/node_example_test.go index 2f9b49a56d..d73b847c0e 100644 --- a/node/node_example_test.go +++ b/node/node_example_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/discover" + rpc "github.com/ethereum/go-ethereum/rpc/v2" ) // SampleService is a trivial network service that can be attached to a node for @@ -35,6 +36,7 @@ import ( type SampleService struct{} func (s *SampleService) Protocols() []p2p.Protocol { return nil } +func (s *SampleService) Apis() []rpc.API { return nil } func (s *SampleService) Start(*p2p.Server) error { fmt.Println("Service starting..."); return nil } func (s *SampleService) Stop() error { fmt.Println("Service stopping..."); return nil } diff --git a/node/service.go b/node/service.go index bfeeb7ab98..85d736191e 100644 --- a/node/service.go +++ b/node/service.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/p2p" + rpc "github.com/ethereum/go-ethereum/rpc/v2" ) // ServiceContext is a collection of service independent options inherited from @@ -70,6 +71,9 @@ type Service interface { // Protocol retrieves the P2P protocols the service wishes to start. Protocols() []p2p.Protocol + // Apis retrieves the list of RPC descriptors the service provides + Apis() []rpc.API + // Start is called after all services have been constructed and the networking // layer was also initialized to spawn any goroutines required by the service. Start(server *p2p.Server) error diff --git a/node/utils_test.go b/node/utils_test.go index 756622c863..3fc046d21f 100644 --- a/node/utils_test.go +++ b/node/utils_test.go @@ -23,12 +23,14 @@ import ( "reflect" "github.com/ethereum/go-ethereum/p2p" + rpc "github.com/ethereum/go-ethereum/rpc/v2" ) // NoopService is a trivial implementation of the Service interface. type NoopService struct{} func (s *NoopService) Protocols() []p2p.Protocol { return nil } +func (s *NoopService) Apis() []rpc.API { return nil } func (s *NoopService) Start(*p2p.Server) error { return nil } func (s *NoopService) Stop() error { return nil } @@ -67,6 +69,10 @@ func (s *InstrumentedService) Protocols() []p2p.Protocol { return s.protocols } +func (s *InstrumentedService) Apis() []rpc.API { + return nil +} + func (s *InstrumentedService) Start(server *p2p.Server) error { if s.startHook != nil { s.startHook(server) diff --git a/rpc/api/mergedapi.go b/rpc/api/mergedapi.go index 8f4ef8e603..92e1e2bb77 100644 --- a/rpc/api/mergedapi.go +++ b/rpc/api/mergedapi.go @@ -39,9 +39,11 @@ func newMergedApi(apis ...shared.EthereumApi) *MergedApi { mergedApi.methods = make(map[string]shared.EthereumApi) for _, api := range apis { - mergedApi.apis[api.Name()] = api.ApiVersion() - for _, method := range api.Methods() { - mergedApi.methods[method] = api + if api != nil { + mergedApi.apis[api.Name()] = api.ApiVersion() + for _, method := range api.Methods() { + mergedApi.methods[method] = api + } } } return mergedApi diff --git a/rpc/api/personal_js.go b/rpc/api/personal_js.go index 81c5d4a366..84c669af7b 100644 --- a/rpc/api/personal_js.go +++ b/rpc/api/personal_js.go @@ -33,6 +33,11 @@ web3._extend({ call: 'personal_unlockAccount', params: 3, inputFormatter: [null, null, null] + }), + new web3._extend.Method({ + name: 'lockAccount', + call: 'personal_lockAccount', + params: 1 }) ], properties: diff --git a/rpc/api/utils.go b/rpc/api/utils.go index d6820cd2ef..794b6abeea 100644 --- a/rpc/api/utils.go +++ b/rpc/api/utils.go @@ -191,6 +191,8 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, stack *no 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) } diff --git a/rpc/comms/ipc.go b/rpc/comms/ipc.go index 882d62ab49..3ba747b1de 100644 --- a/rpc/comms/ipc.go +++ b/rpc/comms/ipc.go @@ -69,13 +69,28 @@ func (self *ipcClient) SupportedModules() (map[string]string, error) { req := shared.Request{ Id: 1, Jsonrpc: "2.0", - Method: "modules", + 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 @@ -108,6 +123,11 @@ func StartIpc(cfg IpcConfig, codec codec.Codec, initializer InitFunc) error { 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) diff --git a/rpc/jeth.go b/rpc/jeth.go index 1260a34042..de7dd1e762 100644 --- a/rpc/jeth.go +++ b/rpc/jeth.go @@ -54,6 +54,78 @@ func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface return res } +// UnlockAccount asks the user for the password and than executes the jeth.UnlockAccount callback in the jsre +func (self *Jeth) UnlockAccount(call otto.FunctionCall) (response otto.Value) { + var cmd, account, passwd string + timeout := int64(300) + var ok bool + + if len(call.ArgumentList) == 0 { + fmt.Println("expected address of account to unlock") + return otto.FalseValue() + } + + if len(call.ArgumentList) >= 1 { + if accountExport, err := call.Argument(0).Export(); err == nil { + if account, ok = accountExport.(string); ok { + if len(call.ArgumentList) == 1 { + fmt.Printf("Unlock account %s\n", account) + passwd, err = utils.PromptPassword("Passphrase: ", true) + if err != nil { + return otto.FalseValue() + } + } + } + } + } + if len(call.ArgumentList) >= 2 { + if passwdExport, err := call.Argument(1).Export(); err == nil { + passwd, _ = passwdExport.(string) + } + } + + if len(call.ArgumentList) >= 3 { + if timeoutExport, err := call.Argument(2).Export(); err == nil { + timeout, _ = timeoutExport.(int64) + } + } + + cmd = fmt.Sprintf("jeth.unlockAccount('%s', '%s', %d)", account, passwd, timeout) + if val, err := call.Otto.Run(cmd); err == nil { + return val + } + + return otto.FalseValue() +} + +// 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) { + if len(call.ArgumentList) == 0 { + passwd, err := utils.PromptPassword("Passphrase: ", true) + if err != nil { + return otto.FalseValue() + } + passwd2, err := utils.PromptPassword("Repeat passphrase: ", true) + if err != nil { + return otto.FalseValue() + } + + if passwd != passwd2 { + fmt.Println("Passphrases don't match") + return otto.FalseValue() + } + + cmd := fmt.Sprintf("jeth.newAccount('%s')", passwd) + if val, err := call.Otto.Run(cmd); err == nil { + return val + } + } else { + fmt.Println("New account doesn't expect argument(s), you will be prompted for a password") + } + + return otto.FalseValue() +} + func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) { reqif, err := call.Argument(0).Export() if err != nil { diff --git a/rpc/v2/doc.go b/rpc/v2/doc.go new file mode 100644 index 0000000000..e51494adb0 --- /dev/null +++ b/rpc/v2/doc.go @@ -0,0 +1,102 @@ +// 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 . + +/* +Package rpc provides access to the exported methods of an object across a network +or other I/O connection. After creating a server instance objects can be registered, +making it visible from the outside. Exported methods that follow specific +conventions can be called remotely. It also has support for the publish/subscribe +pattern. + +Methods that satisfy the following criteria are made available for remote access: + - object must be exported + - method must be exported + - method returns 0, 1 (response or error) or 2 (response and error) values + - method argument(s) must be exported or builtin types + - method returned value(s) must be exported or builtin types + +An example method: + func (s *CalcService) Div(a, b int) (int, error) + +When the returned error isn't nil the returned integer is ignored and the error is +send back to the client. Otherwise the returned integer is send back to the client. + +The server offers the ServeCodec method which accepts a ServerCodec instance. It will +read requests from the codec, process the request and sends the response back to the +client using the codec. The server can execute requests concurrently. Responses +can be send back to the client out of order. + +An example server which uses the JSON codec: + type CalculatorService struct {} + + func (s *CalculatorService) Add(a, b int) int { + return a + b + } + + func (s *CalculatorService Div(a, b int) (int, error) { + if b == 0 { + return 0, errors.New("divide by zero") + } + return a/b, nil + } + + calculator := new(CalculatorService) + server := NewServer() + server.RegisterName("calculator", calculator") + + l, _ := net.ListenUnix("unix", &net.UnixAddr{Net: "unix", Name: "/tmp/calculator.sock"}) + for { + c, _ := l.AcceptUnix() + codec := v2.NewJSONCodec(c) + go server.ServeCodec(codec) + } + +The package also supports the publish subscribe pattern through the use of subscriptions. +A method that is considered eligible for notifications must satisfy the following criteria: + - object must be exported + - method must be exported + - method argument(s) must be exported or builtin types + - method must return the tuple Subscription, error + + +An example method: + func (s *BlockChainService) Head() (Subscription, error) { + sub := s.bc.eventMux.Subscribe(ChainHeadEvent{}) + return v2.NewSubscription(sub), nil + } + +This method will push all raised ChainHeadEvents to subscribed clients. If the client is only +interested in every N'th block it is possible to add a criteria. + + func (s *BlockChainService) HeadFiltered(nth uint64) (Subscription, error) { + sub := s.bc.eventMux.Subscribe(ChainHeadEvent{}) + + criteria := func(event interface{}) bool { + chainHeadEvent := event.(ChainHeadEvent) + if chainHeadEvent.Block.NumberU64() % nth == 0 { + return true + } + return false + } + + return v2.NewSubscriptionFiltered(sub, criteria), nil + } + +Subscriptions are deleted when: + - the user sends an unsubscribe request + - the connection which was used to create the subscription is closed +*/ +package v2 diff --git a/rpc/v2/errors.go b/rpc/v2/errors.go new file mode 100644 index 0000000000..a06d19d84c --- /dev/null +++ b/rpc/v2/errors.go @@ -0,0 +1,85 @@ +// 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 . + +package v2 + +import "fmt" + +// request is for an unknown service +type methodNotFoundError struct { + service string + method string +} + +func (e *methodNotFoundError) Code() int { + return -32601 +} + +func (e *methodNotFoundError) Error() string { + return fmt.Sprintf("The method %s%s%s does not exist/is not available", e.service, serviceMethodSeparator, e.method) +} + +// received message isn't a valid request +type invalidRequestError struct { + message string +} + +func (e *invalidRequestError) Code() int { + return -32600 +} + +func (e *invalidRequestError) Error() string { + return e.message +} + +// received message is invalid +type invalidMessageError struct { + message string +} + +func (e *invalidMessageError) Code() int { + return -32700 +} + +func (e *invalidMessageError) Error() string { + return e.message +} + +// unable to decode supplied params, or an invalid number of parameters +type invalidParamsError struct { + message string +} + +func (e *invalidParamsError) Code() int { + return -32602 +} + +func (e *invalidParamsError) Error() string { + return e.message +} + +// logic error, callback returned an error +type callbackError struct { + message string +} + +func (e *callbackError) Code() int { + return -32000 +} + +func (e *callbackError) Error() string { + return e.message +} diff --git a/rpc/v2/json.go b/rpc/v2/json.go new file mode 100644 index 0000000000..54f2899e26 --- /dev/null +++ b/rpc/v2/json.go @@ -0,0 +1,336 @@ +// 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 . + +package v2 + +import ( + "encoding/json" + "fmt" + "io" + "reflect" + "strings" + "sync/atomic" + + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +const ( + jsonRPCVersion = "2.0" + serviceMethodSeparator = "_" + subscribeMethod = "eth_subscribe" + unsubscribeMethod = "eth_unsubscribe" + notificationMethod = "eth_subscription" +) + +// JSON-RPC request +type jsonRequest struct { + Method string `json:"method"` + Version string `json:"jsonrpc"` + Id int64 `json:"id"` + Payload json.RawMessage `json:"params"` +} + +// JSON-RPC response +type jsonSuccessResponse struct { + Version string `json:"jsonrpc"` + Id int64 `json:"id"` + Result interface{} `json:"result,omitempty"` +} + +// JSON-RPC error object +type jsonError struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data,omitempty"` +} + +// JSON-RPC error response +type jsonErrResponse struct { + Version string `json:"jsonrpc"` + Id *int64 `json:"id,omitempty"` + Error jsonError `json:"error"` +} + +// JSON-RPC notification payload +type jsonSubscription struct { + Subscription string `json:"subscription"` + Result interface{} `json:"result,omitempty"` +} + +// JSON-RPC notification +type jsonNotification struct { + Version string `json:"jsonrpc"` + Method string `json:"method"` + Params jsonSubscription `json:"params"` +} + +// jsonCodec reads and writes JSON-RPC messages to the underlying connection. It also has support for parsing arguments +// and serializing (result) objects. +type jsonCodec struct { + closed chan interface{} + isClosed int32 + d *json.Decoder + e *json.Encoder + req jsonRequest + rw io.ReadWriteCloser +} + +// NewJSONCodec creates a new RPC server codec with support for JSON-RPC 2.0 +func NewJSONCodec(rwc io.ReadWriteCloser) ServerCodec { + d := json.NewDecoder(rwc) + d.UseNumber() + return &jsonCodec{closed: make(chan interface{}), d: d, e: json.NewEncoder(rwc), rw: rwc, isClosed: 0} +} + +// isBatch returns true when the first non-whitespace characters is '[' +func isBatch(msg json.RawMessage) bool { + for _, c := range msg { + // skip insignificant whitespace (http://www.ietf.org/rfc/rfc4627.txt) + if c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d { + continue + } + return c == '[' + } + return false +} + +// ReadRequestHeaders will read new requests without parsing the arguments. It will return a collection of requests, an +// indication if these requests are in batch form or an error when the incoming message could not be read/parsed. +func (c *jsonCodec) ReadRequestHeaders() ([]rpcRequest, bool, RPCError) { + var incomingMsg json.RawMessage + if err := c.d.Decode(&incomingMsg); err != nil { + return nil, false, &invalidRequestError{err.Error()} + } + + if isBatch(incomingMsg) { + return parseBatchRequest(incomingMsg) + } + + return parseRequest(incomingMsg) +} + +// parseRequest will parse a single request from the given RawMessage. It will return the parsed request, an indication +// if the request was a batch or an error when the request could not be parsed. +func parseRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, RPCError) { + var in jsonRequest + if err := json.Unmarshal(incomingMsg, &in); err != nil { + return nil, false, &invalidMessageError{err.Error()} + } + + // subscribe are special, they will always use `subscribeMethod` as service method + if in.Method == subscribeMethod { + reqs := []rpcRequest{rpcRequest{id: in.Id, isPubSub: true}} + if len(in.Payload) > 0 { + // first param must be subscription name + var subscribeMethod [1]string + if err := json.Unmarshal(in.Payload, &subscribeMethod); err != nil { + glog.V(logger.Debug).Infof("Unable to parse subscription method: %v\n", err) + return nil, false, &invalidRequestError{"Unable to parse subscription request"} + } + + // all subscriptions are made on the eth service + reqs[0].service, reqs[0].method = "eth", subscribeMethod[0] + reqs[0].params = in.Payload + return reqs, false, nil + } + return nil, false, &invalidRequestError{"Unable to parse subscription request"} + } + + if in.Method == unsubscribeMethod { + return []rpcRequest{rpcRequest{id: in.Id, isPubSub: true, + method: unsubscribeMethod, params: in.Payload}}, false, nil + } + + // regular RPC call + elems := strings.Split(in.Method, serviceMethodSeparator) + if len(elems) != 2 { + return nil, false, &methodNotFoundError{in.Method, ""} + } + + if len(in.Payload) == 0 { + return []rpcRequest{rpcRequest{service: elems[0], method: elems[1], id: in.Id}}, false, nil + } + + return []rpcRequest{rpcRequest{service: elems[0], method: elems[1], id: in.Id, params: in.Payload}}, false, nil +} + +// parseBatchRequest will parse a batch request into a collection of requests from the given RawMessage, an indication +// if the request was a batch or an error when the request could not be read. +func parseBatchRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, RPCError) { + var in []jsonRequest + if err := json.Unmarshal(incomingMsg, &in); err != nil { + return nil, false, &invalidMessageError{err.Error()} + } + + requests := make([]rpcRequest, len(in)) + for i, r := range in { + // (un)subscribe are special, they will always use the same service.method + if r.Method == subscribeMethod { + requests[i] = rpcRequest{id: r.Id, isPubSub: true} + if len(r.Payload) > 0 { + var subscribeMethod [1]string + if err := json.Unmarshal(r.Payload, &subscribeMethod); err != nil { + glog.V(logger.Debug).Infof("Unable to parse subscription method: %v\n", err) + return nil, false, &invalidRequestError{"Unable to parse subscription request"} + } + + // all subscriptions are made on the eth service + requests[i].service, requests[i].method = "eth", subscribeMethod[0] + requests[i].params = r.Payload + continue + } + + return nil, true, &invalidRequestError{"Unable to parse (un)subscribe request arguments"} + } + + if r.Method == unsubscribeMethod { + requests[i] = rpcRequest{id: r.Id, isPubSub: true, method: unsubscribeMethod, params: r.Payload} + continue + } + + elems := strings.Split(r.Method, serviceMethodSeparator) + if len(elems) != 2 { + return nil, true, &methodNotFoundError{r.Method, ""} + } + + if len(r.Payload) == 0 { + requests[i] = rpcRequest{service: elems[0], method: elems[1], id: r.Id, params: nil} + } else { + requests[i] = rpcRequest{service: elems[0], method: elems[1], id: r.Id, params: r.Payload} + } + } + + return requests, true, nil +} + +// ParseRequestArguments tries to parse the given params (json.RawMessage) with the given types. It returns the parsed +// values or an error when the parsing failed. +func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interface{}) ([]reflect.Value, RPCError) { + if args, ok := params.(json.RawMessage); !ok { + return nil, &invalidParamsError{"Invalid params supplied"} + } else { + return parsePositionalArguments(args, argTypes) + } +} + +func countArguments(args json.RawMessage) (int, error) { + var cnt []interface{} + if err := json.Unmarshal(args, &cnt); err != nil { + return -1, nil + } + return len(cnt), nil +} + +// parsePositionalArguments tries to parse the given args to an array of values with the given types. It returns the +// parsed values or an error when the args could not be parsed. +func parsePositionalArguments(args json.RawMessage, argTypes []reflect.Type) ([]reflect.Value, RPCError) { + argValues := make([]reflect.Value, len(argTypes)) + params := make([]interface{}, len(argTypes)) + + n, err := countArguments(args) + if err != nil { + return nil, &invalidParamsError{err.Error()} + } + if n != len(argTypes) { + return nil, &invalidParamsError{fmt.Sprintf("insufficient params, want %d have %d", len(argTypes), n)} + + } + + for i, t := range argTypes { + if t.Kind() == reflect.Ptr { + // values must be pointers for the Unmarshal method, reflect. + // Dereference otherwise reflect.New would create **SomeType + argValues[i] = reflect.New(t.Elem()) + params[i] = argValues[i].Interface() + + // when not specified blockNumbers are by default latest (-1) + if blockNumber, ok := params[i].(*BlockNumber); ok { + *blockNumber = BlockNumber(-1) + } + } else { + argValues[i] = reflect.New(t) + params[i] = argValues[i].Interface() + + // when not specified blockNumbers are by default latest (-1) + if blockNumber, ok := params[i].(*BlockNumber); ok { + *blockNumber = BlockNumber(-1) + } + } + } + + if err := json.Unmarshal(args, ¶ms); err != nil { + return nil, &invalidParamsError{err.Error()} + } + + // Convert pointers back to values where necessary + for i, a := range argValues { + if a.Kind() != argTypes[i].Kind() { + argValues[i] = reflect.Indirect(argValues[i]) + } + } + + return argValues, nil +} + +// CreateResponse will create a JSON-RPC success response with the given id and reply as result. +func (c *jsonCodec) CreateResponse(id int64, reply interface{}) interface{} { + if isHexNum(reflect.TypeOf(reply)) { + return &jsonSuccessResponse{Version: jsonRPCVersion, Id: id, Result: fmt.Sprintf(`%#x`, reply)} + } + return &jsonSuccessResponse{Version: jsonRPCVersion, Id: id, Result: reply} +} + +// CreateErrorResponse will create a JSON-RPC error response with the given id and error. +func (c *jsonCodec) CreateErrorResponse(id *int64, err RPCError) interface{} { + return &jsonErrResponse{Version: jsonRPCVersion, Id: id, Error: jsonError{Code: err.Code(), Message: err.Error()}} +} + +// CreateErrorResponseWithInfo will create a JSON-RPC error response with the given id and error. +// info is optional and contains additional information about the error. When an empty string is passed it is ignored. +func (c *jsonCodec) CreateErrorResponseWithInfo(id *int64, err RPCError, info interface{}) interface{} { + return &jsonErrResponse{Version: jsonRPCVersion, Id: id, + Error: jsonError{Code: err.Code(), Message: err.Error(), Data: info}} +} + +// CreateNotification will create a JSON-RPC notification with the given subscription id and event as params. +func (c *jsonCodec) CreateNotification(subid string, event interface{}) interface{} { + if isHexNum(reflect.TypeOf(event)) { + return &jsonNotification{Version: jsonRPCVersion, Method: notificationMethod, + Params: jsonSubscription{Subscription: subid, Result: fmt.Sprintf(`%#x`, event)}} + } + + return &jsonNotification{Version: jsonRPCVersion, Method: notificationMethod, + Params: jsonSubscription{Subscription: subid, Result: event}} +} + +// Write message to client +func (c *jsonCodec) Write(res interface{}) error { + return c.e.Encode(res) +} + +// Close the underlying connection +func (c *jsonCodec) Close() { + if atomic.CompareAndSwapInt32(&c.isClosed, 0, 1) { + close(c.closed) + c.rw.Close() + } +} + +// Closed returns a channel which will be closed when Close is called +func (c *jsonCodec) Closed() <-chan interface{} { + return c.closed +} diff --git a/rpc/v2/json_test.go b/rpc/v2/json_test.go new file mode 100644 index 0000000000..dc8a345d7f --- /dev/null +++ b/rpc/v2/json_test.go @@ -0,0 +1,73 @@ +package v2 + +import ( + "bufio" + "bytes" + "reflect" + "testing" +) + +type RWC struct { + *bufio.ReadWriter +} + +func (rwc *RWC) Close() error { + return nil +} + +func TestJSONRequestParsing(t *testing.T) { + server := NewServer() + service := new(Service) + + if err := server.RegisterName("calc", service); err != nil { + t.Fatalf("%v", err) + } + + req := bytes.NewBufferString(`{"id": 1234, "jsonrpc": "2.0", "method": "calc_add", "params": [11, 22]}`) + var str string + reply := bytes.NewBufferString(str) + rw := &RWC{bufio.NewReadWriter(bufio.NewReader(req), bufio.NewWriter(reply))} + + codec := NewJSONCodec(rw) + + requests, batch, err := codec.ReadRequestHeaders() + if err != nil { + t.Fatalf("%v", err) + } + + if batch { + t.Fatalf("Request isn't a batch") + } + + if len(requests) != 1 { + t.Fatalf("Expected 1 request but got %d requests - %v", len(requests), requests) + } + + if requests[0].service != "calc" { + t.Fatalf("Expected service 'calc' but got '%s'", requests[0].service) + } + + if requests[0].method != "add" { + t.Fatalf("Expected method 'Add' but got '%s'", requests[0].method) + } + + if requests[0].id != 1234 { + t.Fatalf("Expected id 1234 but got %d", requests[0].id) + } + + var arg int + args := []reflect.Type{reflect.TypeOf(arg), reflect.TypeOf(arg)} + + v, err := codec.ParseRequestArguments(args, requests[0].params) + if err != nil { + t.Fatalf("%v", err) + } + + if len(v) != 2 { + t.Fatalf("Expected 2 argument values, got %d", len(v)) + } + + if v[0].Int() != 11 || v[1].Int() != 22 { + t.Fatalf("expected %d == 11 && %d == 22", v[0].Int(), v[1].Int()) + } +} diff --git a/rpc/v2/server.go b/rpc/v2/server.go new file mode 100644 index 0000000000..9dcd5f8e2d --- /dev/null +++ b/rpc/v2/server.go @@ -0,0 +1,459 @@ +// 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 . + +package v2 + +import ( + "fmt" + "reflect" + + "runtime" + + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +// NewServer will create a new server instance with no registered handlers. +func NewServer() *Server { + server := &Server{services: make(serviceRegistry), subscriptions: make(subscriptionRegistry)} + + // register a default service which will provide meta information about the RPC service such as the services and + // methods it offers. + rpcService := &RPCService{server} + server.RegisterName("rpc", rpcService) + + return server +} + +// RPCService gives meta information about the server. +// e.g. gives information about the loaded modules. +type RPCService struct { + server *Server +} + +// Modules returns the list of RPC services with their version number +func (s *RPCService) Modules() map[string]string { + modules := make(map[string]string) + for name, _ := range s.server.services { + modules[name] = "1.0" + } + return modules +} + +// RegisterName will create an service for the given rcvr type under the given name. When no methods on the given rcvr +// match the criteria to be either a RPC method or a subscription an error is returned. Otherwise a new service is +// created and added to the service collection this server instance serves. +func (s *Server) RegisterName(name string, rcvr interface{}) error { + if s.services == nil { + s.services = make(serviceRegistry) + } + + svc := new(service) + svc.typ = reflect.TypeOf(rcvr) + rcvrVal := reflect.ValueOf(rcvr) + + if name == "" { + return fmt.Errorf("no service name for type %s", svc.typ.String()) + } + if !isExported(reflect.Indirect(rcvrVal).Type().Name()) { + return fmt.Errorf("%s is not exported", reflect.Indirect(rcvrVal).Type().Name()) + } + + // already a previous service register under given sname, merge methods/subscriptions + if regsvc, present := s.services[name]; present { + methods, subscriptions := suitableCallbacks(rcvrVal, svc.typ) + if len(methods) == 0 && len(subscriptions) == 0 { + return fmt.Errorf("Service doesn't have any suitable methods/subscriptions to expose") + } + + for _, m := range methods { + regsvc.callbacks[formatName(m.method.Name)] = m + } + for _, s := range subscriptions { + regsvc.subscriptions[formatName(s.method.Name)] = s + } + + return nil + } + + svc.name = name + svc.callbacks, svc.subscriptions = suitableCallbacks(rcvrVal, svc.typ) + + if len(svc.callbacks) == 0 && len(svc.subscriptions) == 0 { + return fmt.Errorf("Service doesn't have any suitable methods/subscriptions to expose") + } + + s.services[svc.name] = svc + + return nil +} + +// ServeCodec reads incoming requests from codec, calls the appropriate callback and writes the +// response back using the given codec. It will block until the codec is closed. +// +// This server will: +// 1. allow for asynchronous and parallel request execution +// 2. supports notifications (pub/sub) +// 3. supports request batches +func (s *Server) ServeCodec(codec ServerCodec) { + defer func() { + if err := recover(); err != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + glog.Errorln(string(buf)) + } + codec.Close() + }() + + for { + reqs, batch, err := s.readRequest(codec) + if err != nil { + glog.V(logger.Debug).Infof("%v\n", err) + codec.Write(codec.CreateErrorResponse(nil, err)) + break + } + + if batch { + go s.execBatch(codec, reqs) + } else { + go s.exec(codec, reqs[0]) + } + } +} + +// sendNotification will create a notification from the given event by serializing member fields of the event. +// It will then send the notification to the client, when it fails the codec is closed. When the event has multiple +// fields an array of values is returned. +func sendNotification(codec ServerCodec, subid string, event interface{}) { + notification := codec.CreateNotification(subid, event) + + if err := codec.Write(notification); err != nil { + codec.Close() + } +} + +// createSubscription will register a new subscription and waits for raised events. When an event is raised it will: +// 1. test if the event is raised matches the criteria the user has (optionally) specified +// 2. create a notification of the event and send it the client when it matches the criteria +// It will unsubscribe the subscription when the socket is closed or the subscription is unsubscribed by the user. +func (s *Server) createSubscription(c ServerCodec, req *serverRequest) (string, error) { + args := []reflect.Value{req.callb.rcvr} + if len(req.args) > 0 { + args = append(args, req.args...) + } + + subid, err := newSubscriptionId() + if err != nil { + return "", err + } + + reply := req.callb.method.Func.Call(args) + + if reply[1].IsNil() { // no error + if subscription, ok := reply[0].Interface().(Subscription); ok { + s.muSubcriptions.Lock() + s.subscriptions[subid] = subscription + s.muSubcriptions.Unlock() + go func() { + cases := []reflect.SelectCase{ + reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(subscription.Chan())}, // new event + reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(c.Closed())}, // connection closed + } + + for { + idx, notification, recvOk := reflect.Select(cases) + switch idx { + case 0: // new event, or channel closed + if recvOk { // send notification + if event, ok := notification.Interface().(*event.Event); ok { + if subscription.match == nil || subscription.match(event.Data) { + sendNotification(c, subid, subscription.format(event.Data)) + } + } + } else { // user send an eth_unsubscribe request + return + } + case 1: // connection closed + s.unsubscribe(subid) + return + } + } + }() + } else { // unable to create subscription + s.muSubcriptions.Lock() + delete(s.subscriptions, subid) + s.muSubcriptions.Unlock() + } + } else { + return "", fmt.Errorf("Unable to create subscription") + } + + return subid, nil +} + +// unsubscribe calls the Unsubscribe method on the subscription and removes a subscription from the subscription +// registry. +func (s *Server) unsubscribe(subid string) bool { + s.muSubcriptions.Lock() + defer s.muSubcriptions.Unlock() + if sub, ok := s.subscriptions[subid]; ok { + sub.Unsubscribe() + delete(s.subscriptions, subid) + return true + } + return false +} + +// exec executes the given request and writes the result back using the codec. +func (s *Server) exec(codec ServerCodec, req *serverRequest) { + if req.err != nil { // error during request parsing + rpcErr := codec.CreateErrorResponse(&req.id, req.err) + if err := codec.Write(rpcErr); err != nil { + codec.Close() + } + return + } + + if req.isUnsubscribe { // first param must be the subscription id + if len(req.args) >= 1 && req.args[0].Kind() == reflect.String { + subid := req.args[0].String() + if s.unsubscribe(subid) { + if err := codec.Write(codec.CreateResponse(req.id, true)); err != nil { + codec.Close() + } + } else { + rpcErr := codec.CreateErrorResponse(&req.id, + &callbackError{fmt.Sprintf("subscription '%s' not found", subid)}) + if err := codec.Write(rpcErr); err != nil { + codec.Close() + } + } + } else { + rpcErr := codec.CreateErrorResponse(&req.id, &invalidParamsError{"Expected subscription id as argument"}) + if err := codec.Write(rpcErr); err != nil { + codec.Close() + } + } + return + } + + if req.callb.isSubscribe { + subid, err := s.createSubscription(codec, req) + var response interface{} + if err == nil { + response = codec.CreateResponse(req.id, subid) + } else { + response = codec.CreateErrorResponse(&req.id, &callbackError{err.Error()}) + } + + if err = codec.Write(response); err != nil { + codec.Close() + } + return + } + + // regular RPC call + if len(req.args) != len(req.callb.argTypes) { + rpcErr := &invalidParamsError{fmt.Sprintf("%s%s%s expects %d parameters, got %d", + req.svcname, serviceMethodSeparator, req.callb.method.Name, + len(req.callb.argTypes), len(req.args))} + + res := codec.CreateErrorResponse(&req.id, rpcErr) + if err := codec.Write(res); err != nil { + codec.Close() + } + return + } + + arguments := []reflect.Value{req.callb.rcvr} + if len(req.args) > 0 { + arguments = append(arguments, req.args...) + } + + reply := req.callb.method.Func.Call(arguments) + + if len(reply) == 0 { + if err := codec.Write(codec.CreateResponse(req.id, nil)); err != nil { + codec.Close() + } + return + } + + if req.callb.errPos >= 0 { // test if method returned an error + if !reply[req.callb.errPos].IsNil() { + e := reply[req.callb.errPos].Interface().(error) + res := codec.CreateErrorResponse(&req.id, &callbackError{e.Error()}) + if err := codec.Write(res); err != nil { + codec.Close() + } + return + } + } + + if err := codec.Write(codec.CreateResponse(req.id, reply[0].Interface())); err != nil { + codec.Close() + } +} + +// execBatch executes the given requests and writes the result back using the codec. It will only write the response +// back when the last request is processed. +func (s *Server) execBatch(codec ServerCodec, requests []*serverRequest) { + responses := make([]interface{}, len(requests)) + + for i, req := range requests { + if req.err != nil { // error during parsing of request + responses[i] = codec.CreateErrorResponse(&req.id, req.err) + continue + } + + if req.isUnsubscribe { + if len(req.args) == 1 && req.args[0].Kind() == reflect.String { + subid := req.args[0].String() + if s.unsubscribe(subid) { + responses[i] = codec.CreateResponse(req.id, true) + } else { + e := &callbackError{fmt.Sprintf("subscription '%s' not found", subid)} + responses[i] = codec.CreateErrorResponse(&req.id, e) + } + } else { + e := &invalidParamsError{"Expected subscription id as argument"} + responses[i] = codec.CreateErrorResponse(&req.id, e) + } + continue + } + + if req.callb.isSubscribe { + subid, err := s.createSubscription(codec, req) + var response interface{} + if err == nil { + response = codec.CreateResponse(req.id, subid) + } else { + response = codec.CreateErrorResponse(&req.id, &callbackError{err.Error()}) + } + + responses[i] = response + continue + } + + var reply []reflect.Value + + if len(req.args) != len(req.callb.argTypes) { + rpcErr := &invalidParamsError{fmt.Sprintf("%s%s%s expects %d parameters, got %d", + req.svcname, serviceMethodSeparator, req.callb.method.Name, len(req.callb.argTypes), len(req.args))} + responses[i] = codec.CreateErrorResponse(&req.id, rpcErr) + continue + } + + arguments := []reflect.Value{req.callb.rcvr} + if len(req.args) > 0 { + arguments = append(arguments, req.args...) + } + + reply = req.callb.method.Func.Call(arguments) + + if len(reply) == 0 { + responses[i] = codec.CreateResponse(req.id, nil) + continue + } + + if req.callb.errPos >= 0 { + if !reply[req.callb.errPos].IsNil() { + if e, ok := reply[req.callb.errPos].Interface().(error); ok { + rpcErr := &callbackError{e.Error()} + responses[i] = codec.CreateErrorResponse(&req.id, rpcErr) + continue + } + } + } + + responses[i] = codec.CreateResponse(req.id, reply[0].Interface()) + } + + if err := codec.Write(responses); err != nil { + glog.V(logger.Error).Infof("%v\n", err) + codec.Close() + } +} + +// readRequest requests the next (batch) request from the codec. It will return the collection of requests, an +// indication if the request was a batch, the invalid request identifier and an error when the request could not be +// read/parsed. +func (s *Server) readRequest(codec ServerCodec) ([]*serverRequest, bool, RPCError) { + reqs, batch, err := codec.ReadRequestHeaders() + if err != nil { + return nil, batch, err + } + + requests := make([]*serverRequest, len(reqs)) + + // verify requests + for i, r := range reqs { + var ok bool + var svc *service + + if r.isPubSub && r.method == unsubscribeMethod { + requests[i] = &serverRequest{id: r.id, isUnsubscribe: true} + argTypes := []reflect.Type{reflect.TypeOf("")} + if args, err := codec.ParseRequestArguments(argTypes, r.params); err == nil { + requests[i].args = args + } else { + requests[i].err = &invalidParamsError{err.Error()} + } + continue + } + + if svc, ok = s.services[r.service]; !ok { + requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{r.service, r.method}} + continue + } + + if r.isPubSub { // eth_subscribe + if callb, ok := svc.subscriptions[r.method]; ok { + requests[i] = &serverRequest{id: r.id, svcname: svc.name, callb: callb} + if r.params != nil && len(callb.argTypes) > 0 { + argTypes := []reflect.Type{reflect.TypeOf("")} + argTypes = append(argTypes, callb.argTypes...) + if args, err := codec.ParseRequestArguments(argTypes, r.params); err == nil { + requests[i].args = args[1:] // first one is service.method name which isn't an actual argument + } else { + requests[i].err = &invalidParamsError{err.Error()} + } + } + } else { + requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{subscribeMethod, r.method}} + } + continue + } + + if callb, ok := svc.callbacks[r.method]; ok { + requests[i] = &serverRequest{id: r.id, svcname: svc.name, callb: callb} + if r.params != nil && len(callb.argTypes) > 0 { + if args, err := codec.ParseRequestArguments(callb.argTypes, r.params); err == nil { + requests[i].args = args + } else { + requests[i].err = &invalidParamsError{err.Error()} + } + } + continue + } + + requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{r.service, r.method}} + } + + return requests, batch, nil +} diff --git a/rpc/v2/server_test.go b/rpc/v2/server_test.go new file mode 100644 index 0000000000..ede3ac4abb --- /dev/null +++ b/rpc/v2/server_test.go @@ -0,0 +1,218 @@ +package v2 + +import ( + "encoding/json" + "fmt" + "reflect" + "testing" + "time" +) + +type Service struct{} + +type Args struct { + S string +} + +func (s *Service) NoArgsRets() { +} + +type Result struct { + String string + Int int + Args *Args +} + +func (s *Service) Echo(str string, i int, args *Args) Result { + return Result{str, i, args} +} + +func (s *Service) Rets() (string, error) { + return "", nil +} + +func (s *Service) InvalidRets1() (error, string) { + return nil, "" +} + +func (s *Service) InvalidRets2() (string, string) { + return "", "" +} + +func (s *Service) InvalidRets3() (string, string, error) { + return "", "", nil +} + +func (s *Service) Subscription() (Subscription, error) { + return NewSubscription(nil), nil +} + +func TestServerRegisterName(t *testing.T) { + server := NewServer() + service := new(Service) + + if err := server.RegisterName("calc", service); err != nil { + t.Fatalf("%v", err) + } + + if len(server.services) != 2 { + t.Fatalf("Expected 2 service entries, got %d", len(server.services)) + } + + svc, ok := server.services["calc"] + if !ok { + t.Fatalf("Expected service calc to be registered") + } + + if len(svc.callbacks) != 3 { + t.Errorf("Expected 3 callbacks for service 'calc', got %d", len(svc.callbacks)) + } + + if len(svc.subscriptions) != 1 { + t.Errorf("Expected 1 subscription for service 'calc', got %d", len(svc.subscriptions)) + } +} + +// dummy codec used for testing RPC method execution +type ServerTestCodec struct { + counter int + input []byte + output string + closer chan interface{} +} + +func (c *ServerTestCodec) ReadRequestHeaders() ([]rpcRequest, bool, RPCError) { + c.counter += 1 + + if c.counter == 1 { + var req jsonRequest + json.Unmarshal(c.input, &req) + return []rpcRequest{rpcRequest{id: req.Id, isPubSub: false, service: "test", method: req.Method, params: req.Payload}}, false, nil + } + + // requests are executes in parallel, wait a bit before returning an error so that the previous request has time to + // be executed + timer := time.NewTimer(time.Duration(2) * time.Second) + <-timer.C + + return nil, false, &invalidRequestError{"connection closed"} +} + +func (c *ServerTestCodec) ParseRequestArguments(argTypes []reflect.Type, payload interface{}) ([]reflect.Value, RPCError) { + + args, _ := payload.(json.RawMessage) + + argValues := make([]reflect.Value, len(argTypes)) + params := make([]interface{}, len(argTypes)) + + n, err := countArguments(args) + if err != nil { + return nil, &invalidParamsError{err.Error()} + } + if n != len(argTypes) { + return nil, &invalidParamsError{fmt.Sprintf("insufficient params, want %d have %d", len(argTypes), n)} + + } + + for i, t := range argTypes { + if t.Kind() == reflect.Ptr { + // values must be pointers for the Unmarshal method, reflect. + // Dereference otherwise reflect.New would create **SomeType + argValues[i] = reflect.New(t.Elem()) + params[i] = argValues[i].Interface() + + // when not specified blockNumbers are by default latest (-1) + if blockNumber, ok := params[i].(*BlockNumber); ok { + *blockNumber = BlockNumber(-1) + } + } else { + argValues[i] = reflect.New(t) + params[i] = argValues[i].Interface() + + // when not specified blockNumbers are by default latest (-1) + if blockNumber, ok := params[i].(*BlockNumber); ok { + *blockNumber = BlockNumber(-1) + } + } + } + + if err := json.Unmarshal(args, ¶ms); err != nil { + return nil, &invalidParamsError{err.Error()} + } + + // Convert pointers back to values where necessary + for i, a := range argValues { + if a.Kind() != argTypes[i].Kind() { + argValues[i] = reflect.Indirect(argValues[i]) + } + } + + return argValues, nil +} + +func (c *ServerTestCodec) CreateResponse(id int64, reply interface{}) interface{} { + return &jsonSuccessResponse{Version: jsonRPCVersion, Id: id, Result: reply} +} + +func (c *ServerTestCodec) CreateErrorResponse(id *int64, err RPCError) interface{} { + return &jsonErrResponse{Version: jsonRPCVersion, Id: id, Error: jsonError{Code: err.Code(), Message: err.Error()}} +} + +func (c *ServerTestCodec) CreateErrorResponseWithInfo(id *int64, err RPCError, info interface{}) interface{} { + return &jsonErrResponse{Version: jsonRPCVersion, Id: id, + Error: jsonError{Code: err.Code(), Message: err.Error(), Data: info}} +} + +func (c *ServerTestCodec) CreateNotification(subid string, event interface{}) interface{} { + return &jsonNotification{Version: jsonRPCVersion, Method: notificationMethod, + Params: jsonSubscription{Subscription: subid, Result: event}} +} + +func (c *ServerTestCodec) Write(msg interface{}) error { + if len(c.output) == 0 { // only capture first response + if o, err := json.Marshal(msg); err != nil { + return err + } else { + c.output = string(o) + } + } + + return nil +} + +func (c *ServerTestCodec) Close() { + close(c.closer) +} + +func (c *ServerTestCodec) Closed() <-chan interface{} { + return c.closer +} + +func TestServerMethodExecution(t *testing.T) { + server := NewServer() + service := new(Service) + + if err := server.RegisterName("test", service); err != nil { + t.Fatalf("%v", err) + } + + req := jsonRequest{ + Method: "echo", + Version: "2.0", + Id: 12345, + } + args := []interface{}{"string arg", 1122, &Args{"qwerty"}} + req.Payload, _ = json.Marshal(&args) + + input, _ := json.Marshal(&req) + codec := &ServerTestCodec{input: input, closer: make(chan interface{})} + go server.ServeCodec(codec) + + <-codec.closer + + expected := `{"jsonrpc":"2.0","id":12345,"result":{"String":"string arg","Int":1122,"Args":{"S":"qwerty"}}}` + + if expected != codec.output { + t.Fatalf("expected %s, got %s\n", expected, codec.output) + } +} diff --git a/rpc/v2/types.go b/rpc/v2/types.go new file mode 100644 index 0000000000..d538e0a3f7 --- /dev/null +++ b/rpc/v2/types.go @@ -0,0 +1,352 @@ +// 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 . + +package v2 + +import ( + "fmt" + "math" + "math/big" + "reflect" + "strings" + + "sync" + + "github.com/ethereum/go-ethereum/event" +) + +// API describes the set of methods offered over the RPC interface +type API struct { + Namespace string // namespace under which the rpc methods of Service are exposed + Version string // api version for DApp's + Service interface{} // receiver instance which holds the methods + Public bool // indication if the methods must be considered safe for public use +} + +// callback is a method callback which was registered in the server +type callback struct { + rcvr reflect.Value // receiver of method + method reflect.Method // callback + argTypes []reflect.Type // input argument types + errPos int // err return idx, of -1 when method cannot return error + isSubscribe bool // indication if the callback is a subscription +} + +// service represents a registered object +type service struct { + name string // name for service + rcvr reflect.Value // receiver of methods for the service + typ reflect.Type // receiver type + callbacks callbacks // registered handlers + subscriptions subscriptions // available subscriptions/notifications +} + +// serverRequest is an incoming request +type serverRequest struct { + id int64 + svcname string + rcvr reflect.Value + callb *callback + args []reflect.Value + isUnsubscribe bool + err RPCError +} + +type serviceRegistry map[string]*service // collection of services +type callbacks map[string]*callback // collection of RPC callbacks +type subscriptions map[string]*callback // collection of subscription callbacks +type subscriptionRegistry map[string]Subscription // collection of subscriptions + +// Server represents a RPC server +type Server struct { + services serviceRegistry + muSubcriptions sync.Mutex // protects subscriptions + subscriptions subscriptionRegistry +} + +// rpcRequest represents a raw incoming RPC request +type rpcRequest struct { + service string + method string + id int64 + isPubSub bool + params interface{} +} + +// RPCError implements RPC error, is add support for error codec over regular go errors +type RPCError interface { + // RPC error code + Code() int + // Error message + Error() string +} + +// ServerCodec implements reading, parsing and writing RPC messages for the server side of +// a RPC session. Implementations must be go-routine safe since the codec can be called in +// multiple go-routines concurrently. +type ServerCodec interface { + // Read next request + ReadRequestHeaders() ([]rpcRequest, bool, RPCError) + // Parse request argument to the given types + ParseRequestArguments([]reflect.Type, interface{}) ([]reflect.Value, RPCError) + // Assemble success response + CreateResponse(int64, interface{}) interface{} + // Assemble error response + CreateErrorResponse(*int64, RPCError) interface{} + // Assemble error response with extra information about the error through info + CreateErrorResponseWithInfo(id *int64, err RPCError, info interface{}) interface{} + // Create notification response + CreateNotification(string, interface{}) interface{} + // Write msg to client. + Write(interface{}) error + // Close underlying data stream + Close() + // Closed when underlying connection is closed + Closed() <-chan interface{} +} + +// SubscriptionMatcher returns true if the given value matches the criteria specified by the user +type SubscriptionMatcher func(interface{}) bool + +// SubscriptionOutputFormat accepts event data and has the ability to format the data before it is send to the client +type SubscriptionOutputFormat func(interface{}) interface{} + +// defaultSubscriptionOutputFormatter returns data and is used as default output format for notifications +func defaultSubscriptionOutputFormatter(data interface{}) interface{} { + return data +} + +// Subscription is used by the server to send notifications to the client +type Subscription struct { + sub event.Subscription + match SubscriptionMatcher + format SubscriptionOutputFormat +} + +// NewSubscription create a new RPC subscription +func NewSubscription(sub event.Subscription) Subscription { + return Subscription{sub, nil, defaultSubscriptionOutputFormatter} +} + +// NewSubscriptionWithOutputFormat create a new RPC subscription which a custom notification output format +func NewSubscriptionWithOutputFormat(sub event.Subscription, formatter SubscriptionOutputFormat) Subscription { + return Subscription{sub, nil, formatter} +} + +// NewSubscriptionFiltered will create a new subscription. For each raised event the given matcher is +// called. If it returns true the event is send as notification to the client, otherwise it is ignored. +func NewSubscriptionFiltered(sub event.Subscription, match SubscriptionMatcher) Subscription { + return Subscription{sub, match, defaultSubscriptionOutputFormatter} +} + +// Chan returns the channel where new events will be published. It's up the user to call the matcher to +// determine if the events are interesting for the client. +func (s *Subscription) Chan() <-chan *event.Event { + return s.sub.Chan() +} + +// Unsubscribe will end the subscription and closes the event channel +func (s *Subscription) Unsubscribe() { + s.sub.Unsubscribe() +} + +// HexNumber serializes a number to hex format using the "%#x" format +type HexNumber big.Int + +// NewHexNumber creates a new hex number instance which will serialize the given val with `%#x` on marshal. +func NewHexNumber(val interface{}) *HexNumber { + if val == nil { + return nil + } + + if v, ok := val.(*big.Int); ok && v != nil { + hn := new(big.Int).Set(v) + return (*HexNumber)(hn) + } + + rval := reflect.ValueOf(val) + + var unsigned uint64 + utype := reflect.TypeOf(unsigned) + if t := rval.Type(); t.ConvertibleTo(utype) { + hn := new(big.Int).SetUint64(rval.Convert(utype).Uint()) + return (*HexNumber)(hn) + } + + var signed int64 + stype := reflect.TypeOf(signed) + if t := rval.Type(); t.ConvertibleTo(stype) { + hn := new(big.Int).SetInt64(rval.Convert(stype).Int()) + return (*HexNumber)(hn) + } + + return nil +} + +func (h *HexNumber) UnmarshalJSON(input []byte) error { + length := len(input) + if length >= 2 && input[0] == '"' && input[length-1] == '"' { + input = input[1 : length-1] + } + + hn := (*big.Int)(h) + if _, ok := hn.SetString(string(input), 0); ok { + return nil + } + + return fmt.Errorf("Unable to parse number") +} + +// MarshalJSON serialize the hex number instance to a hex representation. +func (h *HexNumber) MarshalJSON() ([]byte, error) { + if h != nil { + hn := (*big.Int)(h) + if hn.BitLen() == 0 { + return []byte(`"0x0"`), nil + } + return []byte(fmt.Sprintf(`"0x%x"`, hn)), nil + } + return nil, nil +} + +func (h *HexNumber) Int() int { + hn := (*big.Int)(h) + return int(hn.Int64()) +} + +func (h *HexNumber) Int64() int64 { + hn := (*big.Int)(h) + return hn.Int64() +} + +func (h *HexNumber) Uint() uint { + hn := (*big.Int)(h) + return uint(hn.Uint64()) +} + +func (h *HexNumber) Uint64() uint64 { + hn := (*big.Int)(h) + return hn.Uint64() +} + +func (h *HexNumber) BigInt() *big.Int { + return (*big.Int)(h) +} + +type Number int64 + +func (n *Number) UnmarshalJSON(data []byte) error { + input := strings.TrimSpace(string(data)) + + if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { + input = input[1 : len(input)-1] + } + + if len(input) == 0 { + *n = Number(latestBlockNumber.Int64()) + return nil + } + + in := new(big.Int) + _, ok := in.SetString(input, 0) + + if !ok { // test if user supplied string tag + return fmt.Errorf(`invalid number %s`, data) + } + + if in.Cmp(earliestBlockNumber) >= 0 && in.Cmp(maxBlockNumber) <= 0 { + *n = Number(in.Int64()) + return nil + } + + return fmt.Errorf("blocknumber not in range [%d, %d]", earliestBlockNumber, maxBlockNumber) +} + +func (n *Number) Int64() int64 { + return *(*int64)(n) +} + +func (n *Number) BigInt() *big.Int { + return big.NewInt(n.Int64()) +} + +var ( + pendingBlockNumber = big.NewInt(-2) + latestBlockNumber = big.NewInt(-1) + earliestBlockNumber = big.NewInt(0) + maxBlockNumber = big.NewInt(math.MaxInt64) +) + +type BlockNumber int64 + +const ( + PendingBlockNumber = BlockNumber(-2) + LatestBlockNumber = BlockNumber(-1) +) + +// UnmarshalJSON parses the given JSON fragement into a BlockNumber. It supports: +// - "latest" or "earliest" as string arguments +// - the block number +// Returned errors: +// - an unsupported error when "pending" is specified (not yet implemented) +// - an invalid block number error when the given argument isn't a known strings +// - an out of range error when the given block number is either too little or too large +func (bn *BlockNumber) UnmarshalJSON(data []byte) error { + input := strings.TrimSpace(string(data)) + + if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { + input = input[1 : len(input)-1] + } + + if len(input) == 0 { + *bn = BlockNumber(latestBlockNumber.Int64()) + return nil + } + + in := new(big.Int) + _, ok := in.SetString(input, 0) + + if !ok { // test if user supplied string tag + strBlockNumber := input + if strBlockNumber == "latest" { + *bn = BlockNumber(latestBlockNumber.Int64()) + return nil + } + + if strBlockNumber == "earliest" { + *bn = BlockNumber(earliestBlockNumber.Int64()) + return nil + } + + if strBlockNumber == "pending" { + *bn = BlockNumber(pendingBlockNumber.Int64()) + return nil + } + + return fmt.Errorf(`invalid blocknumber %s`, data) + } + + if in.Cmp(earliestBlockNumber) >= 0 && in.Cmp(maxBlockNumber) <= 0 { + *bn = BlockNumber(in.Int64()) + return nil + } + + return fmt.Errorf("blocknumber not in range [%d, %d]", earliestBlockNumber, maxBlockNumber) +} + +func (bn *BlockNumber) Int64() int64 { + return (int64)(*bn) +} diff --git a/rpc/v2/types_test.go b/rpc/v2/types_test.go new file mode 100644 index 0000000000..f73a2369ee --- /dev/null +++ b/rpc/v2/types_test.go @@ -0,0 +1,57 @@ +package v2 + +import ( + "bytes" + "encoding/json" + "math/big" + "testing" +) + +func TestNewHexNumber(t *testing.T) { + tests := []interface{}{big.NewInt(123), int64(123), uint64(123), int8(123), uint8(123)} + + for i, v := range tests { + hn := NewHexNumber(v) + if hn == nil { + t.Fatalf("Unable to create hex number instance for tests[%d]", i) + } + if hn.Int64() != 123 { + t.Fatalf("expected %d, got %d on value tests[%d]", 123, hn.Int64(), i) + } + } + + failures := []interface{}{"", nil, []byte{1, 2, 3, 4}} + for i, v := range failures { + hn := NewHexNumber(v) + if hn != nil { + t.Fatalf("Creating a nex number instance of %T should fail (failures[%d])", failures[i], i) + } + } +} + +func TestHexNumberUnmarshalJSON(t *testing.T) { + tests := []string{`"0x4d2"`, "1234", `"1234"`} + for i, v := range tests { + var hn HexNumber + if err := json.Unmarshal([]byte(v), &hn); err != nil { + t.Fatalf("Test %d failed - %s", i, err) + } + + if hn.Int64() != 1234 { + t.Fatalf("Expected %d, got %d for test[%d]", 1234, hn.Int64(), i) + } + } +} + +func TestHexNumberMarshalJSON(t *testing.T) { + hn := NewHexNumber(1234567890) + got, err := json.Marshal(hn) + if err != nil { + t.Fatalf("Unable to marshal hex number - %s", err) + } + + exp := []byte(`"0x499602d2"`) + if bytes.Compare(exp, got) != 0 { + t.Fatalf("Invalid json.Marshal, expected '%s', got '%s'", exp, got) + } +} diff --git a/rpc/v2/utils.go b/rpc/v2/utils.go new file mode 100644 index 0000000000..a564b24733 --- /dev/null +++ b/rpc/v2/utils.go @@ -0,0 +1,205 @@ +// 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 . + +package v2 + +import ( + "crypto/rand" + "encoding/hex" + "errors" + "math/big" + "reflect" + "unicode" + "unicode/utf8" +) + +// Is this an exported - upper case - name? +func isExported(name string) bool { + rune, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(rune) +} + +// Is this type exported or a builtin? +func isExportedOrBuiltinType(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + // PkgPath will be non-empty even for an exported type, + // so we need to check the type name as well. + return isExported(t.Name()) || t.PkgPath() == "" +} + +var errorType = reflect.TypeOf((*error)(nil)).Elem() + +// Implements this type the error interface +func isErrorType(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t.Implements(errorType) +} + +var subscriptionType = reflect.TypeOf((*Subscription)(nil)).Elem() + +func isSubscriptionType(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t == subscriptionType +} + +// isPubSub tests whether the given method return the pair (v2.Subscription, error) +func isPubSub(methodType reflect.Type) bool { + if methodType.NumOut() != 2 { + return false + } + return isSubscriptionType(methodType.Out(0)) && isErrorType(methodType.Out(1)) +} + +// formatName will convert to first character to lower case +func formatName(name string) string { + ret := []rune(name) + if len(ret) > 0 { + ret[0] = unicode.ToLower(ret[0]) + } + return string(ret) +} + +var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem() + +// Indication if this type should be serialized in hex +func isHexNum(t reflect.Type) bool { + if t == nil { + return false + } + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + + return t == bigIntType +} + +var blockNumberType = reflect.TypeOf((*BlockNumber)(nil)).Elem() + +// Indication if the given block is a BlockNumber +func isBlockNumber(t reflect.Type) bool { + if t == nil { + return false + } + + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + + return t == blockNumberType +} + +// suitableCallbacks iterates over the methods of the given type. It will determine if a method satisfies the criteria +// for a RPC callback or a subscription callback and adds it to the collection of callbacks or subscriptions. See server +// documentation for a summary of these criteria. +func suitableCallbacks(rcvr reflect.Value, typ reflect.Type) (callbacks, subscriptions) { + callbacks := make(callbacks) + subscriptions := make(subscriptions) + +METHODS: + for m := 0; m < typ.NumMethod(); m++ { + method := typ.Method(m) + mtype := method.Type + mname := formatName(method.Name) + if method.PkgPath != "" { // method must be exported + continue + } + + var h callback + h.isSubscribe = isPubSub(mtype) + h.rcvr = rcvr + h.method = method + h.errPos = -1 + + if h.isSubscribe { + h.argTypes = make([]reflect.Type, mtype.NumIn()-1) // skip rcvr type + for i := 1; i < mtype.NumIn(); i++ { + argType := mtype.In(i) + if isExportedOrBuiltinType(argType) { + h.argTypes[i-1] = argType + } else { + continue METHODS + } + } + + subscriptions[mname] = &h + continue METHODS + } + + numIn := mtype.NumIn() + + // determine method arguments, ignore first arg since it's the receiver type + // Arguments must be exported or builtin types + h.argTypes = make([]reflect.Type, numIn-1) + for i := 1; i < numIn; i++ { + argType := mtype.In(i) + if !isExportedOrBuiltinType(argType) { + continue METHODS + } + h.argTypes[i-1] = argType + } + + // check that all returned values are exported or builtin types + for i := 0; i < mtype.NumOut(); i++ { + if !isExportedOrBuiltinType(mtype.Out(i)) { + continue METHODS + } + } + + // when a method returns an error it must be the last returned value + h.errPos = -1 + for i := 0; i < mtype.NumOut(); i++ { + if isErrorType(mtype.Out(i)) { + h.errPos = i + break + } + } + + if h.errPos >= 0 && h.errPos != mtype.NumOut()-1 { + continue METHODS + } + + switch mtype.NumOut() { + case 0, 1: + break + case 2: + if h.errPos == -1 { // method must one return value and 1 error + continue METHODS + } + break + default: + continue METHODS + } + + callbacks[mname] = &h + } + + return callbacks, subscriptions +} + +func newSubscriptionId() (string, error) { + var subid [16]byte + n, _ := rand.Read(subid[:]) + if n != 16 { + return "", errors.New("Unable to generate subscription id") + } + return "0x" + hex.EncodeToString(subid[:]), nil +} diff --git a/whisper/api.go b/whisper/api.go new file mode 100644 index 0000000000..d02be10bad --- /dev/null +++ b/whisper/api.go @@ -0,0 +1,413 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package whisper + +import ( + "encoding/json" + "fmt" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + rpc "github.com/ethereum/go-ethereum/rpc/v2" +) + +// PublicWhisperApi provides the whisper RPC service. +type PublicWhisperApi struct { + w *Whisper + + messagesMu sync.RWMutex + messages map[int]*whisperFilter +} + +type whisperOfflineError struct{} + +func (e *whisperOfflineError) Error() string { + return "whisper is offline" +} + +// whisperOffLineErr is returned when the node doesn't offer the shh service. +var whisperOffLineErr = new(whisperOfflineError) + +// NewPublicWhisperApi create a new RPC whisper service. +func NewPublicWhisperApi(w *Whisper) *PublicWhisperApi { + return &PublicWhisperApi{w: w, messages: make(map[int]*whisperFilter)} +} + +// Version returns the Whisper version this node offers. +func (s *PublicWhisperApi) Version() (*rpc.HexNumber, error) { + if s.w == nil { + return rpc.NewHexNumber(0), whisperOffLineErr + } + return rpc.NewHexNumber(s.w.Version()), nil +} + +// HasIdentity checks if the the whisper node is configured with the private key +// of the specified public pair. +func (s *PublicWhisperApi) HasIdentity(identity string) (bool, error) { + if s.w == nil { + return false, whisperOffLineErr + } + return s.w.HasIdentity(crypto.ToECDSAPub(common.FromHex(identity))), nil +} + +// NewIdentity generates a new cryptographic identity for the client, and injects +// it into the known identities for message decryption. +func (s *PublicWhisperApi) NewIdentity() (string, error) { + if s.w == nil { + return "", whisperOffLineErr + } + + identity := s.w.NewIdentity() + return common.ToHex(crypto.FromECDSAPub(&identity.PublicKey)), nil +} + +type NewFilterArgs struct { + To string + From string + Topics [][][]byte +} + +// NewWhisperFilter creates and registers a new message filter to watch for inbound whisper messages. +func (s *PublicWhisperApi) NewFilter(args *NewFilterArgs) (*rpc.HexNumber, error) { + if s.w == nil { + return nil, whisperOffLineErr + } + + var id int + filter := Filter{ + To: crypto.ToECDSAPub(common.FromHex(args.To)), + From: crypto.ToECDSAPub(common.FromHex(args.From)), + Topics: NewFilterTopics(args.Topics...), + Fn: func(message *Message) { + wmsg := NewWhisperMessage(message) + s.messagesMu.RLock() // Only read lock to the filter pool + defer s.messagesMu.RUnlock() + if s.messages[id] != nil { + s.messages[id].insert(wmsg) + } + }, + } + + id = s.w.Watch(filter) + + s.messagesMu.Lock() + s.messages[id] = newWhisperFilter(id, s.w) + s.messagesMu.Unlock() + + return rpc.NewHexNumber(id), nil +} + +// GetFilterChanges retrieves all the new messages matched by a filter since the last retrieval. +func (s *PublicWhisperApi) GetFilterChanges(filterId rpc.HexNumber) []WhisperMessage { + s.messagesMu.RLock() + defer s.messagesMu.RUnlock() + + if s.messages[filterId.Int()] != nil { + if changes := s.messages[filterId.Int()].retrieve(); changes != nil { + return changes + } + } + return returnWhisperMessages(nil) +} + +// UninstallFilter disables and removes an existing filter. +func (s *PublicWhisperApi) UninstallFilter(filterId rpc.HexNumber) bool { + s.messagesMu.Lock() + defer s.messagesMu.Unlock() + + if _, ok := s.messages[filterId.Int()]; ok { + delete(s.messages, filterId.Int()) + return true + } + return false +} + +// GetMessages retrieves all the known messages that match a specific filter. +func (s *PublicWhisperApi) GetMessages(filterId rpc.HexNumber) []WhisperMessage { + // Retrieve all the cached messages matching a specific, existing filter + s.messagesMu.RLock() + defer s.messagesMu.RUnlock() + + var messages []*Message + if s.messages[filterId.Int()] != nil { + messages = s.messages[filterId.Int()].messages() + } + + return returnWhisperMessages(messages) +} + +// returnWhisperMessages converts aNhisper message to a RPC whisper message. +func returnWhisperMessages(messages []*Message) []WhisperMessage { + msgs := make([]WhisperMessage, len(messages)) + for i, msg := range messages { + msgs[i] = NewWhisperMessage(msg) + } + return msgs +} + +type PostArgs struct { + From string `json:"from"` + To string `json:"to"` + Topics [][]byte `json:"topics"` + Payload string `json:"payload"` + Priority int64 `json:"priority"` + TTL int64 `json:"ttl"` +} + +// Post injects a message into the whisper network for distribution. +func (s *PublicWhisperApi) Post(args *PostArgs) (bool, error) { + if s.w == nil { + return false, whisperOffLineErr + } + + // construct whisper message with transmission options + message := NewMessage(common.FromHex(args.Payload)) + options := Options{ + To: crypto.ToECDSAPub(common.FromHex(args.To)), + TTL: time.Duration(args.TTL) * time.Second, + Topics: NewTopics(args.Topics...), + } + + // set sender identity + if len(args.From) > 0 { + if key := s.w.GetIdentity(crypto.ToECDSAPub(common.FromHex(args.From))); key != nil { + options.From = key + } else { + return false, fmt.Errorf("unknown identity to send from: %s", args.From) + } + } + + // Wrap and send the message + pow := time.Duration(args.Priority) * time.Millisecond + envelope, err := message.Wrap(pow, options) + if err != nil { + return false, err + } + + return true, s.w.Send(envelope) +} + +// WhisperMessage is the RPC representation of a whisper message. +type WhisperMessage struct { + ref *Message + + Payload string `json:"payload"` + To string `json:"to"` + From string `json:"from"` + Sent int64 `json:"sent"` + TTL int64 `json:"ttl"` + Hash string `json:"hash"` +} + +func (args *PostArgs) UnmarshalJSON(data []byte) (err error) { + var obj struct { + From string `json:"from"` + To string `json:"to"` + Topics []string `json:"topics"` + Payload string `json:"payload"` + Priority rpc.HexNumber `json:"priority"` + TTL rpc.HexNumber `json:"ttl"` + } + + if err := json.Unmarshal(data, &obj); err != nil { + return err + } + + args.From = obj.From + args.To = obj.To + args.Payload = obj.Payload + args.Priority = obj.Priority.Int64() + args.TTL = obj.TTL.Int64() + + // decode topic strings + args.Topics = make([][]byte, len(obj.Topics)) + for i, topic := range obj.Topics { + args.Topics[i] = common.FromHex(topic) + } + + return nil +} + +// UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a +// JSON message blob into a WhisperFilterArgs structure. +func (args *NewFilterArgs) 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 err + } + + // Retrieve the simple data contents of the filter arguments + if obj.To == nil { + args.To = "" + } else { + argstr, ok := obj.To.(string) + if !ok { + return fmt.Errorf("to is not a string") + } + args.To = argstr + } + if obj.From == nil { + args.From = "" + } else { + argstr, ok := obj.From.(string) + if !ok { + return fmt.Errorf("from is not a string") + } + args.From = argstr + } + // Construct the nested topic array + if obj.Topics != nil { + // Make sure we have an actual topic array + list, ok := obj.Topics.([]interface{}) + if !ok { + return fmt.Errorf("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 fmt.Errorf("topic[%d][%d] is not a string", idx, i) + } + } + default: + return fmt.Errorf("topic[%d] not a string or array", idx) + } + } + + topicsDecoded := make([][][]byte, len(topics)) + for i, condition := range topics { + topicsDecoded[i] = make([][]byte, len(condition)) + for j, topic := range condition { + topicsDecoded[i][j] = common.FromHex(topic) + } + } + + args.Topics = topicsDecoded + } + return nil +} + +// whisperFilter is the message cache matching a specific filter, accumulating +// inbound messages until the are requested by the client. +type whisperFilter struct { + id int // Filter identifier for old message retrieval + ref *Whisper // Whisper reference for old message retrieval + + cache []WhisperMessage // Cache of messages not yet polled + skip map[common.Hash]struct{} // List of retrieved messages to avoid duplication + update time.Time // Time of the last message query + + lock sync.RWMutex // Lock protecting the filter internals +} + +// messages retrieves all the cached messages from the entire pool matching the +// filter, resetting the filter's change buffer. +func (w *whisperFilter) messages() []*Message { + w.lock.Lock() + defer w.lock.Unlock() + + w.cache = nil + w.update = time.Now() + + w.skip = make(map[common.Hash]struct{}) + messages := w.ref.Messages(w.id) + for _, message := range messages { + w.skip[message.Hash] = struct{}{} + } + return messages +} + +// insert injects a new batch of messages into the filter cache. +func (w *whisperFilter) insert(messages ...WhisperMessage) { + w.lock.Lock() + defer w.lock.Unlock() + + for _, message := range messages { + if _, ok := w.skip[message.ref.Hash]; !ok { + w.cache = append(w.cache, messages...) + } + } +} + +// retrieve fetches all the cached messages from the filter. +func (w *whisperFilter) retrieve() (messages []WhisperMessage) { + w.lock.Lock() + defer w.lock.Unlock() + + messages, w.cache = w.cache, nil + w.update = time.Now() + + return +} + +// activity returns the last time instance when client requests were executed on +// the filter. +func (w *whisperFilter) activity() time.Time { + w.lock.RLock() + defer w.lock.RUnlock() + + return w.update +} + +// newWhisperFilter creates a new serialized, poll based whisper topic filter. +func newWhisperFilter(id int, ref *Whisper) *whisperFilter { + return &whisperFilter{ + id: id, + ref: ref, + + update: time.Now(), + skip: make(map[common.Hash]struct{}), + } +} + +// NewWhisperMessage converts an internal message into an API version. +func NewWhisperMessage(message *Message) WhisperMessage { + return WhisperMessage{ + ref: message, + + Payload: common.ToHex(message.Payload), + From: common.ToHex(crypto.FromECDSAPub(message.Recover())), + To: common.ToHex(crypto.FromECDSAPub(message.To)), + Sent: message.Sent.Unix(), + TTL: int64(message.TTL / time.Second), + Hash: common.ToHex(message.Hash.Bytes()), + } +} diff --git a/whisper/whisper.go b/whisper/whisper.go index 7201062b81..f9f1894f1a 100644 --- a/whisper/whisper.go +++ b/whisper/whisper.go @@ -28,6 +28,8 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/p2p" + rpc "github.com/ethereum/go-ethereum/rpc/v2" + "gopkg.in/fatih/set.v0" ) @@ -98,6 +100,18 @@ func New() *Whisper { return whisper } +// Apis returns the RPC descriptors the Whisper implementation offers +func (s *Whisper) Apis() []rpc.API { + return []rpc.API{ + rpc.API{ + Namespace: "shh", + Version: "1.0", + Service: NewPublicWhisperApi(s), + Public: true, + }, + } +} + // Protocols returns the whisper sub-protocols ran by this particular client. func (self *Whisper) Protocols() []p2p.Protocol { return []p2p.Protocol{self.protocol} From d4d1b8c1d896223dea587bf12589cbebcb7d1d10 Mon Sep 17 00:00:00 2001 From: zelig Date: Fri, 27 Nov 2015 10:59:43 +0000 Subject: [PATCH 19/27] fix address checking used in CLI --- common/bytes.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/common/bytes.go b/common/bytes.go index ba6987a9ec..c6e2cd3127 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -23,9 +23,14 @@ import ( "encoding/hex" "fmt" "math/big" + "regexp" "strings" ) +var ( + hexRe = regexp.MustCompile("^(0x)?([a-fA-f0-9]{2})+$") +) + func ToHex(b []byte) string { hex := Bytes2Hex(b) // Prefer output of "0x0" instead of "0x" @@ -139,8 +144,14 @@ func HasHexPrefix(str string) bool { } func IsHex(str string) bool { - l := len(str) - return l >= 4 && l%2 == 0 && str[0:2] == "0x" + return hexRe.MatchString(str) +} + +func NormaliseHex(str string) (string, bool) { + if HasHexPrefix(str) { + str = str[2:] + } + return str, IsHex(str) } func Bytes2Hex(d []byte) string { @@ -202,8 +213,8 @@ func ParseData(data ...interface{}) (ret []byte) { switch t := item.(type) { case string: var str []byte - if IsHex(t) { - str = Hex2Bytes(t[2:]) + if n, ok := NormaliseHex(t); ok { + str = Hex2Bytes(n) } else { str = []byte(t) } From feb2e262a73f8738aea90059dd8638d1b3419567 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Mon, 28 Sep 2015 11:19:23 +0200 Subject: [PATCH 20/27] core/secp256k1: update libsecp256k1 Go wrapper and tests --- crypto/secp256k1/secp256.go | 4 ++-- crypto/secp256k1/secp256_test.go | 31 +++++++++++++++---------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 41a5608a54..7f26f307cd 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -96,7 +96,7 @@ func GenerateKeyPair() ([]byte, []byte) { var output_len C.size_t - C.secp256k1_ec_pubkey_serialize( // always returns 1 + _ = C.secp256k1_ec_pubkey_serialize( // always returns 1 context, pubkey65_ptr, &output_len, @@ -163,7 +163,7 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) { sig_serialized_ptr := (*C.uchar)(unsafe.Pointer(&sig_serialized[0])) var recid C.int - C.secp256k1_ecdsa_recoverable_signature_serialize_compact( + _ = C.secp256k1_ecdsa_recoverable_signature_serialize_compact( context, sig_serialized_ptr, // 64 byte compact signature &recid, diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index cb71ea5e7d..d3ff2223d5 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -86,10 +86,7 @@ func TestSignAndRecover(t *testing.T) { func TestRandomMessagesWithSameKey(t *testing.T) { pubkey, seckey := GenerateKeyPair() keys := func() ([]byte, []byte) { - // Sign function zeroes the privkey so we need a new one in each call - newkey := make([]byte, len(seckey)) - copy(newkey, seckey) - return pubkey, newkey + return pubkey, seckey } signAndRecoverWithRandomMessages(t, keys) } @@ -209,30 +206,32 @@ func compactSigCheck(t *testing.T, sig []byte) { } } -// godep go test -v -run=XXX -bench=BenchmarkSignRandomInputEachRound +// godep go test -v -run=XXX -bench=BenchmarkSign // add -benchtime=10s to benchmark longer for more accurate average -func BenchmarkSignRandomInputEachRound(b *testing.B) { + +// to avoid compiler optimizing the benchmarked function call +var err error + +func BenchmarkSign(b *testing.B) { for i := 0; i < b.N; i++ { - b.StopTimer() _, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) b.StartTimer() - if _, err := Sign(msg, seckey); err != nil { - b.Fatal(err) - } + _, e := Sign(msg, seckey) + err = e + b.StopTimer() } } -//godep go test -v -run=XXX -bench=BenchmarkRecoverRandomInputEachRound -func BenchmarkRecoverRandomInputEachRound(b *testing.B) { +//godep go test -v -run=XXX -bench=BenchmarkECRec +func BenchmarkRecover(b *testing.B) { for i := 0; i < b.N; i++ { - b.StopTimer() _, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) b.StartTimer() - if _, err := RecoverPubkey(msg, sig); err != nil { - b.Fatal(err) - } + _, e := RecoverPubkey(msg, sig) + err = e + b.StopTimer() } } From 403836eb434ac71ad4d7a71ff7ecb02cfa3bc79e Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Tue, 29 Sep 2015 19:37:44 +0200 Subject: [PATCH 21/27] crypto, crypto/ecies, crypto/secp256k1: libsecp256k1 scalar mult thanks to Felix Lange (fjl) for help with design & impl --- crypto/crypto.go | 26 ++--- crypto/crypto_test.go | 8 +- crypto/ecies/asn1.go | 7 ++ crypto/ecies/ecies.go | 1 + crypto/ecies/ecies_test.go | 123 +++++++++++++++++--- crypto/ecies/params.go | 14 +-- crypto/key.go | 5 +- crypto/{ => secp256k1}/curve.go | 166 +++++++++------------------ crypto/secp256k1/curve_test.go | 39 +++++++ crypto/secp256k1/pubkey_scalar_mul.h | 56 +++++++++ crypto/secp256k1/secp256.go | 28 ++++- crypto/secp256k1/secp256_test.go | 2 +- p2p/discover/node.go | 2 +- p2p/rlpx.go | 4 +- p2p/rlpx_test.go | 2 + whisper/message_test.go | 9 +- 16 files changed, 321 insertions(+), 171 deletions(-) rename crypto/{ => secp256k1}/curve.go (67%) create mode 100644 crypto/secp256k1/curve_test.go create mode 100644 crypto/secp256k1/pubkey_scalar_mul.h diff --git a/crypto/crypto.go b/crypto/crypto.go index 8685d62d3e..7d76237532 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -43,14 +43,6 @@ import ( "golang.org/x/crypto/ripemd160" ) -var secp256k1n *big.Int - -func init() { - // specify the params for the s256 curve - ecies.AddParamsForCurve(S256(), ecies.ECIES_AES128_SHA256) - secp256k1n = common.String2Big("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") -} - func Sha3(data ...[]byte) []byte { d := sha3.NewKeccak256() for _, b := range data { @@ -99,9 +91,9 @@ func ToECDSA(prv []byte) *ecdsa.PrivateKey { } priv := new(ecdsa.PrivateKey) - priv.PublicKey.Curve = S256() + priv.PublicKey.Curve = secp256k1.S256() priv.D = common.BigD(prv) - priv.PublicKey.X, priv.PublicKey.Y = S256().ScalarBaseMult(prv) + priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(prv) return priv } @@ -116,15 +108,15 @@ func ToECDSAPub(pub []byte) *ecdsa.PublicKey { if len(pub) == 0 { return nil } - x, y := elliptic.Unmarshal(S256(), pub) - return &ecdsa.PublicKey{S256(), x, y} + x, y := elliptic.Unmarshal(secp256k1.S256(), pub) + return &ecdsa.PublicKey{secp256k1.S256(), x, y} } func FromECDSAPub(pub *ecdsa.PublicKey) []byte { if pub == nil || pub.X == nil || pub.Y == nil { return nil } - return elliptic.Marshal(S256(), pub.X, pub.Y) + return elliptic.Marshal(secp256k1.S256(), pub.X, pub.Y) } // HexToECDSA parses a secp256k1 private key. @@ -168,7 +160,7 @@ func SaveECDSA(file string, key *ecdsa.PrivateKey) error { } func GenerateKey() (*ecdsa.PrivateKey, error) { - return ecdsa.GenerateKey(S256(), rand.Reader) + return ecdsa.GenerateKey(secp256k1.S256(), rand.Reader) } func ValidateSignatureValues(v byte, r, s *big.Int) bool { @@ -176,7 +168,7 @@ func ValidateSignatureValues(v byte, r, s *big.Int) bool { return false } vint := uint32(v) - if r.Cmp(secp256k1n) < 0 && s.Cmp(secp256k1n) < 0 && (vint == 27 || vint == 28) { + if r.Cmp(secp256k1.N) < 0 && s.Cmp(secp256k1.N) < 0 && (vint == 27 || vint == 28) { return true } else { return false @@ -189,8 +181,8 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { return nil, err } - x, y := elliptic.Unmarshal(S256(), s) - return &ecdsa.PublicKey{S256(), x, y}, nil + x, y := elliptic.Unmarshal(secp256k1.S256(), s) + return &ecdsa.PublicKey{secp256k1.S256(), x, y}, nil } func Sign(hash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) { diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index fdd9c1ee85..d5e19a4bb2 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -181,7 +181,7 @@ func TestValidateSignatureValues(t *testing.T) { minusOne := big.NewInt(-1) one := common.Big1 zero := common.Big0 - secp256k1nMinus1 := new(big.Int).Sub(secp256k1n, common.Big1) + secp256k1nMinus1 := new(big.Int).Sub(secp256k1.N, common.Big1) // correct v,r,s check(true, 27, one, one) @@ -208,9 +208,9 @@ func TestValidateSignatureValues(t *testing.T) { // correct sig with max r,s check(true, 27, secp256k1nMinus1, secp256k1nMinus1) // correct v, combinations of incorrect r,s at upper limit - check(false, 27, secp256k1n, secp256k1nMinus1) - check(false, 27, secp256k1nMinus1, secp256k1n) - check(false, 27, secp256k1n, secp256k1n) + check(false, 27, secp256k1.N, secp256k1nMinus1) + check(false, 27, secp256k1nMinus1, secp256k1.N) + check(false, 27, secp256k1.N, secp256k1.N) // current callers ensures r,s cannot be negative, but let's test for that too // as crypto package could be used stand-alone diff --git a/crypto/ecies/asn1.go b/crypto/ecies/asn1.go index 6eaf3d2ca3..40dabd329b 100644 --- a/crypto/ecies/asn1.go +++ b/crypto/ecies/asn1.go @@ -41,6 +41,8 @@ import ( "fmt" "hash" "math/big" + + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) var ( @@ -81,6 +83,7 @@ func doScheme(base, v []int) asn1.ObjectIdentifier { type secgNamedCurve asn1.ObjectIdentifier var ( + secgNamedCurveS256 = secgNamedCurve{1, 3, 132, 0, 10} secgNamedCurveP256 = secgNamedCurve{1, 2, 840, 10045, 3, 1, 7} secgNamedCurveP384 = secgNamedCurve{1, 3, 132, 0, 34} secgNamedCurveP521 = secgNamedCurve{1, 3, 132, 0, 35} @@ -116,6 +119,8 @@ func (curve secgNamedCurve) Equal(curve2 secgNamedCurve) bool { func namedCurveFromOID(curve secgNamedCurve) elliptic.Curve { switch { + case curve.Equal(secgNamedCurveS256): + return secp256k1.S256() case curve.Equal(secgNamedCurveP256): return elliptic.P256() case curve.Equal(secgNamedCurveP384): @@ -134,6 +139,8 @@ func oidFromNamedCurve(curve elliptic.Curve) (secgNamedCurve, bool) { return secgNamedCurveP384, true case elliptic.P521(): return secgNamedCurveP521, true + case secp256k1.S256(): + return secgNamedCurveS256, true } return nil, false diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index a3b520dd5c..65dc5b38ba 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -125,6 +125,7 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b if skLen+macLen > MaxSharedKeyLength(pub) { return nil, ErrSharedKeyTooBig } + x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, prv.D.Bytes()) if x == nil { return nil, ErrSharedKeyIsPointAtInfinity diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 1c391f938d..6a0ea3f022 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -31,13 +31,18 @@ package ecies import ( "bytes" + "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/sha256" + "encoding/hex" "flag" "fmt" "io/ioutil" + "math/big" "testing" + + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) var dumpEnc bool @@ -65,7 +70,6 @@ func TestKDF(t *testing.T) { } } -var skLen int var ErrBadSharedKeys = fmt.Errorf("ecies: shared keys don't match") // cmpParams compares a set of ECIES parameters. We assume, as per the @@ -117,7 +121,7 @@ func TestSharedKey(t *testing.T) { fmt.Println(err.Error()) t.FailNow() } - skLen = MaxSharedKeyLength(&prv1.PublicKey) / 2 + skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2 prv2, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { @@ -143,6 +147,44 @@ func TestSharedKey(t *testing.T) { } } +func TestSharedKeyPadding(t *testing.T) { + // sanity checks + prv0 := hexKey("1adf5c18167d96a1f9a0b1ef63be8aa27eaf6032c233b2b38f7850cf5b859fd9") + prv1 := hexKey("97a076fc7fcd9208240668e31c9abee952cbb6e375d1b8febc7499d6e16f1a") + x0, _ := new(big.Int).SetString("1a8ed022ff7aec59dc1b440446bdda5ff6bcb3509a8b109077282b361efffbd8", 16) + x1, _ := new(big.Int).SetString("6ab3ac374251f638d0abb3ef596d1dc67955b507c104e5f2009724812dc027b8", 16) + y0, _ := new(big.Int).SetString("e040bd480b1deccc3bc40bd5b1fdcb7bfd352500b477cb9471366dbd4493f923", 16) + y1, _ := new(big.Int).SetString("8ad915f2b503a8be6facab6588731fefeb584fd2dfa9a77a5e0bba1ec439e4fa", 16) + + if prv0.PublicKey.X.Cmp(x0) != 0 { + t.Errorf("mismatched prv0.X:\nhave: %x\nwant: %x\n", prv0.PublicKey.X.Bytes(), x0.Bytes()) + } + if prv0.PublicKey.Y.Cmp(y0) != 0 { + t.Errorf("mismatched prv0.Y:\nhave: %x\nwant: %x\n", prv0.PublicKey.Y.Bytes(), y0.Bytes()) + } + if prv1.PublicKey.X.Cmp(x1) != 0 { + t.Errorf("mismatched prv1.X:\nhave: %x\nwant: %x\n", prv1.PublicKey.X.Bytes(), x1.Bytes()) + } + if prv1.PublicKey.Y.Cmp(y1) != 0 { + t.Errorf("mismatched prv1.Y:\nhave: %x\nwant: %x\n", prv1.PublicKey.Y.Bytes(), y1.Bytes()) + } + + // test shared secret generation + sk1, err := prv0.GenerateShared(&prv1.PublicKey, 16, 16) + if err != nil { + fmt.Println(err.Error()) + } + + sk2, err := prv1.GenerateShared(&prv0.PublicKey, 16, 16) + if err != nil { + t.Fatal(err.Error()) + } + + if !bytes.Equal(sk1, sk2) { + t.Fatal(ErrBadSharedKeys.Error()) + } +} + // Verify that the key generation code fails when too much key data is // requested. func TestTooBigSharedKey(t *testing.T) { @@ -158,13 +200,13 @@ func TestTooBigSharedKey(t *testing.T) { t.FailNow() } - _, err = prv1.GenerateShared(&prv2.PublicKey, skLen*2, skLen*2) + _, err = prv1.GenerateShared(&prv2.PublicKey, 32, 32) if err != ErrSharedKeyTooBig { fmt.Println("ecdh: shared key should be too large for curve") t.FailNow() } - _, err = prv2.GenerateShared(&prv1.PublicKey, skLen*2, skLen*2) + _, err = prv2.GenerateShared(&prv1.PublicKey, 32, 32) if err != ErrSharedKeyTooBig { fmt.Println("ecdh: shared key should be too large for curve") t.FailNow() @@ -176,25 +218,21 @@ func TestTooBigSharedKey(t *testing.T) { func TestMarshalPublic(t *testing.T) { prv, err := GenerateKey(rand.Reader, DefaultCurve, nil) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatalf("GenerateKey error: %s", err) } out, err := MarshalPublic(&prv.PublicKey) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatalf("MarshalPublic error: %s", err) } pub, err := UnmarshalPublic(out) if err != nil { - fmt.Println(err.Error()) - t.FailNow() + t.Fatalf("UnmarshalPublic error: %s", err) } if !cmpPublic(prv.PublicKey, *pub) { - fmt.Println("ecies: failed to unmarshal public key") - t.FailNow() + t.Fatal("ecies: failed to unmarshal public key") } } @@ -304,9 +342,26 @@ func BenchmarkGenSharedKeyP256(b *testing.B) { fmt.Println(err.Error()) b.FailNow() } - + b.ResetTimer() for i := 0; i < b.N; i++ { - _, err := prv.GenerateShared(&prv.PublicKey, skLen, skLen) + _, err := prv.GenerateShared(&prv.PublicKey, 16, 16) + if err != nil { + fmt.Println(err.Error()) + b.FailNow() + } + } +} + +// Benchmark the generation of S256 shared keys. +func BenchmarkGenSharedKeyS256(b *testing.B) { + prv, err := GenerateKey(rand.Reader, secp256k1.S256(), nil) + if err != nil { + fmt.Println(err.Error()) + b.FailNow() + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := prv.GenerateShared(&prv.PublicKey, 16, 16) if err != nil { fmt.Println(err.Error()) b.FailNow() @@ -511,3 +566,43 @@ func TestBasicKeyValidation(t *testing.T) { } } } + +// Verify GenerateShared against static values - useful when +// debugging changes in underlying libs +func TestSharedKeyStatic(t *testing.T) { + prv1 := hexKey("7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad") + prv2 := hexKey("6a3d6396903245bba5837752b9e0348874e72db0c4e11e9c485a81b4ea4353b9") + + skLen := MaxSharedKeyLength(&prv1.PublicKey) / 2 + + sk1, err := prv1.GenerateShared(&prv2.PublicKey, skLen, skLen) + if err != nil { + fmt.Println(err.Error()) + t.FailNow() + } + + sk2, err := prv2.GenerateShared(&prv1.PublicKey, skLen, skLen) + if err != nil { + fmt.Println(err.Error()) + t.FailNow() + } + + if !bytes.Equal(sk1, sk2) { + fmt.Println(ErrBadSharedKeys.Error()) + t.FailNow() + } + + sk, _ := hex.DecodeString("167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62") + if !bytes.Equal(sk1, sk) { + t.Fatalf("shared secret mismatch: want: %x have: %x", sk, sk1) + } +} + +// TODO: remove after refactoring packages crypto and crypto/ecies +func hexKey(prv string) *PrivateKey { + priv := new(ecdsa.PrivateKey) + priv.PublicKey.Curve = secp256k1.S256() + priv.D, _ = new(big.Int).SetString(prv, 16) + priv.PublicKey.X, priv.PublicKey.Y = secp256k1.S256().ScalarBaseMult(priv.D.Bytes()) + return ImportECDSA(priv) +} diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go index 97ddb09730..511c53ebc0 100644 --- a/crypto/ecies/params.go +++ b/crypto/ecies/params.go @@ -41,13 +41,12 @@ import ( "crypto/sha512" "fmt" "hash" + + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) -// The default curve for this package is the NIST P256 curve, which -// provides security equivalent to AES-128. -var DefaultCurve = elliptic.P256() - var ( + DefaultCurve = secp256k1.S256() ErrUnsupportedECDHAlgorithm = fmt.Errorf("ecies: unsupported ECDH algorithm") ErrUnsupportedECIESParameters = fmt.Errorf("ecies: unsupported ECIES parameters") ) @@ -101,9 +100,10 @@ var ( ) var paramsFromCurve = map[elliptic.Curve]*ECIESParams{ - elliptic.P256(): ECIES_AES128_SHA256, - elliptic.P384(): ECIES_AES256_SHA384, - elliptic.P521(): ECIES_AES256_SHA512, + secp256k1.S256(): ECIES_AES128_SHA256, + elliptic.P256(): ECIES_AES128_SHA256, + elliptic.P384(): ECIES_AES256_SHA384, + elliptic.P521(): ECIES_AES256_SHA512, } func AddParamsForCurve(curve elliptic.Curve, params *ECIESParams) { diff --git a/crypto/key.go b/crypto/key.go index 4ec43dfd74..ccf284ad8d 100644 --- a/crypto/key.go +++ b/crypto/key.go @@ -25,6 +25,7 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/secp256k1" "github.com/pborman/uuid" ) @@ -137,7 +138,7 @@ func NewKey(rand io.Reader) *Key { panic("key generation: could not read from random source: " + err.Error()) } reader := bytes.NewReader(randBytes) - privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader) + privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader) if err != nil { panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) } @@ -155,7 +156,7 @@ func NewKeyForDirectICAP(rand io.Reader) *Key { panic("key generation: could not read from random source: " + err.Error()) } reader := bytes.NewReader(randBytes) - privateKeyECDSA, err := ecdsa.GenerateKey(S256(), reader) + privateKeyECDSA, err := ecdsa.GenerateKey(secp256k1.S256(), reader) if err != nil { panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) } diff --git a/crypto/curve.go b/crypto/secp256k1/curve.go similarity index 67% rename from crypto/curve.go rename to crypto/secp256k1/curve.go index 48f3f5e9ce..6e44a6771f 100644 --- a/crypto/curve.go +++ b/crypto/secp256k1/curve.go @@ -29,15 +29,22 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -package crypto +package secp256k1 import ( "crypto/elliptic" "io" "math/big" "sync" + "unsafe" ) +/* +#include "libsecp256k1/include/secp256k1.h" +extern int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar); +*/ +import "C" + // This code is from https://github.com/ThePiachu/GoBit and implements // several Koblitz elliptic curves over prime fields. // @@ -211,44 +218,37 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, return x3, y3, z3 } -//TODO: double check if it is okay -// ScalarMult returns k*(Bx,By) where k is a number in big-endian form. -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { - // We have a slight problem in that the identity of the group (the - // point at infinity) cannot be represented in (x, y) form on a finite - // machine. Thus the standard add/double algorithm has to be tweaked - // slightly: our initial state is not the identity, but x, and we - // ignore the first true bit in |k|. If we don't find any true bits in - // |k|, then we return nil, nil, because we cannot return the identity - // element. - - Bz := new(big.Int).SetInt64(1) - x := Bx - y := By - z := Bz - - seenFirstTrue := false - for _, byte := range k { - for bitNum := 0; bitNum < 8; bitNum++ { - if seenFirstTrue { - x, y, z = BitCurve.doubleJacobian(x, y, z) - } - if byte&0x80 == 0x80 { - if !seenFirstTrue { - seenFirstTrue = true - } else { - x, y, z = BitCurve.addJacobian(Bx, By, Bz, x, y, z) - } - } - byte <<= 1 - } +func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { + // Ensure scalar is exactly 32 bytes. We pad always, even if + // scalar is 32 bytes long, to avoid a timing side channel. + if len(scalar) > 32 { + panic("can't handle scalars > 256 bits") } + padded := make([]byte, 32) + copy(padded[32-len(scalar):], scalar) + scalar = padded - if !seenFirstTrue { + // Do the multiplication in C, updating point. + point := make([]byte, 64) + readBits(point[:32], Bx) + readBits(point[32:], By) + pointPtr := (*C.uchar)(unsafe.Pointer(&point[0])) + scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0])) + res := C.secp256k1_pubkey_scalar_mul(context, pointPtr, scalarPtr) + + // Unpack the result and clear temporaries. + x := new(big.Int).SetBytes(point[:32]) + y := new(big.Int).SetBytes(point[32:]) + for i := range point { + point[i] = 0 + } + for i := range padded { + scalar[i] = 0 + } + if res != 1 { return nil, nil } - - return BitCurve.affineFromJacobian(x, y, z) + return x, y } // ScalarBaseMult returns k*G, where G is the base point of the group and k is @@ -312,86 +312,24 @@ func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { return } -//curve parameters taken from: -//http://www.secg.org/collateral/sec2_final.pdf - -var initonce sync.Once -var ecp160k1 *BitCurve -var ecp192k1 *BitCurve -var ecp224k1 *BitCurve -var ecp256k1 *BitCurve - -func initAll() { - initS160() - initS192() - initS224() - initS256() -} - -func initS160() { - // See SEC 2 section 2.4.1 - ecp160k1 = new(BitCurve) - ecp160k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", 16) - ecp160k1.N, _ = new(big.Int).SetString("0100000000000000000001B8FA16DFAB9ACA16B6B3", 16) - ecp160k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000007", 16) - ecp160k1.Gx, _ = new(big.Int).SetString("3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", 16) - ecp160k1.Gy, _ = new(big.Int).SetString("938CF935318FDCED6BC28286531733C3F03C4FEE", 16) - ecp160k1.BitSize = 160 -} - -func initS192() { - // See SEC 2 section 2.5.1 - ecp192k1 = new(BitCurve) - ecp192k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", 16) - ecp192k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 16) - ecp192k1.B, _ = new(big.Int).SetString("000000000000000000000000000000000000000000000003", 16) - ecp192k1.Gx, _ = new(big.Int).SetString("DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", 16) - ecp192k1.Gy, _ = new(big.Int).SetString("9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", 16) - ecp192k1.BitSize = 192 -} - -func initS224() { - // See SEC 2 section 2.6.1 - ecp224k1 = new(BitCurve) - ecp224k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", 16) - ecp224k1.N, _ = new(big.Int).SetString("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 16) - ecp224k1.B, _ = new(big.Int).SetString("00000000000000000000000000000000000000000000000000000005", 16) - ecp224k1.Gx, _ = new(big.Int).SetString("A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", 16) - ecp224k1.Gy, _ = new(big.Int).SetString("7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", 16) - ecp224k1.BitSize = 224 -} - -func initS256() { - // See SEC 2 section 2.7.1 - ecp256k1 = new(BitCurve) - ecp256k1.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16) - ecp256k1.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) - ecp256k1.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16) - ecp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) - ecp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16) - ecp256k1.BitSize = 256 -} - -// S160 returns a BitCurve which implements secp160k1 (see SEC 2 section 2.4.1) -func S160() *BitCurve { - initonce.Do(initAll) - return ecp160k1 -} - -// S192 returns a BitCurve which implements secp192k1 (see SEC 2 section 2.5.1) -func S192() *BitCurve { - initonce.Do(initAll) - return ecp192k1 -} - -// S224 returns a BitCurve which implements secp224k1 (see SEC 2 section 2.6.1) -func S224() *BitCurve { - initonce.Do(initAll) - return ecp224k1 -} +var ( + initonce sync.Once + theCurve *BitCurve +) // S256 returns a BitCurve which implements secp256k1 (see SEC 2 section 2.7.1) func S256() *BitCurve { - initonce.Do(initAll) - return ecp256k1 + initonce.Do(func() { + // See SEC 2 section 2.7.1 + // curve parameters taken from: + // http://www.secg.org/collateral/sec2_final.pdf + theCurve = new(BitCurve) + theCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16) + theCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16) + theCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16) + theCurve.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16) + theCurve.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16) + theCurve.BitSize = 256 + }) + return theCurve } diff --git a/crypto/secp256k1/curve_test.go b/crypto/secp256k1/curve_test.go new file mode 100644 index 0000000000..d915ee8525 --- /dev/null +++ b/crypto/secp256k1/curve_test.go @@ -0,0 +1,39 @@ +// 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 . + +package secp256k1 + +import ( + "bytes" + "encoding/hex" + "math/big" + "testing" +) + +func TestReadBits(t *testing.T) { + check := func(input string) { + want, _ := hex.DecodeString(input) + int, _ := new(big.Int).SetString(input, 16) + buf := make([]byte, len(want)) + readBits(buf, int) + if !bytes.Equal(buf, want) { + t.Errorf("have: %x\nwant: %x", buf, want) + } + } + check("000000000000000000000000000000000000000000000000000000FEFCF3F8F0") + check("0000000000012345000000000000000000000000000000000000FEFCF3F8F0") + check("18F8F8F1000111000110011100222004330052300000000000000000FEFCF3F8F0") +} diff --git a/crypto/secp256k1/pubkey_scalar_mul.h b/crypto/secp256k1/pubkey_scalar_mul.h new file mode 100644 index 0000000000..0511545ec0 --- /dev/null +++ b/crypto/secp256k1/pubkey_scalar_mul.h @@ -0,0 +1,56 @@ +// 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 . + +/** Multiply point by scalar in constant time. + * Returns: 1: multiplication was successful + * 0: scalar was invalid (zero or overflow) + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: point: the multiplied point (usually secret) + * In: point: pointer to a 64-byte bytepublic point, + encoded as two 256bit big-endian numbers. + * scalar: a 32-byte scalar with which to multiply the point + */ +int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) { + int ret = 0; + int overflow = 0; + secp256k1_fe feX, feY; + secp256k1_gej res; + secp256k1_ge ge; + secp256k1_scalar s; + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + (void)ctx; + + secp256k1_fe_set_b32(&feX, point); + secp256k1_fe_set_b32(&feY, point+32); + secp256k1_ge_set_xy(&ge, &feX, &feY); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_scalar_is_zero(&s)) { + ret = 0; + } else { + secp256k1_ecmult_const(&res, &ge, &s); + secp256k1_ge_set_gej(&ge, &res); + /* Note: can't use secp256k1_pubkey_save here because it is not constant time. */ + secp256k1_fe_normalize(&ge.x); + secp256k1_fe_normalize(&ge.y); + secp256k1_fe_get_b32(point, &ge.x); + secp256k1_fe_get_b32(point+32, &ge.y); + ret = 1; + } + secp256k1_scalar_clear(&s); + return ret; +} + diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 7f26f307cd..8dc2481454 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -20,6 +20,7 @@ package secp256k1 /* #cgo CFLAGS: -I./libsecp256k1 +#cgo CFLAGS: -I./libsecp256k1/src/ #cgo darwin CFLAGS: -I/usr/local/include #cgo freebsd CFLAGS: -I/usr/local/include #cgo linux,arm CFLAGS: -I/usr/local/arm/include @@ -35,6 +36,7 @@ package secp256k1 #define NDEBUG #include "./libsecp256k1/src/secp256k1.c" #include "./libsecp256k1/src/modules/recovery/main_impl.h" +#include "pubkey_scalar_mul.h" typedef void (*callbackFunc) (const char* msg, void* data); extern void secp256k1GoPanicIllegal(const char* msg, void* data); @@ -44,6 +46,7 @@ import "C" import ( "errors" + "math/big" "unsafe" "github.com/ethereum/go-ethereum/crypto/randentropy" @@ -56,13 +59,16 @@ import ( > store private keys in buffer and shuffle (deters persistance on swap disc) > byte permutation (changing) > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?) - > on disk: store keys in wallets */ // holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h) -var context *C.secp256k1_context +var ( + context *C.secp256k1_context + N *big.Int +) func init() { + N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) // around 20 ms on a modern CPU. context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil) @@ -78,7 +84,6 @@ var ( func GenerateKeyPair() ([]byte, []byte) { var seckey []byte = randentropy.GetEntropyCSPRNG(32) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) - var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0])) @@ -96,7 +101,7 @@ func GenerateKeyPair() ([]byte, []byte) { var output_len C.size_t - _ = C.secp256k1_ec_pubkey_serialize( // always returns 1 + C.secp256k1_ec_pubkey_serialize( // always returns 1 context, pubkey65_ptr, &output_len, @@ -163,7 +168,7 @@ func Sign(msg []byte, seckey []byte) ([]byte, error) { sig_serialized_ptr := (*C.uchar)(unsafe.Pointer(&sig_serialized[0])) var recid C.int - _ = C.secp256k1_ecdsa_recoverable_signature_serialize_compact( + C.secp256k1_ecdsa_recoverable_signature_serialize_compact( context, sig_serialized_ptr, // 64 byte compact signature &recid, @@ -254,3 +259,16 @@ func checkSignature(sig []byte) error { } return nil } + +// reads num into buf as big-endian bytes. +func readBits(buf []byte, num *big.Int) { + const wordLen = int(unsafe.Sizeof(big.Word(0))) + i := len(buf) + for _, d := range num.Bits() { + for j := 0; j < wordLen && i > 0; j++ { + i-- + buf[i] = byte(d) + d >>= 8 + } + } +} diff --git a/crypto/secp256k1/secp256_test.go b/crypto/secp256k1/secp256_test.go index d3ff2223d5..fc6fc9b32e 100644 --- a/crypto/secp256k1/secp256_test.go +++ b/crypto/secp256k1/secp256_test.go @@ -24,7 +24,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/randentropy" ) -const TestCount = 10000 +const TestCount = 1000 func TestPrivkeyGenerate(t *testing.T) { _, seckey := GenerateKeyPair() diff --git a/p2p/discover/node.go b/p2p/discover/node.go index a14f294249..dd19df3a2c 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -210,7 +210,7 @@ func PubkeyID(pub *ecdsa.PublicKey) NodeID { // Pubkey returns the public key represented by the node ID. // It returns an error if the ID is not a point on the curve. func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) { - p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)} + p := &ecdsa.PublicKey{Curve: secp256k1.S256(), X: new(big.Int), Y: new(big.Int)} half := len(id) / 2 p.X.SetBytes(id[:half]) p.Y.SetBytes(id[half:]) diff --git a/p2p/rlpx.go b/p2p/rlpx.go index aaa7338547..8f429d6ec1 100644 --- a/p2p/rlpx.go +++ b/p2p/rlpx.go @@ -277,7 +277,7 @@ func newInitiatorHandshake(remoteID discover.NodeID) (*encHandshake, error) { return nil, err } // generate random keypair to use for signing - randpriv, err := ecies.GenerateKey(rand.Reader, crypto.S256(), nil) + randpriv, err := ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) if err != nil { return nil, err } @@ -376,7 +376,7 @@ func decodeAuthMsg(prv *ecdsa.PrivateKey, token []byte, auth []byte) (*encHandsh var err error h := new(encHandshake) // generate random keypair for session - h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil) + h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, secp256k1.S256(), nil) if err != nil { return nil, err } diff --git a/p2p/rlpx_test.go b/p2p/rlpx_test.go index 900353f0ee..7cc7548e2b 100644 --- a/p2p/rlpx_test.go +++ b/p2p/rlpx_test.go @@ -93,6 +93,7 @@ func testEncHandshake(token []byte) error { go func() { r := result{side: "initiator"} defer func() { output <- r }() + defer fd0.Close() dest := &discover.Node{ID: discover.PubkeyID(&prv1.PublicKey)} r.id, r.err = c0.doEncHandshake(prv0, dest) @@ -107,6 +108,7 @@ func testEncHandshake(token []byte) error { go func() { r := result{side: "receiver"} defer func() { output <- r }() + defer fd1.Close() r.id, r.err = c1.doEncHandshake(prv1, nil) if r.err != nil { diff --git a/whisper/message_test.go b/whisper/message_test.go index 6ff95efff5..d70da40a4a 100644 --- a/whisper/message_test.go +++ b/whisper/message_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/secp256k1" ) // Tests whether a message can be wrapped without any identity or encryption. @@ -72,8 +73,8 @@ func TestMessageCleartextSignRecover(t *testing.T) { if pubKey == nil { t.Fatalf("failed to recover public key") } - p1 := elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y) - p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y) + p1 := elliptic.Marshal(secp256k1.S256(), key.PublicKey.X, key.PublicKey.Y) + p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y) if !bytes.Equal(p1, p2) { t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1) } @@ -150,8 +151,8 @@ func TestMessageFullCrypto(t *testing.T) { if pubKey == nil { t.Fatalf("failed to recover public key") } - p1 := elliptic.Marshal(crypto.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y) - p2 := elliptic.Marshal(crypto.S256(), pubKey.X, pubKey.Y) + p1 := elliptic.Marshal(secp256k1.S256(), fromKey.PublicKey.X, fromKey.PublicKey.Y) + p2 := elliptic.Marshal(secp256k1.S256(), pubKey.X, pubKey.Y) if !bytes.Equal(p1, p2) { t.Fatalf("public key mismatch: have 0x%x, want 0x%x", p2, p1) } From 448039fc8beea519a055aee81f00f23ac3e78f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 2 Dec 2015 16:57:15 +0200 Subject: [PATCH 22/27] Makefile: enable 64-bit ARM builds on Linux --- Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 12802647e3..297f3ac006 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,8 @@ # don't need to bother with make. .PHONY: geth geth-cross evm all test travis-test-with-coverage xgo clean -.PHONY: geth-linux geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-386 geth-linux-amd64 +.PHONY: geth-linux geth-linux-386 geth-linux-amd64 +.PHONY: geth-linux-arm geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64 .PHONY: geth-darwin geth-darwin-386 geth-darwin-amd64 .PHONY: geth-windows geth-windows-386 geth-windows-amd64 .PHONY: geth-android geth-ios @@ -37,7 +38,7 @@ geth-linux-amd64: xgo @echo "Linux amd64 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep amd64 -geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 +geth-linux-arm: geth-linux-arm-5 geth-linux-arm-6 geth-linux-arm-7 geth-linux-arm64 @echo "Linux ARM cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep arm @@ -56,6 +57,11 @@ geth-linux-arm-7: xgo @echo "Linux ARMv7 cross compilation done:" @ls -l $(GOBIN)/geth-linux-* | grep arm-7 +geth-linux-arm64: xgo + build/env.sh $(GOBIN)/xgo --go=$(GO) --buildmode=$(MODE) --dest=$(GOBIN) --deps=$(CROSSDEPS) --targets=linux/arm64 -v $(shell build/flags.sh) ./cmd/geth + @echo "Linux ARM64 cross compilation done:" + @ls -l $(GOBIN)/geth-linux-* | grep arm64 + geth-darwin: geth-darwin-386 geth-darwin-amd64 @echo "Darwin cross compilation done:" @ls -l $(GOBIN)/geth-darwin-* From 6f56d5760091aed0facf1a935a9de46b888f38a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=9ETH=CE=9E=D0=AFSPH=CE=9E=D0=AF=CE=9E?= Date: Thu, 3 Dec 2015 21:42:43 +0000 Subject: [PATCH 23/27] Swarm - plan bee for content storage and distribution on web3 --- accounts/account_manager.go | 10 + cmd/geth/js.go | 5 +- cmd/geth/js_bzz_test.go | 83 ++ cmd/geth/js_test.go | 18 +- cmd/geth/main.go | 88 +-- cmd/utils/customflags.go | 4 +- cmd/utils/customflags_test.go | 2 +- cmd/utils/flags.go | 111 ++- common/bytes.go | 19 +- common/chequebook/cheque.go | 660 ++++++++++++++++ common/chequebook/cheque_test.go | 498 ++++++++++++ common/chequebook/chequebook.sol | 49 ++ common/chequebook/contract.go | 63 ++ common/kademlia/address.go | 157 ++++ common/kademlia/address_test.go | 80 ++ common/kademlia/kaddb.go | 360 +++++++++ common/kademlia/kademlia.go | 457 +++++++++++ common/kademlia/kademlia_test.go | 389 +++++++++ common/registrar/ethreg/ethreg.go | 22 +- common/swap/swap.go | 238 ++++++ common/swap/swap_test.go | 178 +++++ common/types.go | 13 + core/genesis.go | 5 + rpc/api/bzz.go | 278 +++++++ rpc/api/bzz_args.go | 322 ++++++++ rpc/api/bzz_js.go | 95 +++ rpc/api/utils.go | 27 +- rpc/shared/utils.go | 3 +- swarm/api/api.go | 456 +++++++++++ swarm/api/api_test.go | 205 +++++ swarm/api/config.go | 105 +++ swarm/api/config_test.go | 107 +++ swarm/api/ethereum.go | 320 ++++++++ swarm/api/http.go | 247 ++++++ swarm/api/manifest.go | 310 ++++++++ swarm/api/manifest_test.go | 61 ++ swarm/api/roundtripper.go | 22 + swarm/api/roundtripper_test.go | 50 ++ swarm/cmd/bzzhash/bzzhash.go | 38 + swarm/cmd/bzzup.sh | 46 ++ swarm/examples/album/add.png | Bin 0 -> 129 bytes swarm/examples/album/back.png | Bin 0 -> 388 bytes swarm/examples/album/cut-left.png | Bin 0 -> 221 bytes swarm/examples/album/cut-mov.png | Bin 0 -> 197 bytes swarm/examples/album/cut-right.png | Bin 0 -> 193 bytes swarm/examples/album/cut-top.png | Bin 0 -> 205 bytes swarm/examples/album/data.json | 1 + swarm/examples/album/delete.png | Bin 0 -> 552 bytes swarm/examples/album/down.png | Bin 0 -> 403 bytes swarm/examples/album/download.png | Bin 0 -> 422 bytes swarm/examples/album/eye.png | Bin 0 -> 525 bytes swarm/examples/album/imgs/apron.jpg | Bin 0 -> 419037 bytes swarm/examples/album/imgs/bekas1.jpg | Bin 0 -> 554726 bytes swarm/examples/album/imgs/bekas2.jpg | Bin 0 -> 508279 bytes swarm/examples/album/imgs/bekas_blanik.jpg | Bin 0 -> 604048 bytes swarm/examples/album/imgs/hangar.jpg | Bin 0 -> 435136 bytes swarm/examples/album/imgs/hangar_inside.jpg | Bin 0 -> 646483 bytes swarm/examples/album/imgs/ruin.jpg | Bin 0 -> 467321 bytes swarm/examples/album/index.css | 291 +++++++ swarm/examples/album/index.html | 20 + swarm/examples/album/index.js | 836 ++++++++++++++++++++ swarm/examples/album/left.png | Bin 0 -> 686 bytes swarm/examples/album/mootools-core-1.4.js | 491 ++++++++++++ swarm/examples/album/mootools-idle.js | 198 +++++ swarm/examples/album/mootools-mooswipe.js | 77 ++ swarm/examples/album/mootools-more-1.4.js | 45 ++ swarm/examples/album/noise.png | Bin 0 -> 65982 bytes swarm/examples/album/right.png | Bin 0 -> 669 bytes swarm/examples/album/throbber.gif | Bin 0 -> 1657 bytes swarm/examples/album/up.png | Bin 0 -> 367 bytes swarm/examples/bzzhandler.html | 15 + swarm/network/depo.go | 190 +++++ swarm/network/forwarding.go | 131 +++ swarm/network/hive.go | 322 ++++++++ swarm/network/messages.go | 294 +++++++ swarm/network/protocol.go | 505 ++++++++++++ swarm/network/protocol_test.go | 1 + swarm/network/syncdb.go | 371 +++++++++ swarm/network/syncdb_test.go | 205 +++++ swarm/network/syncer.go | 762 ++++++++++++++++++ swarm/services/swap/swap.go | 271 +++++++ swarm/services/swear/doc.go | 3 + swarm/services/swear/swear.sol | 161 ++++ swarm/services/swear/swear_test.go | 1 + swarm/storage/chunker.go | 411 ++++++++++ swarm/storage/chunker_test.go | 214 +++++ swarm/storage/chunkreader.go | 194 +++++ swarm/storage/common_test.go | 94 +++ swarm/storage/database.go | 96 +++ swarm/storage/dbstore.go | 457 +++++++++++ swarm/storage/dbstore_test.go | 172 ++++ swarm/storage/dpa.go | 234 ++++++ swarm/storage/dpa_test.go | 133 ++++ swarm/storage/localstore.go | 53 ++ swarm/storage/memstore.go | 336 ++++++++ swarm/storage/memstore_test.go | 34 + swarm/storage/netstore.go | 117 +++ swarm/storage/types.go | 155 ++++ swarm/swarm.go | 231 ++++++ swarm/test/syncing/00.sh | 83 ++ swarm/test/test0/img/logo.png | Bin 0 -> 18136 bytes swarm/test/test0/index.css | 9 + swarm/test/test0/index.html | 10 + 103 files changed, 14314 insertions(+), 111 deletions(-) create mode 100644 cmd/geth/js_bzz_test.go create mode 100644 common/chequebook/cheque.go create mode 100644 common/chequebook/cheque_test.go create mode 100644 common/chequebook/chequebook.sol create mode 100644 common/chequebook/contract.go create mode 100644 common/kademlia/address.go create mode 100644 common/kademlia/address_test.go create mode 100644 common/kademlia/kaddb.go create mode 100644 common/kademlia/kademlia.go create mode 100644 common/kademlia/kademlia_test.go create mode 100644 common/swap/swap.go create mode 100644 common/swap/swap_test.go create mode 100644 rpc/api/bzz.go create mode 100644 rpc/api/bzz_args.go create mode 100644 rpc/api/bzz_js.go create mode 100644 swarm/api/api.go create mode 100644 swarm/api/api_test.go create mode 100644 swarm/api/config.go create mode 100644 swarm/api/config_test.go create mode 100644 swarm/api/ethereum.go create mode 100644 swarm/api/http.go create mode 100644 swarm/api/manifest.go create mode 100644 swarm/api/manifest_test.go create mode 100644 swarm/api/roundtripper.go create mode 100644 swarm/api/roundtripper_test.go create mode 100644 swarm/cmd/bzzhash/bzzhash.go create mode 100755 swarm/cmd/bzzup.sh create mode 100644 swarm/examples/album/add.png create mode 100644 swarm/examples/album/back.png create mode 100644 swarm/examples/album/cut-left.png create mode 100644 swarm/examples/album/cut-mov.png create mode 100644 swarm/examples/album/cut-right.png create mode 100644 swarm/examples/album/cut-top.png create mode 100644 swarm/examples/album/data.json create mode 100644 swarm/examples/album/delete.png create mode 100644 swarm/examples/album/down.png create mode 100644 swarm/examples/album/download.png create mode 100644 swarm/examples/album/eye.png create mode 100644 swarm/examples/album/imgs/apron.jpg create mode 100644 swarm/examples/album/imgs/bekas1.jpg create mode 100644 swarm/examples/album/imgs/bekas2.jpg create mode 100644 swarm/examples/album/imgs/bekas_blanik.jpg create mode 100644 swarm/examples/album/imgs/hangar.jpg create mode 100644 swarm/examples/album/imgs/hangar_inside.jpg create mode 100644 swarm/examples/album/imgs/ruin.jpg create mode 100644 swarm/examples/album/index.css create mode 100644 swarm/examples/album/index.html create mode 100644 swarm/examples/album/index.js create mode 100644 swarm/examples/album/left.png create mode 100644 swarm/examples/album/mootools-core-1.4.js create mode 100644 swarm/examples/album/mootools-idle.js create mode 100644 swarm/examples/album/mootools-mooswipe.js create mode 100644 swarm/examples/album/mootools-more-1.4.js create mode 100644 swarm/examples/album/noise.png create mode 100644 swarm/examples/album/right.png create mode 100644 swarm/examples/album/throbber.gif create mode 100644 swarm/examples/album/up.png create mode 100644 swarm/examples/bzzhandler.html create mode 100644 swarm/network/depo.go create mode 100644 swarm/network/forwarding.go create mode 100644 swarm/network/hive.go create mode 100644 swarm/network/messages.go create mode 100644 swarm/network/protocol.go create mode 100644 swarm/network/protocol_test.go create mode 100644 swarm/network/syncdb.go create mode 100644 swarm/network/syncdb_test.go create mode 100644 swarm/network/syncer.go create mode 100644 swarm/services/swap/swap.go create mode 100644 swarm/services/swear/doc.go create mode 100644 swarm/services/swear/swear.sol create mode 100644 swarm/services/swear/swear_test.go create mode 100644 swarm/storage/chunker.go create mode 100644 swarm/storage/chunker_test.go create mode 100644 swarm/storage/chunkreader.go create mode 100644 swarm/storage/common_test.go create mode 100644 swarm/storage/database.go create mode 100644 swarm/storage/dbstore.go create mode 100644 swarm/storage/dbstore_test.go create mode 100644 swarm/storage/dpa.go create mode 100644 swarm/storage/dpa_test.go create mode 100644 swarm/storage/localstore.go create mode 100644 swarm/storage/memstore.go create mode 100644 swarm/storage/memstore_test.go create mode 100644 swarm/storage/netstore.go create mode 100644 swarm/storage/types.go create mode 100644 swarm/swarm.go create mode 100644 swarm/test/syncing/00.sh create mode 100644 swarm/test/test0/img/logo.png create mode 100644 swarm/test/test0/index.css create mode 100644 swarm/test/test0/index.html diff --git a/accounts/account_manager.go b/accounts/account_manager.go index 74006395cd..2ada1a9804 100644 --- a/accounts/account_manager.go +++ b/accounts/account_manager.go @@ -91,6 +91,16 @@ func (am *Manager) Sign(a Account, toSign []byte) (signature []byte, err error) return signature, err } +func (am *Manager) GetUnlocked(addr common.Address) (prvkey *ecdsa.PrivateKey, err error) { + am.mutex.RLock() + defer am.mutex.RUnlock() + unlockedKey, found := am.unlocked[addr] + if !found { + return nil, ErrLocked + } + return unlockedKey.PrivateKey, nil +} + // Unlock unlocks the given account indefinitely. func (am *Manager) Unlock(addr common.Address, keyAuth string) error { return am.TimedUnlock(addr, keyAuth, 0) diff --git a/cmd/geth/js.go b/cmd/geth/js.go index 56b7a8b001..008b581024 100644 --- a/cmd/geth/js.go +++ b/cmd/geth/js.go @@ -24,9 +24,8 @@ import ( "os/signal" "path/filepath" "regexp" - "strings" - "sort" + "strings" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" @@ -190,6 +189,8 @@ func newJSRE(stack *node.Node, docRoot, corsDomain string, client comms.Ethereum 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...)) + } else { + utils.Fatalf("Unable to offer apis: %v", err) } } diff --git a/cmd/geth/js_bzz_test.go b/cmd/geth/js_bzz_test.go new file mode 100644 index 0000000000..2d8b70efb9 --- /dev/null +++ b/cmd/geth/js_bzz_test.go @@ -0,0 +1,83 @@ +package main + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/swarm" + "github.com/ethereum/go-ethereum/swarm/api" +) + +var port = 8500 + +func bzzREPL(t *testing.T, configf func(*api.Config)) (string, string, *testjethre, *node.Node) { + prvKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal("unable to generate key") + } + bzztmp, err := ioutil.TempDir("", "bzz-js-test") + config, err := api.NewConfig(bzztmp, common.Address{}, prvKey) + if err != nil { + t.Fatal("unable to configure swarm") + } + if configf != nil { + configf(config) + } + tmp, repl, stack := testREPL(t, func(n *node.Node) { + if err := n.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return swarm.NewSwarm(ctx, config, false) + }); err != nil { + t.Fatalf("Failed to register the Swarm service: %v", err) + } + }) + return bzztmp, tmp, repl, stack +} + +func withREPL(t *testing.T, cf func(*api.Config), f func(repl *testjethre)) { + bzztmp, tmp, repl, stack := bzzREPL(t, cf) + defer stack.Stop() + defer os.RemoveAll(tmp) + defer os.RemoveAll(bzztmp) + f(repl) +} + +func TestBzzPutGet(t *testing.T) { + withREPL(t, + func(c *api.Config) { + c.Port = "" + }, func(repl *testjethre) { + if checkEvalJSON(t, repl, `hash = bzz.put("console.log(\"hello from console\")", "application/javascript")`, `"97f1b7c7ea12468fd37c262383b9aa862d0cfbc4fc7218652374679fc5cf40cd"`) != nil { + return + } + want := `{"content":"console.log(\"hello from console\")","contentType":"application/javascript","size":"33","status":"0"}` + if checkEvalJSON(t, repl, `bzz.get(hash)`, want) != nil { + return + } + }) +} + +// the server can be initialized only once per test session ! +// until we implement a stoppable http server +// further http tests will need to make sure the correct server is running +func TestHTTP(t *testing.T) { + withREPL(t, nil, func(repl *testjethre) { + if checkEvalJSON(t, repl, `hash = bzz.put("f42 = function() { return 42 }", "application/javascript")`, `"e6847876f00102441f850b2d438a06d10e3bf24e6a0a76d47b073a86c3c2f9ac"`) != nil { + return + } + if checkEvalJSON(t, repl, `admin.httpGet("bzz://"+hash)`, `"f42 = function() { return 42 }"`) != nil { + return + } + + // if checkEvalJSON(t, repl, `http.loadScript("bzz://"+hash)`, `true`) != nil { + // return + // } + + // if checkEvalJSON(t, repl, `f42()`, `42`) != nil { + // return + // } + }) +} diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go index ca636188f4..975f8dde5e 100644 --- a/cmd/geth/js_test.go +++ b/cmd/geth/js_test.go @@ -91,7 +91,7 @@ func testJEthRE(t *testing.T) (string, *testjethre, *node.Node) { return testREPL(t, nil) } -func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *node.Node) { +func testREPL(t *testing.T, config func(*node.Node)) (string, *testjethre, *node.Node) { tmp, err := ioutil.TempDir("", "geth-test") if err != nil { t.Fatal(err) @@ -107,17 +107,16 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod db, _ := ethdb.NewMemDatabase() core.WriteGenesisBlockForTesting(db, core.GenesisAccount{common.HexToAddress(testAddress), common.String2Big(testBalance)}) + coinbase := common.HexToAddress(testAddress) ethConf := ð.Config{ TestGenesisState: db, AccountManager: accman, DocRoot: "/", SolcPath: testSolcPath, + Etherbase: coinbase, PowTest: true, } - if config != nil { - config(ethConf) - } 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) } @@ -133,6 +132,12 @@ func testREPL(t *testing.T, config func(*eth.Config)) (string, *testjethre, *nod if err := accman.Unlock(key.Address, ""); err != nil { t.Fatal(err) } + + // tests can register services here + if config != nil { + config(stack) + } + // Start the node and assemble the REPL tester if err := stack.Start(); err != nil { t.Fatalf("failed to start test stack: %v", err) @@ -267,10 +272,7 @@ func TestSignature(t *testing.T) { func TestContract(t *testing.T) { t.Skip("contract testing is implemented with mining in ethash test mode. This takes about 7seconds to run. Unskip and run on demand") coinbase := common.HexToAddress(testAddress) - tmp, repl, ethereum := testREPL(t, func(conf *eth.Config) { - conf.Etherbase = coinbase - conf.PowTest = true - }) + tmp, repl, ethereum := testREPL(t, nil) if err := ethereum.Start(); err != nil { t.Errorf("error starting ethereum: %v", err) return diff --git a/cmd/geth/main.go b/cmd/geth/main.go index bb291ccde2..6557de2df8 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -4,7 +4,7 @@ // go-ethereum is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// (at your option) any later version. // // go-ethereum is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,9 +30,7 @@ import ( "github.com/codegangsta/cli" "github.com/ethereum/ethash" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" @@ -316,6 +314,9 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso utils.IPCExperimental, utils.ExecFlag, utils.WhisperEnabledFlag, + utils.SwarmConfigPathFlag, + utils.SwarmAccountAddrFlag, + utils.ChequebookAddrFlag, utils.DevModeFlag, utils.TestNetFlag, utils.VMDebugFlag, @@ -427,6 +428,7 @@ func attach(ctx *cli.Context) { func console(ctx *cli.Context) { // Create and start the node based on the CLI flags node := utils.MakeSystemNode(ClientIdentifier, nodeNameVersion, makeDefaultExtra(), ctx) + startNode(ctx, node) // Attach to the newly started node, and either execute script or become interactive @@ -465,46 +467,14 @@ func execScripts(ctx *cli.Context) { node.Stop() } -// tries unlocking the specified account a few times. -func unlockAccount(ctx *cli.Context, accman *accounts.Manager, address string, i int, passwords []string) (common.Address, string) { - account, err := utils.MakeAddress(accman, address) - if err != nil { - utils.Fatalf("Unlock error: %v", err) - } - - for trials := 0; trials < 3; trials++ { - prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) - password := getPassPhrase(prompt, false, i, passwords) - if err := accman.Unlock(account, password); err == nil { - return account, password - } - } - // All trials expended to unlock account, bail out - utils.Fatalf("Failed to unlock account: %s", address) - return common.Address{}, "" -} - -// startNode boots up the system node and all registered protocols, after which -// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the +// startNode unlocks any requested accounts the boots up the system node +// starts all registered protocols and +// starts the RPC/IPC interfaces and the // miner. func startNode(ctx *cli.Context, stack *node.Node) { // Start up the node itself utils.StartNode(stack) - // Unlock any account specifically requested - var ethereum *eth.Ethereum - if err := stack.Service(ðereum); err != nil { - utils.Fatalf("ethereum service not running: %v", err) - } - accman := ethereum.AccountManager() - passwords := utils.MakePasswordList(ctx) - - accounts := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") - for i, account := range accounts { - if trimmed := strings.TrimSpace(account); trimmed != "" { - unlockAccount(ctx, accman, trimmed, i, passwords) - } - } // Start auxiliary services if enabled. if !ctx.GlobalBool(utils.IPCDisabledFlag.Name) { if err := utils.StartIPC(stack, ctx); err != nil { @@ -516,6 +486,10 @@ func startNode(ctx *cli.Context, stack *node.Node) { utils.Fatalf("Failed to start RPC: %v", err) } } + var ethereum *eth.Ethereum + if err := stack.Service(ðereum); err != nil { + utils.Fatalf("ethereum service not running: %v", err) + } if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil { utils.Fatalf("Failed to start mining: %v", err) @@ -534,38 +508,10 @@ func accountList(ctx *cli.Context) { } } -// getPassPhrase retrieves the passwor associated with an account, either fetched -// from a list of preloaded passphrases, or requested interactively from the user. -func getPassPhrase(prompt string, confirmation bool, i int, passwords []string) string { - // If a list of passwords was supplied, retrieve from them - if len(passwords) > 0 { - if i < len(passwords) { - return passwords[i] - } - return passwords[len(passwords)-1] - } - // Otherwise prompt the user for the password - fmt.Println(prompt) - password, err := utils.PromptPassword("Passphrase: ", true) - if err != nil { - utils.Fatalf("Failed to read passphrase: %v", err) - } - if confirmation { - confirm, err := utils.PromptPassword("Repeat passphrase: ", false) - if err != nil { - utils.Fatalf("Failed to read passphrase confirmation: %v", err) - } - if password != confirm { - utils.Fatalf("Passphrases do not match") - } - } - return password -} - // accountCreate creates a new account into the keystore defined by the CLI flags. func accountCreate(ctx *cli.Context) { accman := utils.MakeAccountManager(ctx) - password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) + password := utils.GetPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) account, err := accman.NewAccount(password) if err != nil { @@ -582,8 +528,8 @@ func accountUpdate(ctx *cli.Context) { } accman := utils.MakeAccountManager(ctx) - account, oldPassword := unlockAccount(ctx, accman, ctx.Args().First(), 0, nil) - newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil) + account, oldPassword := utils.UnlockAccount(ctx, accman, ctx.Args().First(), 0, nil) + newPassword := utils.GetPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil) if err := accman.Update(account, oldPassword, newPassword); err != nil { utils.Fatalf("Could not update the account: %v", err) } @@ -600,7 +546,7 @@ func importWallet(ctx *cli.Context) { } accman := utils.MakeAccountManager(ctx) - passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx)) + passphrase := utils.GetPassPhrase("", false, 0, utils.MakePasswordList(ctx)) acct, err := accman.ImportPreSaleKey(keyJson, passphrase) if err != nil { @@ -615,7 +561,7 @@ func accountImport(ctx *cli.Context) { utils.Fatalf("keyfile must be given as argument") } accman := utils.MakeAccountManager(ctx) - passphrase := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) + passphrase := utils.GetPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) acct, err := accman.Import(keyfile, passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) diff --git a/cmd/utils/customflags.go b/cmd/utils/customflags.go index 4450065c14..faf531121d 100644 --- a/cmd/utils/customflags.go +++ b/cmd/utils/customflags.go @@ -39,7 +39,7 @@ func (self *DirectoryString) String() string { } func (self *DirectoryString) Set(value string) error { - self.Value = expandPath(value) + self.Value = ExpandPath(value) return nil } @@ -135,7 +135,7 @@ func (self *DirectoryFlag) Set(value string) { // 2. expands embedded environment variables // 3. cleans the path, e.g. /a/b/../c -> /a/c // Note, it has limitations, e.g. ~someuser/tmp will not be expanded -func expandPath(p string) string { +func ExpandPath(p string) string { if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { if user, err := user.Current(); err == nil { p = user.HomeDir + p[1:] diff --git a/cmd/utils/customflags_test.go b/cmd/utils/customflags_test.go index de39ca36a1..05e47abe4d 100644 --- a/cmd/utils/customflags_test.go +++ b/cmd/utils/customflags_test.go @@ -33,7 +33,7 @@ func TestPathExpansion(t *testing.T) { } os.Setenv("DDDXXX", "/tmp") for test, expected := range tests { - got := expandPath(test) + got := ExpandPath(test) if got != expected { t.Errorf("test %s, got %s, expected %s\n", test, got, expected) } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index abee6210f3..0e65daa7cb 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -55,6 +55,8 @@ import ( "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/swarm" + bzzapi "github.com/ethereum/go-ethereum/swarm/api" "github.com/ethereum/go-ethereum/whisper" "github.com/ethereum/go-ethereum/xeth" ) @@ -351,6 +353,22 @@ var ( Name: "shh", Usage: "Enable Whisper", } + ChequebookAddrFlag = cli.StringFlag{ + Name: "chequebook", + Usage: "chequebook contract address", + } + SwarmAccountAddrFlag = cli.StringFlag{ + Name: "bzzaccount", + Usage: "Swarm account address (swarm disabled if empty)", + } + SwarmConfigPathFlag = cli.StringFlag{ + Name: "bzzconfig", + Usage: "Swarm config file path (datadir/bzz)", + } + SwarmSwapDisabled = cli.BoolFlag{ + Name: "bzznoswap", + Usage: "Swarm SWAP disabled (false)", + } // ATM the url is left to the user and deployment to JSpathFlag = cli.StringFlag{ Name: "jspath", @@ -582,6 +600,53 @@ func MakePasswordList(ctx *cli.Context) []string { return nil } +func UnlockAccount(ctx *cli.Context, accman *accounts.Manager, address string, i int, passwords []string) (common.Address, string) { + // Try to unlock the specified account a few times + account, err := MakeAddress(accman, address) + if err != nil { + Fatalf("unable to unlock account %v: %v", address, err) + } + + for trials := 0; trials < 3; trials++ { + prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) + password := GetPassPhrase(prompt, false, i, passwords) + if err := accman.Unlock(account, password); err == nil { + return account, password + } + } + // All trials expended to unlock account, bail out + Fatalf("Failed to unlock account: %s", address) + return common.Address{}, "" +} + +// getPassPhrase retrieves the passwor associated with an account, either fetched +// from a list of preloaded passphrases, or requested interactively from the user. +func GetPassPhrase(prompt string, confirmation bool, i int, passwords []string) string { + // If a list of passwords was supplied, retrieve from them + if len(passwords) > 0 { + if i < len(passwords) { + return passwords[i] + } + return passwords[len(passwords)-1] + } + // Otherwise prompt the user for the password + fmt.Println(prompt) + password, err := PromptPassword("Passphrase: ", true) + if err != nil { + Fatalf("Failed to read passphrase: %v", err) + } + if confirmation { + confirm, err := PromptPassword("Repeat passphrase: ", false) + if err != nil { + Fatalf("Failed to read passphrase confirmation: %v", err) + } + if password != confirm { + Fatalf("Passphrases do not match") + } + } + return password +} + // MakeSystemNode sets up a local node, configures the services to launch and // assembles the P2P protocol stack. func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node.Node { @@ -595,10 +660,12 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. if networks > 1 { Fatalf("The %v flags are mutually exclusive", netFlags) } + datadir := MustMakeDataDir(ctx) + netprv := MakeNodeKey(ctx) // Configure the node's service container stackConf := &node.Config{ - DataDir: MustMakeDataDir(ctx), - PrivateKey: MakeNodeKey(ctx), + DataDir: datadir, + PrivateKey: netprv, Name: MakeNodeName(name, version, ctx), NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name), BootstrapNodes: MakeBootstrapNodes(ctx), @@ -609,6 +676,14 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. } // Configure the Ethereum service accman := MakeAccountManager(ctx) + passwords := MakePasswordList(ctx) + + accounts := strings.Split(ctx.GlobalString(UnlockedAccountFlag.Name), ",") + for i, account := range accounts { + if trimmed := strings.TrimSpace(account); trimmed != "" { + UnlockAccount(ctx, accman, trimmed, i, passwords) + } + } ethConf := ð.Config{ Genesis: MakeGenesisBlock(ctx), @@ -685,17 +760,49 @@ func MakeSystemNode(name, version string, extra []byte, ctx *cli.Context) *node. if err != nil { Fatalf("Failed to create the protocol stack: %v", err) } + + // eth.Ethereum: ethereum if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil { Fatalf("Failed to register the Ethereum service: %v", err) } + + // Whisper if shhEnable { if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { Fatalf("Failed to register the Whisper service: %v", err) } } + // bzz. Swarm + var bzzconfig *bzzapi.Config + hexaddr := ctx.GlobalString(SwarmAccountAddrFlag.Name) + if hexaddr != "" { + swarmaccount := common.HexToAddress(hexaddr) + if !accman.HasAccount(swarmaccount) { + Fatalf("swarm account '%v' does not exist: %v", hexaddr, err) + } + prvkey, err := accman.GetUnlocked(swarmaccount) + if err != nil { + Fatalf("unable to unlock swarm account: %v", err) + } + chbookaddr := common.HexToAddress(ctx.GlobalString(ChequebookAddrFlag.Name)) + bzzdir := ctx.GlobalString(SwarmConfigPathFlag.Name) + if bzzdir == "" { + bzzdir = filepath.Join(datadir, "bzz") + } + bzzconfig, err = bzzapi.NewConfig(bzzdir, chbookaddr, prvkey) + if err != nil { + Fatalf("unable to configure swarm: %v", err) + } + swap := ctx.GlobalBool(SwarmSwapDisabled.Name) + if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { + return swarm.NewSwarm(ctx, bzzconfig, swap) + }); err != nil { + Fatalf("Failed to register the Swarm service: %v", err) + } + } return stack } diff --git a/common/bytes.go b/common/bytes.go index c6e2cd3127..ba6987a9ec 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -23,14 +23,9 @@ import ( "encoding/hex" "fmt" "math/big" - "regexp" "strings" ) -var ( - hexRe = regexp.MustCompile("^(0x)?([a-fA-f0-9]{2})+$") -) - func ToHex(b []byte) string { hex := Bytes2Hex(b) // Prefer output of "0x0" instead of "0x" @@ -144,14 +139,8 @@ func HasHexPrefix(str string) bool { } func IsHex(str string) bool { - return hexRe.MatchString(str) -} - -func NormaliseHex(str string) (string, bool) { - if HasHexPrefix(str) { - str = str[2:] - } - return str, IsHex(str) + l := len(str) + return l >= 4 && l%2 == 0 && str[0:2] == "0x" } func Bytes2Hex(d []byte) string { @@ -213,8 +202,8 @@ func ParseData(data ...interface{}) (ret []byte) { switch t := item.(type) { case string: var str []byte - if n, ok := NormaliseHex(t); ok { - str = Hex2Bytes(n) + if IsHex(t) { + str = Hex2Bytes(t[2:]) } else { str = []byte(t) } diff --git a/common/chequebook/cheque.go b/common/chequebook/cheque.go new file mode 100644 index 0000000000..41c89418b0 --- /dev/null +++ b/common/chequebook/cheque.go @@ -0,0 +1,660 @@ +package chequebook + +import ( + "bytes" + "crypto/ecdsa" + "encoding/json" + "fmt" + "io/ioutil" + "math/big" + "os" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/swap" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +/* +Chequebook package is a go API to the 'chequebook' ethereum smart contract +With convenience methods that allow using chequebook for +* issuing, receiving, verifying cheques in ether +* (auto)cashing cheques in ether +* (auto)depositing ether to the chequebook contract +TODO: +* watch peer solvency and notify of bouncing cheques +* enable paying with cheque by signing off + +Some functionality require interacting with the blockchain: +* setting current balance on peer's chequebook +* sending the transaction to cash the cheque +* depositing ether to the chequebook +* watching incoming ether + +Backend is the interface for that +*/ + +const ( + gasToCash = "2000000" // gas cost of a cash transaction using chequebook + getSentAbiPre = "d75d691d" // sent amount accessor in the chequebook contract + cashAbiPre = "fbf788d6" // abi preamble signature for cash method of the chequebook + queryInterval = 15000000000 // 15 seconds + deployGas = "3000000" + // confirmationInterval = 3 * 10 * *11 // 5 minutes +) + +// Backend is the interface to interact with the Ethereum blockchain +// implemented by xeth.XEth +type Backend interface { + Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) + Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) + GetTxReceipt(txhash common.Hash) *types.Receipt + CodeAt(address string) string +} + +// rlp serialised cheque model for use with the chequebook +type Cheque struct { + // the address of the contract itself needed to avoid cross-contract submission + Contract common.Address // contract address + Beneficiary common.Address // beneficiary + Amount *big.Int // cumulative amount of all funds sent + Sig []byte // signature Sign(Sha3(contract, beneficiary, amount), prvKey) +} + +type Params struct { + ContractCode, ContractAbi, ContractSource string +} + +var ContractParams = &Params{ContractCode, ContractAbi, ContractSource} + +func (self *Cheque) String() string { + return fmt.Sprintf("contract: %s, beneficiary: %s, amount: %v, signature: %x", self.Contract.Hex(), self.Beneficiary.Hex(), self.Amount, self.Sig) +} + +// chequebook to create, sign cheques from single contract to multiple beneficiarys +// outgoing payment handler for peer to peer micropayments +type Chequebook struct { + path string // path to chequebook file + prvKey *ecdsa.PrivateKey // private key to sign cheque with + lock sync.Mutex // + backend Backend // blockchain API + quit chan bool // when closed causes autodeposit to stop + owner common.Address // owner address (derived from pubkey) + + // persisted fields + balance *big.Int // not synced with blockchain + contract common.Address // contract address + sent map[common.Address]*big.Int //tallies for beneficiarys + + txhash string // tx hash of last deposit tx + threshold *big.Int // threshold that triggers autodeposit if not nil + buffer *big.Int // buffer to keep on top of balance for fork protection +} + +func Deploy(owner common.Address, backend Backend, amount *big.Int, confirmationInterval, timeout time.Duration) (contract common.Address, err error) { + if (owner == common.Address{}) { + return contract, fmt.Errorf("invalid owner %v. Owner needed to deploy chequebook contract: %v", owner.Hex(), err) + } + + txhash, err := backend.Transact(owner.Hex(), "", "", amount.String(), deployGas, "", ContractCode) + if err != nil { + return contract, fmt.Errorf("unable to send chequebook creation transaction: %v", err) + } + + timer := time.NewTimer(timeout).C + ticker := time.NewTicker(queryInterval).C +OUT: + for { + select { + + case <-timer: + if ticker == nil { + // ticker is nil, receipt was found and confirmation interval passed + err = Validate(contract, backend) + if err != nil { + return contract, fmt.Errorf("invalid contract at %v after %v: %v", contract.Hex(), confirmationInterval, err) + } + break OUT + } + // ticker is non-nil meaning receipt not found yet + return contract, fmt.Errorf("chequebook deployment timed out in %v", timeout) + + case <-ticker: + receipt := backend.GetTxReceipt(common.HexToHash(txhash)) + if receipt != nil { + contract = receipt.ContractAddress + glog.V(logger.Detail).Infof("[CHEQUEBOOK] chequebook deployed at %v (owner: %v)", contract.Hex(), owner.Hex()) + timer = time.NewTimer(confirmationInterval).C + ticker = nil + } else { + glog.V(logger.Detail).Infof("[CHEQUEBOOK] check if chequebook deployed (txhash: %v)", txhash) + } + + } + } + return contract, nil +} + +func Validate(contract common.Address, backend Backend) (err error) { + if (contract == common.Address{}) { + return fmt.Errorf("zero address") + } + code := backend.CodeAt(contract.Hex()) + if code != ContractDeployedCode { + return fmt.Errorf("incorrect code %v:\n%v\n%v", contract.Hex(), code, ContractDeployedCode) + } + return nil +} + +// NewChequebook(path, contract, balance, prvKey) creates a new Chequebook +func NewChequebook(path string, contract common.Address, prvKey *ecdsa.PrivateKey, backend Backend) (self *Chequebook, err error) { + balance := new(big.Int) + sent := make(map[common.Address]*big.Int) + owner := crypto.PubkeyToAddress(prvKey.PublicKey) + self = &Chequebook{ + balance: balance, + contract: contract, + sent: sent, + path: path, + prvKey: prvKey, + backend: backend, + owner: owner, + } + if (contract != common.Address{}) { + glog.V(logger.Detail).Infof("[CHEQUEBOOK] new chequebook initialised from %v (owner: %v)", contract.Hex(), owner.Hex()) + } + return +} + +// LoadChequebook(path, prvKey, backend) loads a chequebook from disk (file path) +func LoadChequebook(path string, prvKey *ecdsa.PrivateKey, backend Backend) (self *Chequebook, err error) { + var data []byte + data, err = ioutil.ReadFile(path) + if err != nil { + return + } + + self, _ = NewChequebook(path, common.Address{}, prvKey, backend) + + err = json.Unmarshal(data, self) + if err != nil { + return nil, err + } + glog.V(logger.Detail).Infof("[CHEQUEBOOK] loaded chequebook (%s, owner: %v) initialised from %v", self.contract.Hex(), self.owner.Hex(), path) + + return +} + +// chequebook serialisation +type chequebookFile struct { + Balance string + Contract string + Owner string + Sent map[string]string +} + +func (self *Chequebook) UnmarshalJSON(data []byte) error { + var file chequebookFile + err := json.Unmarshal(data, &file) + if err != nil { + return err + } + _, ok := self.balance.SetString(file.Balance, 10) + if !ok { + return fmt.Errorf("cumulative amount sent: unable to convert string to big integer: %v", file.Balance) + } + self.contract = common.HexToAddress(file.Contract) + for addr, sent := range file.Sent { + self.sent[common.HexToAddress(addr)], ok = new(big.Int).SetString(sent, 10) + if !ok { + return fmt.Errorf("beneficiary %v cumulative amount sent: unable to convert string to big integer: %v", addr, sent) + } + } + return nil +} + +func (self *Chequebook) MarshalJSON() ([]byte, error) { + var file = &chequebookFile{ + Balance: self.balance.String(), + Contract: self.contract.Hex(), + Owner: self.owner.Hex(), + Sent: make(map[string]string), + } + for addr, sent := range self.sent { + file.Sent[addr.Hex()] = sent.String() + } + return json.Marshal(file) +} + +// Save() persists the chequebook on disk +// remembers balance, contract address and +// cumulative amount of funds sent for each beneficiary +func (self *Chequebook) Save() (err error) { + data, err := json.MarshalIndent(self, "", " ") + if err != nil { + return err + } + glog.V(logger.Detail).Infof("[CHEQUEBOOK] saving chequebook (%s) to %v", self.contract.Hex(), self.path) + + return ioutil.WriteFile(self.path, data, os.ModePerm) +} + +// Stop() quits the autodeposit go routine to terminate +func (self *Chequebook) Stop() { + defer self.lock.Unlock() + self.lock.Lock() + if self.quit != nil { + close(self.quit) + self.quit = nil + } +} + +// Issue(beneficiary, amount) will create a Cheque +// the cheque is signed by the chequebook owner's private key +// the signer commits to a contract (one that they own), a beneficiary and amount +func (self *Chequebook) Issue(beneficiary common.Address, amount *big.Int) (ch *Cheque, err error) { + defer self.lock.Unlock() + self.lock.Lock() + if amount.Cmp(common.Big0) <= 0 { + return nil, fmt.Errorf("amount must be greater than zero (%v)", amount) + } + if self.balance.Cmp(amount) < 0 { + err = fmt.Errorf("insufficent funds to issue cheque for amount: %v. balance: %v", amount, self.balance) + } else { + var sig []byte + sent, found := self.sent[beneficiary] + if !found { + sent = new(big.Int) + self.sent[beneficiary] = sent + } + sum := new(big.Int).Set(sent) + sum.Add(sum, amount) + sig, err = crypto.Sign(sigHash(self.contract, beneficiary, sum), self.prvKey) + if err == nil { + ch = &Cheque{ + Contract: self.contract, + Beneficiary: beneficiary, + Amount: sum, + Sig: sig, + } + sent.Set(sum) + self.balance.Sub(self.balance, amount) // subtract amount from balance + } + } + + // auto deposit if threshold is set and balance is less then threshold + // note this is called even if issueing cheque fails + // so we reattempt depositing + if self.threshold != nil { + if self.balance.Cmp(self.threshold) < 0 { + send := new(big.Int).Sub(self.buffer, self.balance) + self.deposit(send) + } + } + + return +} + +// convenience method to cash any cheque +func (self *Chequebook) Cash(ch *Cheque) (txhash string, err error) { + return ch.Cash(self.owner, self.backend) +} + +// data to sign: contract address, beneficiary, cumulative amount of funds ever sent +func sigHash(contract, beneficiary common.Address, sum *big.Int) []byte { + bigamount := sum.Bytes() + if len(bigamount) > 32 { + return nil + } + var amount32 [32]byte + copy(amount32[32-len(bigamount):32], bigamount) + input := append(contract.Bytes(), beneficiary.Bytes()...) + input = append(input, amount32[:]...) + return crypto.Sha3(input) +} + +// Balance() public accessor for balance +func (self *Chequebook) Balance() *big.Int { + defer self.lock.Unlock() + self.lock.Lock() + return new(big.Int).Set(self.balance) +} + +// Balance() public accessor for balance +func (self *Chequebook) Owner() common.Address { + return self.owner +} + +// Backend() public accessor for backend +func (self *Chequebook) Backend() Backend { + return self.backend +} + +// Address() public accessor for contract +func (self *Chequebook) Address() common.Address { + return self.contract +} + +// Deposit(amount) deposits amount to the chequebook account +func (self *Chequebook) Deposit(amount *big.Int) (string, error) { + defer self.lock.Unlock() + self.lock.Lock() + return self.deposit(amount) +} + +// deposit(amount) deposits amount to the chequebook account +// caller holds the lock +func (self *Chequebook) deposit(amount *big.Int) (string, error) { + txhash, err := self.backend.Transact(self.owner.Hex(), self.contract.Hex(), "", amount.String(), "", "", "") + // assume that transaction is actually successful, we add the amount to balance right away + if err != nil { + glog.V(logger.Warn).Infof("[CHEQUEBOOK] error depositing %d wei to chequebook (%s, balance: %v, target: %v): %v", amount, self.contract.Hex(), self.balance, self.buffer, err) + } else { + self.balance.Add(self.balance, amount) + glog.V(logger.Detail).Infof("[CHEQUEBOOK] deposited %d wei to chequebook (%s, balance: %v, target: %v)", amount, self.contract.Hex(), self.balance, self.buffer) + } + return txhash, err +} + +// AutoDeposit(interval, threshold, buffer) (re)sets interval time and amount +// which triggers sending funds to the chequebook contract +// backend needs to be set +// if threshold is not less than buffer, then deposit will be triggered on +// every new cheque issued +func (self *Chequebook) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { + defer self.lock.Unlock() + self.lock.Lock() + self.threshold = threshold + self.buffer = buffer + self.autoDeposit(interval) +} + +// autoDeposit(interval) starts a go routine that periodically sends funds to the +// chequebook contract +// caller holds the lock +// the go routine terminates if Chequebook.quit us closed +func (self *Chequebook) autoDeposit(interval time.Duration) { + if self.quit != nil { + close(self.quit) + self.quit = nil + } + // if threshold >= balance autodeposit after every cheque issued + if interval == time.Duration(0) || self.threshold != nil && self.buffer != nil && self.threshold.Cmp(self.buffer) >= 0 { + return + } + + ticker := time.NewTicker(interval) + self.quit = make(chan bool) + quit := self.quit + go func() { + FOR: + for { + select { + case <-quit: + break FOR + case <-ticker.C: + self.lock.Lock() + if self.balance.Cmp(self.buffer) < 0 { + amount := new(big.Int).Sub(self.buffer, self.balance) + txhash, err := self.deposit(amount) + if err == nil { + self.txhash = txhash + } + } + self.lock.Unlock() + } + } + }() + return +} + +type Outbox struct { + chequeBook *Chequebook + beneficiary common.Address +} + +func NewOutbox(chbook *Chequebook, beneficiary common.Address) *Outbox { + return &Outbox{chbook, beneficiary} +} + +func (self *Outbox) Issue(amount *big.Int) (swap.Promise, error) { + return self.chequeBook.Issue(self.beneficiary, amount) +} + +func (self *Outbox) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { + self.chequeBook.AutoDeposit(interval, threshold, buffer) +} + +func (self *Outbox) Stop() {} + +func (self *Outbox) String() string { + return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.chequeBook.Address().Hex(), self.beneficiary.Hex(), self.chequeBook.Balance()) +} + +// type ChequeQueue struct { +// beneficiary common.Address +// last map[string]*Inbox +// } + +// inbox to deposit, verify and cash cheques +// from a single contract to single beneficiary +// incoming payment handler for peer to peer micropayments +type Inbox struct { + lock sync.Mutex + contract common.Address // peer's chequebook contract + beneficiary common.Address // local peer's receiving address + sender common.Address // local peer's address to send cashing tx from + signer *ecdsa.PublicKey // peer's public key + txhash string // tx hash of last cashing tx + backend Backend // blockchain API + quit chan bool // when closed causes autocash to stop + maxUncashed *big.Int // threshold that triggers autocashing + cashed *big.Int // cumulative amount cashed + cheque *Cheque // last cheque, nil if none yet received +} + +// NewInbox(contract, beneficiary, signer, backend) constructor for Inbox +// not persisted, cumulative sum updated from blockchain when first cheque received +// backend used to sync amount (Call) as well as cash the cheques (Transact) +func NewInbox(contract, sender, beneficiary common.Address, signer *ecdsa.PublicKey, backend Backend) (self *Inbox, err error) { + + if signer == nil { + return nil, fmt.Errorf("signer is null") + } + + self = &Inbox{ + contract: contract, + beneficiary: beneficiary, + sender: sender, + signer: signer, + backend: backend, + cashed: new(big.Int).Set(common.Big0), + } + glog.V(logger.Detail).Infof("[CHEQUEBOOK] initialised inbox (%s -> %s) expected signer: %x", self.contract.Hex(), self.beneficiary.Hex(), crypto.FromECDSAPub(signer)) + return +} + +func (self *Inbox) String() string { + return fmt.Sprintf("chequebook: %v, beneficiary: %s, balance: %v", self.contract.Hex(), self.beneficiary.Hex(), self.cheque.Amount) +} + +// Stop() quits the autocash go routine to terminate +func (self *Inbox) Stop() { + defer self.lock.Unlock() + self.lock.Lock() + if self.quit != nil { + close(self.quit) + self.quit = nil + } +} + +func (self *Inbox) Cash() (txhash string, err error) { + if self.cheque != nil { + txhash, err = self.cheque.Cash(self.sender, self.backend) + glog.V(logger.Detail).Infof("[CHEQUEBOOK] cashing cheque (total: %v) on chequebook (%s) sending to %v", self.cheque.Amount, self.contract.Hex(), self.beneficiary.Hex()) + self.cashed = self.cheque.Amount + } + return +} + +// AutoCash(cashInterval, maxUncashed) (re)sets maximum time and amount which +// triggers cashing of the last uncashed cheque +// if maxUncashed is set to 0, then autocash on receipt +func (self *Inbox) AutoCash(cashInterval time.Duration, maxUncashed *big.Int) { + defer self.lock.Unlock() + self.lock.Lock() + self.maxUncashed = maxUncashed + self.autoCash(cashInterval) +} + +// autoCash(d) starts a loop that periodically clears the last check +// if the peer is trusted, clearing period could be 24h, or a week +// caller holds the lock +func (self *Inbox) autoCash(cashInterval time.Duration) { + if self.quit != nil { + close(self.quit) + self.quit = nil + } + // if maxUncashed is set to 0, then autocash on receipt + if cashInterval == time.Duration(0) || self.maxUncashed != nil && self.maxUncashed.Cmp(common.Big0) == 0 { + return + } + + ticker := time.NewTicker(cashInterval) + self.quit = make(chan bool) + quit := self.quit + go func() { + FOR: + for { + select { + case <-quit: + break FOR + case <-ticker.C: + self.lock.Lock() + if self.cheque != nil && self.cheque.Amount.Cmp(self.cashed) != 0 { + txhash, err := self.Cash() + if err == nil { + self.txhash = txhash + } + } + self.lock.Unlock() + } + } + }() + return +} + +// Reveive(cheque) called to deposit latest cheque to incoming Inbox +func (self *Inbox) Receive(promise swap.Promise) (*big.Int, error) { + ch := promise.(*Cheque) + + defer self.lock.Unlock() + self.lock.Lock() + var sum *big.Int + if self.cheque == nil { + // the sum is checked against the blockchain once a check is received + tallyhex, _, err := self.backend.Call(self.beneficiary.Hex(), self.contract.Hex(), "", "", "", getSentAbiEncode(ch.Contract)) + if err != nil { + return nil, fmt.Errorf("inbox: error calling backend to set amount: %v", err) + } + + tally := common.FromHex(tallyhex) + // var ok bool + // sum, ok = new(big.Int).SetString(tally, 10) + // if !ok { + // return nil, fmt.Errorf("inbox: cannot convert amount '%s' (%v) to integer", tallyhex, tally) + // } + sum = new(big.Int).SetBytes(tally) + } else { + sum = self.cheque.Amount + } + + amount, err := ch.Verify(self.signer, self.contract, self.beneficiary, sum) + var uncashed *big.Int + if err == nil { + self.cheque = ch + + if self.maxUncashed != nil { + uncashed = new(big.Int).Sub(ch.Amount, self.cashed) + if self.maxUncashed.Cmp(uncashed) < 0 { + self.Cash() + } + } + glog.V(logger.Detail).Infof("[CHEQUEBOOK] received cheque of %v wei in inbox (%s, uncashed: %v)", amount, self.contract.Hex(), uncashed) + } + + return amount, err +} + +// RSV representation of signature +func sig2rsv(sig []byte) (v byte, r, s []byte) { + v = sig[64] + 27 + r = sig[:32] + s = sig[32:64] + return +} + +func getSentAbiEncode(beneficiary common.Address) string { + var beneficiary32 [32]byte + copy(beneficiary32[12:], beneficiary.Bytes()) + return getSentAbiPre + common.Bytes2Hex(beneficiary32[:]) +} + +// abi encoding of a cheque to send as eth tx data +func (self *Cheque) cashAbiEncode() string { + v, r, s := sig2rsv(self.Sig) + // cashAbiPre, beneficiary, amount, v, r, s + bigamount := self.Amount.Bytes() + if len(bigamount) > 32 { + glog.V(logger.Detail).Infof("[CHEQUEBOOK] number too big: %v (>32 bytes)", self.Amount) + return "" + } + var beneficiary32, amount32, vabi [32]byte + copy(beneficiary32[12:], self.Beneficiary.Bytes()) + copy(amount32[32-len(bigamount):32], bigamount) + vabi[31] = v + return cashAbiPre + common.Bytes2Hex(beneficiary32[:]) + common.Bytes2Hex(amount32[:]) + + common.Bytes2Hex(vabi[:]) + common.Bytes2Hex(r) + common.Bytes2Hex(s) +} + +// Verify(cheque) verifies cheque for signer, contract, beneficiary, amount, valid signature +func (self *Cheque) Verify(signerKey *ecdsa.PublicKey, contract, beneficiary common.Address, sum *big.Int) (*big.Int, error) { + glog.V(logger.Detail).Infof("[CHEQUEBOOK] verify cheque: %v - sum: %v", self, sum) + if sum == nil { + return nil, fmt.Errorf("invalid amount") + } + + if self.Beneficiary != beneficiary { + return nil, fmt.Errorf("beneficiary mismatch: %v != %v", self.Beneficiary.Hex(), beneficiary.Hex()) + } + if self.Contract != contract { + return nil, fmt.Errorf("contract mismatch: %v != %v", self.Contract.Hex(), contract.Hex()) + } + + amount := new(big.Int).Set(self.Amount) + if sum != nil { + amount.Sub(amount, sum) + if amount.Cmp(common.Big0) <= 0 { + return nil, fmt.Errorf("incorrect amount: %v <= 0", amount) + } + } + + pubKey, err := crypto.SigToPub(sigHash(self.Contract, beneficiary, self.Amount), self.Sig) + if err != nil { + return nil, fmt.Errorf("invalid signature: %v", err) + } + if !bytes.Equal(crypto.FromECDSAPub(pubKey), crypto.FromECDSAPub(signerKey)) { + return nil, fmt.Errorf("signer mismatch: %x != %x", crypto.FromECDSAPub(pubKey), crypto.FromECDSAPub(signerKey)) + } + return amount, nil +} + +// Cash(backend) will cash the check using xeth backend to send a transaction +// Beneficiary address should be unlocked +func (self *Cheque) Cash(sender common.Address, backend Backend) (string, error) { + return backend.Transact(sender.Hex(), self.Contract.Hex(), "", "", "", gasToCash, self.cashAbiEncode()) +} diff --git a/common/chequebook/cheque_test.go b/common/chequebook/cheque_test.go new file mode 100644 index 0000000000..06d95ff380 --- /dev/null +++ b/common/chequebook/cheque_test.go @@ -0,0 +1,498 @@ +package chequebook + +import ( + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" +) + +type testBackend struct { + calls []string + errs []error + txs []string +} + +func newTestBackend() *testBackend { + return &testBackend{} +} + +func (b *testBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { + txhash := string(crypto.Sha3([]byte(codeStr))) + b.txs = append(b.txs, txhash) + return txhash, nil +} + +func (b *testBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, string, error) { + if len(b.calls) == 0 { + panic("test backend called too many times") + } + res := b.calls[0] + err := b.errs[0] + b.calls = b.calls[1:] + b.errs = b.errs[1:] + return res, "", err +} + +func (b *testBackend) GetTxReceipt(txhash common.Hash) *types.Receipt { + return nil +} + +func (b *testBackend) CodeAt(address string) string { + return "" +} + +func genAddr() common.Address { + prvKey, _ := crypto.GenerateKey() + return crypto.PubkeyToAddress(prvKey.PublicKey) +} + +func TestIssueAndReceive(t *testing.T) { + prvKey, _ := crypto.GenerateKey() + sender := genAddr() + path := "/tmp/checkbook.json" + chbook, err := NewChequebook(path, sender, prvKey, nil) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + recipient := genAddr() + chbook.sent[recipient] = new(big.Int).SetUint64(42) + amount := common.Big1 + ch, err := chbook.Issue(recipient, amount) + if err == nil { + t.Errorf("expected insufficient funds error, got none") + } + + chbook.balance = new(big.Int).Set(common.Big1) + if chbook.Balance().Cmp(common.Big1) != 0 { + t.Errorf("expected: %v, got %v", "0", chbook.Balance()) + } + + ch, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if chbook.Balance().Cmp(common.Big0) != 0 { + t.Errorf("expected: %v, got %v", "0", chbook.Balance()) + } + + backend := newTestBackend() + backend.calls = []string{common.ToHex(big.NewInt(42).Bytes())} + backend.errs = []error{nil} + chbox, err := NewInbox(sender, recipient, recipient, &prvKey.PublicKey, backend) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + received, err := chbox.Receive(ch) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if received.Cmp(common.Big1) != 0 { + t.Errorf("expected: %v, got %v", "1", received) + } + +} + +func TestCheckbookFile(t *testing.T) { + prvKey, _ := crypto.GenerateKey() + sender := genAddr() + path := "/tmp/checkbook.json" + chbook, err := NewChequebook(path, sender, prvKey, nil) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + recipient := genAddr() + chbook.sent[recipient] = new(big.Int).SetUint64(42) + chbook.balance = new(big.Int).Set(common.Big1) + + chbook.Save() + + chbook, err = LoadChequebook(path, prvKey, nil) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if chbook.Balance().Cmp(common.Big1) != 0 { + t.Errorf("expected: %v, got %v", "0", chbook.Balance()) + } + + ch, err := chbook.Issue(recipient, common.Big1) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if ch.Amount.Cmp(new(big.Int).SetUint64(43)) != 0 { + t.Errorf("expected: %v, got %v", "0", ch.Amount) + } + + err = chbook.Save() + if err != nil { + t.Fatalf("expected no error, got %v", err) + } +} + +func TestVerifyErrors(t *testing.T) { + prvKey, _ := crypto.GenerateKey() + sender0 := genAddr() + sender1 := genAddr() + path0 := "/tmp/checkbook0.json" + chbook0, err := NewChequebook(path0, sender0, prvKey, nil) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + path1 := "/tmp/checkbook1.json" + chbook1, err := NewChequebook(path1, sender1, prvKey, nil) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + recipient0 := genAddr() + recipient1 := genAddr() + chbook0.balance = new(big.Int).Set(common.Big2) + chbook1.balance = new(big.Int).Set(common.Big1) + chbook0.sent[recipient0] = new(big.Int).SetUint64(42) + amount := common.Big1 + ch0, err := chbook0.Issue(recipient0, amount) + + backend := newTestBackend() + backend.calls = []string{common.ToHex(big.NewInt(42).Bytes())} + backend.errs = []error{nil} + chbox, err := NewInbox(sender0, recipient0, recipient0, &prvKey.PublicKey, backend) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + received, err := chbox.Receive(ch0) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if received.Cmp(common.Big1) != 0 { + t.Errorf("expected: %v, got %v", "1", received) + } + + ch1, err := chbook0.Issue(recipient1, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + received, err = chbox.Receive(ch1) + t.Log(err) + if err == nil { + t.Fatalf("expected receiver error, got none") + } + + ch2, err := chbook1.Issue(recipient0, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + received, err = chbox.Receive(ch2) + t.Log(err) + if err == nil { + t.Fatalf("expected sender error, got none") + } + + _, err = chbook1.Issue(recipient0, new(big.Int).SetInt64(-1)) + t.Log(err) + if err == nil { + t.Fatalf("expected incorrect amount error, got none") + } + + received, err = chbox.Receive(ch0) + t.Log(err) + if err == nil { + t.Fatalf("expected incorrect amount error, got none") + } + +} + +func TestDeposit(t *testing.T) { + prvKey, _ := crypto.GenerateKey() + sender := genAddr() + path := "/tmp/checkbook.json" + + backend := newTestBackend() + chbook, err := NewChequebook(path, sender, prvKey, backend) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + + balance := new(big.Int).SetUint64(42) + chbook.Deposit(balance) + if len(backend.txs) != 1 { + t.Fatalf("expected 1 txs to send, got %v", len(backend.txs)) + } + if chbook.balance.Cmp(balance) != 0 { + t.Fatalf("expected balance %v, got %v", balance, chbook.balance) + } + + recipient := genAddr() + amount := common.Big1 + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + exp := new(big.Int).SetUint64(41) + if chbook.balance.Cmp(exp) != 0 { + t.Fatalf("expected balance %v, got %v", exp, chbook.balance) + } + + // autodeposit on each issue + chbook.AutoDeposit(0, balance, balance) + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if len(backend.txs) != 3 { + t.Fatalf("expected 3 txs to send, got %v", len(backend.txs)) + } + if chbook.balance.Cmp(balance) != 0 { + t.Fatalf("expected balance %v, got %v", balance, chbook.balance) + } + + // autodeposit off + chbook.AutoDeposit(0, common.Big0, balance) + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if len(backend.txs) != 3 { + t.Fatalf("expected 3 txs to send, got %v", len(backend.txs)) + } + exp = new(big.Int).SetUint64(40) + if chbook.balance.Cmp(exp) != 0 { + t.Fatalf("expected balance %v, got %v", exp, chbook.balance) + } + + // autodeposit every 10ms if new cheque issued + interval := 30 * time.Millisecond + chbook.AutoDeposit(interval, common.Big1, balance) + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if len(backend.txs) != 3 { + t.Fatalf("expected 3 txs to send, got %v", len(backend.txs)) + } + exp = new(big.Int).SetUint64(38) + if chbook.balance.Cmp(exp) != 0 { + t.Fatalf("expected balance %v, got %v", exp, chbook.balance) + } + + time.Sleep(3 * interval) + if len(backend.txs) != 4 { + t.Fatalf("expected 4 txs to send, got %v", len(backend.txs)) + } + if chbook.balance.Cmp(balance) != 0 { + t.Fatalf("expected balance %v, got %v", balance, chbook.balance) + } + + exp = new(big.Int).SetUint64(40) + chbook.AutoDeposit(4*interval, exp, balance) + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + time.Sleep(3 * interval) + if len(backend.txs) != 4 { + t.Fatalf("expected 4 txs to send, got %v", len(backend.txs)) + } + if chbook.balance.Cmp(exp) != 0 { + t.Fatalf("expected balance %v, got %v", exp, chbook.balance) + } + + _, err = chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + time.Sleep(1 * interval) + + if len(backend.txs) != 5 { + t.Fatalf("expected 5 txs to send, got %v", len(backend.txs)) + } + if chbook.balance.Cmp(balance) != 0 { + t.Fatalf("expected balance %v, got %v", balance, chbook.balance) + } + + chbook.AutoDeposit(1*interval, common.Big0, balance) + chbook.Stop() + + _, err = chbook.Issue(recipient, common.Big1) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + _, err = chbook.Issue(recipient, common.Big2) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + time.Sleep(1 * interval) + + if len(backend.txs) != 5 { + t.Fatalf("expected 5 txs to send, got %v", len(backend.txs)) + } + exp = new(big.Int).SetUint64(39) + if chbook.balance.Cmp(exp) != 0 { + t.Fatalf("expected balance %v, got %v", exp, chbook.balance) + } + +} + +func TestCash(t *testing.T) { + prvKey, _ := crypto.GenerateKey() + sender := genAddr() + path := "/tmp/checkbook.json" + chbook, err := NewChequebook(path, sender, prvKey, nil) + if err != nil { + t.Errorf("expected no error, got %v", err) + } + recipient := genAddr() + chbook.sent[recipient] = new(big.Int).SetUint64(42) + amount := common.Big1 + chbook.balance = new(big.Int).Set(common.Big1) + ch, err := chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + backend := newTestBackend() + backend.calls = []string{common.ToHex(big.NewInt(42).Bytes())} + backend.errs = []error{nil} + chbox, err := NewInbox(sender, recipient, recipient, &prvKey.PublicKey, backend) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + // cashing latest cheque + _, err = chbox.Receive(ch) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = ch.Cash(recipient, backend) + if len(backend.txs) != 1 { + t.Fatalf("expected 1 txs to send, got %v", len(backend.txs)) + } + + chbook.balance = new(big.Int).Set(common.Big3) + ch0, err := chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + ch1, err := chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + interval := 10 * time.Millisecond + // setting autocash with interval of 10ms + chbox.AutoCash(interval, nil) + _, err = chbox.Receive(ch0) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = chbox.Receive(ch1) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + // after < interval time and 2 cheques received, no new cashing tx is sent + if len(backend.txs) != 1 { + t.Fatalf("expected 1 txs to send, got %v", len(backend.txs)) + } + // after 3x interval time and 2 cheques received, exactly one cashing tx is sent + time.Sleep(4 * interval) + if len(backend.txs) != 2 { + t.Fatalf("expected 2 txs to send, got %v", len(backend.txs)) + } + + // after stopping autocash no more tx are sent + ch2, err := chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + chbox.Stop() + time.Sleep(interval) // make sure loop stops + _, err = chbox.Receive(ch2) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + time.Sleep(2 * interval) + if len(backend.txs) != 2 { + t.Fatalf("expected 2 txs to send, got %v", len(backend.txs)) + } + + // autocash below 1 + chbook.balance = new(big.Int).Set(common.Big2) + chbox.AutoCash(0, common.Big1) + + ch3, err := chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + ch4, err := chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + _, err = chbox.Receive(ch3) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = chbox.Receive(ch4) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + // 2 checks of amount 1 received, exactly 1 tx is sent + if len(backend.txs) != 3 { + t.Fatalf("expected 3 txs to send, got %v", len(backend.txs)) + } + + // autochash on receipt when maxUncashed is 0 + chbook.balance = new(big.Int).Set(common.Big2) + chbox.AutoCash(0, common.Big0) + + ch5, err := chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + ch6, err := chbook.Issue(recipient, amount) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = chbox.Receive(ch5) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + _, err = chbox.Receive(ch6) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if len(backend.txs) != 5 { + t.Fatalf("expected 5 txs to send, got %v", len(backend.txs)) + } + +} diff --git a/common/chequebook/chequebook.sol b/common/chequebook/chequebook.sol new file mode 100644 index 0000000000..836d570472 --- /dev/null +++ b/common/chequebook/chequebook.sol @@ -0,0 +1,49 @@ +import "mortal"; + +/// @title Chequebook for Ethereum micropayments +/// @author Daniel A. Nagy +contract chequebook is mortal { + // Cumulative paid amount in wei to each beneficiary + mapping (address => uint256) sent; + + /// @notice Overdraft event + event Overdraft(address deadbeat); + + /// @notice Accessor for sent map + /// + /// @param beneficiary beneficiary address + /// @return cumulative amount in wei sent to beneficiary + function getSent(address beneficiary) constant returns (uint256) { + return sent[beneficiary]; + } + + /// @notice Cash cheque + /// + /// @param beneficiary beneficiary address + /// @param amount cumulative amount in wei + /// @param sig_v signature parameter v + /// @param sig_r signature parameter r + /// @param sig_s signature parameter s + /// The digital signature is calculated on the concatenated triplet of contract address, beneficiary address and cumulative amount + function cash(address beneficiary, uint256 amount, + uint8 sig_v, bytes32 sig_r, bytes32 sig_s) { + // Check if the cheque is old. + // Only cheques that are more recent than the last cashed one are considered. + if(amount <= sent[beneficiary]) return; + // Check the digital signature of the cheque. + bytes32 hash = sha3(address(this), beneficiary, amount); + if(owner != ecrecover(hash, sig_v, sig_r, sig_s)) return; + // Attempt sending the difference between the cumulative amount on the cheque + // and the cumulative amount on the last cashed cheque to beneficiary. + if (beneficiary.send(amount - sent[beneficiary])) { + // Upon success, update the cumulative amount. + sent[beneficiary] = amount; + } else { + // Upon failure, punish owner for writing a bounced cheque. + // owner.sendToDebtorsPrison(); + Overdraft(owner); + // Compensate beneficiary. + suicide(beneficiary); + } + } +} diff --git a/common/chequebook/contract.go b/common/chequebook/contract.go new file mode 100644 index 0000000000..866d7c3358 --- /dev/null +++ b/common/chequebook/contract.go @@ -0,0 +1,63 @@ +package chequebook + +import () + +const ( + ContractCode = `606060405260008054600160a060020a03191633179055610201806100246000396000f3606060405260e060020a600035046341c0e1b58114610031578063d75d691d14610059578063fbf788d61461007e575b005b61002f60005433600160a060020a03908116911614156101ff57600054600160a060020a0316ff5b600160a060020a03600435166000908152600160205260409020546060908152602090f35b61002f600435602435604435606435608435600160a060020a03851660009081526001602052604081205485116100b8575b505050505050565b30600160a060020a039081166c0100000000000000000000000090810260609081529188160260745260888690526048812080825260ff8616608090815260a086905260c0859052909260019260e0926020928290866161da5a03f11561000257505060405151600054600160a060020a03908116911614610139576100b0565b85600160a060020a031660006001600050600089600160a060020a03168152602001908152602001600020600050548703604051809050600060405180830381858888f19350505050156101b357846001600050600088600160a060020a03168152602001908152602001600020600050819055506100b0565b60005460408051600160a060020a03929092168252517f2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f9789181900360200190a185600160a060020a0316ff5b56` + + ContractDeployedCode = `0x606060405260e060020a600035046341c0e1b58114610031578063d75d691d14610059578063fbf788d61461007e575b005b61002f60005433600160a060020a03908116911614156101ff57600054600160a060020a0316ff5b600160a060020a03600435166000908152600160205260409020546060908152602090f35b61002f600435602435604435606435608435600160a060020a03851660009081526001602052604081205485116100b8575b505050505050565b30600160a060020a039081166c0100000000000000000000000090810260609081529188160260745260888690526048812080825260ff8616608090815260a086905260c0859052909260019260e0926020928290866161da5a03f11561000257505060405151600054600160a060020a03908116911614610139576100b0565b85600160a060020a031660006001600050600089600160a060020a03168152602001908152602001600020600050548703604051809050600060405180830381858888f19350505050156101b357846001600050600088600160a060020a03168152602001908152602001600020600050819055506100b0565b60005460408051600160a060020a03929092168252517f2250e2993c15843b32621c89447cc589ee7a9f049c026986e545d3c2c0c6f9789181900360200190a185600160a060020a0316ff5b56` + + ContractAbi = `[{"constant":false,"inputs":[],"name":"kill","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"beneficiary","type":"address"}],"name":"getSent","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"beneficiary","type":"address"},{"name":"amount","type":"uint256"},{"name":"sig_v","type":"uint8"},{"name":"sig_r","type":"bytes32"},{"name":"sig_s","type":"bytes32"}],"name":"cash","outputs":[],"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"deadbeat","type":"address"}],"name":"Overdraft","type":"event"}]` + + ContractSource = ` +import "mortal"; + +/// @title Chequebook for Ethereum micropayments +/// @author Daniel A. Nagy +contract chequebook is mortal { + // Cumulative paid amount in wei to each beneficiary + mapping (address => uint256) sent; + + /// @notice Overdraft event + event Overdraft(address deadbeat); + + /// @notice Accessor for sent map + /// + /// @param beneficiary beneficiary address + /// @return cumulative amount in wei sent to beneficiary + function getSent(address beneficiary) returns (uint256) { + return sent[beneficiary]; + } + + /// @notice Cash cheque + /// + /// @param beneficiary beneficiary address + /// @param amount cumulative amount in wei + /// @param sig_v signature parameter v + /// @param sig_r signature parameter r + /// @param sig_s signature parameter s + /// The digital signature is calculated on the concatenated triplet of contract address, beneficiary address and cumulative amount + function cash(address beneficiary, uint256 amount, + uint8 sig_v, bytes32 sig_r, bytes32 sig_s) { + // Check if the cheque is old. + // Only cheques that are more recent than the last cashed one are considered. + if(amount <= sent[beneficiary]) return; + // Check the digital signature of the cheque. + bytes32 hash = sha3(address(this), beneficiary, amount); + if(owner != ecrecover(hash, sig_v, sig_r, sig_s)) return; + // Attempt sending the difference between the cumulative amount on the cheque + // and the cumulative amount on the last cashed cheque to beneficiary. + if (beneficiary.send(amount - sent[beneficiary])) { + // Upon success, update the cumulative amount. + sent[beneficiary] = amount; + } else { + // Upon failure, punish owner for writing a bounced cheque. + // owner.sendToDebtorsPrison(); + Overdraft(owner); + // Compensate beneficiary. + suicide(beneficiary); + } + } +} +` +) diff --git a/common/kademlia/address.go b/common/kademlia/address.go new file mode 100644 index 0000000000..a6ce4e4770 --- /dev/null +++ b/common/kademlia/address.go @@ -0,0 +1,157 @@ +package kademlia + +import ( + "fmt" + "math/rand" + "strings" + + "github.com/ethereum/go-ethereum/common" +) + +type Address common.Hash + +func (a Address) String() string { + return fmt.Sprintf("%x", a[:]) +} + +func (a *Address) MarshalJSON() (out []byte, err error) { + return []byte(`"` + a.String() + `"`), nil +} + +func (a *Address) UnmarshalJSON(value []byte) error { + *a = Address(common.HexToHash(string(value[1 : len(value)-1]))) + return nil +} + +// the string form of the binary representation of an address (only first 8 bits) +func (a Address) Bin() string { + var bs []string + for _, b := range a[:] { + bs = append(bs, fmt.Sprintf("%08b", b)) + } + return strings.Join(bs, "") +} + +/* +Proximity(x, y) returns the proximity order of the MSB distance between x and y + +The distance metric MSB(x, y) of two equal length byte sequences x an y is the +value of the binary integer cast of the x^y, ie., x and y bitwise xor-ed. +the binary cast is big endian: most significant bit first (=MSB). + +Proximity(x, y) is a discrete logarithmic scaling of the MSB distance. +It is defined as the reverse rank of the integer part of the base 2 +logarithm of the distance. +It is calculated by counting the number of common leading zeros in the (MSB) +binary representation of the x^y. + +(0 farthest, 255 closest, 256 self) +*/ +func proximity(one, other Address) (ret int) { + for i := 0; i < len(one); i++ { + oxo := one[i] ^ other[i] + for j := 0; j < 8; j++ { + if (uint8(oxo)>>uint8(7-j))&0x01 != 0 { + return i*8 + j + } + } + } + return len(one) * 8 +} + +// Address.ProxCmp compares the distances a->target and b->target. +// Returns -1 if a is closer to target, 1 if b is closer to target +// and 0 if they are equal. +func (target Address) ProxCmp(a, b Address) int { + for i := range target { + da := a[i] ^ target[i] + db := b[i] ^ target[i] + if da > db { + return 1 + } else if da < db { + return -1 + } + } + return 0 +} + +// randomAddressAt(address, prox) generates a random address +// at proximity order prox relative to address +// if prox is negative a random address is generated +func RandomAddressAt(self Address, prox int) (addr Address) { + addr = self + var pos int + if prox >= 0 { + pos = prox / 8 + trans := prox % 8 + transbytea := byte(0) + for j := 0; j <= trans; j++ { + transbytea |= 1 << uint8(7-j) + } + flipbyte := byte(1 << uint8(7-trans)) + transbyteb := transbytea ^ byte(255) + randbyte := byte(rand.Intn(255)) + addr[pos] = ((addr[pos] & transbytea) ^ flipbyte) | randbyte&transbyteb + } + for i := pos + 1; i < len(addr); i++ { + addr[i] = byte(rand.Intn(255)) + } + + return +} + +// KeyRange(a0, a1, proxLimit) returns the address inclusive address +// range that contain addresses closer to one than other +func KeyRange(one, other Address, proxLimit int) (start, stop Address) { + prox := proximity(one, other) + if prox >= proxLimit { + prox = proxLimit + } + start = CommonBitsAddrByte(one, other, byte(0x00), prox) + stop = CommonBitsAddrByte(one, other, byte(0xff), prox) + return +} + +func CommonBitsAddrF(self, other Address, f func() byte, p int) (addr Address) { + prox := proximity(self, other) + var pos int + if p <= prox { + prox = p + } + pos = prox / 8 + addr = self + trans := byte(prox % 8) + var transbytea byte + if p > prox { + transbytea = byte(0x7f) + } else { + transbytea = byte(0xff) + } + transbytea >>= trans + transbyteb := transbytea ^ byte(0xff) + addrpos := addr[pos] + addrpos &= transbyteb + if p > prox { + addrpos ^= byte(0x80 >> trans) + } + addrpos |= transbytea & f() + addr[pos] = addrpos + for i := pos + 1; i < len(addr); i++ { + addr[i] = f() + } + + return +} + +func CommonBitsAddr(self, other Address, prox int) (addr Address) { + return CommonBitsAddrF(self, other, func() byte { return byte(rand.Intn(255)) }, prox) +} + +func CommonBitsAddrByte(self, other Address, b byte, prox int) (addr Address) { + return CommonBitsAddrF(self, other, func() byte { return b }, prox) +} + +// randomAddressAt() generates a random address +func RandomAddress() Address { + return RandomAddressAt(Address{}, -1) +} diff --git a/common/kademlia/address_test.go b/common/kademlia/address_test.go new file mode 100644 index 0000000000..b0577dc243 --- /dev/null +++ b/common/kademlia/address_test.go @@ -0,0 +1,80 @@ +package kademlia + +import ( + "math/rand" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +func (Address) Generate(rand *rand.Rand, size int) reflect.Value { + var id Address + for i := 0; i < len(id); i++ { + id[i] = byte(uint8(rand.Intn(255))) + } + return reflect.ValueOf(id) +} + +func TestCommonBitsAddrF(t *testing.T) { + a := Address(common.HexToHash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) + b := Address(common.HexToHash("0x8123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) + c := Address(common.HexToHash("0x4123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) + d := Address(common.HexToHash("0x0023456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) + e := Address(common.HexToHash("0x01A3456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) + ab := CommonBitsAddrF(a, b, func() byte { return byte(0x00) }, 10) + expab := Address(common.HexToHash("0x8000000000000000000000000000000000000000000000000000000000000000")) + + if ab != expab { + t.Fatalf("%v != %v", ab, expab) + } + ac := CommonBitsAddrF(a, c, func() byte { return byte(0x00) }, 10) + expac := Address(common.HexToHash("0x4000000000000000000000000000000000000000000000000000000000000000")) + + if ac != expac { + t.Fatalf("%v != %v", ac, expac) + } + ad := CommonBitsAddrF(a, d, func() byte { return byte(0x00) }, 10) + expad := Address(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")) + + if ad != expad { + t.Fatalf("%v != %v", ad, expad) + } + ae := CommonBitsAddrF(a, e, func() byte { return byte(0x00) }, 10) + expae := Address(common.HexToHash("0x0180000000000000000000000000000000000000000000000000000000000000")) + + if ae != expae { + t.Fatalf("%v != %v", ae, expae) + } + acf := CommonBitsAddrF(a, c, func() byte { return byte(0xff) }, 10) + expacf := Address(common.HexToHash("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) + + if acf != expacf { + t.Fatalf("%v != %v", acf, expacf) + } + aeo := CommonBitsAddrF(a, e, func() byte { return byte(0x00) }, 2) + expaeo := Address(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")) + + if aeo != expaeo { + t.Fatalf("%v != %v", aeo, expaeo) + } + aep := CommonBitsAddrF(a, e, func() byte { return byte(0xff) }, 2) + expaep := Address(common.HexToHash("0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) + + if aep != expaep { + t.Fatalf("%v != %v", aep, expaep) + } + +} + +func TestRandomAddressAt(t *testing.T) { + var a Address + for i := 0; i < 100; i++ { + a = RandomAddress() + prox := rand.Intn(255) + b := RandomAddressAt(a, prox) + if proximity(a, b) != prox { + t.Fatalf("incorrect address prox(%v, %v) == %v (expected %v)", a, b, proximity(a, b), prox) + } + } +} diff --git a/common/kademlia/kaddb.go b/common/kademlia/kaddb.go new file mode 100644 index 0000000000..e45a9dc48e --- /dev/null +++ b/common/kademlia/kaddb.go @@ -0,0 +1,360 @@ +package kademlia + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "sync" + "time" + + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +type Time time.Time + +func (t *Time) MarshalJSON() (out []byte, err error) { + return []byte(fmt.Sprintf("%d", t.Unix())), nil +} + +func (t *Time) UnmarshalJSON(value []byte) error { + var i int64 + _, err := fmt.Sscanf(string(value), "%d", &i) + if err != nil { + return err + } + *t = Time(time.Unix(i, 0)) + return nil +} + +func (t Time) Unix() int64 { + return time.Time(t).Unix() +} + +type NodeData interface { + json.Marshaler + json.Unmarshaler +} + +// allow inactive peers under +type NodeRecord struct { + Addr Address // address of node + Url string // Url, used to connect to node + After Time // next call after time + Seen Time // last connected at time + Meta *json.RawMessage // arbitrary metadata saved for a peer + + node Node + connected bool +} + +// set checked to current time, +func (self *NodeRecord) setSeen() { + self.Seen = Time(time.Now()) +} + +func (self *NodeRecord) String() string { + return fmt.Sprintf("<%v>", self.Addr) +} + +// persisted node record database () +type KadDb struct { + Address Address + Nodes [][]*NodeRecord + index map[Address]*NodeRecord + cursors []int + lock sync.Mutex + purgeInterval time.Duration + initialRetryInterval time.Duration + connRetryExp int +} + +func newKadDb(addr Address, params *KadParams) *KadDb { + return &KadDb{ + Address: addr, + Nodes: make([][]*NodeRecord, params.MaxProx+1), // overwritten by load + cursors: make([]int, params.MaxProx+1), + index: make(map[Address]*NodeRecord), + purgeInterval: params.PurgeInterval, + initialRetryInterval: params.InitialRetryInterval, + connRetryExp: params.ConnRetryExp, + } +} + +func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord { + defer self.lock.Unlock() + self.lock.Lock() + + record, found := self.index[a] + if !found { + record = &NodeRecord{ + Addr: a, + Url: url, + } + glog.V(logger.Info).Infof("[KΛÐ]: add new record %v to kaddb", record) + // insert in kaddb + self.index[a] = record + self.Nodes[index] = append(self.Nodes[index], record) + } else { + glog.V(logger.Info).Infof("[KΛÐ]: found record %v in kaddb", record) + } + // update last seen time + record.setSeen() + // update with url in case IP/port changes + record.Url = url + return record +} + +// add adds node records to kaddb (persisted node record db) +func (self *KadDb) add(nrs []*NodeRecord, proximityBin func(Address) int) { + defer self.lock.Unlock() + self.lock.Lock() + var n int + var nodes []*NodeRecord + for _, node := range nrs { + _, found := self.index[node.Addr] + if !found && node.Addr != self.Address { + node.setSeen() + self.index[node.Addr] = node + index := proximityBin(node.Addr) + dbcursor := self.cursors[index] + nodes = self.Nodes[index] + // this is inefficient for allocation, need to just append then shift + newnodes := make([]*NodeRecord, len(nodes)+1) + copy(newnodes[:], nodes[:dbcursor]) + newnodes[dbcursor] = node + copy(newnodes[dbcursor+1:], nodes[dbcursor:]) + glog.V(logger.Detail).Infof("[KΛÐ]: new nodes: %v (keys: %v)\nnodes: %v", newnodes, nodes) + self.Nodes[index] = newnodes + n++ + } + } + glog.V(logger.Detail).Infof("[KΛÐ]: received %d node records, added %d new", len(nrs), n) +} + +/* +next return one node record with the highest priority for desired +connection. +This is used to pick candidates for live nodes that are most wanted for +a higly connected low centrality network structure for Swarm which best suits +for a Kademlia-style routing. + +The candidate is chosen using the following strategy. +We check for missing online nodes in the buckets for 1 upto Max BucketSize rounds. +On each round we proceed from the low to high proximity order buckets. +If the number of active nodes (=connected peers) is < rounds, then start looking +for a known candidate. To determine if there is a candidate to recommend the +node record database row corresponding to the bucket is checked.a +If the row cursor is on position i, the ith element in the row is chosen. +If the record is scheduled not to be retried before NOW, the next element is taken. +If the record is scheduled can be retried, it is set as checked, scheduled for +checking and is returned. The time of the next check is in X (duration) such that +X = ConnRetryExp * delta where delta is the time past since the last check and +ConnRetryExp is constant obsoletion factor. (Note that when node records are added +from peer messages, they are marked as checked and placed at the cursor, ie. +given priority over older entries). Entries which were checked more than +purgeInterval ago are deleted from the kaddb row. If no candidate is found after +a full round of checking the next bucket up is considered. If no candidate is +found when we reach the maximum-proximity bucket, the next round starts. + +node record a is more favoured to b a > b iff a is a passive node (record of +offline past peer) +|proxBin(a)| < |proxBin(b)| +|| (proxBin(a) < proxBin(b) && |proxBin(a)| == |proxBin(b)|) +|| (proxBin(a) == proxBin(b) && lastChecked(a) < lastChecked(b)) + +This has double role. Starting as naive node with empty db, this implements +Kademlia bootstrapping +As a mature node, it fills short lines. All on demand. + +The second argument returned names the first missing slot found +*/ +func (self *KadDb) findBest(bucketSize int, binsize func(int) int) (node *NodeRecord, proxLimit int) { + // return value -1 indicates that buckets are filled in all + proxLimit = -1 + defer self.lock.Unlock() + self.lock.Lock() + + var interval int64 + var found bool + for rounds := 1; rounds <= bucketSize; rounds++ { + ROUND: + for po, dbrow := range self.Nodes { + if po > len(self.Nodes) { + break ROUND + } + size := binsize(po) + if size < rounds { + if proxLimit < 0 { + // set the first missing slot found + proxLimit = po + } + var count int + var purge []int + n := self.cursors[po] + + // try node records in the relavant kaddb row (of identical prox order) + // if they are ripe for checking + ROW: + for count < len(dbrow) { + node = dbrow[n] + + // skip already connected nodes + if !node.connected { + + glog.V(logger.Detail).Infof("[KΛÐ]: kaddb record %v (PO%03d:%d) not to be retried before %v", node.Addr, po, n, node.After) + + // time since last known connection attempt + delta := node.After.Unix() - node.Seen.Unix() + // if delta < 4 { + // node.After = Time(time.Time{}) + // } + + // if node is scheduled to connect + if time.Time(node.After).Before(time.Now()) { + + // if checked longer than purge interval + if time.Time(node.Seen).Add(self.purgeInterval).Before(time.Now()) { + // delete node + purge = append(purge, n) + glog.V(logger.Detail).Infof("[KΛÐ]: inactive node record %v (PO%03d:%d) last check: %v, next check: %v", node.Addr, po, n, node.Seen, node.After) + } else { + // scheduling next check + if (node.After == Time(time.Time{})) { + node.After = Time(time.Now().Add(self.initialRetryInterval)) + } else { + interval = delta * int64(self.connRetryExp) + node.After = Time(time.Unix(time.Now().Unix()+interval, 0)) + } + + glog.V(logger.Detail).Infof("[KΛÐ]: serve node record %v (PO%03d:%d), last check: %v, next check: %v", node.Addr, po, n, node.Seen, node.After) + } + found = true + break ROW + } + glog.V(logger.Detail).Infof("[KΛÐ]: kaddb record %v (PO%03d:%d) not ready. skipped. not to be retried before: %v", node.Addr, po, n, node.After) + } // if node.node == nil + n++ + count++ + // cycle: n = n % len(dbrow) + if n >= len(dbrow) { + n = 0 + } + } + self.cursors[po] = n + self.delete(po, purge...) + if found { + glog.V(logger.Detail).Infof("[KΛÐ]: rounds %d: prox limit: PO%03d\n%v", rounds, proxLimit, node) + node.setSeen() + return + } + } // if len < rounds + } // for po-s + glog.V(logger.Detail).Infof("[KΛÐ]: rounds %d: proxlimit: PO%03d", rounds, proxLimit) + if proxLimit == 0 || proxLimit < 0 && bucketSize == rounds { + return + } + } // for round + + return +} + +// deletes the noderecords of a kaddb row corresponding to the indexes +// caller must hold the dblock +// the call is unsafe, no index checks +func (self *KadDb) delete(row int, indexes ...int) { + var prev int + var nodes []*NodeRecord + dbrow := self.Nodes[row] + for _, next := range indexes { + // need to adjust dbcursor + if next > 0 { + if next <= self.cursors[row] { + self.cursors[row]-- + } + nodes = append(nodes, dbrow[prev:next]...) + } + prev = next + 1 + delete(self.index, dbrow[next].Addr) + } + self.Nodes[row] = append(nodes, dbrow[prev:]...) +} + +// save persists kaddb on disk (written to file on path in json format. +func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error { + defer self.lock.Unlock() + self.lock.Lock() + + var n int + + for _, b := range self.Nodes { + for _, node := range b { + n++ + node.After = Time(time.Now()) + node.Seen = Time(time.Now()) + if cb != nil { + cb(node, node.node) + } + } + } + + data, err := json.MarshalIndent(self, "", " ") + if err != nil { + return err + } + err = ioutil.WriteFile(path, data, os.ModePerm) + if err != nil { + glog.V(logger.Warn).Infof("[KΛÐ]: unable to save kaddb with %v nodes to %v: err", n, path, err) + } else { + glog.V(logger.Info).Infof("[KΛÐ] saved kaddb with %v nodes to %v", n, path) + } + return err +} + +// Load(path) loads the node record database (kaddb) from file on path. +func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err error) { + defer self.lock.Unlock() + self.lock.Lock() + + var data []byte + data, err = ioutil.ReadFile(path) + if err != nil { + return + } + + err = json.Unmarshal(data, self) + if err != nil { + return + } + var n int + var purge []int + for po, b := range self.Nodes { + ROW: + for i, node := range b { + if cb != nil { + err = cb(node, node.node) + if err != nil { + purge = append(purge, i) + continue ROW + } + } + n++ + if (node.After == Time(time.Time{})) { + node.After = Time(time.Now()) + } + self.index[node.Addr] = node + } + self.delete(po, purge...) + } + glog.V(logger.Info).Infof("[KΛÐ] loaded kaddb with %v nodes from %v", n, path) + + return +} + +// accessor for KAD offline db count +func (self *KadDb) count() int { + defer self.lock.Unlock() + self.lock.Lock() + return len(self.index) +} diff --git a/common/kademlia/kademlia.go b/common/kademlia/kademlia.go new file mode 100644 index 0000000000..ac80e8b406 --- /dev/null +++ b/common/kademlia/kademlia.go @@ -0,0 +1,457 @@ +package kademlia + +import ( + "fmt" + "sort" + "strings" + "sync" + "time" + + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +const ( + bucketSize = 20 + maxProx = 255 + connRetryExp = 2 +) + +var ( + purgeInterval = 42 * time.Hour + initialRetryInterval = 42 * 100 * time.Millisecond +) + +type KadParams struct { + // adjustable parameters + MaxProx int + ProxBinSize int + BucketSize int + PurgeInterval time.Duration + InitialRetryInterval time.Duration + ConnRetryExp int +} + +func NewKadParams() *KadParams { + return &KadParams{ + MaxProx: maxProx, + ProxBinSize: bucketSize, + BucketSize: bucketSize, + PurgeInterval: purgeInterval, + InitialRetryInterval: initialRetryInterval, + ConnRetryExp: connRetryExp, + } +} + +// Kademlia is a table of active nodes +type Kademlia struct { + addr Address // immutable baseaddress of the table + *KadParams // Kademlia configuration parameters + proxLimit int // state, the PO of the first row of the most proximate bin + proxSize int // state, the number of peers in the most proximate bin + count int // number of active peers (w live connection) + buckets []*bucket // the actual bins + db *KadDb // kaddb, node record database + lock sync.RWMutex // mutex to access buckets +} + +type Node interface { + Addr() Address + Url() string + LastActive() time.Time + Drop() +} + +// public constructor +// add is the base address of the table +// params is KadParams configuration +func New(addr Address, params *KadParams) *Kademlia { + buckets := make([]*bucket, params.MaxProx+1) + for i, _ := range buckets { + buckets[i] = &bucket{size: params.BucketSize} // will initialise bucket{int(0),[]Node(nil),sync.Mutex} + } + glog.V(logger.Info).Infof("[KΛÐ] base address %v", addr) + + return &Kademlia{ + addr: addr, + KadParams: params, + buckets: buckets, + db: newKadDb(addr, params), + } +} + +// accessor for KAD base address +func (self *Kademlia) Addr() Address { + return self.addr +} + +// accessor for KAD active node count +func (self *Kademlia) Count() int { + defer self.lock.Unlock() + self.lock.Lock() + return self.count +} + +// accessor for KAD active node count +func (self *Kademlia) DBCount() int { + return self.db.count() +} + +// On is the entry point called when a new nodes is added +// unsafe in that node is not checked to be already active node (to be called once) +func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error) { + index := self.proximityBin(node.Addr()) + record := self.db.findOrCreate(index, node.Addr(), node.Url()) + // callback on add node + // setting the node on the record, set it checked (for connectivity) + record.node = node + + glog.V(logger.Info).Infof("[KΛÐ]: add node record %v with node %v", record, node) + if cb != nil { + err = cb(record, node) + glog.V(logger.Info).Infof("[KΛÐ]: cb(%v, %v) ->%v", record, node, err) + if err != nil { + return fmt.Errorf("node %v not added: %v", node.Addr(), err) + } + } + record.connected = true + + defer self.lock.Unlock() + self.lock.Lock() + + // insert in kademlia table of active nodes + bucket := self.buckets[index] + // if bucket is full insertion replaces the worst node + // TODO: give priority to peers with active traffic + if worst, pos := bucket.insert(node); worst != nil { + glog.V(logger.Info).Infof("[KΛÐ]: replace node %v (%d) with node %v", worst, pos, node) + // no prox adjustment needed + // do not change count + } else { + glog.V(logger.Info).Infof("[KΛÐ]: add node %v to table", node) + self.count++ + self.adjustProxMore(index) + } + + return + +} + +// is the entrypoint called when a node is taken offline +func (self *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) { + self.lock.Lock() + defer self.lock.Unlock() + + var found bool + index := self.proximityBin(node.Addr()) + bucket := self.buckets[index] + for i := 0; i < len(bucket.nodes); i++ { + if node.Addr() == bucket.nodes[i].Addr() { + found = true + bucket.nodes = append(bucket.nodes[:i], bucket.nodes[(i+1):]...) + } + } + + if !found { + return + } + glog.V(logger.Info).Infof("[KΛÐ]: remove node %v from table", node) + + self.count-- + if len(bucket.nodes) < bucket.size { + err = fmt.Errorf("insufficient nodes (%v) in bucket %v", len(bucket.nodes), index) + } + self.adjustProxLess(index) + + r := self.db.index[node.Addr()] + // callback on remove + if cb != nil { + cb(r, r.node) + } + r.node = nil + r.connected = false + + return +} + +// proxLimit is dynamically adjusted so that 1) there is no +// empty buckets in bin < proxLimit and 2) the sum of all items sare the maximum +// possible but lower than ProxBinSize +// adjust Prox (proxLimit and proxSize after an insertion of add nodes into bucket r) +func (self *Kademlia) adjustProxMore(r int) { + if r >= self.proxLimit { + exLimit := self.proxLimit + exSize := self.proxSize + self.proxSize++ + + var i int + for i = self.proxLimit; i < self.MaxProx && len(self.buckets[i].nodes) > 0 && self.proxSize-len(self.buckets[i].nodes) > self.ProxBinSize; i++ { + self.proxSize -= len(self.buckets[i].nodes) + } + self.proxLimit = i + + glog.V(logger.Detail).Infof("[KΛÐ]: Max Prox Bin: Lower Limit: %v (was %v): Bin Size: %v (was %v)", self.proxLimit, exLimit, self.proxSize, exSize) + } +} + +func (self *Kademlia) adjustProxLess(r int) { + exLimit := self.proxLimit + exSize := self.proxSize + if r >= self.proxLimit { + self.proxSize-- + } + + if r < self.proxLimit && len(self.buckets[r].nodes) == 0 { + for i := self.proxLimit - 1; i > r; i-- { + self.proxSize += len(self.buckets[i].nodes) + } + self.proxLimit = r + } else if self.proxLimit > 0 && r >= self.proxLimit-1 { + var i int + for i = self.proxLimit - 1; i > 0 && len(self.buckets[i].nodes)+self.proxSize <= self.ProxBinSize; i-- { + self.proxSize += len(self.buckets[i].nodes) + } + self.proxLimit = i + } + + if exLimit != self.proxLimit || exSize != self.proxSize { + glog.V(logger.Detail).Infof("[KΛÐ]: Max Prox Bin: Lower Limit: %v (was %v): Bin Size: %v (was %v)", self.proxLimit, exLimit, self.proxSize, exSize) + } +} + +/* +returns the list of nodes belonging to the same proximity bin +as the target. The most proximate bin will be the union of the bins between +proxLimit and MaxProx. +*/ +func (self *Kademlia) FindClosest(target Address, max int) []Node { + defer self.lock.RUnlock() + self.lock.RLock() + r := nodesByDistance{ + target: target, + } + index := self.proximityBin(target) + + start := index + var down bool + if index >= self.proxLimit { + index = self.proxLimit + start = self.MaxProx + down = true + } + var n int + limit := max + if max == 0 { + limit = 1000 + } + for { + + bucket := self.buckets[start].nodes + for i := 0; i < len(bucket); i++ { + r.push(bucket[i], limit) + n++ + } + if max == 0 && start <= index && (n > 0 || start == 0) || + max > 0 && down && start <= index && (n >= limit || n == self.count || start == 0) { + break + } + if down { + start-- + } else { + if start == self.MaxProx { + if index == 0 { + break + } + start = index - 1 + down = true + } else { + start++ + } + } + } + glog.V(logger.Detail).Infof("[KΛÐ]: serve %d (=<%d) nodes for target lookup %v (PO%d)", n, self.MaxProx, target, index) + return r.nodes +} + +func (self *Kademlia) binsize(p int) int { + b := self.buckets[p] + defer b.lock.RUnlock() + b.lock.RLock() + return len(b.nodes) +} + +func (self *Kademlia) FindBest() (node *NodeRecord, proxLimit int) { + return self.db.findBest(self.BucketSize, self.binsize) +} + +// adds node records to kaddb (persisted node record db) +func (self *Kademlia) Add(nrs []*NodeRecord) { + self.db.add(nrs, self.proximityBin) +} + +// in situ mutable bucket +type bucket struct { + size int + nodes []Node + lock sync.RWMutex +} + +// nodesByDistance is a list of nodes, ordered by distance to target. +type nodesByDistance struct { + nodes []Node + target Address +} + +func sortedByDistanceTo(target Address, slice []Node) bool { + var last Address + for i, node := range slice { + if i > 0 { + if target.ProxCmp(node.Addr(), last) < 0 { + return false + } + } + last = node.Addr() + } + return true +} + +// push(node, max) adds the given node to the list, keeping the total size +// below max elements. +func (h *nodesByDistance) push(node Node, max int) { + // returns the firt index ix such that func(i) returns true + ix := sort.Search(len(h.nodes), func(i int) bool { + return h.target.ProxCmp(h.nodes[i].Addr(), node.Addr()) >= 0 + }) + + if len(h.nodes) < max { + h.nodes = append(h.nodes, node) + } + if ix < len(h.nodes) { + copy(h.nodes[ix+1:], h.nodes[ix:]) + h.nodes[ix] = node + } +} + +// insert adds a peer to a bucket either by appending to existing items if +// bucket length does not exceed bucketSize, or by replacing the worst +// Node in the bucket +func (self *bucket) insert(node Node) (dropped Node, pos int) { + self.lock.Lock() + defer self.lock.Unlock() + if len(self.nodes) >= self.size { // >= allows us to add peers beyond the bucketsize limitation + dropped, pos = self.worstNode() + if dropped != nil { + self.nodes[pos] = node + glog.V(logger.Info).Infof("[KΛÐ] dropping node %v (%d)", dropped, pos) + dropped.Drop() + return + } + } + self.nodes = append(self.nodes, node) + return +} + +func (self *bucket) length(node Node) int { + self.lock.Lock() + defer self.lock.Unlock() + return len(self.nodes) +} + +// worst expunges the single worst node in a row, where worst entry is the node +// that has been inactive for the longests time +func (self *bucket) worstNode() (node Node, pos int) { + var oldest time.Time + for p, n := range self.nodes { + if (oldest == time.Time{}) || !oldest.Before(n.LastActive()) { + oldest = n.LastActive() + node = n + pos = p + } + } + return +} + +/* +Taking the proximity order relative to a fix point x classifies the points in +the space (n byte long byte sequences) into bins. Items in each are at +most half as distant from x as items in the previous bin. Given a sample of +uniformly distributed items (a hash function over arbitrary sequence) the +proximity scale maps onto series of subsets with cardinalities on a negative +exponential scale. + +It also has the property that any two item belonging to the same bin are at +most half as distant from each other as they are from x. + +If we think of random sample of items in the bins as connections in a network of interconnected nodes than relative proximity can serve as the basis for local +decisions for graph traversal where the task is to find a route between two +points. Since in every hop, the finite distance halves, there is +a guaranteed constant maximum limit on the number of hops needed to reach one +node from the other. +*/ + +func (self *Kademlia) proximityBin(other Address) (ret int) { + ret = proximity(self.addr, other) + if ret > self.MaxProx { + ret = self.MaxProx + } + return +} + +// provides keyrange for chunk db iteration +func (self *Kademlia) KeyRange(other Address) (start, stop Address) { + defer self.lock.RUnlock() + self.lock.RLock() + return KeyRange(self.addr, other, self.proxLimit) +} + +// save persists kaddb on disk (written to file on path in json format. +func (self *Kademlia) Save(path string, cb func(*NodeRecord, Node)) error { + return self.db.save(path, cb) +} + +// Load(path) loads the node record database (kaddb) from file on path. +func (self *Kademlia) Load(path string, cb func(*NodeRecord, Node) error) (err error) { + return self.db.load(path, cb) +} + +// kademlia table + kaddb table displayed with ascii +func (self *Kademlia) String() string { + + var rows []string + rows = append(rows, "=========================================================================") + rows = append(rows, fmt.Sprintf("%v : MaxProx: %d, ProxBinSize: %d, BucketSize: %d, proxLimit: %d, proxSize: %d", time.Now(), self.MaxProx, self.ProxBinSize, self.BucketSize, self.proxLimit, self.proxSize)) + + for i, b := range self.buckets { + + if i == self.proxLimit { + rows = append(rows, fmt.Sprintf("===================== PROX LIMIT: %d =================================", i)) + } + row := []string{fmt.Sprintf("%03d", i), fmt.Sprintf("%2d", len(b.nodes))} + var k int + c := self.db.cursors[i] + for ; k < len(b.nodes); k++ { + p := b.nodes[(c+k)%len(b.nodes)] + row = append(row, fmt.Sprintf("%s", p.Addr().String()[:8])) + if k == 3 { + break + } + } + for ; k < 3; k++ { + row = append(row, " ") + } + row = append(row, fmt.Sprintf("| %2d %2d", len(self.db.Nodes[i]), self.db.cursors[i])) + + for j, p := range self.db.Nodes[i] { + row = append(row, fmt.Sprintf("%08x", p.Addr[:4])) + if j == 2 { + break + } + } + rows = append(rows, strings.Join(row, " ")) + if i == self.MaxProx { + break + } + } + rows = append(rows, "=========================================================================") + return strings.Join(rows, "\n") +} diff --git a/common/kademlia/kademlia_test.go b/common/kademlia/kademlia_test.go new file mode 100644 index 0000000000..f36158c378 --- /dev/null +++ b/common/kademlia/kademlia_test.go @@ -0,0 +1,389 @@ +package kademlia + +import ( + "fmt" + "math/rand" + "reflect" + "testing" + "testing/quick" + "time" +) + +var ( + quickrand = rand.New(rand.NewSource(time.Now().Unix())) + quickcfgFindClosest = &quick.Config{MaxCount: 5000, Rand: quickrand} + quickcfgBootStrap = &quick.Config{MaxCount: 1000, Rand: quickrand} +) + +type testNode struct { + addr Address +} + +func (n *testNode) String() string { + return fmt.Sprintf("%x", n.addr[:]) +} + +func (n *testNode) Addr() Address { + return n.addr +} + +func (n *testNode) Drop() { +} + +func (n *testNode) Url() string { + return "" +} + +func (n *testNode) LastActive() time.Time { + return time.Now() +} + +func TestOn(t *testing.T) { + addr, ok := gen(Address{}, quickrand).(Address) + other, ok := gen(Address{}, quickrand).(Address) + if !ok { + t.Errorf("oops") + } + kad := New(addr, NewKadParams()) + err := kad.On(&testNode{addr: other}, nil) + _ = err +} + +func TestBootstrap(t *testing.T) { + + test := func(test *bootstrapTest) bool { + // for any node kad.le, Target and N + params := NewKadParams() + params.MaxProx = test.MaxProx + params.BucketSize = test.BucketSize + params.ProxBinSize = test.BucketSize + kad := New(test.Self, params) + var err error + + addr := RandomAddress() + prox := proximity(addr, test.Self) + + for p := 0; p <= prox; p++ { + var nrs []*NodeRecord + for i := 0; i < 3; i++ { + nrs = append(nrs, &NodeRecord{ + Addr: RandomAddressAt(test.Self, p), + }) + } + kad.Add(nrs) + } + + node := &testNode{addr} + + n := 0 + for n < 100 { + err = kad.On(node, nil) + if err != nil { + t.Errorf("backend not accepting node") + return false + } + var nrs []*NodeRecord + prox := proximity(test.Self, node.addr) + for i := 0; i < 13; i++ { + nrs = append(nrs, &NodeRecord{ + Addr: RandomAddressAt(test.Self, prox+1), + }) + } + kad.Add(nrs) + + record, _ := kad.FindBest() + if record == nil { + break + } + node = &testNode{record.Addr} + n++ + } + exp := test.BucketSize * (test.MaxProx + 1) + if kad.Count() != exp { + t.Errorf("incorrect number of peers, expected %d, got %d\n%v", exp, kad.Count(), kad) + return false + } + return true + } + if err := quick.Check(test, quickcfgBootStrap); err != nil { + t.Error(err) + } + +} + +func TestFindClosest(t *testing.T) { + + test := func(test *FindClosestTest) bool { + // for any node kad.le, Target and N + params := NewKadParams() + params.MaxProx = 10 + kad := New(test.Self, params) + var err error + // t.Logf("FindClosestTest %v: %v\n", len(test.All), test) + for _, node := range test.All { + err = kad.On(node, nil) + if err != nil { + t.Errorf("backend not accepting node") + return false + } + } + + if len(test.All) == 0 || test.N == 0 { + return true + } + nodes := kad.FindClosest(test.Target, test.N) + + // check that the number of results is min(N, kad.len) + wantN := test.N + if tlen := kad.Count(); tlen < test.N { + wantN = tlen + } + + if len(nodes) != wantN { + t.Errorf("wrong number of nodes: got %d, want %d", len(nodes), wantN) + return false + } + + if hasDuplicates(nodes) { + t.Errorf("result contains duplicates") + return false + } + + if !sortedByDistanceTo(test.Target, nodes) { + t.Errorf("result is not sorted by distance to target") + return false + } + + // check that the result nodes have minimum distance to target. + farthestResult := nodes[len(nodes)-1].Addr() + for i, b := range kad.buckets { + for j, n := range b.nodes { + if contains(nodes, n.Addr()) { + continue // don't run the check below for nodes in result + } + if test.Target.ProxCmp(n.Addr(), farthestResult) < 0 { + _ = i * j + t.Errorf("kad.le contains node that is closer to target but it's not in result") + // t.Logf("bucket %v, item %v\n", i, j) + // t.Logf(" Target: %x", test.Target) + // t.Logf(" Farthest Result: %x", farthestResult) + // t.Logf(" ID: %x (%d)", n.Addr(), kad.proximityBin(n.Addr())) + return false + } + } + } + return true + } + if err := quick.Check(test, quickcfgFindClosest); err != nil { + t.Error(err) + } +} + +type proxTest struct { + add bool + index int + addr Address +} + +var ( + addresses []Address +) + +func TestProxAdjust(t *testing.T) { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + self := gen(Address{}, r).(Address) + params := NewKadParams() + params.MaxProx = 10 + kad := New(self, params) + + var err error + for i := 0; i < 100; i++ { + a := gen(Address{}, r).(Address) + addresses = append(addresses, a) + err = kad.On(&testNode{addr: a}, nil) + if err != nil { + t.Errorf("backend not accepting node") + return + } + if !kad.proxCheck(t) { + return + } + } + + test := func(test *proxTest) bool { + node := &testNode{test.addr} + if test.add { + kad.On(node, nil) + } else { + kad.Off(node, nil) + } + return kad.proxCheck(t) + } + if err := quick.Check(test, quickcfgFindClosest); err != nil { + t.Error(err) + } +} + +func TestSaveLoad(t *testing.T) { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + addresses := gen([]Address{}, r).([]Address) + self := RandomAddress() + params := NewKadParams() + params.MaxProx = 10 + kad := New(self, params) + + var err error + + for _, a := range addresses { + err = kad.On(&testNode{addr: a}, nil) + if err != nil { + t.Errorf("backend not accepting node") + return + } + } + nodes := kad.FindClosest(self, 100) + path := "/tmp/bzz.peers" + err = kad.Save(path, nil) + if err != nil { + t.Fatalf("unepected error saving kaddb: %v", err) + } + kad = New(self, params) + err = kad.Load(path, nil) + if err != nil { + t.Fatalf("unepected error loading kaddb: %v", err) + } + for _, b := range kad.db.Nodes { + for _, node := range b { + err = kad.On(&testNode{node.Addr}, nil) + if err != nil { + t.Errorf("backend not accepting node") + return + } + } + } + loadednodes := kad.FindClosest(self, 100) + for i, node := range loadednodes { + if nodes[i].Addr() != node.Addr() { + t.Errorf("node mismatch at %d/%d: %v != %v", i, len(nodes), nodes[i].Addr(), node.Addr()) + } + } +} + +func (self *Kademlia) proxCheck(t *testing.T) bool { + var sum, i int + var b *bucket + for i, b = range self.buckets { + l := len(b.nodes) + // if we are in the high prox multibucket + if i >= self.proxLimit { + sum += l + } else if l == 0 { + t.Errorf("bucket %d empty, yet proxLimit is %d\n%v", len(b.nodes), self.proxLimit, self) + return false + } + } + // check if merged high prox bucket does not exceed size + if sum > 0 { + // if sum > self.ProxBinSize { + // t.Errorf("bucket %d is empty, yet proxSize is %d\n%v", i, self.proxSize, self) + // return false + // } + if sum != self.proxSize { + t.Errorf("proxSize incorrect, expected %v, got %v", sum, self.proxSize) + return false + } + if self.proxLimit > 0 && sum+len(self.buckets[self.proxLimit-1].nodes) < self.ProxBinSize { + t.Errorf("proxBinSize incorrect, expected %v got %v", sum, self.proxSize) + return false + } + } + return true +} + +type bootstrapTest struct { + MaxProx int + BucketSize int + Self Address +} + +func (*bootstrapTest) Generate(rand *rand.Rand, size int) reflect.Value { + t := &bootstrapTest{ + Self: gen(Address{}, rand).(Address), + MaxProx: 10 + rand.Intn(3), + BucketSize: rand.Intn(3) + 1, + } + return reflect.ValueOf(t) +} + +type FindClosestTest struct { + Self Address + Target Address + All []Node + N int +} + +func (c FindClosestTest) String() string { + return fmt.Sprintf("A: %064x\nT: %064x\n(%d)\n", c.Self[:], c.Target[:], c.N) +} + +func (*FindClosestTest) Generate(rand *rand.Rand, size int) reflect.Value { + t := &FindClosestTest{ + Self: gen(Address{}, rand).(Address), + Target: gen(Address{}, rand).(Address), + N: rand.Intn(bucketSize), + } + for _, a := range gen([]Address{}, rand).([]Address) { + t.All = append(t.All, &testNode{addr: a}) + } + return reflect.ValueOf(t) +} + +func (*proxTest) Generate(rand *rand.Rand, size int) reflect.Value { + var add bool + if rand.Intn(1) == 0 { + add = true + } + var t *proxTest + if add { + t = &proxTest{ + addr: gen(Address{}, rand).(Address), + add: add, + } + } else { + t = &proxTest{ + index: rand.Intn(len(addresses)), + add: add, + } + } + return reflect.ValueOf(t) +} + +func hasDuplicates(slice []Node) bool { + seen := make(map[Address]bool) + for _, node := range slice { + if seen[node.Addr()] { + return true + } + seen[node.Addr()] = true + } + return false +} + +func contains(nodes []Node, addr Address) bool { + for _, n := range nodes { + if n.Addr() == addr { + return true + } + } + return false +} + +// gen wraps quick.Value so it's easier to use. +// it generates a random value of the given value's type. +func gen(typ interface{}, rand *rand.Rand) interface{} { + v, ok := quick.Value(reflect.TypeOf(typ), rand) + if !ok { + panic(fmt.Sprintf("couldn't generate random value of type %T", typ)) + } + return v.Interface() +} diff --git a/common/registrar/ethreg/ethreg.go b/common/registrar/ethreg/ethreg.go index 626ebe1d74..7b3b41769c 100644 --- a/common/registrar/ethreg/ethreg.go +++ b/common/registrar/ethreg/ethreg.go @@ -20,18 +20,22 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common/registrar" - "github.com/ethereum/go-ethereum/xeth" ) +type Backend interface { + registrar.Backend + AtStateNum(int64) registrar.Backend +} + // implements a versioned Registrar on an archiving full node type EthReg struct { - backend *xeth.XEth + backend Backend registry *registrar.Registrar } -func New(xe *xeth.XEth) (self *EthReg) { - self = &EthReg{backend: xe} - self.registry = registrar.New(xe) +func New(backend Backend) (self *EthReg) { + self = &EthReg{backend: backend} + self.registry = registrar.New(backend) return } @@ -40,9 +44,11 @@ func (self *EthReg) Registry() *registrar.Registrar { } func (self *EthReg) Resolver(n *big.Int) *registrar.Registrar { - xe := self.backend + var s registrar.Backend if n != nil { - xe = self.backend.AtStateNum(n.Int64()) + s = self.backend.AtStateNum(n.Int64()) + } else { + s = registrar.Backend(self.backend) } - return registrar.New(xe) + return registrar.New(s) } diff --git a/common/swap/swap.go b/common/swap/swap.go new file mode 100644 index 0000000000..c8cf7a7770 --- /dev/null +++ b/common/swap/swap.go @@ -0,0 +1,238 @@ +package swap + +import ( + "fmt" + "math/big" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +// SwAP Swarm Accounting Protocol with +// Swift Automatic Payments +// a peer to peer micropayment system + +// public swap profile +// public parameters for SWAP, serializable config struct passed in handshake +type Profile struct { + BuyAt *big.Int // accepted max price for chunk + SellAt *big.Int // offered sale price for chunk + PayAt uint // threshold that triggers payment request + DropAt uint // threshold that triggers disconnect +} + +// Strategy encapsulates parameters relating to +// automatic deposit and automatic cashing +type Strategy struct { + AutoCashInterval time.Duration // default interval for autocash + AutoCashThreshold *big.Int // threshold that triggers autocash (wei) + AutoDepositInterval time.Duration // default interval for autocash + AutoDepositThreshold *big.Int // threshold that triggers autodeposit (wei) + AutoDepositBuffer *big.Int // buffer that is surplus for fork protection etc (wei) +} + +// Params extends the public profile with private parameters relating to +// automatic deposit and automatic cashing +type Params struct { + *Profile + *Strategy +} + +// Promise +// 3rd party Provable Promise of Payment +// issued by outPayment +// serialisable to send with Protocol +type Promise interface{} + +// interface for the peer protocol for testing or external alternative payment +type Protocol interface { + Pay(int, Promise) // units, payment proof + Drop() + String() string +} + +// interface for the (delayed) ougoing payment system with autodeposit +type OutPayment interface { + Issue(amount *big.Int) (promise Promise, err error) + AutoDeposit(interval time.Duration, threshold, buffer *big.Int) + Stop() +} + +// interface for the (delayed) incoming payment system with autocash +type InPayment interface { + Receive(promise Promise) (*big.Int, error) + AutoCash(cashInterval time.Duration, maxUncashed *big.Int) + Stop() +} + +// swap is the swarm accounting protocol instance +// * pairwise accounting and payments +type Swap struct { + lock sync.Mutex // mutex for balance access + balance int // units of chunk/retrieval request + local *Params // local peer's swap parameters + remote *Profile // remote peer's swap profile + proto Protocol // peer communication protocol + Payment +} + +type Payment struct { + Out OutPayment // outgoing payment handler + In InPayment // incoming payment handler + Buys, Sells bool +} + +// swap constructor +func New(local *Params, pm Payment, proto Protocol) (self *Swap, err error) { + + self = &Swap{ + local: local, + Payment: pm, + proto: proto, + } + + self.SetParams(local) + + return +} + +// entry point for setting remote swap profile (e.g from handshake or other message) +func (self *Swap) SetRemote(remote *Profile) { + defer self.lock.Unlock() + self.lock.Lock() + + self.remote = remote + if self.Sells && (remote.BuyAt.Cmp(common.Big0) <= 0 || self.local.SellAt.Cmp(common.Big0) <= 0 || remote.BuyAt.Cmp(self.local.SellAt) < 0) { + self.Out.Stop() + self.Sells = false + } + if self.Buys && (remote.SellAt.Cmp(common.Big0) <= 0 || self.local.BuyAt.Cmp(common.Big0) <= 0 || self.local.BuyAt.Cmp(self.remote.SellAt) < 0) { + self.In.Stop() + self.Buys = false + } + + glog.V(logger.Debug).Infof("[SWAP] <%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", self.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt) + +} + +// to set strategy dynamically +func (self *Swap) SetParams(local *Params) { + defer self.lock.Unlock() + self.lock.Lock() + self.local = local + self.setParams(local) +} + +// caller holds the lock + +func (self *Swap) setParams(local *Params) { + + if self.Sells { + self.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold) + glog.V(logger.Info).Infof("[SWAP] <%v> set autocash to every %v, max uncashed limit: %v", self.proto, local.AutoCashInterval, local.AutoCashThreshold) + } else { + glog.V(logger.Info).Infof("[SWAP] <%v> autocash off (not selling)", self.proto) + } + if self.Buys { + self.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer) + glog.V(logger.Info).Infof("[SWAP] <%v> set autodeposit to every %v, pay at: %v, buffer: %v", self.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer) + } else { + glog.V(logger.Info).Infof("[SWAP] <%v> autodeposit off (not buying)", self.proto) + } +} + +// Add(n) +// n > 0 called when promised/provided n units of service +// n < 0 called when used/requested n units of service +func (self *Swap) Add(n int) error { + defer self.lock.Unlock() + self.lock.Lock() + self.balance += n + if !self.Sells && self.balance > 0 { + glog.V(logger.Detail).Infof("[SWAP] <%v> remote peer cannot have debt (unable to buy)", self.proto, self.balance) + self.proto.Drop() + return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (unable to buy)", self.proto, self.balance) + } + if !self.Buys && self.balance < 0 { + glog.V(logger.Detail).Infof("[SWAP] <%v> we cannot have debt (unable to buy)", self.proto, self.balance) + return fmt.Errorf("[SWAP] <%v> we cannot have debt (unable to buy)", self.proto, self.balance) + } + if self.balance >= int(self.local.DropAt) { + glog.V(logger.Detail).Infof("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt) + self.proto.Drop() + return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt) + } else if self.balance <= -int(self.remote.PayAt) { + self.send() + } + return nil +} + +func (self *Swap) Balance() int { + defer self.lock.Unlock() + self.lock.Lock() + return self.balance +} + +// send(units) is called when payment is due +// In case of insolvency no promise is issued and sent, safe against fraud +// No return value: no error = payment is opportunistic = hang in till dropped +func (self *Swap) send() { + if self.local.BuyAt != nil && self.balance < 0 { + amount := big.NewInt(int64(-self.balance)) + amount.Mul(amount, self.remote.SellAt) + promise, err := self.Out.Issue(amount) + if err != nil { + glog.V(logger.Warn).Infof("[SWAP] <%v> cannot issue cheque (amount: %v, channel: %v): %v", self.proto, amount, self.Out, err) + } else { + glog.V(logger.Warn).Infof("[SWAP] <%v> cheque issued (amount: %v, channel: %v)", self.proto, amount, self.Out) + self.proto.Pay(-self.balance, promise) + self.balance = 0 + } + } +} + +// receive(units, promise) is called by the protocol when a payment msg is received +// returns error if promise is invalid. +func (self *Swap) Receive(units int, promise Promise) error { + if units <= 0 { + return fmt.Errorf("invalid units: %v <= 0", units) + } + + price := new(big.Int).SetInt64(int64(units)) + price.Mul(price, self.local.SellAt) + + amount, err := self.In.Receive(promise) + + if err != nil { + err = fmt.Errorf("invalid promise: %v", err) + } else if price.Cmp(amount) != 0 { + // verify amount = units * unit sale price + return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, self.local.SellAt, amount) + } + if err != nil { + glog.V(logger.Detail).Infof("[SWAP] <%v> invalid promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, err) + return err + } + + // credit remote peer with units + self.Add(-units) + glog.V(logger.Detail).Infof("[SWAP] <%v> received promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, promise) + + return nil +} + +// stop() causes autocash loop to terminate. +// Called after protocol handle loop terminates. +func (self *Swap) Stop() { + defer self.lock.Unlock() + self.lock.Lock() + if self.Buys { + self.Out.Stop() + } + if self.Sells { + self.In.Stop() + } +} diff --git a/common/swap/swap_test.go b/common/swap/swap_test.go new file mode 100644 index 0000000000..664cd81d20 --- /dev/null +++ b/common/swap/swap_test.go @@ -0,0 +1,178 @@ +package swap + +import ( + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" +) + +type testInPayment struct { + received []*testPromise + autocashInterval time.Duration + autocashLimit *big.Int +} + +type testPromise struct { + amount *big.Int +} + +func (self *testInPayment) Receive(promise Promise) (*big.Int, error) { + p := promise.(*testPromise) + self.received = append(self.received, p) + return p.amount, nil +} + +func (self *testInPayment) AutoCash(interval time.Duration, limit *big.Int) { + self.autocashInterval = interval + self.autocashLimit = limit +} + +func (self *testInPayment) Cash() (string, error) { return "", nil } + +func (self *testInPayment) Stop() {} + +type testOutPayment struct { + deposits []*big.Int + autodepositInterval time.Duration + autodepositThreshold *big.Int + autodepositBuffer *big.Int +} + +func (self *testOutPayment) Issue(amount *big.Int) (promise Promise, err error) { + return &testPromise{amount}, nil +} + +func (self *testOutPayment) Deposit(amount *big.Int) (string, error) { + self.deposits = append(self.deposits, amount) + return "", nil +} + +func (self *testOutPayment) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) { + self.autodepositInterval = interval + self.autodepositThreshold = threshold + self.autodepositBuffer = buffer +} + +func (self *testOutPayment) Stop() {} + +type testProtocol struct { + drop bool + amounts []int + promises []*testPromise +} + +func (self *testProtocol) Drop() { + self.drop = true +} + +func (self *testProtocol) String() string { + return "" +} + +func (self *testProtocol) Pay(amount int, promise Promise) { + p := promise.(*testPromise) + self.promises = append(self.promises, p) + self.amounts = append(self.amounts, amount) +} + +func TestSwap(t *testing.T) { + + strategy := &Strategy{ + AutoCashInterval: 1 * time.Second, + AutoCashThreshold: big.NewInt(20), + AutoDepositInterval: 1 * time.Second, + AutoDepositThreshold: big.NewInt(20), + AutoDepositBuffer: big.NewInt(40), + } + + local := &Params{ + Profile: &Profile{ + PayAt: 5, + DropAt: 10, + BuyAt: common.Big3, + SellAt: common.Big2, + }, + Strategy: strategy, + } + + in := &testInPayment{} + out := &testOutPayment{} + proto := &testProtocol{} + + swap, _ := New(local, Payment{In: in, Out: out, Buys: true, Sells: true}, proto) + + if in.autocashInterval != strategy.AutoCashInterval { + t.Fatalf("autocash interval not properly set, expect %v, got ", strategy.AutoCashInterval, in.autocashInterval) + } + if out.autodepositInterval != strategy.AutoDepositInterval { + t.Fatalf("autodeposit interval not properly set, expect %v, got ", strategy.AutoDepositInterval, out.autodepositInterval) + } + + remote := &Profile{ + PayAt: 3, + DropAt: 10, + BuyAt: common.Big2, + SellAt: common.Big3, + } + swap.SetRemote(remote) + + swap.Add(9) + if proto.drop { + t.Fatalf("not expected peer to be dropped") + } + swap.Add(1) + if !proto.drop { + t.Fatalf("expected peer to be dropped") + } + if !proto.drop { + t.Fatalf("expected peer to be dropped") + } + proto.drop = false + + swap.Receive(10, &testPromise{big.NewInt(20)}) + if swap.balance != 0 { + t.Fatalf("expected zero balance, got %v", swap.balance) + } + + if len(proto.amounts) != 0 { + t.Fatalf("expected zero balance, got %v", swap.balance) + } + + swap.Add(-2) + if len(proto.amounts) > 0 { + t.Fatalf("expected no payments yet, got %v", proto.amounts) + } + + swap.Add(-1) + if len(proto.amounts) != 1 { + t.Fatalf("expected one payment, got %v", len(proto.amounts)) + } + + if proto.amounts[0] != 3 { + t.Fatalf("expected payment for %v units, got %v", proto.amounts[0]) + } + + exp := new(big.Int).Mul(big.NewInt(int64(proto.amounts[0])), remote.SellAt) + if proto.promises[0].amount.Cmp(exp) != 0 { + t.Fatalf("expected payment amount %v, got %v", exp, proto.promises[0].amount) + } + + swap.SetParams(&Params{ + Profile: &Profile{ + PayAt: 5, + DropAt: 10, + BuyAt: common.Big3, + SellAt: common.Big2, + }, + Strategy: &Strategy{ + AutoCashInterval: 2 * time.Second, + AutoCashThreshold: big.NewInt(40), + AutoDepositInterval: 2 * time.Second, + AutoDepositThreshold: big.NewInt(40), + AutoDepositBuffer: big.NewInt(60), + }, + }) + +} diff --git a/common/types.go b/common/types.go index b1666d7338..4e5500c06c 100644 --- a/common/types.go +++ b/common/types.go @@ -187,3 +187,16 @@ func PP(value []byte) string { return fmt.Sprintf("%x...%x", value[:4], value[len(value)-4]) } + +func (a *Address) MarshalJSON() (out []byte, err error) { + return []byte(quote(a.Hex())), nil +} + +func (m *Address) UnmarshalJSON(value []byte) error { + m.Set(HexToAddress(string(value[1 : len(value)-1]))) + return nil +} + +func quote(s string) string { + return `"` + s + `"` +} diff --git a/core/genesis.go b/core/genesis.go index d8c6e9cea3..6e54f50495 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -35,6 +35,11 @@ import ( "github.com/ethereum/go-ethereum/params" ) +const ( + TestAccount = "e273f01c99144c438695e10f24926dc1f9fbf62d" + TestBalance = "1000000000000" +) + // WriteGenesisBlock writes the genesis block to the database as block number 0 func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) { contents, err := ioutil.ReadAll(reader) diff --git a/rpc/api/bzz.go b/rpc/api/bzz.go new file mode 100644 index 0000000000..c258879857 --- /dev/null +++ b/rpc/api/bzz.go @@ -0,0 +1,278 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with go-ethereum. If not, see . + +package api + +import ( + "encoding/json" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "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/swarm" +) + +const ( + BzzApiVersion = "1.0" +) + +// eth api provider +// See https://github.com/ethereum/wiki/wiki/JSON-RPC +type bzzApi struct { + swarm *swarm.Swarm + methods map[string]bzzhandler + codec codec.ApiCoder +} + +// eth callback handler +type bzzhandler func(*bzzApi, *shared.Request) (interface{}, error) + +var ( + bzzMapping = map[string]bzzhandler{ + "bzz_info": (*bzzApi).Info, + "bzz_issue": (*bzzApi).Issue, + "bzz_cash": (*bzzApi).Cash, + "bzz_deposit": (*bzzApi).Deposit, + "bzz_register": (*bzzApi).Register, + "bzz_resolve": (*bzzApi).Resolve, + "bzz_download": (*bzzApi).Download, + "bzz_upload": (*bzzApi).Upload, + "bzz_get": (*bzzApi).Get, + "bzz_put": (*bzzApi).Put, + "bzz_modify": (*bzzApi).Modify, + } +) + +func newSwarmOfflineError(method string) error { + return shared.NewNotAvailableError(method, "swarm offline") +} + +// create new bzzApi instance +func NewBzzApi(stack *node.Node, codec codec.Codec) *bzzApi { + var swarm *swarm.Swarm + stack.Service(&swarm) + return &bzzApi{swarm, bzzMapping, codec.New(nil)} +} + +// collection with supported methods +func (self *bzzApi) 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 *bzzApi) 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 *bzzApi) Name() string { + return shared.BzzApiName +} + +func (self *bzzApi) ApiVersion() string { + return BzzApiVersion +} + +func (self *bzzApi) Info(req *shared.Request) (interface{}, error) { + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + return s.Api().Info(), nil +} + +func (self *bzzApi) Issue(req *shared.Request) (interface{}, error) { + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzIssueArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + cheque, err := s.Api().Issue(common.HexToAddress(args.Beneficiary), args.Amount) + if err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + out, err := json.MarshalIndent(cheque, " ", "") + if err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + return string(out), nil +} + +func (self *bzzApi) Cash(req *shared.Request) (interface{}, error) { + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzCashArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + return s.Api().Cash(args.Cheque) + +} + +func (self *bzzApi) Deposit(req *shared.Request) (interface{}, error) { + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzDepositArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + return s.Api().Deposit(args.Amount) +} + +func (self *bzzApi) Register(req *shared.Request) (interface{}, error) { + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzRegisterArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + err := s.Api().Register(common.HexToAddress(args.Address), args.Domain, common.HexToHash(args.ContentHash)) + return err == nil, err +} + +func (self *bzzApi) Resolve(req *shared.Request) (interface{}, error) { + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzResolveArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + key, err := s.Api().Resolve(args.Domain) + return key.Hex(), err +} + +func (self *bzzApi) Download(req *shared.Request) (interface{}, error) { + + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzDownloadArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + err := s.Api().Download(args.BzzPath, args.LocalPath) + return err == nil, err +} + +func (self *bzzApi) Upload(req *shared.Request) (interface{}, error) { + + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzUploadArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + return s.Api().Upload(args.LocalPath, args.Index) +} + +func (self *bzzApi) Get(req *shared.Request) (interface{}, error) { + + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzGetArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + var content []byte + var mimeType string + var status, size int + var err error + content, mimeType, status, size, err = s.Api().Get(args.Path) + + obj := map[string]string{ + "content": string(content), + "contentType": mimeType, + "status": fmt.Sprintf("%v", status), + "size": fmt.Sprintf("%v", size), + } + + return obj, err +} + +func (self *bzzApi) Put(req *shared.Request) (interface{}, error) { + + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzPutArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + return s.Api().Put(args.Content, args.ContenType) +} + +func (self *bzzApi) Modify(req *shared.Request) (interface{}, error) { + + s := self.swarm + if s == nil { + return nil, newSwarmOfflineError(req.Method) + } + + args := new(BzzModifyArgs) + if err := self.codec.Decode(req.Params, &args); err != nil { + return nil, shared.NewDecodeParamError(err.Error()) + } + + return s.Api().Modify(args.RootHash, args.Path, args.ContentHash, args.ContentType) +} diff --git a/rpc/api/bzz_args.go b/rpc/api/bzz_args.go new file mode 100644 index 0000000000..2aee255e15 --- /dev/null +++ b/rpc/api/bzz_args.go @@ -0,0 +1,322 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with go-ethereum. If not, see . + +package api + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common/chequebook" + "github.com/ethereum/go-ethereum/rpc/shared" +) + +type BzzDepositArgs struct { + Amount *big.Int +} + +func (args *BzzDepositArgs) 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) + } + + amount, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("Amount", "not a string") + } + args.Amount, ok = new(big.Int).SetString(amount, 10) + if !ok { + return shared.NewInvalidTypeError("Amount", "not a number") + } + + return nil +} + +type BzzCashArgs struct { + Cheque *chequebook.Cheque +} + +func (args *BzzCashArgs) 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) + } + + chequestr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("Cheque", "not a string") + } + var cheque chequebook.Cheque + err = json.Unmarshal([]byte(chequestr), &cheque) + if err != nil { + return shared.NewDecodeParamError(err.Error()) + } + args.Cheque = &cheque + + return nil +} + +type BzzIssueArgs struct { + Beneficiary string + Amount *big.Int +} + +func (args *BzzIssueArgs) 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) + } + + beneficiary, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("Amount", "not a string") + } + args.Beneficiary = beneficiary + + amount, ok := obj[1].(string) + if !ok { + return shared.NewInvalidTypeError("Amount", "not a string") + } + args.Amount, ok = new(big.Int).SetString(amount, 10) + if !ok { + return shared.NewInvalidTypeError("Amount", "not a number") + } + + return nil +} + +type BzzRegisterArgs struct { + Address, ContentHash, Domain string +} + +func (args *BzzRegisterArgs) 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), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("Address", "not a string") + } + args.Address = addstr + + addstr, ok = obj[1].(string) + if !ok { + return shared.NewInvalidTypeError("Domain", "not a string") + } + args.Domain = addstr + + addstr, ok = obj[2].(string) + if !ok { + return shared.NewInvalidTypeError("ContentHash", "not a string") + } + args.ContentHash = addstr + + return nil +} + +type BzzResolveArgs struct { + Domain string +} + +func (args *BzzResolveArgs) 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) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("Domain", "not a string") + } + args.Domain = addstr + + return nil +} + +type BzzDownloadArgs struct { + BzzPath, LocalPath string +} + +func (args *BzzDownloadArgs) 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), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("BzzPath", "not a string") + } + args.BzzPath = addstr + + addstr, ok = obj[1].(string) + if !ok { + return shared.NewInvalidTypeError("LocalPath", "not a string") + } + args.LocalPath = addstr + + return nil +} + +type BzzUploadArgs struct { + LocalPath, Index string +} + +func (args *BzzUploadArgs) 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) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("LocalPath", "not a string") + } + args.LocalPath = addstr + + if len(obj) > 1 { + addstr, ok := obj[1].(string) + if ok { + args.Index = addstr + } + } + + return nil +} + +type BzzGetArgs struct { + Path string +} + +func (args *BzzGetArgs) 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) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("Path", "not a string") + } + args.Path = addstr + + return nil +} + +type BzzPutArgs struct { + Content, ContenType string +} + +func (args *BzzPutArgs) 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) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("Content", "not a string") + } + args.Content = addstr + + addstr, ok = obj[1].(string) + if !ok { + return shared.NewInvalidTypeError("ContenType", "not a string") + } + args.ContenType = addstr + + return nil +} + +type BzzModifyArgs struct { + RootHash, Path, ContentHash, ContentType string +} + +func (args *BzzModifyArgs) 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), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return shared.NewInvalidTypeError("RootHash", "not a string") + } + args.RootHash = addstr + + addstr, ok = obj[1].(string) + if !ok { + return shared.NewInvalidTypeError("Path", "not a string") + } + args.Path = addstr + + if len(obj) >= 4 { + addstr, ok = obj[2].(string) + if ok { + args.ContentHash = addstr + } + + addstr, ok = obj[3].(string) + if ok { + args.ContentType = addstr + } + } + + return nil +} diff --git a/rpc/api/bzz_js.go b/rpc/api/bzz_js.go new file mode 100644 index 0000000000..50bbd43d07 --- /dev/null +++ b/rpc/api/bzz_js.go @@ -0,0 +1,95 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with go-ethereum. If not, see . + +package api + +const Bzz_JS = ` +web3._extend({ + property: 'bzz', + methods: + [ + new web3._extend.Method({ + name: 'deposit', + call: 'bzz_deposit', + params: 1, + inputFormatter: [null] + }), + new web3._extend.Method({ + name: 'info', + call: 'bzz_info', + params: 1, + inputFormatter: [null] + }), + new web3._extend.Method({ + name: 'cash', + call: 'bzz_cash', + params: 1, + inputFormatter: [null] + }), + new web3._extend.Method({ + name: 'issue', + call: 'bzz_issue', + params: 2, + inputFormatter: [null, null] + }), + new web3._extend.Method({ + name: 'register', + call: 'bzz_register', + params: 3, + inputFormatter: [null, null, null] + }), + new web3._extend.Method({ + name: 'resolve', + call: 'bzz_resolve', + params: 1, + inputFormatter: [null] + }), + new web3._extend.Method({ + name: 'download', + call: 'bzz_download', + params: 2, + inputFormatter: [null, null] + }), + new web3._extend.Method({ + name: 'upload', + call: 'bzz_upload', + params: 2, + inputFormatter: [null, null] + }), + new web3._extend.Method({ + name: 'get', + call: 'bzz_get', + params: 1, + inputFormatter: [null] + }), + new web3._extend.Method({ + name: 'put', + call: 'bzz_put', + params: 2, + inputFormatter: [null, null] + }), + new web3._extend.Method({ + name: 'modify', + call: 'bzz_modify', + params: 4, + inputFormatter: [null, null, null, null] + }) + ], + properties: + [ + ] +}); +` diff --git a/rpc/api/utils.go b/rpc/api/utils.go index 794b6abeea..d52f6b3dc3 100644 --- a/rpc/api/utils.go +++ b/rpc/api/utils.go @@ -54,8 +54,28 @@ var ( "startRPC", "stopNatSpec", "stopRPC", + "setGlobalRegistrar", + "setHashReg", + "setUrlHint", + "saveInfo", + "getContractInfo", + "sleep", + "httpGet", "verbosity", }, + "bzz": []string{ + "info", + "issue", + "cash", + "deposit", + "register", + "resolve", + "download", + "upload", + "get", + "put", + "modify", + }, "db": []string{ "getString", "putString", @@ -102,7 +122,7 @@ var ( "hashrate", "mining", "namereg", - "pendingTransactions", + "getPendingTransactions", "resend", "sendRawTransaction", "sendTransaction", @@ -116,6 +136,7 @@ var ( "setExtra", "setGasPrice", "startAutoDAG", + "setEtherbase", "start", "stopAutoDAG", "stop", @@ -173,6 +194,8 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, stack *no switch strings.ToLower(strings.TrimSpace(name)) { case shared.AdminApiName: apis[i] = NewAdminApi(xeth, stack, codec) + case shared.BzzApiName: + apis[i] = NewBzzApi(stack, codec) case shared.DebugApiName: apis[i] = NewDebugApi(xeth, eth, codec) case shared.DbApiName: @@ -204,6 +227,8 @@ func Javascript(name string) string { switch strings.ToLower(strings.TrimSpace(name)) { case shared.AdminApiName: return Admin_JS + case shared.BzzApiName: + return Bzz_JS case shared.DebugApiName: return Debug_JS case shared.DbApiName: diff --git a/rpc/shared/utils.go b/rpc/shared/utils.go index b13e9eb1b4..1590265a01 100644 --- a/rpc/shared/utils.go +++ b/rpc/shared/utils.go @@ -20,6 +20,7 @@ import "strings" const ( AdminApiName = "admin" + BzzApiName = "bzz" EthApiName = "eth" DbApiName = "db" DebugApiName = "debug" @@ -37,7 +38,7 @@ const ( var ( // All API's AllApis = strings.Join([]string{ - AdminApiName, DbApiName, EthApiName, DebugApiName, MinerApiName, NetApiName, + AdminApiName, BzzApiName, DbApiName, EthApiName, DebugApiName, MinerApiName, NetApiName, ShhApiName, TxPoolApiName, PersonalApiName, Web3ApiName, }, ",") ) diff --git a/swarm/api/api.go b/swarm/api/api.go new file mode 100644 index 0000000000..11bf4d81ec --- /dev/null +++ b/swarm/api/api.go @@ -0,0 +1,456 @@ +package api + +import ( + "bufio" + "fmt" + "io" + "math/big" + "net/http" + "os" + "path/filepath" + "regexp" + "strings" + "sync" + + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/chequebook" + "github.com/ethereum/go-ethereum/common/registrar" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +var ( + hashMatcher = regexp.MustCompile("^[0-9A-Fa-f]{64}") + slashes = regexp.MustCompile("/+") + domainAndVersion = regexp.MustCompile("[@:;,]+") +) + +/* +Api implements webserver/file system related content storage and retrieval +on top of the dpa +it is the public interface of the dpa which is included in the ethereum stack +*/ +type Api struct { + dpa *storage.DPA + registrar registrar.VersionedRegistrar + conf *Config +} + +//the api constructor initialises +func NewApi(dpa *storage.DPA, registrar registrar.VersionedRegistrar, conf *Config) (self *Api) { + return &Api{dpa, registrar, conf} +} + +// this should move over to chequebook ipc api +func (self *Api) Issue(beneficiary common.Address, amount *big.Int) (cheque *chequebook.Cheque, err error) { + return self.conf.Swap.Chequebook().Issue(beneficiary, amount) +} + +func (self *Api) Cash(cheque *chequebook.Cheque) (txhash string, err error) { + return self.conf.Swap.Chequebook().Cash(cheque) +} + +func (self *Api) Deposit(amount *big.Int) (txhash string, err error) { + return self.conf.Swap.Chequebook().Deposit(amount) +} + +// serialisable info about swarm +type Info struct { + *Config + *chequebook.Params +} + +func (self *Api) Info() *Info { + + return &Info{ + Config: self.conf, + Params: chequebook.ContractParams, + } + +} + +// Get uses iterative manifest retrieval and prefix matching +// to resolve path to content using dpa retrieve +func (self *Api) Get(bzzpath string) (content []byte, mimeType string, status int, size int, err error) { + var reader storage.SectionReader + reader, mimeType, status, err = self.getPath("/" + bzzpath) + if err != nil { + return + } + content = make([]byte, reader.Size()) + size, err = reader.Read(content) + if err == io.EOF { + err = nil + } + return +} + +// Put provides singleton manifest creation and optional name registration +// on top of dpa store +func (self *Api) Put(content, contentType string) (string, error) { + sr := io.NewSectionReader(strings.NewReader(content), 0, int64(len(content))) + wg := &sync.WaitGroup{} + key, err := self.dpa.Store(sr, wg) + if err != nil { + return "", err + } + manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType) + sr = io.NewSectionReader(strings.NewReader(manifest), 0, int64(len(manifest))) + key, err = self.dpa.Store(sr, wg) + if err != nil { + return "", err + } + wg.Wait() + return key.String(), nil +} + +func (self *Api) Modify(rootHash, path, contentHash, contentType string) (newRootHash string, err error) { + root := common.Hex2Bytes(rootHash) + trie, err := loadManifest(self.dpa, root) + if err != nil { + return + } + + if contentHash != "" { + entry := &manifestTrieEntry{ + Path: path, + Hash: contentHash, + ContentType: contentType, + } + trie.addEntry(entry) + } else { + trie.deleteEntry(path) + } + + err = trie.recalcAndStore() + if err != nil { + return + } + return trie.hash.String(), nil +} + +const maxParallelFiles = 5 + +// Download replicates the manifest path structure on the local filesystem +// under localpath +func (self *Api) Download(bzzpath, localpath string) (err error) { + lpath, err := filepath.Abs(filepath.Clean(localpath)) + if err != nil { + return + } + err = os.MkdirAll(lpath, os.ModePerm) + if err != nil { + return + } + + parts := slashes.Split(bzzpath, 3) + if len(parts) < 2 { + return fmt.Errorf("Invalid bzz path") + } + hostPort := parts[1] + var path string + if len(parts) > 2 { + path = regularSlashes(parts[2]) + "/" + } + glog.V(logger.Debug).Infof("[BZZ] Swarm: host: '%s', path '%s' requested.", hostPort, path) + + //resolving host and port + var key storage.Key + key, err = self.Resolve(hostPort) + if err != nil { + err = errResolve(err) + glog.V(logger.Debug).Infof("[BZZ] Swarm: error : %v", err) + return + } + + trie, err := loadManifest(self.dpa, key) + if err != nil { + glog.V(logger.Debug).Infof("[BZZ] Swarm: loadManifestTrie error: %v", err) + return + } + + type downloadListEntry struct { + key storage.Key + path string + } + + var list []*downloadListEntry + var mde, mderr error + + prevPath := lpath + err = trie.listWithPrefix(path, func(entry *manifestTrieEntry, suffix string) { // TODO: paralellize + key := common.Hex2Bytes(entry.Hash) + path := lpath + "/" + suffix + dir := filepath.Dir(path) + if dir != prevPath { + mde = os.MkdirAll(dir, os.ModePerm) + if mde != nil { + mderr = mde + } + prevPath = dir + } + if (mde == nil) && (path != dir+"/") { + list = append(list, &downloadListEntry{key: key, path: path}) + } + }) + if err == nil { + err = mderr + } + + cnt := len(list) + errors := make([]error, cnt) + done := make(chan bool, maxParallelFiles) + dcnt := 0 + + for i, entry := range list { + if i >= dcnt+maxParallelFiles { + <-done + dcnt++ + } + go func(i int, entry *downloadListEntry, done chan bool) { + f, err := os.Create(entry.path) // TODO: path separators + if err == nil { + reader := self.dpa.Retrieve(entry.key) + writer := bufio.NewWriter(f) + _, err = io.CopyN(writer, reader, reader.Size()) // TODO: handle errors + err2 := writer.Flush() + if err == nil { + err = err2 + } + err2 = f.Close() + if err == nil { + err = err2 + } + } + + errors[i] = err + done <- true + }(i, entry, done) + } + for dcnt < cnt { + <-done + dcnt++ + } + + if err != nil { + return + } + for i, _ := range list { + if errors[i] != nil { + return errors[i] + } + } + return +} + +// Upload replicates a local directory as a manifest file and uploads it +// using dpa store +// TODO: localpath should point to a manifest +func (self *Api) Upload(lpath, index string) (string, error) { + var list []*manifestTrieEntry + localpath, err := filepath.Abs(filepath.Clean(lpath)) + if err != nil { + return "", err + } + + f, err := os.Open(localpath) + if err != nil { + return "", err + } + stat, err := f.Stat() + if err != nil { + return "", err + } + + var start int + if stat.IsDir() { + start = len(localpath) + glog.V(logger.Debug).Infof("[BZZ] uploading '%s'", localpath) + err = filepath.Walk(localpath, func(path string, info os.FileInfo, err error) error { + if (err == nil) && !info.IsDir() { + //fmt.Printf("lp %s path %s\n", localpath, path) + if len(path) <= start { + return fmt.Errorf("Path is too short") + } + if path[:start] != localpath { + return fmt.Errorf("Path prefix of '%s' does not match localpath '%s'", path, localpath) + } + entry := &manifestTrieEntry{ + Path: path, + } + list = append(list, entry) + } + return err + }) + if err != nil { + return "", err + } + } else { + dir := filepath.Dir(localpath) + start = len(dir) + if len(localpath) <= start { + return "", fmt.Errorf("Path is too short") + } + if localpath[:start] != dir { + return "", fmt.Errorf("Path prefix of '%s' does not match dir '%s'", localpath, dir) + } + entry := &manifestTrieEntry{ + Path: localpath, + } + list = append(list, entry) + } + + cnt := len(list) + errors := make([]error, cnt) + done := make(chan bool, maxParallelFiles) + dcnt := 0 + + for i, entry := range list { + if i >= dcnt+maxParallelFiles { + <-done + dcnt++ + } + go func(i int, entry *manifestTrieEntry, done chan bool) { + f, err := os.Open(entry.Path) + if err == nil { + stat, _ := f.Stat() + sr := io.NewSectionReader(f, 0, stat.Size()) + wg := &sync.WaitGroup{} + var hash storage.Key + hash, err = self.dpa.Store(sr, wg) + if hash != nil { + list[i].Hash = hash.String() + } + wg.Wait() + if err == nil { + first512 := make([]byte, 512) + fread, _ := sr.ReadAt(first512, 0) + if fread > 0 { + mimeType := http.DetectContentType(first512[:fread]) + if filepath.Ext(entry.Path) == ".css" { + mimeType = "text/css" + } + list[i].ContentType = mimeType + //fmt.Printf("%v %v %v\n", entry.Path, mimeType, filepath.Ext(entry.Path)) + } + } + f.Close() + } + errors[i] = err + done <- true + }(i, entry, done) + } + for dcnt < cnt { + <-done + dcnt++ + } + + trie := &manifestTrie{ + dpa: self.dpa, + } + for i, entry := range list { + if errors[i] != nil { + return "", errors[i] + } + entry.Path = regularSlashes(entry.Path[start:]) + if entry.Path == index { + ientry := &manifestTrieEntry{ + Path: "", + Hash: entry.Hash, + ContentType: entry.ContentType, + } + trie.addEntry(ientry) + } + trie.addEntry(entry) + } + + err2 := trie.recalcAndStore() + var hs string + if err2 == nil { + hs = trie.hash.String() + } + return hs, err2 +} + +func (self *Api) Register(sender common.Address, domain string, hash common.Hash) (err error) { + domainhash := common.BytesToHash(crypto.Sha3([]byte(domain))) + + if self.registrar != nil { + glog.V(logger.Debug).Infof("[BZZ] Swarm: host '%s' (hash: '%v') to be registered as '%v'", domain, domainhash.Hex(), hash.Hex()) + _, err = self.registrar.Registry().SetHashToHash(sender, domainhash, hash) + } else { + err = fmt.Errorf("no registry: %v", err) + } + return +} + +type errResolve error + +func (self *Api) Resolve(hostPort string) (contentHash storage.Key, err error) { + host := hostPort + if hashMatcher.MatchString(host) { + contentHash = storage.Key(common.Hex2Bytes(host)) + glog.V(logger.Debug).Infof("[BZZ] Swarm: host is a contentHash: '%v'", contentHash) + } else { + if self.registrar != nil { + var hash common.Hash + var version *big.Int + parts := domainAndVersion.Split(host, 3) + if len(parts) > 1 && parts[1] != "" { + host = parts[0] + version = common.Big(parts[1]) + } + hostHash := crypto.Sha3Hash([]byte(host)) + hash, err = self.registrar.Resolver(version).HashToHash(hostHash) + if err != nil { + err = fmt.Errorf("unable to resolve '%s': %v", hostPort, err) + } + contentHash = storage.Key(hash.Bytes()) + glog.V(logger.Debug).Infof("[BZZ] Swarm: resolve host '%s' to contentHash: '%v'", hostPort, contentHash) + } else { + err = fmt.Errorf("no resolver '%s': %v", hostPort, err) + } + } + return +} + +func (self *Api) getPath(uri string) (reader storage.SectionReader, mimeType string, status int, err error) { + parts := slashes.Split(uri, 3) + hostPort := parts[1] + var path string + if len(parts) > 2 { + path = parts[2] + } + glog.V(logger.Debug).Infof("[BZZ] Swarm: host: '%s', path '%s' requested.", hostPort, path) + + //resolving host and port + var key storage.Key + key, err = self.Resolve(hostPort) + if err != nil { + err = errResolve(err) + glog.V(logger.Debug).Infof("[BZZ] Swarm: error : %v", err) + return + } + + trie, err := loadManifest(self.dpa, key) + if err != nil { + glog.V(logger.Debug).Infof("[BZZ] Swarm: loadManifestTrie error: %v", err) + return + } + + glog.V(logger.Debug).Infof("[BZZ] Swarm: getEntry(%s)", path) + entry, _ := trie.getEntry(path) + if entry != nil { + key = common.Hex2Bytes(entry.Hash) + status = entry.Status + mimeType = entry.ContentType + glog.V(logger.Debug).Infof("[BZZ] Swarm: content lookup key: '%v' (%v)", key, mimeType) + reader = self.dpa.Retrieve(key) + } else { + err = fmt.Errorf("manifest entry for '%s' not found", path) + glog.V(logger.Debug).Infof("[BZZ] Swarm: %v", err) + } + return +} diff --git a/swarm/api/api_test.go b/swarm/api/api_test.go new file mode 100644 index 0000000000..81156afcd8 --- /dev/null +++ b/swarm/api/api_test.go @@ -0,0 +1,205 @@ +package api + +import ( + "bytes" + "io/ioutil" + "os" + "path" + "runtime" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +//TODO: add tests for resolver/registrar +// will most likely be its own package under service? + +var ( + testDir string +) + +func init() { + _, filename, _, _ := runtime.Caller(1) + testDir = path.Join(path.Dir(filename), "../test") +} + +func testApi() (api *Api, err error) { + datadir, err := ioutil.TempDir("", "bzz-test") + if err != nil { + return nil, err + } + os.RemoveAll(datadir) + dpa, err := storage.NewLocalDPA(datadir) + if err != nil { + return + } + prvkey, _ := crypto.GenerateKey() + + config, err := NewConfig(datadir, common.Address{}, prvkey) + if err != nil { + return + } + api = NewApi(dpa, nil, config) + api.dpa.Start() + + return +} + +func TestApiPut(t *testing.T) { + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + defer api.dpa.Stop() + expContent := "hello" + expMimeType := "text/plain" + expStatus := 0 + expSize := len(expContent) + bzzhash, err := api.Put(expContent, expMimeType) + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + testGet(t, api, bzzhash, []byte(expContent), expMimeType, expStatus, expSize) +} + +func testGet(t *testing.T, api *Api, bzzhash string, expContent []byte, expMimeType string, expStatus int, expSize int) { + content, mimeType, status, size, err := api.Get(bzzhash) + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + if !bytes.Equal(content, expContent) { + t.Errorf("incorrect content. expected '%s...', got '%s...'", string(expContent), string(content)) + } + if mimeType != expMimeType { + t.Errorf("incorrect mimeType. expected '%s', got '%s'", expMimeType, mimeType) + } + if status != expStatus { + t.Errorf("incorrect status. expected '%d', got '%d'", expStatus, status) + } + if size != expSize { + t.Errorf("incorrect size. expected '%d', got '%d'", expSize, size) + } +} + +func TestApiDirUpload(t *testing.T) { + t.Skip("FIXME") + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err := api.Upload(path.Join(testDir, "test0"), "") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + content, err := ioutil.ReadFile(path.Join(testDir, "test0", "index.html")) + testGet(t, api, path.Join(bzzhash, "index.html"), content, "text/html; charset=utf-8", 0, 202) + + content, err = ioutil.ReadFile(path.Join(testDir, "test0", "index.css")) + testGet(t, api, path.Join(bzzhash, "index.css"), content, "text/css", 0, 132) + + content, err = ioutil.ReadFile(path.Join(testDir, "test0", "img", "logo.png")) + testGet(t, api, path.Join(bzzhash, "img", "logo.png"), content, "image/png", 0, 18136) + + _, _, _, _, err = api.Get(bzzhash) + if err == nil { + t.Errorf("expected error: %v", err) + } +} + +func TestApiDirUploadModify(t *testing.T) { + t.Skip("FIXME") + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err := api.Upload(path.Join(testDir, "test0"), "") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + bzzhash, err = api.Modify(bzzhash, "index.html", "", "") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err = api.Modify(bzzhash, "index2.html", "9ea1f60ebd80786d6005f6b256376bdb494a82496cd86fe8c307cdfb23c99e71", "text/html; charset=utf-8") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err = api.Modify(bzzhash, "img/logo.png", "9ea1f60ebd80786d6005f6b256376bdb494a82496cd86fe8c307cdfb23c99e71", "text/html; charset=utf-8") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + content, err := ioutil.ReadFile(path.Join(testDir, "test0", "index.html")) + testGet(t, api, path.Join(bzzhash, "index2.html"), content, "text/html; charset=utf-8", 0, 202) + testGet(t, api, path.Join(bzzhash, "img", "logo.png"), content, "text/html; charset=utf-8", 0, 202) + + content, err = ioutil.ReadFile(path.Join(testDir, "test0", "index.css")) + testGet(t, api, path.Join(bzzhash, "index.css"), content, "text/css", 0, 132) + + _, _, _, _, err = api.Get(bzzhash) + if err == nil { + t.Errorf("expected error: %v", err) + } +} + +func TestApiDirUploadWithRootFile(t *testing.T) { + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err := api.Upload(path.Join(testDir, "test0"), "index.html") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + content, err := ioutil.ReadFile(path.Join(testDir, "test0", "index.html")) + testGet(t, api, bzzhash, content, "text/html; charset=utf-8", 0, 202) +} + +func TestApiFileUpload(t *testing.T) { + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err := api.Upload(path.Join(testDir, "test0", "index.html"), "") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + content, err := ioutil.ReadFile(path.Join(testDir, "test0", "index.html")) + testGet(t, api, path.Join(bzzhash, "index.html"), content, "text/html; charset=utf-8", 0, 202) +} + +func TestApiFileUploadWithRootFile(t *testing.T) { + api, err := testApi() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + bzzhash, err := api.Upload(path.Join(testDir, "test0", "index.html"), "index.html") + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + + content, err := ioutil.ReadFile(path.Join(testDir, "test0", "index.html")) + testGet(t, api, bzzhash, content, "text/html; charset=utf-8", 0, 202) +} diff --git a/swarm/api/config.go b/swarm/api/config.go new file mode 100644 index 0000000000..6657167984 --- /dev/null +++ b/swarm/api/config.go @@ -0,0 +1,105 @@ +package api + +import ( + "crypto/ecdsa" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/ethereum/go-ethereum/swarm/network" + "github.com/ethereum/go-ethereum/swarm/services/swap" + "github.com/ethereum/go-ethereum/swarm/storage" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +const ( + port = "8500" +) + +// separate bzz directories +// allow several bzz nodes running in parallel +type Config struct { + // serialised/persisted fields + *storage.StoreParams + *storage.ChunkerParams + *network.HiveParams + Swap *swap.SwapParams + *network.SyncParams + Path string + Port string + PublicKey string + BzzKey string +} + +// config is agnostic to where private key is coming from +// so managing accounts is outside swarm and left to wrappers +func NewConfig(path string, contract common.Address, prvKey *ecdsa.PrivateKey) (self *Config, err error) { + + address := crypto.PubkeyToAddress(prvKey.PublicKey) // default beneficiary address + dirpath := filepath.Join(path, common.Bytes2Hex(address.Bytes())) + err = os.MkdirAll(dirpath, os.ModePerm) + if err != nil { + return + } + confpath := filepath.Join(dirpath, "config.json") + var data []byte + pubkey := crypto.FromECDSAPub(&prvKey.PublicKey) + pubkeyhex := common.ToHex(pubkey) + keyhex := crypto.Sha3Hash(pubkey).Hex() + + self = &Config{ + SyncParams: network.NewSyncParams(dirpath), + HiveParams: network.NewHiveParams(dirpath), + ChunkerParams: storage.NewChunkerParams(), + StoreParams: storage.NewStoreParams(dirpath), + Port: port, + Path: dirpath, + Swap: swap.DefaultSwapParams(contract, prvKey), + PublicKey: pubkeyhex, + BzzKey: keyhex, + } + data, err = ioutil.ReadFile(confpath) + if err != nil { + if !os.IsNotExist(err) { + return + } + // file does not exist + // write out config file + err = self.Save() + if err != nil { + err = fmt.Errorf("error writing config: %v", err) + } + return + } + // file exists, deserialise + err = json.Unmarshal(data, self) + if err != nil { + return nil, fmt.Errorf("unable to parse config: %v", err) + } + // check public key + if pubkeyhex != self.PublicKey { + return nil, fmt.Errorf("public key does not match the one in the config file %v != %v", pubkeyhex, self.PublicKey) + } + if keyhex != self.BzzKey { + return nil, fmt.Errorf("bzz key does not match the one in the config file %v != %v", keyhex, self.BzzKey) + } + self.Swap.SetKey(prvKey) + + return +} + +func (self *Config) Save() error { + data, err := json.MarshalIndent(self, "", " ") + if err != nil { + return err + } + err = os.MkdirAll(self.Path, os.ModePerm) + if err != nil { + return err + } + confpath := filepath.Join(self.Path, "config.json") + return ioutil.WriteFile(confpath, data, os.ModePerm) +} diff --git a/swarm/api/config_test.go b/swarm/api/config_test.go new file mode 100644 index 0000000000..44bb484667 --- /dev/null +++ b/swarm/api/config_test.go @@ -0,0 +1,107 @@ +package api + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +var ( + hexprvkey = "65138b2aa745041b372153550584587da326ab440576b2a1191dd95cee30039c" + defaultConfig = `{ + "ChunkDbPath": "` + filepath.Join("TMPDIR", "0d2f62485607cf38d9d795d93682a517661e513e", "chunks") + `", + "DbCapacity": 5000000, + "CacheCapacity": 5000, + "Radius": 0, + "Branches": 128, + "Hash": "SHA256", + "JoinTimeout": 120, + "SplitTimeout": 120, + "CallInterval": 10000000000, + "KadDbPath": "` + filepath.Join("TMPDIR", "0d2f62485607cf38d9d795d93682a517661e513e", "bzz-peers.json") + `", + "MaxProx": 10, + "ProxBinSize": 8, + "BucketSize": 3, + "PurgeInterval": 151200000000000, + "InitialRetryInterval": 4200000000, + "ConnRetryExp": 2, + "Swap": { + "BuyAt": 20000000000, + "SellAt": 20000000000, + "PayAt": 100, + "DropAt": 10000, + "AutoCashInterval": 300000000000, + "AutoCashThreshold": 50000000000000, + "AutoDepositInterval": 300000000000, + "AutoDepositThreshold": 50000000000000, + "AutoDepositBuffer": 100000000000000, + "PublicKey": "0x045f5cfd26692e48d0017d380349bcf50982488bc11b5145f3ddf88b24924299048450542d43527fbe29a5cb32f38d62755393ac002e6bfdd71b8d7ba725ecd7a3", + "Contract": "0x0000000000000000000000000000000000000000", + "Beneficiary": "0x0d2f62485607cf38d9d795d93682a517661e513e" + }, + "RequestDbPath": "` + filepath.Join("TMPDIR", "0d2f62485607cf38d9d795d93682a517661e513e", "requests") + `", + "RequestDbBatchSize": 512, + "KeyBufferSize": 1024, + "SyncBatchSize": 128, + "SyncBufferSize": 128, + "SyncCacheSize": 1024, + "SyncPriorities": [ + 2, + 1, + 1, + 0, + 0 + ], + "SyncModes": [ + true, + true, + true, + true, + false + ], + "Path": "` + filepath.Join("TMPDIR", "0d2f62485607cf38d9d795d93682a517661e513e") + `", + "Port": "8500", + "PublicKey": "0x045f5cfd26692e48d0017d380349bcf50982488bc11b5145f3ddf88b24924299048450542d43527fbe29a5cb32f38d62755393ac002e6bfdd71b8d7ba725ecd7a3", + "BzzKey": "0xe861964402c0b78e2d44098329b8545726f215afa737d803714a4338552fcb81" +}` +) + +func TestConfigWriteRead(t *testing.T) { + tmp, err := ioutil.TempDir(os.TempDir(), "bzz-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmp) + + prvkey := crypto.ToECDSA(common.Hex2Bytes(hexprvkey)) + orig, err := NewConfig(tmp, common.Address{}, prvkey) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + account := crypto.PubkeyToAddress(prvkey.PublicKey) + dirpath := filepath.Join(tmp, common.Bytes2Hex(account.Bytes())) + confpath := filepath.Join(dirpath, "config.json") + data, err := ioutil.ReadFile(confpath) + if err != nil { + t.Fatalf("default config file cannot be read: %v", err) + } + exp := strings.Replace(defaultConfig, "TMPDIR", tmp, -1) + + if string(data) != exp { + t.Fatalf("default config mismatch:\nexpected:\n'%v'\ngot:\n'%v'", exp, string(data)) + } + + conf, err := NewConfig(tmp, common.Address{}, prvkey) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if conf.Swap.Beneficiary.Hex() != orig.Swap.Beneficiary.Hex() { + t.Fatalf("expected beneficiary from loaded config %v to match original %v", conf.Swap.Beneficiary.Hex(), orig.Swap.Beneficiary.Hex()) + } + +} diff --git a/swarm/api/ethereum.go b/swarm/api/ethereum.go new file mode 100644 index 0000000000..1027d1e768 --- /dev/null +++ b/swarm/api/ethereum.go @@ -0,0 +1,320 @@ +package api + +import ( + "errors" + "fmt" + "math/big" + "regexp" + "sync" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/registrar" + "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/eth" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +/* +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! THIS IS CURRENTLY A PLACEHOLEDER (HACK) UNTIL PRC v2 +!! https://github.com/ethereum/go-ethereum/pull/1912 is merged +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +*/ + +var ( + defaultGasPrice = big.NewInt(10000000000000) //150000000000 + defaultGas = big.NewInt(90000) //500000 + addrReg = regexp.MustCompile(`^(0x)?[a-fA-F0-9]{40}$`) +) + +type ethApi struct { + eth *eth.Ethereum + gpo *eth.GasPriceOracle + transactionMu sync.RWMutex + transactMu sync.RWMutex + state *state.StateDB +} + +func NewEthApi(ethereum *eth.Ethereum) *ethApi { + return ðApi{ + eth: ethereum, + gpo: eth.NewGasPriceOracle(ethereum), + } +} + +// subscribes to new head block events and +// waits until blockchain height is greater n at any time +// given the current head, waits for the next chain event +// sets the state to the current head +// loop is async and quit by closing the channel +// used in tests and JS console debug module to control advancing private chain manually +// Note: this is not threadsafe, only called in JS single process and tests +func (self *ethApi) UpdateState() (wait chan *big.Int) { + wait = make(chan *big.Int) + self.state, _ = state.New(self.eth.BlockChain().GetBlockByNumber(0).Root(), self.eth.ChainDb()) + + go func() { + eventSub := self.eth.EventMux().Subscribe(core.ChainHeadEvent{}) + defer eventSub.Unsubscribe() + + var m, n *big.Int + var ok bool + + eventCh := eventSub.Chan() + for { + select { + case event, ok := <-eventCh: + if !ok { + // Event subscription closed, set the channel to nil to stop spinning + eventCh = nil + continue + } + // A real event arrived, process if new head block assignment + if event, ok := event.Data.(core.ChainHeadEvent); ok { + m = event.Block.Number() + if n != nil && n.Cmp(m) < 0 { + wait <- n + n = nil + } + statedb, err := state.New(event.Block.Root(), self.eth.ChainDb()) + if err != nil { + glog.V(logger.Error).Infoln("Could not create new state: %v", err) + return + } + self.state = statedb + } + case n, ok = <-wait: + if !ok { + return + } + } + } + }() + return +} + +func (self *ethApi) AtStateNum(num int64) registrar.Backend { + var st *state.StateDB + var err error + switch num { + case -2: + st = self.eth.Miner().PendingState().Copy() + default: + if block := self.getBlockByHeight(num); block != nil { + st, err = state.New(block.Root(), self.eth.ChainDb()) + if err != nil { + return nil + } + } else { + st, err = state.New(self.eth.BlockChain().GetBlockByNumber(0).Root(), self.eth.ChainDb()) + if err != nil { + return nil + } + } + } + return registrar.Backend(ðApi{ + eth: self.eth, + state: st, + }) +} +func (self *ethApi) GetTxReceipt(txhash common.Hash) *types.Receipt { + return core.GetReceipt(self.eth.ChainDb(), txhash) +} + +func (self *ethApi) StorageAt(addr, storageAddr string) string { + return self.state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex() +} + +func (self *ethApi) CodeAt(address string) string { + return common.ToHex(self.state.GetCode(common.HexToAddress(address))) +} + +func (self *ethApi) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr string) (string, string, error) { + statedb := self.state.Copy() + var from *state.StateObject + if len(fromStr) == 0 { + accounts, err := self.eth.AccountManager().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 = self.DefaultGasPrice() + } + + header := self.CurrentBlock().Header() + vmenv := core.NewEnv(statedb, self.eth.BlockChain(), msg, header) + gp := new(core.GasPool).AddGas(common.MaxBig) + res, gas, err := core.ApplyMessage(vmenv, msg, gp) + return common.ToHex(res), gas.String(), err +} + +func (self *ethApi) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { + + if len(toStr) > 0 && toStr != "0x" && !isAddress(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 = DefaultGas() + } else { + gas = common.Big(gasStr) + } + + if len(gasPriceStr) == 0 { + price = self.DefaultGasPrice() + } else { + price = common.Big(gasPriceStr) + } + + data = common.FromHex(codeStr) + if len(toStr) == 0 { + contractCreation = true + } + + self.transactMu.Lock() + defer self.transactMu.Unlock() + + var nonce uint64 + if len(nonceStr) != 0 { + nonce = common.Big(nonceStr).Uint64() + } else { + state := self.eth.TxPool().State() + nonce = state.GetNonce(from) + } + var tx *types.Transaction + if contractCreation { + tx = types.NewContractCreation(nonce, value, gas, price, data) + } else { + tx = types.NewTransaction(nonce, to, value, gas, price, data) + } + + signed, err := self.sign(tx, from, false) + if err != nil { + return "", err + } + if err = self.eth.TxPool().Add(signed); err != nil { + return "", err + } + + if contractCreation { + addr := crypto.CreateAddress(from, nonce) + glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signed.Hash().Hex(), addr.Hex()) + } else { + glog.V(logger.Info).Infof("Tx(%s) to: %s\n", signed.Hash().Hex(), tx.To().Hex()) + } + + return signed.Hash().Hex(), nil +} + +func (self *ethApi) sign(tx *types.Transaction, from common.Address, didUnlock bool) (*types.Transaction, error) { + hash := tx.SigHash() + sig, err := self.doSign(from, hash, didUnlock) + if err != nil { + return tx, err + } + return tx.WithSignature(sig) +} + +func (self *ethApi) doSign(from common.Address, hash common.Hash, didUnlock bool) ([]byte, error) { + sig, err := self.eth.AccountManager().Sign(accounts.Account{Address: from}, hash.Bytes()) + if err == accounts.ErrLocked { + if didUnlock { + return nil, fmt.Errorf("signer account still locked after successful unlock") + } + // retry signing, the account should now be unlocked. + return self.doSign(from, hash, true) + } else if err != nil { + return nil, err + } + return sig, nil +} + +func DefaultGas() *big.Int { return new(big.Int).Set(defaultGas) } + +func (self *ethApi) DefaultGasPrice() *big.Int { + return self.gpo.SuggestPrice() +} + +func (self *ethApi) CurrentBlock() *types.Block { + return self.eth.BlockChain().CurrentBlock() +} + +func (self *ethApi) getBlockByHeight(height int64) *types.Block { + var num uint64 + + switch height { + case -2: + return self.eth.Miner().PendingBlock() + case -1: + return self.CurrentBlock() + default: + if height < 0 { + return nil + } + + num = uint64(height) + } + + return self.eth.BlockChain().GetBlockByNumber(num) +} + +// 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 +} + +func isAddress(addr string) bool { + return addrReg.MatchString(addr) +} + +// 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 } diff --git a/swarm/api/http.go b/swarm/api/http.go new file mode 100644 index 0000000000..b1cd039cce --- /dev/null +++ b/swarm/api/http.go @@ -0,0 +1,247 @@ +/* +A simple http server interface to Swarm +*/ +package api + +import ( + "bytes" + "io" + "net/http" + "regexp" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" +) + +const ( + rawType = "application/octet-stream" +) + +var ( + bzzPrefix = regexp.MustCompile("^/+bzz:/+") + rawUrl = regexp.MustCompile("^/+raw/*") + trailingSlashes = regexp.MustCompile("/+$") + // forever = func() time.Time { return time.Unix(0, 0) } + forever = time.Now +) + +type sequentialReader struct { + reader io.Reader + pos int64 + ahead map[int64](chan bool) + lock sync.Mutex +} + +// browser API for registering bzz url scheme handlers: +// https://developer.mozilla.org/en/docs/Web-based_protocol_handlers +// electron (chromium) api for registering bzz url scheme handlers: +// https://github.com/atom/electron/blob/master/docs/api/protocol.md + +// starts up http server +func StartHttpServer(api *Api, port string) { + serveMux := http.NewServeMux() + serveMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + handler(w, r, api) + }) + go http.ListenAndServe(":"+port, serveMux) + glog.V(logger.Info).Infof("[BZZ] Swarm HTTP proxy started on localhost:%s", port) +} + +func handler(w http.ResponseWriter, r *http.Request, api *Api) { + requestURL := r.URL + // This is wrong + // if requestURL.Host == "" { + // var err error + // requestURL, err = url.Parse(r.Referer() + requestURL.String()) + // if err != nil { + // http.Error(w, err.Error(), http.StatusBadRequest) + // return + // } + // } + glog.V(logger.Debug).Infof("[BZZ] Swarm: HTTP request URL: '%s', Host: '%s', Path: '%s', Referer: '%s', Accept: '%s'", r.RequestURI, requestURL.Host, requestURL.Path, r.Referer(), r.Header.Get("Accept")) + uri := requestURL.Path + var raw bool + + // HTTP-based URL protocol handler + uri = bzzPrefix.ReplaceAllString(uri, "") + glog.V(logger.Debug).Infof("[BZZ] Swarm: BZZ request URI: '%s'", uri) + + path := rawUrl.ReplaceAllStringFunc(uri, func(string) string { + raw = true + return "" + }) + + glog.V(logger.Debug).Infof("[BZZ] Swarm: %s request '%s' received.", r.Method, uri) + + switch { + case r.Method == "POST" || r.Method == "PUT": + key, err := api.dpa.Store(io.NewSectionReader(&sequentialReader{ + reader: r.Body, + ahead: make(map[int64]chan bool), + }, 0, r.ContentLength), nil) + if err == nil { + glog.V(logger.Debug).Infof("[BZZ] Swarm: Content for %v stored", key.Log()) + } else { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if r.Method == "POST" { + if raw { + w.Header().Set("Content-Type", "text/plain") + http.ServeContent(w, r, "", time.Now(), bytes.NewReader([]byte(common.Bytes2Hex(key)))) + } else { + http.Error(w, "No POST to "+uri+" allowed.", http.StatusBadRequest) + return + } + } else { + // PUT + if raw { + http.Error(w, "No PUT to /raw allowed.", http.StatusBadRequest) + return + } else { + path = regularSlashes(path) + mime := r.Header.Get("Content-Type") + // TODO proper root hash separation + glog.V(logger.Debug).Infof("[BZZ] Modify '%s' to store %v as '%s'.", path, key.Log(), mime) + newKey, err := api.Modify(path[:64], path[65:], common.Bytes2Hex(key), mime) + if err == nil { + glog.V(logger.Debug).Infof("[BZZ] Swarm replaced manifest by '%s'", newKey) + w.Header().Set("Content-Type", "text/plain") + http.ServeContent(w, r, "", time.Now(), bytes.NewReader([]byte(newKey))) + } else { + http.Error(w, "PUT to "+path+"failed.", http.StatusBadRequest) + return + } + } + } + case r.Method == "DELETE": + if raw { + http.Error(w, "No DELETE to /raw allowed.", http.StatusBadRequest) + return + } else { + path = regularSlashes(path) + glog.V(logger.Debug).Infof("[BZZ] Delete '%s'.", path) + newKey, err := api.Modify(path[:64], path[65:], "", "") + if err == nil { + glog.V(logger.Debug).Infof("[BZZ] Swarm replaced manifest by '%s'", newKey) + w.Header().Set("Content-Type", "text/plain") + http.ServeContent(w, r, "", time.Now(), bytes.NewReader([]byte(newKey))) + } else { + http.Error(w, "DELETE to "+path+"failed.", http.StatusBadRequest) + return + } + } + case r.Method == "GET" || r.Method == "HEAD": + path = trailingSlashes.ReplaceAllString(path, "") + if raw { + // resolving host + key, err := api.Resolve(path) + if err != nil { + glog.V(logger.Error).Infof("[BZZ] Swarm: %v", err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // retrieving content + reader := api.dpa.Retrieve(key) + glog.V(logger.Debug).Infof("[BZZ] Swarm: Reading %d bytes.", reader.Size()) + + // setting mime type + qv := requestURL.Query() + mimeType := qv.Get("content_type") + if mimeType == "" { + mimeType = rawType + } + + w.Header().Set("Content-Type", mimeType) + http.ServeContent(w, r, uri, forever(), reader) + glog.V(logger.Debug).Infof("[BZZ] Swarm: Serve raw content '%s' (%d bytes) as '%s'", uri, reader.Size(), mimeType) + + // retrieve path via manifest + } else { + + glog.V(logger.Debug).Infof("[BZZ] Swarm: Structured GET request '%s' received.", uri) + + // call to api.getPath on uri + reader, mimeType, status, err := api.getPath(path) + if err != nil { + if _, ok := err.(errResolve); ok { + glog.V(logger.Debug).Infof("[BZZ] Swarm: %v", err) + status = http.StatusBadRequest + } else { + glog.V(logger.Debug).Infof("[BZZ] Swarm: error retrieving '%s': %v", uri, err) + status = http.StatusNotFound + } + http.Error(w, err.Error(), status) + return + } + + // set mime type and status headers + w.Header().Set("Content-Type", mimeType) + if status > 0 { + w.WriteHeader(status) + } else { + status = 200 + } + glog.V(logger.Debug).Infof("[BZZ] Swarm: Served '%s' (%d bytes) as '%s' (status code: %v)", uri, reader.Size(), mimeType, status) + + http.ServeContent(w, r, path, forever(), reader) + + } + default: + http.Error(w, "Method "+r.Method+" is not supported.", http.StatusMethodNotAllowed) + } +} + +func (self *sequentialReader) ReadAt(target []byte, off int64) (n int, err error) { + self.lock.Lock() + // assert self.pos <= off + if self.pos > off { + glog.V(logger.Error).Infof("[BZZ] Swarm: non-sequential read attempted from sequentialReader; %d > %d", + self.pos, off) + panic("Non-sequential read attempt") + } + if self.pos != off { + glog.V(logger.Debug).Infof("[BZZ] Swarm: deferred read in POST at position %d, offset %d.", + self.pos, off) + wait := make(chan bool) + self.ahead[off] = wait + self.lock.Unlock() + if <-wait { + // failed read behind + n = 0 + err = io.ErrUnexpectedEOF + return + } + self.lock.Lock() + } + localPos := 0 + for localPos < len(target) { + n, err = self.reader.Read(target[localPos:]) + localPos += n + glog.V(logger.Debug).Infof("[BZZ] Swarm: Read %d bytes into buffer size %d from POST, error %v.", + n, len(target), err) + if err != nil { + glog.V(logger.Debug).Infof("[BZZ] Swarm: POST stream's reading terminated with %v.", err) + for i := range self.ahead { + self.ahead[i] <- true + delete(self.ahead, i) + } + self.lock.Unlock() + return localPos, err + } + self.pos += int64(n) + } + wait := self.ahead[self.pos] + if wait != nil { + glog.V(logger.Debug).Infof("[BZZ] Swarm: deferred read in POST at position %d triggered.", + self.pos) + delete(self.ahead, self.pos) + close(wait) + } + self.lock.Unlock() + return localPos, err +} diff --git a/swarm/api/manifest.go b/swarm/api/manifest.go new file mode 100644 index 0000000000..c1781ab7d3 --- /dev/null +++ b/swarm/api/manifest.go @@ -0,0 +1,310 @@ +package api + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/swarm/storage" +) + +const ( + manifestType = "application/bzz-manifest+json" +) + +type manifestTrie struct { + dpa *storage.DPA + entries [257]*manifestTrieEntry // indexed by first character of path, entries[256] is the empty path entry + hash storage.Key // if hash != nil, it is stored +} + +type manifestJSON struct { + Entries []*manifestTrieEntry `json:"entries"` +} + +type manifestTrieEntry struct { + Path string `json:"path"` + Hash string `json:"hash"` // for manifest content type, empty until subtrie is evaluated + ContentType string `json:"contentType"` + Status int `json:"status"` + subtrie *manifestTrie +} + +func loadManifest(dpa *storage.DPA, hash storage.Key) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand + + glog.V(logger.Detail).Infof("[BZZ] manifest lookup key: '%v'.", hash.Log()) + // retrieve manifest via DPA + manifestReader := dpa.Retrieve(hash) + return readManifest(manifestReader, hash, dpa) +} + +func readManifest(manifestReader storage.SectionReader, hash storage.Key, dpa *storage.DPA) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand + + // TODO check size for oversized manifests + manifestData := make([]byte, manifestReader.Size()) + var size int + size, err = manifestReader.Read(manifestData) + if int64(size) < manifestReader.Size() { + glog.V(logger.Detail).Infof("[BZZ] Manifest %v not found.", hash.Log()) + if err == nil { + err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", size, manifestReader.Size()) + } + return + } + + glog.V(logger.Detail).Infof("[BZZ] Manifest %v retrieved", hash.Log()) + man := manifestJSON{} + err = json.Unmarshal(manifestData, &man) + if err != nil { + err = fmt.Errorf("Manifest %v is malformed: %v", hash.Log(), err) + glog.V(logger.Detail).Infof("[BZZ] %v", err) + return + } + + glog.V(logger.Detail).Infof("[BZZ] Manifest %v has %d entries.", hash.Log(), len(man.Entries)) + + trie = &manifestTrie{ + dpa: dpa, + } + for _, entry := range man.Entries { + trie.addEntry(entry) + } + return +} + +func (self *manifestTrie) addEntry(entry *manifestTrieEntry) { + self.hash = nil // trie modified, hash needs to be re-calculated on demand + + if len(entry.Path) == 0 { + self.entries[256] = entry + return + } + + b := byte(entry.Path[0]) + if (self.entries[b] == nil) || (self.entries[b].Path == entry.Path) { + self.entries[b] = entry + return + } + + oldentry := self.entries[b] + cpl := 0 + for (len(entry.Path) > cpl) && (len(oldentry.Path) > cpl) && (entry.Path[cpl] == oldentry.Path[cpl]) { + cpl++ + } + + if (oldentry.ContentType == manifestType) && (cpl == len(oldentry.Path)) { + if self.loadSubTrie(oldentry) != nil { + return + } + entry.Path = entry.Path[cpl:] + oldentry.subtrie.addEntry(entry) + oldentry.Hash = "" + return + } + + commonPrefix := entry.Path[:cpl] + + subtrie := &manifestTrie{ + dpa: self.dpa, + } + entry.Path = entry.Path[cpl:] + oldentry.Path = oldentry.Path[cpl:] + subtrie.addEntry(entry) + subtrie.addEntry(oldentry) + + self.entries[b] = &manifestTrieEntry{ + Path: commonPrefix, + Hash: "", + ContentType: manifestType, + subtrie: subtrie, + } +} + +func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) { + for _, e := range self.entries { + if e != nil { + cnt++ + entry = e + } + } + return +} + +func (self *manifestTrie) deleteEntry(path string) { + self.hash = nil // trie modified, hash needs to be re-calculated on demand + + if len(path) == 0 { + self.entries[256] = nil + return + } + + b := byte(path[0]) + entry := self.entries[b] + if (entry != nil) && (entry.Path == path) { + self.entries[b] = nil + return + } + + epl := len(entry.Path) + if (entry.ContentType == manifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) { + if self.loadSubTrie(entry) != nil { + return + } + entry.subtrie.deleteEntry(path[epl:]) + entry.Hash = "" + // remove subtree if it has less than 2 elements + cnt, lastentry := entry.subtrie.getCountLast() + if cnt < 2 { + if lastentry != nil { + lastentry.Path = entry.Path + lastentry.Path + } + self.entries[b] = lastentry + } + } +} + +func (self *manifestTrie) recalcAndStore() error { + if self.hash != nil { + return nil + } + + var buffer bytes.Buffer + buffer.WriteString(`{"entries":[`) + + list := &manifestJSON{} + for _, entry := range self.entries { + if entry != nil { + if entry.Hash == "" { // TODO: paralellize + err := entry.subtrie.recalcAndStore() + if err != nil { + return err + } + entry.Hash = entry.subtrie.hash.String() + } + list.Entries = append(list.Entries, entry) + } + } + + manifest, err := json.Marshal(list) + if err != nil { + return err + } + + sr := io.NewSectionReader(bytes.NewReader(manifest), 0, int64(len(manifest))) + wg := &sync.WaitGroup{} + key, err2 := self.dpa.Store(sr, wg) + wg.Wait() + self.hash = key + return err2 +} + +func (self *manifestTrie) loadSubTrie(entry *manifestTrieEntry) (err error) { + if entry.subtrie == nil { + hash := common.Hex2Bytes(entry.Hash) + entry.subtrie, err = loadManifest(self.dpa, hash) + entry.Hash = "" // might not match, should be recalculated + } + return +} + +func (self *manifestTrie) listWithPrefixInt(prefix, rp string, cb func(entry *manifestTrieEntry, suffix string)) (err error) { + plen := len(prefix) + var start, stop int + if plen == 0 { + start = 0 + stop = 256 + } else { + start = int(prefix[0]) + stop = start + } + + for i := start; i <= stop; i++ { + entry := self.entries[i] + if entry != nil { + epl := len(entry.Path) + if entry.ContentType == manifestType { + l := plen + if epl < l { + l = epl + } + if prefix[:l] == entry.Path[:l] { + sterr := self.loadSubTrie(entry) + if sterr == nil { + entry.subtrie.listWithPrefixInt(prefix[l:], rp+entry.Path[l:], cb) + } else { + err = sterr + } + } + } else { + if (epl >= plen) && (prefix == entry.Path[:plen]) { + cb(entry, rp+entry.Path[plen:]) + } + } + } + } + return +} + +func (self *manifestTrie) listWithPrefix(prefix string, cb func(entry *manifestTrieEntry, suffix string)) (err error) { + return self.listWithPrefixInt(prefix, "", cb) +} + +func (self *manifestTrie) findPrefixOf(path string) (entry *manifestTrieEntry, pos int) { + + glog.V(logger.Detail).Infof("[BZZ] findPrefixOf(%s)", path) + + if len(path) == 0 { + return self.entries[256], 0 + } + + b := byte(path[0]) + entry = self.entries[b] + if entry == nil { + return self.entries[256], 0 + } + epl := len(entry.Path) + glog.V(logger.Detail).Infof("[BZZ] path = %v entry.Path = %v epl = %v", path, entry.Path, epl) + if (len(path) >= epl) && (path[:epl] == entry.Path) { + glog.V(logger.Detail).Infof("[BZZ] entry.ContentType = %v", entry.ContentType) + if entry.ContentType == manifestType { + if self.loadSubTrie(entry) != nil { + return nil, 0 + } + entry, pos = entry.subtrie.findPrefixOf(path[epl:]) + if entry != nil { + pos += epl + } + } else { + pos = epl + } + } else { + entry = nil + } + return +} + +// file system manifest always contains regularized paths +// no leading or trailing slashes, only single slashes inside +func regularSlashes(path string) (res string) { + for i := 0; i < len(path); i++ { + if (path[i] != '/') || ((i > 0) && (path[i-1] != '/')) { + res = res + path[i:i+1] + } + } + if (len(res) > 0) && (res[len(res)-1] == '/') { + res = res[:len(res)-1] + } + return +} + +func (self *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) { + path := regularSlashes(spath) + var pos int + entry, pos = self.findPrefixOf(path) + return entry, path[:pos] +} diff --git a/swarm/api/manifest_test.go b/swarm/api/manifest_test.go new file mode 100644 index 0000000000..558bdfb51b --- /dev/null +++ b/swarm/api/manifest_test.go @@ -0,0 +1,61 @@ +package api + +import ( + // "encoding/json" + "fmt" + "io" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/swarm/storage" +) + +func manifest(paths ...string) (manifestReader storage.SectionReader) { + var entries []string + for _, path := range paths { + entry := fmt.Sprintf(`{"path":"%s"}`, path) + entries = append(entries, entry) + } + manifest := fmt.Sprintf(`{"entries":[%s]}`, strings.Join(entries, ",")) + return io.NewSectionReader(strings.NewReader(manifest), 0, int64(len(manifest))) +} + +func testGetEntry(t *testing.T, path, match string, paths ...string) *manifestTrie { + trie, err := readManifest(manifest(paths...), nil, nil) + if err != nil { + t.Errorf("unexpected error making manifest: %v", err) + } + checkEntry(t, path, match, trie) + return trie +} + +func checkEntry(t *testing.T, path, match string, trie *manifestTrie) { + entry, fullpath := trie.getEntry(path) + if match == "-" && entry != nil { + t.Errorf("expected no match for '%s', got '%s'", path, fullpath) + } else if entry == nil { + if match != "-" { + t.Errorf("expected entry '%s' to match '%s', got no match", match, path) + } + } else if fullpath != match { + t.Errorf("incorrect entry retrieved for '%s'. expected path '%v', got '%s'", path, match, fullpath) + } +} + +func TestGetEntry(t *testing.T) { + // file system manifest always contains regularized paths + testGetEntry(t, "a", "a", "a") + testGetEntry(t, "b", "-", "a") + testGetEntry(t, "/a//", "a", "a") + // fallback + testGetEntry(t, "/a", "", "") + testGetEntry(t, "/a/b", "a/b", "a/b") + // longest/deepest math + testGetEntry(t, "a/b", "-", "a", "a/ba", "a/b/c") + testGetEntry(t, "a/b", "a/b", "a", "a/b", "a/bb", "a/b/c") + testGetEntry(t, "//a//b//", "a/b", "a", "a/b", "a/bb", "a/b/c") +} + +func TestDeleteEntry(t *testing.T) { + +} diff --git a/swarm/api/roundtripper.go b/swarm/api/roundtripper.go new file mode 100644 index 0000000000..3dad7d04ef --- /dev/null +++ b/swarm/api/roundtripper.go @@ -0,0 +1,22 @@ +package api + +import ( + "fmt" + "net/http" + + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + + // "github.com/ethereum/go-ethereum/common/httpclient" + // "github.com/ethereum/go-ethereum/jsre" +) + +type RoundTripper struct { + Port string +} + +func (self *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) { + url := fmt.Sprintf("http://localhost:%s/%s/%s", self.Port, req.URL.Host, req.URL.Path) + glog.V(logger.Info).Infof("[BZZ] roundtripper: proxying request '%s' to '%s'", req.RequestURI, url) + return http.Get(url) +} diff --git a/swarm/api/roundtripper_test.go b/swarm/api/roundtripper_test.go new file mode 100644 index 0000000000..e0b15658dc --- /dev/null +++ b/swarm/api/roundtripper_test.go @@ -0,0 +1,50 @@ +package api + +import ( + "io/ioutil" + "net/http" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/httpclient" +) + +func TestRoundTripper(t *testing.T) { + serveMux := http.NewServeMux() + serveMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + if r.Method == "GET" { + w.Header().Set("Content-Type", "text/plain") + http.ServeContent(w, r, "", time.Unix(0, 0), strings.NewReader(r.RequestURI)) + } else { + http.Error(w, "Method "+r.Method+" is not supported.", http.StatusMethodNotAllowed) + } + }) + go http.ListenAndServe(":8600", serveMux) + + rt := &RoundTripper{"8600"} + client := httpclient.New("/") + client.RegisterProtocol("bzz", rt) + + resp, err := client.Client().Get("bzz://test.com/path") + if err != nil { + t.Errorf("expected no error, got %v", err) + return + } + + defer func() { + if resp != nil { + resp.Body.Close() + } + }() + + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("expected no error, got %v", err) + return + } + if string(content) != "/test.com/path" { + t.Errorf("incorrect response from http server: expected '%v', got '%v'", "/test.com/path", string(content)) + } + +} diff --git a/swarm/cmd/bzzhash/bzzhash.go b/swarm/cmd/bzzhash/bzzhash.go new file mode 100644 index 0000000000..d4df5fb50b --- /dev/null +++ b/swarm/cmd/bzzhash/bzzhash.go @@ -0,0 +1,38 @@ +// bzzhash +package main + +import ( + "fmt" + "io" + "os" + "runtime" + + "github.com/ethereum/go-ethereum/swarm/storage" +) + +func main() { + runtime.GOMAXPROCS(runtime.NumCPU()) + + if len(os.Args) < 2 { + fmt.Println("Usage: bzzhash ") + os.Exit(0) + } + f, err := os.Open(os.Args[1]) + if err != nil { + fmt.Println("Error opening file " + os.Args[1]) + os.Exit(1) + } + + stat, _ := f.Stat() + sr := io.NewSectionReader(f, 0, stat.Size()) + chunker := storage.NewTreeChunker(storage.NewChunkerParams()) + hash := make([]byte, chunker.KeySize()) + errC := chunker.Split(hash, sr, nil, nil) + err, ok := <-errC + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + } + if !ok { + fmt.Printf("%064x\n", hash) + } +} diff --git a/swarm/cmd/bzzup.sh b/swarm/cmd/bzzup.sh new file mode 100755 index 0000000000..dc6490ad70 --- /dev/null +++ b/swarm/cmd/bzzup.sh @@ -0,0 +1,46 @@ +#! /bin/bash + +INDEX='index.html' +port="8500" +delimiter='{"entries":[{' + +if [[ ! -z "$2" ]]; then + port="$2" +fi + +if [ -f "$1" ]; then +hash=`wget -q -O- --post-file="$1" http://localhost:$port/raw` +mime=`mimetype -b "$1"` +wget -q -O- --post-data="$delimiter\"hash\":\"$hash\",\"contentType\":\"$mime\"}]}" http://localhost:8500/raw +echo + +else + +[ -d "$1" ] || exit -1 + +bzzroot="$1" +[ "_$1" = _ ] && bzzroot=. + +pushd "$bzzroot" > /dev/null + +(for path in `find . -type f` +do +name=`echo "$path" | cut -c3-` +[ _`basename "$name"` = "_$INDEX" ] && name=`dirname "$name"` +echo -n "$delimiter" +hash=`wget -q -O- --post-file="$path" http://localhost:$port/raw` +mime=`mimetype -b "$path"` +if [ "_$name" = '_.' ]; then +echo -n "\"hash\":\"$hash\",\"contentType\":\"$mime\"" +else +echo -n "\"hash\":\"$hash\",\"path\":\"$name\",\"contentType\":\"$mime\"" +fi +delimiter='},{' + +done +echo -n '}]}') | wget -q -O- --post-data=`cat` http://localhost:$port/raw +echo + +popd > /dev/null + +fi diff --git a/swarm/examples/album/add.png b/swarm/examples/album/add.png new file mode 100644 index 0000000000000000000000000000000000000000..6d87680603e65a28a5a4c61eaf741c3ea654b527 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz4^J1zkch)?uQ_r7C0qiR|Gr;& zXG>qpfdlX3Y9)AFee^@6bADR{Xq}C@D-Kl8z;IXX&gY}nhLubV4F66t*0}(MB)As{ XF$(gSIfYuy0V(lx^>bP0l+XkK7q}(Y literal 0 HcmV?d00001 diff --git a/swarm/examples/album/back.png b/swarm/examples/album/back.png new file mode 100644 index 0000000000000000000000000000000000000000..d05b45d9bd130af04157570b915780d20a9073e6 GIT binary patch literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^5V!L}5I};u8FPv(%iY|@b)X~;(f#<_bs-w_RuxcKiiVetbQP4 z*}A1=Mc>LBtsf}rOiyV6Ze! zM5iLy+{rW6RzIR>W!R(#vQh^m4d&-Is4Un0wK>7GQ&{8F1>EMFXD_?Ddd}sL ze+KTRUma?L`af~adR6K+!HwrlQ`N7_k9w+vIoy=~bDiF=dv4YC+Jg~G6lB9b{8W29 grPWHj+Lht`ZkN^&^K?xCV0bZjy85}Sb4q9e0FytQB>(^b literal 0 HcmV?d00001 diff --git a/swarm/examples/album/cut-left.png b/swarm/examples/album/cut-left.png new file mode 100644 index 0000000000000000000000000000000000000000..f24692daa3880047ac14bce2760e68bb1a8fc770 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4u_bxCyDx`7I;J! zGcYi}0Aa?h)j`=nLG}_)Usv|KT*Bg3M)T_Hdx1h(o-U3d5|?|=1#%s7;9)&*b6Zg9 z_nNqK(o^F6HA1e;XYmrueIUqmSedoFr^1zM*9lJMWsLr7D)Jrrr)fM?4v^>Ny}o04 z2cP!=!+^WWfwg^YQoG*-9@^!&Z($4X^mvW>Kix%XcVuQbzhD-;ExKjaxA%vEwla9S L`njxgN@xNA55Y_F literal 0 HcmV?d00001 diff --git a/swarm/examples/album/cut-mov.png b/swarm/examples/album/cut-mov.png new file mode 100644 index 0000000000000000000000000000000000000000..9744870681bfff97b86fcdb6e42d45aabb6b9358 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&kwj^(N7l!{JxM1({$v_d#0*}aI z1_tgOAk1jDNkSYb$X?><>&kwYn@LEaloaenK>gPabEJkIgIWKTYo zIrvoOf4u_bxCyDx`7I;J! zGcYi}0Aa?h)j`=nLG}_)Usv|KT*BfqCR+|g&H)PfdAc};NL=ncW6js#z{7m;r0Vx6 zGW<>lw|9njvz*AgW5ZjKtvBnC1FwP%%bLUmEYp5CP8XQ)vC*&bmwVs~4Fm38*M)l> h`aE10zGW?~U_QT7t=;`^W+KpJ22WQ%mvv4FO#oH3K5hU2 literal 0 HcmV?d00001 diff --git a/swarm/examples/album/cut-top.png b/swarm/examples/album/cut-top.png new file mode 100644 index 0000000000000000000000000000000000000000..61b0fd59788f663c64b1cccacabf558da28979e8 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4u_bxCyDx`7I;J! zGcYi}0Aa?h)j`=nLG}_)Usv|KTp|o?QZenyM}R_6o-U3d5|?|=S#vcw@UR~E82;kb z*PJ~ID?DcNwzys~d3f;2<%bRjgQ`6%kG2%AS=id>Hb*i|q>^Ka-tuc^h&N!X?vqbITNpfD{an^LB{Ts5w9rWI literal 0 HcmV?d00001 diff --git a/swarm/examples/album/data.json b/swarm/examples/album/data.json new file mode 100644 index 0000000000..20efd5d4f0 --- /dev/null +++ b/swarm/examples/album/data.json @@ -0,0 +1 @@ +{"blur":[600,336],"data":[{"blur":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gADKv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAAcACgMBEQACEQEDEQH/xAAVAAEBAAAAAAAAAAAAAAAAAAAEBv/EACEQAAAEBQUAAAAAAAAAAAAAAAABAgMFCBESFSIlMVNh/8QAFwEAAwEAAAAAAAAAAAAAAAAAAAIDBf/EAB8RAAIBAgcAAAAAAAAAAAAAAAADAQIFBhESFBYxUv/aAAwDAQACEQMRAD8AQcxWXhlzcAaStB66uHQy8FF4mfXGekzItq56JpcwDN6thb57AvJneQ2FB//Z","file":["imgs/apron.jpg"],"img":["imgs/apron.jpg",[1600,1059]],"thumb":["data:image/jpeg;base64,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",[169,112]]},{"img":["imgs/bekas1.jpg",[1600,1059]],"thumb":["data:image/jpeg;base64,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",[169,112]],"blur":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gADKv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAAcACgMBEQACEQEDEQH/xAAVAAEBAAAAAAAAAAAAAAAAAAABB//EACAQAAIBBAEFAAAAAAAAAAAAAAECAwAEBREGBxIhMUH/xAAWAQEBAQAAAAAAAAAAAAAAAAAFAwT/xAAeEQABAwQDAAAAAAAAAAAAAAABAAIDBAURIRQyQf/aAAwDAQACEQMRAD8And/zrLQzK9nBFaoGBHnZ19pCW7SmQkHXiPjoGNZhw2h+oefZ2IykignYHb6rIbhUk9lfhxr/2Q=="},{"thumb":["data:image/jpeg;base64,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",[169,112]],"img":["imgs/bekas2.jpg",[1600,1059]],"blur":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gADKv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAAcACgMBEQACEQEDEQH/xAAVAAEBAAAAAAAAAAAAAAAAAAAEB//EACAQAAECBQUAAAAAAAAAAAAAAAMABAECBxESFCNSYXH/xAAXAQADAQAAAAAAAAAAAAAAAAABAgMF/8QAHhEAAgIBBQEAAAAAAAAAAAAAAQMAAhEEBRQWIVH/2gAMAwEAAhEDEQA/AIkCpj5sFuDSDMTLcJPx6Ulb++tcWOTM86NNj4IqapjrKNmwbeI9if8AI3CXP//Z"},{"stamp":4,"blur":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gADKv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAAcACgMBEQACEQEDEQH/xAAVAAEBAAAAAAAAAAAAAAAAAAAFBv/EACAQAAAGAAcAAAAAAAAAAAAAAAABAgMEBQYRFBdDUpH/xAAWAQEBAQAAAAAAAAAAAAAAAAAEAwX/xAAeEQABBAEFAAAAAAAAAAAAAAAAAQIDBAYRFBYiMv/aAAwDAQACEQMRAD8AhqfGtrXtElyRqMu6QCPILcSJ31Mp9au5fIpuZNLha8COT2iOygP/2Q==","thumb":["data:image/jpeg;base64,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",[169,112]],"img":["imgs/bekas_blanik.jpg",[1600,1059]]},{"stamp":5,"blur":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gADKv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAAcACgMBEQACEQEDEQH/xAAVAAEBAAAAAAAAAAAAAAAAAAAEBv/EAB8QAAECBgMAAAAAAAAAAAAAAAECEQADBAUGEiEiM//EABUBAQEAAAAAAAAAAAAAAAAAAAIE/8QAHREAAgIBBQAAAAAAAAAAAAAAAAIBExESITFRYf/aAAwDAQACEQMRAD8ABZMSmVpBYoCB01mM0T6VVt5zALmxwVCcdu6UgCp4Ab0MK6OgW+H/2Q==","img":["imgs/hangar_inside.jpg",[1600,1059]],"thumb":["data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gADKv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAHAAqQMBEQACEQEDEQH/xAAdAAACAgMBAQEAAAAAAAAAAAAEBQMGAgcIAQAJ/8QASRAAAgECBQIEAwQGBQgLAQAAAQIDBBEABQYSITFBBxMiURRhcRUjgZEIMkJSodEWYpOxwRckM0NTgtLhGFRVVmNyc5KV4vDx/8QAHAEAAgMBAQEBAAAAAAAAAAAAAgMAAQQFBgcI/8QAOhEAAQMCAwMJBwQCAgMAAAAAAQACEQMhBBIxE0FRBSJhcYGRocHwBhQyUrHR4SNCkvEWYlPSFTOC/9oADAMBAAIRAxEAPwDXEGbrNUzCqocyZphczVUtLGqC3IIBLADjoCPrjhAAUsojfxldA/HPUpRnNHSUTO9DFE0fEVLJVoy3H+sHH4gWPPYY1DMYYCe5JLRd3mi8tzTZDJWPTiqkI81Wp63dIOOjBbEn64Go4kwNBxCJrB2qb7UrA8jM5AlIM8VZTEoqkcKrEkH8yPpgAA7QItE/yTMkl2ItPSej7p7DayccWIIH4Wxoa2LpbjJhE1ksKxo600y7rgyJt4YdGYLYj8D0wTiYuULRfRB/aLy1HlR15kcReeISm8hr2vcgjntzc2wotIEQmggXlSUdRL5S+dDFmEMcisriQllYixG0FrDsRYDAlwFgYV6jihWzenpPu71mUmNXYMilfM624Fuh7W5HS+C550hVDQi6XNnqKamrhVJmM4W67kCsFJAYqSFIAPUE3464mkgNMoSL3NljBmRV5atoVLKpDyU6EAmxIYH9ph+FxxhREHmXPqydJIhxhqDm1K+UrHWrOK6W6XSIlGVWa25o+456gfji9mahipfo3KZ2tEUxHTvU8lalfVTy5vPHT7E8vyaYGoEsZIKsRtLqPpdbdwellhLRPdp47/qgDg0wO9ZU+sKzTlPSU1LTw0tA9RaOkZfivPPvHtPpb53v7nthlnS0fY9yXF5J+3emGX1ArqB56ONstknkkMUWdzBWj3H/AFIPB9VxtJX2sTibIkhxi2/7hEKkDLcTuCM+1W2CNopM6kPKiZjDGTYgt6vaxBA5BFiOmBZSDyTVJcfAJpqlkbIBv1TxMwGaFfh8yaCkNKWqIKJDI6SX/YlUc8Wvdee4HJxtaYMDXoWQtJElEUFJU5THP5ckOVZYm55WzOqkmkqbrtJKi4QHcL2v2uOBh4d82qWWxYaLCWCo1dNRU1MJKehWKTynMjPWJNxtur+h4S3RksAWUEJzjoMcwDMBJ37gfz6usTmvBgmPE/0qRozxXzrwp1LFqHT2Y1ubVEm6ISLcU0o/aimiJurKeqSEMpHHc41vbnGR8Njdv9HiLFZGnIQ9mZxO/d6HTcL9A/AP9JDIPG/Ko4l8vKdTxRb6vJpJldltwXjYf6RL9+ouNwBxy6tI0zxHFb6dUPEGx3iZW3r4Qnr8GKPLBLWiPzoQ5tZSDcFgCB0t3xma4uY2d3ktjmhr39KdSZVLGF2SROUBZlDKDb355xZcJJ7EABgN7UP9lVVQHlWmLSSNa6KGsPlbEAEBs6K81y6EfGmaZW/3seYUq9LMkqL8z0tgsgNiFRdvVgy/VNS0d5KzzQpVtspV+h4vcYIU2zogkhSVWu6iJ3LwwP6vMGyPYWb5lSCfxxbqQ1UBIsgU8QbwiNo2F0ZTabeVubg3dSbj26YUaAJsfXYmh8I6k11Tbg89O8ERIawjsXbuSyNz9CLYWcOYkH13KZ7xvTjL9VUcspMTyCYIUhV6tgj7uTcMQD178jscKdTc34vopmB0UslFXVaxvUTpLOXDvTqPL+RKm4DG3sb/AFxQ1O4IrCIUwrzlzV0LytHIigtTyLtXgdm5UqRbqPr8izSBHghyzr4qE1FJVzwRTxbQImVkiTeu3sWY3Bt8r2F/a2BaD6+6LS6yp6WSVzXVojrTC3lQSxvaWIXuoEgHPf8AWW/Psb4jWwcrd+715K3G0nVT5dVCgjky7KJUpayd/OkgAUzSB+d21rq1jcH5EEEWIwWa8uED12hLLZ0ujF25hUZjujWpNkbfXtekjkVeTYkgN3uvfqcDmNg0T06eu5EGiJcY8fXemsLCpanLTSZsfh1lhip4l8tWB5KSkbRzyL/hfB3fOY93mqkM0HenNEYIYI4KSt+HllJaWCmqd1TKtr3Yk7ePUD26EEcjDwwNtMBAXudciSim1dBQ1MSfZqJAj7ftCWTe7WW24Ei7cWB57WvwMHmA3R1qg0m8z1Inzq3Noo8xzOapq1ikWeh8mpakp4jb0vvsJA3UHp7Wsb4aHlohomUstBN7Ql81PTVGZZbR5zW0kkRaSOqpKKBWo3D3IkqQqbkkS+4TAhCb7lW4YMbVEW13ak9XV49aU6naDcHsHr1ZUak01n+j80psz09Spp/MaWSRkl3moqlVCVFRBICzSQuLkMdpsbMGucdAPz2eS7wb5Qe/oWB1PZn9OG263ecq7/8ATd8Uf+/+W/8AwsX/AB4P3Uf8Z7/wke9H/kH8fytYS+FdNW5j9qQ6yyuW8iu5aHy7ldoJ4awvb2748qyrUYyHUzv3/hepeym51n+H5XlT4QV3k1ElPm+VVpeJkUQzm/PTj/ng/eRPwkIBRPzBKqDwy1Hlz0qvQxyotfFIzRyqfuwRc9etr8Yc2uxzt6A0nALsZ80y16p4qOVmy9DtvwVH09vxx2c+Hdo8Lk5awElpUr6L0rnMaNOKGRutpo0/j88EKVN0QR3oTVe3UEKr51+j/pHUDNHFldDDMHZQ6RWY2F/2SOOfrizhrwFBiCBK1xqH9HHT1CJnko6umEfeOocW+diTxjO6g5oT24iSqHm/hBTUUU8+X11a0aAD74JIQDbvYYzEuFwnBwIhVKr8MqqFy8GZRSbTYCSJlJ+VwSP4YVn4hNmVXv6RZjkFVLTNKJo4JWXbL60FjY2B/wCWIWBwlMCsFD4gU+YWo6iGBI2cvIlR94g+kfHP+9fr1wh1LeimLJ4lfEweWmf4Wnc7FQHzYmf96wBZDbrcduTgLix+yrW4WULJHDTIrMtPDd2np23RgjgkkG6kHoL+3GLzzIUg6qN6xRAkgpxskkBD04As377XHXrwbHnvi5O/d661IA0KkfOXeGqZpI6mk2Amd2JnjINwdzHctu3pYAE24OLy6evqqRtNNNXmoqaWrqasxJGvwgUteI8MPUQrE9bgjoeAcVlJMqw4AQrTkdFLmkYpMrjaKWCX4dYVlaSU35UKsQ3C1zxcnpe+Him4SNPBJ2gN9Va6XR+opFiXNKVaXdPtapdUo2VlW7bnqXHVR1234tybYYKYkn8oDUS2ppssyPNA9Xn9FMZZXAKTS10aJ6uLDYnYEXa3IscQlk3Mq254sF9L4n5HSyD4GozGWOWQGUxGOnLABdxsgdhe1lu1+TfoML2lPUHwhO2NU2IXreKuUZfUxrlOhsvkpoXm21NbLNPUxpItpDHJM33e7i4Cgd7XscaDij8LR3nXsQtwejnEA9Xmq/8A5RH9qX+xo/8AgwXvP+vruRe5u+ZVuuyWni0zmj09LtYB1JaAWtfjkdfrjjbRxICMNCqVOONpiTjpdRYYa290BsEDAJ5anylZ4ZnltF5TkC9+OQwOHGGjNuRAzZMct1BqGPYtJm1ZSxFjvaSscC3FuCTfvg3NYNQgDjuKb5jrvUGnNG1+eS6grqhKPcTE0sYVwLW5ZGI/LC2sa94ZGqI1HATKcZd4haykmkSLNUMSkMDUUqNwyg8lQvPNuLYYKYBkWQ5y6ykr/GPX+WStDUUuVZjGVIDBZEDA9b+o2xMxBgPPepDTq0IB/wBJZFhEOY6Dy0CRARLQVrMrrfjrGLi4PfjFlr9GvPcqGTUtWNH49aWqK1zU6YrKWCTabU1QhKkewLAfngBTq/MO5EcnBa9z1NM5xnFdU0OZV2XU08skiRVlJ5zJc3sWjbm5v9MObnDQH3KhLZ5uiTnIYpGZaevpJhew3Fo78fukdfri83QqUtLT5vl1XTRU9QJaiQF6enhlEkjgEA7EB3dSOnuPfEIB3Ku1X/TOn9XZlO6y0BoZorPK9RKKQxqTtLSeZsWwsSb36HuMUaNrFDtL3Tysy/SOnykmZ67yxK2FPLmXJZmzCSIggFZI6YbA1je2/kDjEyNaYcfX1Ul7hIChOuPDzJqnfQ5PnuezQ3fzSKahic3O5rDzZRwRz6eSb8YoPYLAIjSebkwsq3xqjkoZGy7R2RZeAlmapjmzKdD15eYhbjsdg6dMG5/ypbafzG6Lq/F7X2c0t31BXxxSMA4y9o6MAkdLQhbWHYW9/c4QXyRFloyNaSHJO0T1z/F1dTNVzW8vz5JWZyLD0sbk3PsevXnAgDQn12lXngy0R66AnuTZRlmYwXAXcq2Z5QxN+w2ix/n29gAyix9dyIvebj13ppHklEg2XKWuQ+3y93y9V7D53Fu/vi22Nh4fdC55dqfH7I6kzGioKepoJ1imDqFEcsm8q4vtNhfaw3cH8GuLWeZAJG/iR9AhZBe2ePA+ag+Ck9/4DGaV2sq15DDWCjeMVUqxSAqUDk3/AI++FZL6LkEgCVnHSiniVXs7se/bD2tISSUYrCIRmOGFHWRbSlbWF8W9kgyra6CEoEVoNpsF3A3Xr3BwwgpcwiKmiq/s+SlUqaOQ7xFIA6uO9wQQe1x7+2MxnNO9PBblhNcnrosuWSHMWValzcbiLEAWHy7YaHEhAYmyXZ9nC1QVYvvVBBIVrAj2vgiJMoZVVioIKWhpaGnhKU1PEIkWRt5sL9TYX6+2IS5zi470UgNyhA1mS0ssZugQ/wBUWwwEhAU10tkOVVVDmGWvk7ZlnUwSamzH7QeJaaPgNGYbFJOV3Bj6hyAQDgX1Qy7tFYaTotl0tLp/SeVTSDQ+U1GYRQsJKvN6+qq43vzcU6+VGCACPx74AYlsgNCIU5EyiW8UtTQDyMuz6m0xTblPwWm6CloEUgWB3IhkBt7Pits4otneAJVFzfLKPMpTV5jNUZ1WCN9lTmlRJWSqdoJ9crMRzyeeT88CXkkklHkedBHcFTmhppYo3WCNImACC143AHHqtdTa17ixvjRBSi6LSjaKnCOQisJU5v5n3gt7G/qHzxR4IJRlfDC1BVTXiWoaFh50YHIK/qn+Vvw74kdHrvVtN9UwomqKGqV4TsLot4StxIOO5Xjv1/A4BrebomVnc83TyGrSpG9JJ1qNuzyX45vyLbfV7269/mCgsFvXglyHWPrxUcExWcVFLMaaqKkMCNwcdxz1B+Y+vTdg5Lxfz/CUQG6eX5VgyzMYa9RuMdPWqbhlQFm+YZv7/wA/fAuYR/X3KIGT+fsEZPKI12+aFa9hCkoBYk8mwb63H5e2BLy0Fpd4jyT6bZeDG/pTX4tP3kxmyFdrO3gVW8nyerzmtjoqGiFVU3LiNdoJUdSL2v1GPS1OSq1Jud7hHWfsvHe+0zYSn+U6NymKpEmf5jNBZvVQ5UqPJH/VaVvQCOhCq1j3x8+5Q5ep4V5pYZm0cLE/t8p7F3KOGdUAc8wFsBarwciovg6jQ1VWKb75Z84maR/rbaB9ALY8q/l/lUulrQO3yy+a2DCUo19d6jMfgjLD5Y0fm1MtgLU+dSi1unU4r/IuVG3LR4f9UXulOCAdVj9jeCFREkf2ZqiCMG+1MzD35vb1C+IPaflEGTRn+P4Q+5M+b6oWbw+8F619xzXWFNf3amk/vTD2+1ONA52G+n/ZAcE35lGPCDwhmFota6lp/wD1aCnf+4DGge1df92G9fyQ+4/7eu5RnwA8PauJpabxHr4477d9Rkl1B7AlXHPyw8e1RAzOw7o6j+UPuTpjMEum/Ro0xVEim8VsuHPSoyWYH+EmHU/ayg7Wi7uP/VUcFU4hDD9FTyKgzZb4r6eDFNhvBUwEjnqRf3w1/tJg3603euxHTw1Rmqjm/RYzqoSQDWukK4ldoZ8zlU9P60RxGe0eAnnSOz+k00asWCEzvwE1BkBiEa5Rm25CxXK8xSbZbqWBCkC3fvz0x6LkvE0OWajqWBMuESDA103xuWHEVBhGB2IkDqJ+iFk8HdVV+VTbcojAkR0ExqYlSIkcFzuuvJ5Nu98ejfyPj2OymkSeggz1XusTeVMEWFwqW6iPJIo/0WfECLKICIcg+LSML5b51EiW4/Vksb3+YH0x5jFctYLBVTh8USx41BaZHX/aeyk+uNpTuDvBsm0H6MObz5PSPLmlDl+YGO1VRy18MkSSe8MsbAhfmRfHQ96whYHCuy/+wSYqZjzHdxQaeAmsBHW001XkDoYmSKb7bh3sSLAMCBcfPr9cJGKwpMDEUz/9hGM4g7N38Uzk8C9Syu3+dafaDd/ozncX5iykj6YPa0AP/dT/AJj7Inlz3ktY7+Kree6ZrskzGXLnpzXzwqm6Sgk+IjAN+N68duh5GCNRo0cD0ggj6IIO8R1/2vqHTWZ5xLGpy+u9QFpkhf5gX7/j1xYc06H6Iucpc18Pc9Vvu6evhqE+8RnjKMR6ef1t1+RY97/iTFUDXyULDqPNQ0OU5vBIlTXwvFHA4aWU8cX/AGh25/D6dMC6owgtBuUyk052kpt9rU378P8A71wrMF08ruKu/hR4u5LqfP0y7KtMxZS9fSmR3aVn3LGwPpJTpc9QVPA649pXxoxNPKWwddfwvCOwzqILi+ez8qn6g/zOqnmiDx+ZUPHHBMbm+5rDdxe9uw/njweI9mGvqVDRfYc6443iRa39rq4flnnNpVGQdJH2SzLauXN9yinkgqFAZ4ZXAcA37W+R/LHHb7OVqglrx3Fdl+ObTMOCr+YeI1Bl9fX0TUVe9TRlA8ce0lyxt6B3tYk4T/jWJccrXAnqKP35kZjonVNnTtUw08uWV9HUSR+Z5VTsRluAyqw7Fgbge3W1xiD2XxjbktHeh/8AIUiYEqKs1bFS10lEIpGqUVn2tLGoNl3EAsVBNh0vyeOuH/4vj3NzDKR0FCeUKLTBlBUXinlUbxSVVDmhhkB9SQghCCL35t0INiRcd+DgG+zeLpO/WbZF79TcOaVtLKKbM6jJKTMshrYKg5htZkqIwjeTbiKSmkUm53epbEgWHzwnEcl16VJ9GQ4m5AkWFxDbmZ38LSs/v9E1A2DPfr08ETqDQn2BGaqqkp9PVXnrTPSPUB6SSVuEEUrH7osbBUlO0llUOCQMefwlN9Zgexsgid8gdIibb40XTe4MdBKq9BWy5tmeY5TSU+YjMqBGeqgqKGSHyLX4ZmAAJtdefUORcc46NTk+qwNccsO0hwM93jw0N1GVWkwCe5UuPUGocylSLLaP4aVnKs9TIQVHY8X/ACGOnR9nQ936zuwLQ51YWaI610j+j74cwadqUzvOZBWV5BJqJ77Uv1sCTbHvuT8BSwbYphc6sZEanjvXSlVq7KqHLzVPRTTwqOJI4BZja9hcgk2+WO7h2jE4gYVjhnImOA0k8BOnFeXx1RuBpGvWMCY6SeAXOniT4OV2vNc5nnmSZmuU0lbslFHU07Mwk2gNba3QkX6cXOOPyh7Ge9VnV9sASbiCdBBvmEbty5lL2vo0AKeycQN8geH5VD1P4P5porKqnPs9+NbKstjElUKJE3zC9jt3MAg5F2PQDgFiBjy9T2ZfhQ2BzidRBA6TxPnrZelo8vYTFSKNSTGlwe77JTkunc+11QZpqnLsvmk0flEINRWhoo46dVDGQbmYFlUAHcATySSTxjceTcCx/wCqSe7xgeC1sxNWo4gWHrRWzTdD8bGPhMup2jlQKJJXEl1I6qbdxzcY3tweE0bT8U1zy74itpac0R5ZWV6OljcptZIo9oYc/re/U9cahgsMbuZ9UB2cXCttJoundfVQRA7t24Ehgfe45GNDcNh26MUDqY3KfKMk0vVrK4bLJ0prI7tWq4jAIsCd3pAbixtziOpYbQtCsPYNAndFprQNUsqvS6bqRId0ivPC4b5sLm/44SaWHbcMA7Ar2g3Sjv6GeHf/AGLpP8qbEinwCvaHpXKmU6LyHw211kOX6alWKlNJMUpZ65pqt3NywjUgnYE3MzFgAdoAJbjS15uzVeVLtrTdUdrK5gzjOtXwa1rJ1kgjy4Zk4aEShh5PxFntcA7igYj2Jt0GEUjGYOMAreylTaWOjgUXk+eZ9TZrmVWlJFA1ROzCpR/NLqCQhaM2A9IUkKRzfDQ9rCcggFR9PNqdFDS6Wz/UmqoJYaekqK2oqVZJd4S5F2ClXta59NrkerrjpYXEU6VJ7SOc7QrLWpOc5pmwXU2T/oQ63qaqHUr1FHRJOnnNlryNJU07Nyw4up6kAXNuOcYGkOdle6IWh1RoEtbquafEjwd1DpPXMz53VGaukp0eahpgrSX3uo3bjsW4UG4v9MPO1wzswdrePVkIqMrtAA0t5+aFybIdRTRNVOlDk+XxMUSmHmTTzy29O5lSwUD1HbY8AX5xirYrEPOXKSOz14JzKVIXm6tHhyk2k8y210a51TT1MUxSaCUGKXeLyq7dCe/A6A481ylg62MYXsplrgDfML29QoaTDUY8VIgjdrfRbw1t4oZdqXVWb6SrshWfKahDT1nx9nR42WzKuwg89QTe3Btjx3JFWpQwdGtWfncNJ+K3+2vfK9TUwdWvUdsGGOjT7Kzad+yMt09SZNQwzrltLEIoYazeGjUCwCTkfwcbfph1aiMS816b8rjeCLd4t9CocNUoNDapbHQ4E9wJP1Vak8PvsfMlzGGlaWkc7yrKA8V/3wCR/vKWX59se6wmJDwxtZuR5GhiCegix6tUw1WmWtcHAbx+YPeFtzJcuizDLoC/ESi+wcDHoWiQuY5xabIDVuoZcro6ChilCFquZgr8kqqKSB7kDm3sDjo+yuEov5Sx9c/HFMdkGOmJMda8H7VOcRh2H4ece3+k1TUFXlWW5Vm0QSSnmcJK7kbQrX9Q73A7fzx7F2HZVqPoHUadn3Xz6LEJtp/UMWolzCJ2hqKZZ2V/2ldGjDG/Yjk/hjHicMKIEjUecJEOBad65DovGLUGmvDSl0vQT0lPpdKeXLoKRFjljmpCXVQWUbgdhI68EA2JW+Ph+Kxbqdao4AfEe6ejRfsjkv2XwmMwtEkuk02k9DiBOsyJPalq6rXO/DWXS1Fm9dFkWXqagUCy+XUwou0lVkv64xa6hbAEWNumNNLFE03VGNJIv0269fUwVkq+zuFoV2UcTUyyYnNYzpcXaeM33iQqhq3xKky/LYaHL8+npFilfMo/s9SJ5Kl/LRZH3XvYRkBR6PWxsSbjoYY1XzUqDUW1B6oXC5Uo8mYdzaOEqc6edfM2ANxA1OkRM7lW6LWL51X5qJ8wrMrlqKAs0VXVTRyCQSKDIoL223PqA6fQjG5jXE3XnK1SmAAw8N2vX6ujdAT6jy/Ruq6DLs3Wj0vm2+CthYKYpNrvKwVypIJazkixNrdrY00KBcA58DLoTxPBYsRVYajtkLGbdCqtBpqn0xPm9KMopDNUQR089RBAGjKkpN+sV5DeWlgSOnTiwy46hs5zGTvT8FULnNyiAr3/AEEpv+rQf2C/yx52F6TN0q/eEeaxad1HlgqqGn+NkeRYqplFlIQh47ke1z9Ppj1jXZHaLxFSHUzGlk9rJqb4mdosppiHlc7yepuTis7dwTmtsLoOWaN14y2Jb9LbuBgNoTo1N2Y+ZJauGiqY4J6+GSmMd2SOIHm/fkE/TDTdKAT2m19qWnpooaDVufU1DHaMQGrl2L323J6dOB2wrMdQqDWncqxS5HWVmdNIa6SauqwFaoqDcsBua7Ek8KCxPsL4ScQ4OAG/tRFs2O5E5q1TIyLQ5nULSQgRRL5SncOpkbvuc3PsOB2ww1ntU2bY6UJNT16lVfMHYsDdHst/mLdMJdXc113KiwApYNQakilknNe1TUXKrJI6udoNlB47C3UnpjhnBYOTs2COiRdaBinuHxT1rOLxy1RlrCKpelA5AE0Q9RHWxBBP5YocnUXWYfFNFcnQhWLTf6RlSM0po5HhgdwbtSlgl/6ym4tjbhaIwzTTfdp3ECJTWVGuMVBHSrHR/pT5zp7NMxpajJKPOoVlVIGo5DD5bHgqeCGF/wBrjnt3x06OJFEGnMwYuZN9BPhe6GpXotqFpOi1/wCJ/wCk1r7UGdTUWlaeLLMoJAnjmpElmWQEqziUkjaVtb0gjuD2AAUsU/F0Za82kawPLes1QsxDA1+nA+tVa/DnxrzjWOTnSmf0lRLPU0kkMgljSE0NSQLstj94OLhvT3sOtvofI2LfiamSq6X2gxcxuMd68LytyfSpEYig3KBqJ9dSgzPWGvNA1FTp/Kc1GUwSRxyFjEamaQmMKSrPdQb7haxFh0GOZy1yhiqGKdQLgQ3Qxcg+EzO5acBgcDiaIrvZfeJMA9C1/m2i84zWjqo83zGpzCplSJS11gkKqrD0hAoXhv2QPljxtVrXHaPEnsXuKeNrUaWSlUcBwk/dTZfpXM6WnmgeGpekmVQfKqLAW6gg9iO2BFUMYeab6LE6s5zg4ieKnbTeVx1MS1uTysyjgqhBS3Isymwt1698ZnYkAyQVTsS1mrSsMxyHTeZV8NXV0GcOiIYmiNbuWQHqpLXYDnsR0GFjlBotdJONYZBGqBrMkyWjjlgpsrkny0srJQ1UzOEZTuVwb/rBibe2NrOVGtaKeo17ZlK29MulouftCs2a00MmjXo6JhTrEsQ+GjPMgseD1uF6/U4rE16daiNk6Tv4rpYGrTNaXO6la/LpPf8Auxh2K7PvISbQlTHmGo0pYHLTLPNMF2lrLz6uOR35+du+O/GbReTcclO/QiswrGoJcypa6SKKsoZXaZjEU82F3bY6hupHCn34YdSArTXVa2EPaC1Vyp1FAkd1qm2dWW/X8RfCyXxAF02d4UI1bDPOuypikv0UXN/ztbCTTqHUqjG9LpdVmOZzFFGYxbletu3GEPpYkmJSHF82VqOrnynI6eKOhQ1tbGDLJL6RDAbFFN72L2DEdl2g/rHGh4exstF0xznHRJW1lCagF4lfY5s0bWAPt0xhDnt5z23ShVePiai31RTtGVmp7uw3KoYnuPz7YA1hMFslJdictokrFKqCtMgSjdLpdg3p3D2wt9RpM5UZxTTulY0uRpVyIi5dZ1J4CKTcj5nk/wAcaaTohzU8VA4AgKbM9LVBDNHR/CgAXLqpYDtcgH54rEVXOhoBCRVqOsBMpKtPU5LXRy1axLTvGDu8sXuCbOW+Vlt72Pe2OvhKbMge4An1Hco9uYQ7VG6a0zUwpMzyMZTzGYkuCe++9+o73wunRFMHM4omtcwTqic90dJWzr5MAp5gfMilklZOO49Iv0vyDhfvTKZjMVb6jI530Vo8O9KJkeQxwZlK7VPmO5R9xQL2s/7X4274e+q15BeT2/dG0tbornLTUJiHlVDp5a7QRyDz2H/7phDnNMwU0wUqk0w0tS0prwm4EABX6f4dTjk1G5jmLoWCpRLnZiYX1Zpythplk+OWoinLL5Zup4tz7j8RjLUNSmAc0gpbqdVgs6UGMiDkiaORSbgDaSV9jx8+e/0xlLzvCSWuaJcFPWZBlsVOjVUuyRiQ4IUX7Aj3uevQDFh8iAyepEzK6waPFFto/L7+Wm/zWJIBAIF/3bHn8cIziJcEwUabwC0LH/J/S/7Kf+x/+2A94o8VPdz8pWpfDxKzSuoosxFYlRFNTtDNCI2srF2br0JsSL3x76m7KSttemKrI4Jnmzx6m1BPmtZmtPSybhGKZNtygJ2hhckkdCRgX35xV0W7NoY0FFZh4dU2ZNFTrM4iqHPk+u6AcnZu23A9vf3xnDgJhay0wksWhYaCvmpIqZhURt5TxoHla5tbvze/FvfCKldw/bKxVKjmnIGyUbJomooaktW0cUcgt900FpEPbctuPx54wmtiKws0a9qz1n1ZgD7rHMaOeKfzJKVqsyHczKB6uO9ufbr74z5q7BMyUjZ4huhTGh03FV06OlI1NtO0ogADdLXHPGLzVMpLnea0MZUF3lNaLT8UNRuLxTAkkF1I8vnm47k/LGdzxSFhPZdMDRTaSRm7Ez+zomm2rVwJJe48tQNw/wAL++I6uAyXCJSH16Y5pEIr7JSlgXfOCSVO4sQD7jbz9MZqddxcWjTtWeniHNdl0CJqsklzGE1NoSARx5xufcccj6jGh2Y88hazSe4h1lLTxVuXshiphHJCDtlSMbuR3Nub4puKqU3fFHrpRRWmCQApqn7WzBi5mUy2H3kii9h2+XU9sazjcxBe6VpykaIpsrapfllXd1QMWUfIXN7YU/FNfqZlWAT8S9j0pEyFzVS7TdtjMAPytzjOHBxtKHYjNKOpctpoI18m6LawLkMCf4WxDUJjKE0NGiNaBFsG2vc3tuW/4dcQ1CLkKc0GDqpC4V9q/d7v1X4t+R5wplVxEhLzzfcgWo5sxg5eKcRm5Ze34XwRG2bx8EtwFVkCHeCmi0bNU0gqSlK77rReYtnIHW1sMZhXhktMT2yltoua2W2S6vOZUSCKSI00gsUMLB+O1yb2xnOF50FMaHfCZCh+0sy93/s1/litg3j9E7KfmPh9lpqnyakpK5VijV6hwGO9L7rc/rEcW/xx6JlYPMNBhA2sHmACm60299v3JldDGWiIkMdzw3A4NxY/jgy7KbwnSnOl2rci8uGrjMWXNIPImdhdGFrdfc8gf4Yx7octNFzjrqFjm9Y76hjSXN6evra7dNBtlRZiEYAsu23CsQu4Di9sKcBSOcOMaRuWOrT2VU1nOPkiVonilaapn2ySHl2dn3H3JF/zOLNVsCNFTqoIDhJngpGo4oghjV5iWsTGoYj62wxrWHRPDRCMq8tWgC7ZS1xc7VI2/wA8ZnPDZypZj9t1HDC0ot5ckg/8mMpe52jJQ5nbgmsWnIqnYzoQQOQ/pP05vg20XmCBARBubVEU+nqWNi81OZKdOC7SEBPne3bjAVG1GfuCx12hkFhAPSi6Y/Z7mGSDsGHm8XBFwQLC4t0OEZXZuffv+iVtXtgbl7G6AiRYgHvdSyt/PF5HNOUzC2l7Jgt7YUpjnqCCkwF+6HviNZkM/VPBBEjREwUkrybnAQ7du6OMC/1/nhzXNJFgrtKcx0hqqfaPho/KO/c7KvA+pH8MaXOcWgNAEIXCbyvp440jDRrHcH9lRZhf3GKJP7ihOsqGooo5WJ88CQC6GKm3/wB+FOYzKXSqcM7ZSsvRzupSrlSRWttBCfwI/wAMZqVejdgdfgRBKUyo1vMJv3JpNTLEpAkYqRZzvANvyxoNTIYBTXuyxcLFIaZmZI2aIKByGI3XA7fXFhz/ANxntU110U65fSVJO1C7joxF+e564DLJIBJRw1y9+w6X/wAT+P8APBx0+CmVabnzCWtgRl+CpZnsR5FOJXb5DcW5OOy6sFeUCxcsk0xmc0Uks9XXgN0V5fKDDr0Xbb5d+MZ31LTKI6WKbZDl9HSwutVQ0800bGQvVQhgGI9J9V7sOoJwplTMee1JaS4QWwps2ySDOniVKOYMeIzGwiVTz2At3PHz6jCarqtWQAAELmVKvNdoiafTNTBG0MiyjyjtZJOSvyv7YsUC5oa+IWhtNrRlARJYRQAGTZbj25xDDRc2RmALqOCoib0i5Avwgxn2tKA10lJ2jdAjp2dAhpYGjFufN5b+FsbBUkfphWXEjmhER+YkCvUOl26KpBP/ACw0ZzqiAd+5Q1DfE2INmH7vF8ZqlBpMwlupMccxF1FVyzZdIEqI96hQdrct+fOML6b6TswvKS5ppmW3TnKX+PiBETRqR1cWB/HHTpND2zFlqac10/n09JQxJOQjxDlo4iQxH198EaDSUWVCJRzyozqoliIuFB6H5i+DbSA1VQUkqX2pI7wECO25uCvt0+uMddzmyXNsO3wSXOc2ZFlhFmwnXbsaSMC5YXUD6/8A9xhbWNWxZI3zZKbUzthwt0pnRVdKFusTRnsdxP8AjiHLllrUxgblloTH4GnqiJSirIV3CSwv7W98W2kPiFkWVszChqaCOslS8Y3R9CGFwPf64a+iXgAoKtAVRBU1PlsUFOolYzMvWRgNxHbjDGtFNuWVGsDG5RuQklCrZlHLBLJEYxYIzlUI9iMA6k17g8fEOmPwqLQSHb0w+En/ANjS/wBsv88P2T/RH3RrTNA8gqJTAPIeLaUllANj+7a179+cES9wKRSFRx5w7U5mlqhTRs85chiVCt5jAXvtJ79iPncYgEAAla8pjVYxGOaV5Zw7G6kAnlWtyR2wbcs5ioJ4o+Et5lxNZB/rJL3Iw0OEEqyQBKaCnytYrx1ckshvuABsVtyR3OKzDipLRqYS6WWhqOEURbP1jK9/xPYYyNqNqbu9A14eFD8ZTBSioGNxYqCLD5AYqGVNAlCpTqiApGqHEa+s7uRySTb64e2jABBhPDA3RexUk9XILAszfmcPYCLIwE3GSeRsCybyVvu6L78YblRaKWaCMSIrKQyfrb+Pni8qoo6trW2K0dOQtgq7TbjF6K04yXOfjw0NQGiZBdY3O/cfpioVzKxrI6XMakQRgUs6/wCkVVILe/I6YIqoS77KkdTHCkpeIkOy2YDnpc4y1GZjLTdLc2dEtqzClQUU+UrC7h0JDG3S9+McytUyO4T4rJVeGOvZRfYMrMPKluWv6SxsMZThXVJNN1kRoteLJlSUFbTn0zxsAALL157m/UYNjauHEEymta4C5TdKdvIjaa4kt1v/ABONhNUAF7bIpKBrq+oYsEYSX/aYc/x6Yfsy4c66GJ1UUeYpHKscgtIeQQ3+BxAwMNghJAsivOTGvsVL/9k=",[169,112]]},{"blur":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gADKv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAAcACgMBEQACEQEDEQH/xAAUAAEAAAAAAAAAAAAAAAAAAAAF/8QAIBAAAQIFBQAAAAAAAAAAAAAAAgEEAAMFBhIRFSFhcv/EABUBAQEAAAAAAAAAAAAAAAAAAAQF/8QAHhEAAQMEAwAAAAAAAAAAAAAAAAECAwYREhUWUmL/2gAMAwEAAhEDEQA/AE31/XI4MRZs2R08jyKXOVchTqLzaimvkrSNqY8bIojv6LytNl6+4VyWXoG03o//2Q==","thumb":["data:image/jpeg;base64,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",[169,112]],"img":["imgs/hangar.jpg",[1600,1059]]},{"img":["imgs/ruin.jpg",[1600,1059]],"thumb":["data:image/jpeg;base64,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",[169,112]],"blur":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD//gADKv/bAEMAAwICAwICAwMDAwQDAwQFCAUFBAQFCgcHBggMCgwMCwoLCw0OEhANDhEOCwsQFhARExQVFRUMDxcYFhQYEhQVFP/bAEMBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIAAcACgMBEQACEQEDEQH/xAAVAAEBAAAAAAAAAAAAAAAAAAAEB//EAB8QAAICAQQDAAAAAAAAAAAAAAECAwQRAAUIFCJRYf/EABYBAQEBAAAAAAAAAAAAAAAAAAQAAv/EAB8RAAEDAwUAAAAAAAAAAAAAAAABAgQFFSERFDJRUv/aAAwDAQACEQMRAD8AFPyPsWtum72xxTRIPKWBwjD6AdMSuSl4uA26NrhuCZy8hqjSuUvWkUscKYc4HrW7xM7LYRvJ/9k="}],"thumb":{"min":[150,112],"max":[267,200]}} diff --git a/swarm/examples/album/delete.png b/swarm/examples/album/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..dfa04c717b3d5bdd01dd357c5fb6b586793d786f GIT binary patch literal 552 zcmV+@0@wYCP)1-C zVx^7I#v&vT5JeFz3~3V4ynvcc?G%D(EF^wuc43%1J2Th2TbLZU)t>YF&dlsCccuSb zrWrHPFKJfNgrvUghomz}r;@%(+A_wRmf8}S2ELQ7Z@^?3;9g+239zdjpy#geDd4gN zc&>}4cLNv)u1kRDx(1%7!iOkl<*qJ)!IT1f6~J@t#^A3igy(u0DsWhovON93mdEl1 z7`1#w+Ao4X3DtJIZNQp!`7`jq@q{#z``WF{Y~*-4jWNF@$r$qocrEFnq?)8TW6X`^ z?Fh}1G$ZN61#CuIF9XKOv;%FPvhO0Z)_p7d5eWgT0=39aEhNl2@CDBkf&fc6J7LXu zn>gbv&)BQE4Xw;lhm*_UMp9Sej7Ao4(8}ub62M}@oW@5H*ocHa;+%g5bZ^XB<_*bv z6V69Mbr0x0{->iJnf1n3U^tZUz*nuyD>Uv-NCQP@nDQ#F1D`yW4?t%^0spHw3%!Um zZ&kOzSYd&z#CC-RHiPi2z$4&i1@IHBBZ`%H2K+7&eg!;Df?FjX1IH!6kAUH(;8uwq qTK`+#eJ8k6q_Pi_`|)Y^PwOweFYLKGQkMJx0000P)LQib`tZe2rU=L zrR~^CNLLcGtBJWyv{wp`#GTkn$d{s-<;4A6bbcs23h2gBA)tYIEF{7Yz4yIWC^6vq zbBwvmub5N(_|)*I#7|r#PTb@ILthdel^DZKBK#VoUm6~jn81A$ev9#M36Dz5<}czS xepU6n`k|C1gs_gjEX)3d5H_lMYHDg~o&acrlchZ9WZwV)002ovPDHLkV1o27v$g;L literal 0 HcmV?d00001 diff --git a/swarm/examples/album/download.png b/swarm/examples/album/download.png new file mode 100644 index 0000000000000000000000000000000000000000..6a160c8d524f29c4de63da98eac050f41fdbc170 GIT binary patch literal 422 zcmV;X0a^ZuP)L{SihzZHaHttce6Qiw*QlXZ>$=ar-RwzD-n=>Y%{w!9DynpkXJ8SyOND{( zyax6HQ?#|$5bpyu;1rnsbJ`Y~DuF55+GP|s)Hn4-os7Qyao8;`fNfw3sOMVl1s}O& znSxbd8W>LU@4y4_`72vuhPinbaxmj);~%$IKm%BgayzuvsL)|2t|hML`*F*K=zGE3 z40Asni{3{Qy$Xzn*fIqHn!rkdb{@r>WiMq&J?^klyDAk`;0d@XaPSDM(^~8kU?Fqn z09XaAsJA6rJ_NRaiO}L)q#XfEz!yN--HTaQ??ans>PW2jQV?|}%(Rwj-^4+;1paU= Q5C8xG07*qoM6N<$g70st&Hw-a literal 0 HcmV?d00001 diff --git a/swarm/examples/album/eye.png b/swarm/examples/album/eye.png new file mode 100644 index 0000000000000000000000000000000000000000..562942a58062015c716132f39fd1dfefaf44fde9 GIT binary patch literal 525 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�U^4-pN)4aqy@k)i6A4d*Yq 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

M@rT;E{K(`&p!NM*N2GwNY%qZ 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

9Qhd^qHwDSTC$)8B#-ScQ%8Y#? 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 literal 0 HcmV?d00001 diff --git a/swarm/examples/album/imgs/bekas1.jpg b/swarm/examples/album/imgs/bekas1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e38e5f55bd8abb0b681173d42c6ed27ae0b2998 GIT binary patch literal 554726 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 I*T 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%0DRZ+zyB=Mn1HHo0Jiynv){&ytfui|x} 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%0DLB-E>Bk4d$`)qt%SNh1-WvaoR7hf(c@ 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