From bdba044a8031d810555196cde1b97792fa2b8084 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Mar 2015 02:46:56 +0100 Subject: [PATCH 1/7] ethutil: remove Config variable Various functions throughout the codebase used it to grab settings. This has to stop because I want to use them without reading the config file. These functions can now be used without reading the config first: * ethdb.NewLDBDatabase * ethrepl.NewJSRepl * vm.New --- cmd/ethereum/repl/repl.go | 2 +- cmd/mist/bindings.go | 4 ++-- cmd/mist/gui.go | 2 +- eth/backend.go | 7 +++++-- ethdb/database.go | 11 +++-------- ethutil/config.go | 35 ++++++++++++++++------------------- vm/vm.go | 5 +---- 7 files changed, 29 insertions(+), 37 deletions(-) diff --git a/cmd/ethereum/repl/repl.go b/cmd/ethereum/repl/repl.go index ec1aa6918..05ea71e79 100644 --- a/cmd/ethereum/repl/repl.go +++ b/cmd/ethereum/repl/repl.go @@ -54,7 +54,7 @@ type JSRepl struct { } func NewJSRepl(ethereum *eth.Ethereum) *JSRepl { - hist, err := os.OpenFile(path.Join(ethutil.Config.ExecPath, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) + hist, err := os.OpenFile(path.Join(ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) if err != nil { panic(err) } diff --git a/cmd/mist/bindings.go b/cmd/mist/bindings.go index 9623538a3..f21aa3135 100644 --- a/cmd/mist/bindings.go +++ b/cmd/mist/bindings.go @@ -79,14 +79,14 @@ func (self *Gui) AddPlugin(pluginPath string) { self.plugins[pluginPath] = plugin{Name: pluginPath, Path: pluginPath} json, _ := json.MarshalIndent(self.plugins, "", " ") - ethutil.WriteFile(ethutil.Config.ExecPath+"/plugins.json", json) + ethutil.WriteFile(self.eth.DataDir+"/plugins.json", json) } func (self *Gui) RemovePlugin(pluginPath string) { delete(self.plugins, pluginPath) json, _ := json.MarshalIndent(self.plugins, "", " ") - ethutil.WriteFile(ethutil.Config.ExecPath+"/plugins.json", json) + ethutil.WriteFile(self.eth.DataDir+"/plugins.json", json) } // this extra function needed to give int typecast value to gui widget diff --git a/cmd/mist/gui.go b/cmd/mist/gui.go index cbd8daf2f..5f444dd95 100644 --- a/cmd/mist/gui.go +++ b/cmd/mist/gui.go @@ -100,7 +100,7 @@ func NewWindow(ethereum *eth.Ethereum, config *ethutil.ConfigManager, session st plugins: make(map[string]plugin), serviceEvents: make(chan ServEv, 1), } - data, _ := ethutil.ReadAllFile(path.Join(ethutil.Config.ExecPath, "plugins.json")) + data, _ := ethutil.ReadAllFile(path.Join(ethereum.DataDir, "plugins.json")) json.Unmarshal([]byte(data), &gui.plugins) return gui diff --git a/eth/backend.go b/eth/backend.go index 88708b997..7351b4168 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -132,13 +132,15 @@ type Ethereum struct { logger logger.LogSystem - Mining bool + Mining bool + DataDir string } func New(config *Config) (*Ethereum, error) { // Boostrap database ethlogger := logger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat) - db, err := ethdb.NewLDBDatabase("blockchain") + + db, err := ethdb.NewLDBDatabase(path.Join(config.DataDir, "blockchain")) if err != nil { return nil, err } @@ -175,6 +177,7 @@ func New(config *Config) (*Ethereum, error) { blacklist: p2p.NewBlacklist(), eventMux: &event.TypeMux{}, logger: ethlogger, + DataDir: config.DataDir, } eth.chainManager = core.NewChainManager(db, eth.EventMux()) diff --git a/ethdb/database.go b/ethdb/database.go index f020af8f2..4e3d01da0 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -1,11 +1,10 @@ package ethdb import ( - "path" "fmt" - "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/compression/rle" + "github.com/ethereum/go-ethereum/ethutil" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/iterator" ) @@ -15,17 +14,13 @@ type LDBDatabase struct { comp bool } -func NewLDBDatabase(name string) (*LDBDatabase, error) { - dbPath := path.Join(ethutil.Config.ExecPath, name) - +func NewLDBDatabase(file string) (*LDBDatabase, error) { // Open the db - db, err := leveldb.OpenFile(dbPath, nil) + db, err := leveldb.OpenFile(file, nil) if err != nil { return nil, err } - database := &LDBDatabase{db: db, comp: true} - return database, nil } diff --git a/ethutil/config.go b/ethutil/config.go index fc8fb4e3f..c45c310ce 100644 --- a/ethutil/config.go +++ b/ethutil/config.go @@ -20,30 +20,27 @@ type ConfigManager struct { conf *globalconf.GlobalConf } -var Config *ConfigManager - // Read config // // Initialize Config from Config File func ReadConfig(ConfigFile string, Datadir string, EnvPrefix string) *ConfigManager { - if Config == nil { - // create ConfigFile if does not exist, otherwise globalconf panic when trying to persist flags - if !FileExist(ConfigFile) { - fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile) - os.Create(ConfigFile) - } - g, err := globalconf.NewWithOptions(&globalconf.Options{ - Filename: ConfigFile, - EnvPrefix: EnvPrefix, - }) - if err != nil { - fmt.Println(err) - } else { - g.ParseAll() - } - Config = &ConfigManager{ExecPath: Datadir, Debug: true, conf: g, Paranoia: true} + if !FileExist(ConfigFile) { + // create ConfigFile if it does not exist, otherwise + // globalconf will panic when trying to persist flags. + fmt.Printf("config file '%s' doesn't exist, creating it\n", ConfigFile) + os.Create(ConfigFile) } - return Config + g, err := globalconf.NewWithOptions(&globalconf.Options{ + Filename: ConfigFile, + EnvPrefix: EnvPrefix, + }) + if err != nil { + fmt.Println(err) + } else { + g.ParseAll() + } + cfg := &ConfigManager{ExecPath: Datadir, Debug: true, conf: g, Paranoia: true} + return cfg } // provides persistence for flags diff --git a/vm/vm.go b/vm/vm.go index bce8088ef..165bb0329 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -30,10 +30,7 @@ type Vm struct { func New(env Environment) *Vm { lt := LogTyPretty - if ethutil.Config.Diff { - lt = LogTyDiff - } - + // lt = LogTyDiff return &Vm{debug: true, env: env, logTy: lt, Recoverable: true} } From f9c6bc63df8170c6a3b1bb7848b92759b17e7d58 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Mar 2015 02:54:57 +0100 Subject: [PATCH 2/7] Godeps: delete golang.org/x/net/websocket It is no longer imported by any package in our tree. --- Godeps/Godeps.json | 4 - .../src/golang.org/x/net/websocket/client.go | 112 ---- .../x/net/websocket/exampledial_test.go | 31 - .../x/net/websocket/examplehandler_test.go | 26 - .../src/golang.org/x/net/websocket/hybi.go | 564 ----------------- .../golang.org/x/net/websocket/hybi_test.go | 590 ------------------ .../src/golang.org/x/net/websocket/server.go | 114 ---- .../golang.org/x/net/websocket/websocket.go | 411 ------------ .../x/net/websocket/websocket_test.go | 414 ------------ 9 files changed, 2266 deletions(-) delete mode 100644 Godeps/_workspace/src/golang.org/x/net/websocket/client.go delete mode 100644 Godeps/_workspace/src/golang.org/x/net/websocket/exampledial_test.go delete mode 100644 Godeps/_workspace/src/golang.org/x/net/websocket/examplehandler_test.go delete mode 100644 Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go delete mode 100644 Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go delete mode 100644 Godeps/_workspace/src/golang.org/x/net/websocket/server.go delete mode 100644 Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go delete mode 100644 Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index a1025c85d..f0a3448c7 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -97,10 +97,6 @@ "ImportPath": "golang.org/x/crypto/scrypt", "Rev": "4ed45ec682102c643324fae5dff8dab085b6c300" }, - { - "ImportPath": "golang.org/x/net/websocket", - "Rev": "59b0df9b1f7abda5aab0495ee54f408daf182ce7" - }, { "ImportPath": "gopkg.in/check.v1", "Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673" diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/client.go b/Godeps/_workspace/src/golang.org/x/net/websocket/client.go deleted file mode 100644 index ef11a51e4..000000000 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/client.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "crypto/tls" - "io" - "net" - "net/http" - "net/url" -) - -// DialError is an error that occurs while dialling a websocket server. -type DialError struct { - *Config - Err error -} - -func (e *DialError) Error() string { - return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error() -} - -// NewConfig creates a new WebSocket config for client connection. -func NewConfig(server, origin string) (config *Config, err error) { - config = new(Config) - config.Version = ProtocolVersionHybi13 - config.Location, err = url.ParseRequestURI(server) - if err != nil { - return - } - config.Origin, err = url.ParseRequestURI(origin) - if err != nil { - return - } - config.Header = http.Header(make(map[string][]string)) - return -} - -// NewClient creates a new WebSocket client connection over rwc. -func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) { - br := bufio.NewReader(rwc) - bw := bufio.NewWriter(rwc) - err = hybiClientHandshake(config, br, bw) - if err != nil { - return - } - buf := bufio.NewReadWriter(br, bw) - ws = newHybiClientConn(config, buf, rwc) - return -} - -// Dial opens a new client connection to a WebSocket. -func Dial(url_, protocol, origin string) (ws *Conn, err error) { - config, err := NewConfig(url_, origin) - if err != nil { - return nil, err - } - if protocol != "" { - config.Protocol = []string{protocol} - } - return DialConfig(config) -} - -var portMap = map[string]string{ - "ws": "80", - "wss": "443", -} - -func parseAuthority(location *url.URL) string { - if _, ok := portMap[location.Scheme]; ok { - if _, _, err := net.SplitHostPort(location.Host); err != nil { - return net.JoinHostPort(location.Host, portMap[location.Scheme]) - } - } - return location.Host -} - -// DialConfig opens a new client connection to a WebSocket with a config. -func DialConfig(config *Config) (ws *Conn, err error) { - var client net.Conn - if config.Location == nil { - return nil, &DialError{config, ErrBadWebSocketLocation} - } - if config.Origin == nil { - return nil, &DialError{config, ErrBadWebSocketOrigin} - } - switch config.Location.Scheme { - case "ws": - client, err = net.Dial("tcp", parseAuthority(config.Location)) - - case "wss": - client, err = tls.Dial("tcp", parseAuthority(config.Location), config.TlsConfig) - - default: - err = ErrBadScheme - } - if err != nil { - goto Error - } - - ws, err = NewClient(config, client) - if err != nil { - goto Error - } - return - -Error: - return nil, &DialError{config, err} -} diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/exampledial_test.go b/Godeps/_workspace/src/golang.org/x/net/websocket/exampledial_test.go deleted file mode 100644 index 72bb9d48e..000000000 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/exampledial_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket_test - -import ( - "fmt" - "log" - - "golang.org/x/net/websocket" -) - -// This example demonstrates a trivial client. -func ExampleDial() { - origin := "http://localhost/" - url := "ws://localhost:12345/ws" - ws, err := websocket.Dial(url, "", origin) - if err != nil { - log.Fatal(err) - } - if _, err := ws.Write([]byte("hello, world!\n")); err != nil { - log.Fatal(err) - } - var msg = make([]byte, 512) - var n int - if n, err = ws.Read(msg); err != nil { - log.Fatal(err) - } - fmt.Printf("Received: %s.\n", msg[:n]) -} diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/examplehandler_test.go b/Godeps/_workspace/src/golang.org/x/net/websocket/examplehandler_test.go deleted file mode 100644 index f22a98fcd..000000000 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/examplehandler_test.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket_test - -import ( - "io" - "net/http" - - "golang.org/x/net/websocket" -) - -// Echo the data received on the WebSocket. -func EchoServer(ws *websocket.Conn) { - io.Copy(ws, ws) -} - -// This example demonstrates a trivial echo server. -func ExampleHandler() { - http.Handle("/echo", websocket.Handler(EchoServer)) - err := http.ListenAndServe(":12345", nil) - if err != nil { - panic("ListenAndServe: " + err.Error()) - } -} diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go b/Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go deleted file mode 100644 index f8c0b2e29..000000000 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/hybi.go +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -// This file implements a protocol of hybi draft. -// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 - -import ( - "bufio" - "bytes" - "crypto/rand" - "crypto/sha1" - "encoding/base64" - "encoding/binary" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "strings" -) - -const ( - websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - - closeStatusNormal = 1000 - closeStatusGoingAway = 1001 - closeStatusProtocolError = 1002 - closeStatusUnsupportedData = 1003 - closeStatusFrameTooLarge = 1004 - closeStatusNoStatusRcvd = 1005 - closeStatusAbnormalClosure = 1006 - closeStatusBadMessageData = 1007 - closeStatusPolicyViolation = 1008 - closeStatusTooBigData = 1009 - closeStatusExtensionMismatch = 1010 - - maxControlFramePayloadLength = 125 -) - -var ( - ErrBadMaskingKey = &ProtocolError{"bad masking key"} - ErrBadPongMessage = &ProtocolError{"bad pong message"} - ErrBadClosingStatus = &ProtocolError{"bad closing status"} - ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"} - ErrNotImplemented = &ProtocolError{"not implemented"} - - handshakeHeader = map[string]bool{ - "Host": true, - "Upgrade": true, - "Connection": true, - "Sec-Websocket-Key": true, - "Sec-Websocket-Origin": true, - "Sec-Websocket-Version": true, - "Sec-Websocket-Protocol": true, - "Sec-Websocket-Accept": true, - } -) - -// A hybiFrameHeader is a frame header as defined in hybi draft. -type hybiFrameHeader struct { - Fin bool - Rsv [3]bool - OpCode byte - Length int64 - MaskingKey []byte - - data *bytes.Buffer -} - -// A hybiFrameReader is a reader for hybi frame. -type hybiFrameReader struct { - reader io.Reader - - header hybiFrameHeader - pos int64 - length int -} - -func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) { - n, err = frame.reader.Read(msg) - if err != nil { - return 0, err - } - if frame.header.MaskingKey != nil { - for i := 0; i < n; i++ { - msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4] - frame.pos++ - } - } - return n, err -} - -func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode } - -func (frame *hybiFrameReader) HeaderReader() io.Reader { - if frame.header.data == nil { - return nil - } - if frame.header.data.Len() == 0 { - return nil - } - return frame.header.data -} - -func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil } - -func (frame *hybiFrameReader) Len() (n int) { return frame.length } - -// A hybiFrameReaderFactory creates new frame reader based on its frame type. -type hybiFrameReaderFactory struct { - *bufio.Reader -} - -// NewFrameReader reads a frame header from the connection, and creates new reader for the frame. -// See Section 5.2 Base Framing protocol for detail. -// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2 -func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) { - hybiFrame := new(hybiFrameReader) - frame = hybiFrame - var header []byte - var b byte - // First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits) - b, err = buf.ReadByte() - if err != nil { - return - } - header = append(header, b) - hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0 - for i := 0; i < 3; i++ { - j := uint(6 - i) - hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0 - } - hybiFrame.header.OpCode = header[0] & 0x0f - - // Second byte. Mask/Payload len(7bits) - b, err = buf.ReadByte() - if err != nil { - return - } - header = append(header, b) - mask := (b & 0x80) != 0 - b &= 0x7f - lengthFields := 0 - switch { - case b <= 125: // Payload length 7bits. - hybiFrame.header.Length = int64(b) - case b == 126: // Payload length 7+16bits - lengthFields = 2 - case b == 127: // Payload length 7+64bits - lengthFields = 8 - } - for i := 0; i < lengthFields; i++ { - b, err = buf.ReadByte() - if err != nil { - return - } - header = append(header, b) - hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b) - } - if mask { - // Masking key. 4 bytes. - for i := 0; i < 4; i++ { - b, err = buf.ReadByte() - if err != nil { - return - } - header = append(header, b) - hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b) - } - } - hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length) - hybiFrame.header.data = bytes.NewBuffer(header) - hybiFrame.length = len(header) + int(hybiFrame.header.Length) - return -} - -// A HybiFrameWriter is a writer for hybi frame. -type hybiFrameWriter struct { - writer *bufio.Writer - - header *hybiFrameHeader -} - -func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) { - var header []byte - var b byte - if frame.header.Fin { - b |= 0x80 - } - for i := 0; i < 3; i++ { - if frame.header.Rsv[i] { - j := uint(6 - i) - b |= 1 << j - } - } - b |= frame.header.OpCode - header = append(header, b) - if frame.header.MaskingKey != nil { - b = 0x80 - } else { - b = 0 - } - lengthFields := 0 - length := len(msg) - switch { - case length <= 125: - b |= byte(length) - case length < 65536: - b |= 126 - lengthFields = 2 - default: - b |= 127 - lengthFields = 8 - } - header = append(header, b) - for i := 0; i < lengthFields; i++ { - j := uint((lengthFields - i - 1) * 8) - b = byte((length >> j) & 0xff) - header = append(header, b) - } - if frame.header.MaskingKey != nil { - if len(frame.header.MaskingKey) != 4 { - return 0, ErrBadMaskingKey - } - header = append(header, frame.header.MaskingKey...) - frame.writer.Write(header) - data := make([]byte, length) - for i := range data { - data[i] = msg[i] ^ frame.header.MaskingKey[i%4] - } - frame.writer.Write(data) - err = frame.writer.Flush() - return length, err - } - frame.writer.Write(header) - frame.writer.Write(msg) - err = frame.writer.Flush() - return length, err -} - -func (frame *hybiFrameWriter) Close() error { return nil } - -type hybiFrameWriterFactory struct { - *bufio.Writer - needMaskingKey bool -} - -func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) { - frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType} - if buf.needMaskingKey { - frameHeader.MaskingKey, err = generateMaskingKey() - if err != nil { - return nil, err - } - } - return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil -} - -type hybiFrameHandler struct { - conn *Conn - payloadType byte -} - -func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) { - if handler.conn.IsServerConn() { - // The client MUST mask all frames sent to the server. - if frame.(*hybiFrameReader).header.MaskingKey == nil { - handler.WriteClose(closeStatusProtocolError) - return nil, io.EOF - } - } else { - // The server MUST NOT mask all frames. - if frame.(*hybiFrameReader).header.MaskingKey != nil { - handler.WriteClose(closeStatusProtocolError) - return nil, io.EOF - } - } - if header := frame.HeaderReader(); header != nil { - io.Copy(ioutil.Discard, header) - } - switch frame.PayloadType() { - case ContinuationFrame: - frame.(*hybiFrameReader).header.OpCode = handler.payloadType - case TextFrame, BinaryFrame: - handler.payloadType = frame.PayloadType() - case CloseFrame: - return nil, io.EOF - case PingFrame: - pingMsg := make([]byte, maxControlFramePayloadLength) - n, err := io.ReadFull(frame, pingMsg) - if err != nil && err != io.ErrUnexpectedEOF { - return nil, err - } - io.Copy(ioutil.Discard, frame) - n, err = handler.WritePong(pingMsg[:n]) - if err != nil { - return nil, err - } - return nil, nil - case PongFrame: - return nil, ErrNotImplemented - } - return frame, nil -} - -func (handler *hybiFrameHandler) WriteClose(status int) (err error) { - handler.conn.wio.Lock() - defer handler.conn.wio.Unlock() - w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame) - if err != nil { - return err - } - msg := make([]byte, 2) - binary.BigEndian.PutUint16(msg, uint16(status)) - _, err = w.Write(msg) - w.Close() - return err -} - -func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) { - handler.conn.wio.Lock() - defer handler.conn.wio.Unlock() - w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame) - if err != nil { - return 0, err - } - n, err = w.Write(msg) - w.Close() - return n, err -} - -// newHybiConn creates a new WebSocket connection speaking hybi draft protocol. -func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { - if buf == nil { - br := bufio.NewReader(rwc) - bw := bufio.NewWriter(rwc) - buf = bufio.NewReadWriter(br, bw) - } - ws := &Conn{config: config, request: request, buf: buf, rwc: rwc, - frameReaderFactory: hybiFrameReaderFactory{buf.Reader}, - frameWriterFactory: hybiFrameWriterFactory{ - buf.Writer, request == nil}, - PayloadType: TextFrame, - defaultCloseStatus: closeStatusNormal} - ws.frameHandler = &hybiFrameHandler{conn: ws} - return ws -} - -// generateMaskingKey generates a masking key for a frame. -func generateMaskingKey() (maskingKey []byte, err error) { - maskingKey = make([]byte, 4) - if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil { - return - } - return -} - -// generateNonce generates a nonce consisting of a randomly selected 16-byte -// value that has been base64-encoded. -func generateNonce() (nonce []byte) { - key := make([]byte, 16) - if _, err := io.ReadFull(rand.Reader, key); err != nil { - panic(err) - } - nonce = make([]byte, 24) - base64.StdEncoding.Encode(nonce, key) - return -} - -// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of -// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string. -func getNonceAccept(nonce []byte) (expected []byte, err error) { - h := sha1.New() - if _, err = h.Write(nonce); err != nil { - return - } - if _, err = h.Write([]byte(websocketGUID)); err != nil { - return - } - expected = make([]byte, 28) - base64.StdEncoding.Encode(expected, h.Sum(nil)) - return -} - -// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17 -func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) { - bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") - - bw.WriteString("Host: " + config.Location.Host + "\r\n") - bw.WriteString("Upgrade: websocket\r\n") - bw.WriteString("Connection: Upgrade\r\n") - nonce := generateNonce() - if config.handshakeData != nil { - nonce = []byte(config.handshakeData["key"]) - } - bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n") - bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") - - if config.Version != ProtocolVersionHybi13 { - return ErrBadProtocolVersion - } - - bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n") - if len(config.Protocol) > 0 { - bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n") - } - // TODO(ukai): send Sec-WebSocket-Extensions. - err = config.Header.WriteSubset(bw, handshakeHeader) - if err != nil { - return err - } - - bw.WriteString("\r\n") - if err = bw.Flush(); err != nil { - return err - } - - resp, err := http.ReadResponse(br, &http.Request{Method: "GET"}) - if err != nil { - return err - } - if resp.StatusCode != 101 { - return ErrBadStatus - } - if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" || - strings.ToLower(resp.Header.Get("Connection")) != "upgrade" { - return ErrBadUpgrade - } - expectedAccept, err := getNonceAccept(nonce) - if err != nil { - return err - } - if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) { - return ErrChallengeResponse - } - if resp.Header.Get("Sec-WebSocket-Extensions") != "" { - return ErrUnsupportedExtensions - } - offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol") - if offeredProtocol != "" { - protocolMatched := false - for i := 0; i < len(config.Protocol); i++ { - if config.Protocol[i] == offeredProtocol { - protocolMatched = true - break - } - } - if !protocolMatched { - return ErrBadWebSocketProtocol - } - config.Protocol = []string{offeredProtocol} - } - - return nil -} - -// newHybiClientConn creates a client WebSocket connection after handshake. -func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn { - return newHybiConn(config, buf, rwc, nil) -} - -// A HybiServerHandshaker performs a server handshake using hybi draft protocol. -type hybiServerHandshaker struct { - *Config - accept []byte -} - -func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) { - c.Version = ProtocolVersionHybi13 - if req.Method != "GET" { - return http.StatusMethodNotAllowed, ErrBadRequestMethod - } - // HTTP version can be safely ignored. - - if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" || - !strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") { - return http.StatusBadRequest, ErrNotWebSocket - } - - key := req.Header.Get("Sec-Websocket-Key") - if key == "" { - return http.StatusBadRequest, ErrChallengeResponse - } - version := req.Header.Get("Sec-Websocket-Version") - switch version { - case "13": - c.Version = ProtocolVersionHybi13 - default: - return http.StatusBadRequest, ErrBadWebSocketVersion - } - var scheme string - if req.TLS != nil { - scheme = "wss" - } else { - scheme = "ws" - } - c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI()) - if err != nil { - return http.StatusBadRequest, err - } - protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol")) - if protocol != "" { - protocols := strings.Split(protocol, ",") - for i := 0; i < len(protocols); i++ { - c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i])) - } - } - c.accept, err = getNonceAccept([]byte(key)) - if err != nil { - return http.StatusInternalServerError, err - } - return http.StatusSwitchingProtocols, nil -} - -// Origin parses Origin header in "req". -// If origin is "null", returns (nil, nil). -func Origin(config *Config, req *http.Request) (*url.URL, error) { - var origin string - switch config.Version { - case ProtocolVersionHybi13: - origin = req.Header.Get("Origin") - } - if origin == "null" { - return nil, nil - } - return url.ParseRequestURI(origin) -} - -func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) { - if len(c.Protocol) > 0 { - if len(c.Protocol) != 1 { - // You need choose a Protocol in Handshake func in Server. - return ErrBadWebSocketProtocol - } - } - buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n") - buf.WriteString("Upgrade: websocket\r\n") - buf.WriteString("Connection: Upgrade\r\n") - buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n") - if len(c.Protocol) > 0 { - buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n") - } - // TODO(ukai): send Sec-WebSocket-Extensions. - if c.Header != nil { - err := c.Header.WriteSubset(buf, handshakeHeader) - if err != nil { - return err - } - } - buf.WriteString("\r\n") - return buf.Flush() -} - -func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { - return newHybiServerConn(c.Config, buf, rwc, request) -} - -// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol. -func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { - return newHybiConn(config, buf, rwc, request) -} diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go b/Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go deleted file mode 100644 index d6a19108a..000000000 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/hybi_test.go +++ /dev/null @@ -1,590 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "bytes" - "fmt" - "io" - "net/http" - "net/url" - "strings" - "testing" -) - -// Test the getNonceAccept function with values in -// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 -func TestSecWebSocketAccept(t *testing.T) { - nonce := []byte("dGhlIHNhbXBsZSBub25jZQ==") - expected := []byte("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=") - accept, err := getNonceAccept(nonce) - if err != nil { - t.Errorf("getNonceAccept: returned error %v", err) - return - } - if !bytes.Equal(expected, accept) { - t.Errorf("getNonceAccept: expected %q got %q", expected, accept) - } -} - -func TestHybiClientHandshake(t *testing.T) { - b := bytes.NewBuffer([]byte{}) - bw := bufio.NewWriter(b) - br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= -Sec-WebSocket-Protocol: chat - -`)) - var err error - config := new(Config) - config.Location, err = url.ParseRequestURI("ws://server.example.com/chat") - if err != nil { - t.Fatal("location url", err) - } - config.Origin, err = url.ParseRequestURI("http://example.com") - if err != nil { - t.Fatal("origin url", err) - } - config.Protocol = append(config.Protocol, "chat") - config.Protocol = append(config.Protocol, "superchat") - config.Version = ProtocolVersionHybi13 - - config.handshakeData = map[string]string{ - "key": "dGhlIHNhbXBsZSBub25jZQ==", - } - err = hybiClientHandshake(config, br, bw) - if err != nil { - t.Errorf("handshake failed: %v", err) - } - req, err := http.ReadRequest(bufio.NewReader(b)) - if err != nil { - t.Fatalf("read request: %v", err) - } - if req.Method != "GET" { - t.Errorf("request method expected GET, but got %q", req.Method) - } - if req.URL.Path != "/chat" { - t.Errorf("request path expected /chat, but got %q", req.URL.Path) - } - if req.Proto != "HTTP/1.1" { - t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto) - } - if req.Host != "server.example.com" { - t.Errorf("request Host expected server.example.com, but got %v", req.Host) - } - var expectedHeader = map[string]string{ - "Connection": "Upgrade", - "Upgrade": "websocket", - "Sec-Websocket-Key": config.handshakeData["key"], - "Origin": config.Origin.String(), - "Sec-Websocket-Protocol": "chat, superchat", - "Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi13), - } - for k, v := range expectedHeader { - if req.Header.Get(k) != v { - t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k))) - } - } -} - -func TestHybiClientHandshakeWithHeader(t *testing.T) { - b := bytes.NewBuffer([]byte{}) - bw := bufio.NewWriter(b) - br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= -Sec-WebSocket-Protocol: chat - -`)) - var err error - config := new(Config) - config.Location, err = url.ParseRequestURI("ws://server.example.com/chat") - if err != nil { - t.Fatal("location url", err) - } - config.Origin, err = url.ParseRequestURI("http://example.com") - if err != nil { - t.Fatal("origin url", err) - } - config.Protocol = append(config.Protocol, "chat") - config.Protocol = append(config.Protocol, "superchat") - config.Version = ProtocolVersionHybi13 - config.Header = http.Header(make(map[string][]string)) - config.Header.Add("User-Agent", "test") - - config.handshakeData = map[string]string{ - "key": "dGhlIHNhbXBsZSBub25jZQ==", - } - err = hybiClientHandshake(config, br, bw) - if err != nil { - t.Errorf("handshake failed: %v", err) - } - req, err := http.ReadRequest(bufio.NewReader(b)) - if err != nil { - t.Fatalf("read request: %v", err) - } - if req.Method != "GET" { - t.Errorf("request method expected GET, but got %q", req.Method) - } - if req.URL.Path != "/chat" { - t.Errorf("request path expected /chat, but got %q", req.URL.Path) - } - if req.Proto != "HTTP/1.1" { - t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto) - } - if req.Host != "server.example.com" { - t.Errorf("request Host expected server.example.com, but got %v", req.Host) - } - var expectedHeader = map[string]string{ - "Connection": "Upgrade", - "Upgrade": "websocket", - "Sec-Websocket-Key": config.handshakeData["key"], - "Origin": config.Origin.String(), - "Sec-Websocket-Protocol": "chat, superchat", - "Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi13), - "User-Agent": "test", - } - for k, v := range expectedHeader { - if req.Header.Get(k) != v { - t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k))) - } - } -} - -func TestHybiServerHandshake(t *testing.T) { - config := new(Config) - handshaker := &hybiServerHandshaker{Config: config} - br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 -Host: server.example.com -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -Origin: http://example.com -Sec-WebSocket-Protocol: chat, superchat -Sec-WebSocket-Version: 13 - -`)) - req, err := http.ReadRequest(br) - if err != nil { - t.Fatal("request", err) - } - code, err := handshaker.ReadHandshake(br, req) - if err != nil { - t.Errorf("handshake failed: %v", err) - } - if code != http.StatusSwitchingProtocols { - t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code) - } - expectedProtocols := []string{"chat", "superchat"} - if fmt.Sprintf("%v", config.Protocol) != fmt.Sprintf("%v", expectedProtocols) { - t.Errorf("protocol expected %q but got %q", expectedProtocols, config.Protocol) - } - b := bytes.NewBuffer([]byte{}) - bw := bufio.NewWriter(b) - - config.Protocol = config.Protocol[:1] - - err = handshaker.AcceptHandshake(bw) - if err != nil { - t.Errorf("handshake response failed: %v", err) - } - expectedResponse := strings.Join([]string{ - "HTTP/1.1 101 Switching Protocols", - "Upgrade: websocket", - "Connection: Upgrade", - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", - "Sec-WebSocket-Protocol: chat", - "", ""}, "\r\n") - - if b.String() != expectedResponse { - t.Errorf("handshake expected %q but got %q", expectedResponse, b.String()) - } -} - -func TestHybiServerHandshakeNoSubProtocol(t *testing.T) { - config := new(Config) - handshaker := &hybiServerHandshaker{Config: config} - br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 -Host: server.example.com -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -Origin: http://example.com -Sec-WebSocket-Version: 13 - -`)) - req, err := http.ReadRequest(br) - if err != nil { - t.Fatal("request", err) - } - code, err := handshaker.ReadHandshake(br, req) - if err != nil { - t.Errorf("handshake failed: %v", err) - } - if code != http.StatusSwitchingProtocols { - t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code) - } - if len(config.Protocol) != 0 { - t.Errorf("len(config.Protocol) expected 0, but got %q", len(config.Protocol)) - } - b := bytes.NewBuffer([]byte{}) - bw := bufio.NewWriter(b) - - err = handshaker.AcceptHandshake(bw) - if err != nil { - t.Errorf("handshake response failed: %v", err) - } - expectedResponse := strings.Join([]string{ - "HTTP/1.1 101 Switching Protocols", - "Upgrade: websocket", - "Connection: Upgrade", - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", - "", ""}, "\r\n") - - if b.String() != expectedResponse { - t.Errorf("handshake expected %q but got %q", expectedResponse, b.String()) - } -} - -func TestHybiServerHandshakeHybiBadVersion(t *testing.T) { - config := new(Config) - handshaker := &hybiServerHandshaker{Config: config} - br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 -Host: server.example.com -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -Sec-WebSocket-Origin: http://example.com -Sec-WebSocket-Protocol: chat, superchat -Sec-WebSocket-Version: 9 - -`)) - req, err := http.ReadRequest(br) - if err != nil { - t.Fatal("request", err) - } - code, err := handshaker.ReadHandshake(br, req) - if err != ErrBadWebSocketVersion { - t.Errorf("handshake expected err %q but got %q", ErrBadWebSocketVersion, err) - } - if code != http.StatusBadRequest { - t.Errorf("status expected %q but got %q", http.StatusBadRequest, code) - } -} - -func testHybiFrame(t *testing.T, testHeader, testPayload, testMaskedPayload []byte, frameHeader *hybiFrameHeader) { - b := bytes.NewBuffer([]byte{}) - frameWriterFactory := &hybiFrameWriterFactory{bufio.NewWriter(b), false} - w, _ := frameWriterFactory.NewFrameWriter(TextFrame) - w.(*hybiFrameWriter).header = frameHeader - _, err := w.Write(testPayload) - w.Close() - if err != nil { - t.Errorf("Write error %q", err) - } - var expectedFrame []byte - expectedFrame = append(expectedFrame, testHeader...) - expectedFrame = append(expectedFrame, testMaskedPayload...) - if !bytes.Equal(expectedFrame, b.Bytes()) { - t.Errorf("frame expected %q got %q", expectedFrame, b.Bytes()) - } - frameReaderFactory := &hybiFrameReaderFactory{bufio.NewReader(b)} - r, err := frameReaderFactory.NewFrameReader() - if err != nil { - t.Errorf("Read error %q", err) - } - if header := r.HeaderReader(); header == nil { - t.Errorf("no header") - } else { - actualHeader := make([]byte, r.Len()) - n, err := header.Read(actualHeader) - if err != nil { - t.Errorf("Read header error %q", err) - } else { - if n < len(testHeader) { - t.Errorf("header too short %q got %q", testHeader, actualHeader[:n]) - } - if !bytes.Equal(testHeader, actualHeader[:n]) { - t.Errorf("header expected %q got %q", testHeader, actualHeader[:n]) - } - } - } - if trailer := r.TrailerReader(); trailer != nil { - t.Errorf("unexpected trailer %q", trailer) - } - frame := r.(*hybiFrameReader) - if frameHeader.Fin != frame.header.Fin || - frameHeader.OpCode != frame.header.OpCode || - len(testPayload) != int(frame.header.Length) { - t.Errorf("mismatch %v (%d) vs %v", frameHeader, len(testPayload), frame) - } - payload := make([]byte, len(testPayload)) - _, err = r.Read(payload) - if err != nil { - t.Errorf("read %v", err) - } - if !bytes.Equal(testPayload, payload) { - t.Errorf("payload %q vs %q", testPayload, payload) - } -} - -func TestHybiShortTextFrame(t *testing.T) { - frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame} - payload := []byte("hello") - testHybiFrame(t, []byte{0x81, 0x05}, payload, payload, frameHeader) - - payload = make([]byte, 125) - testHybiFrame(t, []byte{0x81, 125}, payload, payload, frameHeader) -} - -func TestHybiShortMaskedTextFrame(t *testing.T) { - frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame, - MaskingKey: []byte{0xcc, 0x55, 0x80, 0x20}} - payload := []byte("hello") - maskedPayload := []byte{0xa4, 0x30, 0xec, 0x4c, 0xa3} - header := []byte{0x81, 0x85} - header = append(header, frameHeader.MaskingKey...) - testHybiFrame(t, header, payload, maskedPayload, frameHeader) -} - -func TestHybiShortBinaryFrame(t *testing.T) { - frameHeader := &hybiFrameHeader{Fin: true, OpCode: BinaryFrame} - payload := []byte("hello") - testHybiFrame(t, []byte{0x82, 0x05}, payload, payload, frameHeader) - - payload = make([]byte, 125) - testHybiFrame(t, []byte{0x82, 125}, payload, payload, frameHeader) -} - -func TestHybiControlFrame(t *testing.T) { - frameHeader := &hybiFrameHeader{Fin: true, OpCode: PingFrame} - payload := []byte("hello") - testHybiFrame(t, []byte{0x89, 0x05}, payload, payload, frameHeader) - - frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame} - testHybiFrame(t, []byte{0x8A, 0x05}, payload, payload, frameHeader) - - frameHeader = &hybiFrameHeader{Fin: true, OpCode: CloseFrame} - payload = []byte{0x03, 0xe8} // 1000 - testHybiFrame(t, []byte{0x88, 0x02}, payload, payload, frameHeader) -} - -func TestHybiLongFrame(t *testing.T) { - frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame} - payload := make([]byte, 126) - testHybiFrame(t, []byte{0x81, 126, 0x00, 126}, payload, payload, frameHeader) - - payload = make([]byte, 65535) - testHybiFrame(t, []byte{0x81, 126, 0xff, 0xff}, payload, payload, frameHeader) - - payload = make([]byte, 65536) - testHybiFrame(t, []byte{0x81, 127, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, payload, payload, frameHeader) -} - -func TestHybiClientRead(t *testing.T) { - wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o', - 0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping - 0x81, 0x05, 'w', 'o', 'r', 'l', 'd'} - br := bufio.NewReader(bytes.NewBuffer(wireData)) - bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) - conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil) - - msg := make([]byte, 512) - n, err := conn.Read(msg) - if err != nil { - t.Errorf("read 1st frame, error %q", err) - } - if n != 5 { - t.Errorf("read 1st frame, expect 5, got %d", n) - } - if !bytes.Equal(wireData[2:7], msg[:n]) { - t.Errorf("read 1st frame %v, got %v", wireData[2:7], msg[:n]) - } - n, err = conn.Read(msg) - if err != nil { - t.Errorf("read 2nd frame, error %q", err) - } - if n != 5 { - t.Errorf("read 2nd frame, expect 5, got %d", n) - } - if !bytes.Equal(wireData[16:21], msg[:n]) { - t.Errorf("read 2nd frame %v, got %v", wireData[16:21], msg[:n]) - } - n, err = conn.Read(msg) - if err == nil { - t.Errorf("read not EOF") - } - if n != 0 { - t.Errorf("expect read 0, got %d", n) - } -} - -func TestHybiShortRead(t *testing.T) { - wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o', - 0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping - 0x81, 0x05, 'w', 'o', 'r', 'l', 'd'} - br := bufio.NewReader(bytes.NewBuffer(wireData)) - bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) - conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil) - - step := 0 - pos := 0 - expectedPos := []int{2, 5, 16, 19} - expectedLen := []int{3, 2, 3, 2} - for { - msg := make([]byte, 3) - n, err := conn.Read(msg) - if step >= len(expectedPos) { - if err == nil { - t.Errorf("read not EOF") - } - if n != 0 { - t.Errorf("expect read 0, got %d", n) - } - return - } - pos = expectedPos[step] - endPos := pos + expectedLen[step] - if err != nil { - t.Errorf("read from %d, got error %q", pos, err) - return - } - if n != endPos-pos { - t.Errorf("read from %d, expect %d, got %d", pos, endPos-pos, n) - } - if !bytes.Equal(wireData[pos:endPos], msg[:n]) { - t.Errorf("read from %d, frame %v, got %v", pos, wireData[pos:endPos], msg[:n]) - } - step++ - } -} - -func TestHybiServerRead(t *testing.T) { - wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20, - 0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello - 0x89, 0x85, 0xcc, 0x55, 0x80, 0x20, - 0xa4, 0x30, 0xec, 0x4c, 0xa3, // ping: hello - 0x81, 0x85, 0xed, 0x83, 0xb4, 0x24, - 0x9a, 0xec, 0xc6, 0x48, 0x89, // world - } - br := bufio.NewReader(bytes.NewBuffer(wireData)) - bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) - conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request)) - - expected := [][]byte{[]byte("hello"), []byte("world")} - - msg := make([]byte, 512) - n, err := conn.Read(msg) - if err != nil { - t.Errorf("read 1st frame, error %q", err) - } - if n != 5 { - t.Errorf("read 1st frame, expect 5, got %d", n) - } - if !bytes.Equal(expected[0], msg[:n]) { - t.Errorf("read 1st frame %q, got %q", expected[0], msg[:n]) - } - - n, err = conn.Read(msg) - if err != nil { - t.Errorf("read 2nd frame, error %q", err) - } - if n != 5 { - t.Errorf("read 2nd frame, expect 5, got %d", n) - } - if !bytes.Equal(expected[1], msg[:n]) { - t.Errorf("read 2nd frame %q, got %q", expected[1], msg[:n]) - } - - n, err = conn.Read(msg) - if err == nil { - t.Errorf("read not EOF") - } - if n != 0 { - t.Errorf("expect read 0, got %d", n) - } -} - -func TestHybiServerReadWithoutMasking(t *testing.T) { - wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o'} - br := bufio.NewReader(bytes.NewBuffer(wireData)) - bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) - conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request)) - // server MUST close the connection upon receiving a non-masked frame. - msg := make([]byte, 512) - _, err := conn.Read(msg) - if err != io.EOF { - t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err) - } -} - -func TestHybiClientReadWithMasking(t *testing.T) { - wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20, - 0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello - } - br := bufio.NewReader(bytes.NewBuffer(wireData)) - bw := bufio.NewWriter(bytes.NewBuffer([]byte{})) - conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil) - - // client MUST close the connection upon receiving a masked frame. - msg := make([]byte, 512) - _, err := conn.Read(msg) - if err != io.EOF { - t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err) - } -} - -// Test the hybiServerHandshaker supports firefox implementation and -// checks Connection request header include (but it's not necessary -// equal to) "upgrade" -func TestHybiServerFirefoxHandshake(t *testing.T) { - config := new(Config) - handshaker := &hybiServerHandshaker{Config: config} - br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1 -Host: server.example.com -Upgrade: websocket -Connection: keep-alive, upgrade -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -Origin: http://example.com -Sec-WebSocket-Protocol: chat, superchat -Sec-WebSocket-Version: 13 - -`)) - req, err := http.ReadRequest(br) - if err != nil { - t.Fatal("request", err) - } - code, err := handshaker.ReadHandshake(br, req) - if err != nil { - t.Errorf("handshake failed: %v", err) - } - if code != http.StatusSwitchingProtocols { - t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code) - } - b := bytes.NewBuffer([]byte{}) - bw := bufio.NewWriter(b) - - config.Protocol = []string{"chat"} - - err = handshaker.AcceptHandshake(bw) - if err != nil { - t.Errorf("handshake response failed: %v", err) - } - expectedResponse := strings.Join([]string{ - "HTTP/1.1 101 Switching Protocols", - "Upgrade: websocket", - "Connection: Upgrade", - "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", - "Sec-WebSocket-Protocol: chat", - "", ""}, "\r\n") - - if b.String() != expectedResponse { - t.Errorf("handshake expected %q but got %q", expectedResponse, b.String()) - } -} diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/server.go b/Godeps/_workspace/src/golang.org/x/net/websocket/server.go deleted file mode 100644 index 70322133c..000000000 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/server.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bufio" - "fmt" - "io" - "net/http" -) - -func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) { - var hs serverHandshaker = &hybiServerHandshaker{Config: config} - code, err := hs.ReadHandshake(buf.Reader, req) - if err == ErrBadWebSocketVersion { - fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) - fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion) - buf.WriteString("\r\n") - buf.WriteString(err.Error()) - buf.Flush() - return - } - if err != nil { - fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) - buf.WriteString("\r\n") - buf.WriteString(err.Error()) - buf.Flush() - return - } - if handshake != nil { - err = handshake(config, req) - if err != nil { - code = http.StatusForbidden - fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) - buf.WriteString("\r\n") - buf.Flush() - return - } - } - err = hs.AcceptHandshake(buf.Writer) - if err != nil { - code = http.StatusBadRequest - fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) - buf.WriteString("\r\n") - buf.Flush() - return - } - conn = hs.NewServerConn(buf, rwc, req) - return -} - -// Server represents a server of a WebSocket. -type Server struct { - // Config is a WebSocket configuration for new WebSocket connection. - Config - - // Handshake is an optional function in WebSocket handshake. - // For example, you can check, or don't check Origin header. - // Another example, you can select config.Protocol. - Handshake func(*Config, *http.Request) error - - // Handler handles a WebSocket connection. - Handler -} - -// ServeHTTP implements the http.Handler interface for a WebSocket -func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { - s.serveWebSocket(w, req) -} - -func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) { - rwc, buf, err := w.(http.Hijacker).Hijack() - if err != nil { - panic("Hijack failed: " + err.Error()) - return - } - // The server should abort the WebSocket connection if it finds - // the client did not send a handshake that matches with protocol - // specification. - defer rwc.Close() - conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake) - if err != nil { - return - } - if conn == nil { - panic("unexpected nil conn") - } - s.Handler(conn) -} - -// Handler is a simple interface to a WebSocket browser client. -// It checks if Origin header is valid URL by default. -// You might want to verify websocket.Conn.Config().Origin in the func. -// If you use Server instead of Handler, you could call websocket.Origin and -// check the origin in your Handshake func. So, if you want to accept -// non-browser client, which doesn't send Origin header, you could use Server -//. that doesn't check origin in its Handshake. -type Handler func(*Conn) - -func checkOrigin(config *Config, req *http.Request) (err error) { - config.Origin, err = Origin(config, req) - if err == nil && config.Origin == nil { - return fmt.Errorf("null origin") - } - return err -} - -// ServeHTTP implements the http.Handler interface for a WebSocket -func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - s := Server{Handler: h, Handshake: checkOrigin} - s.serveWebSocket(w, req) -} diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go b/Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go deleted file mode 100644 index 0f4917bf7..000000000 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/websocket.go +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package websocket implements a client and server for the WebSocket protocol -// as specified in RFC 6455. -package websocket - -import ( - "bufio" - "crypto/tls" - "encoding/json" - "errors" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "sync" - "time" -) - -const ( - ProtocolVersionHybi13 = 13 - ProtocolVersionHybi = ProtocolVersionHybi13 - SupportedProtocolVersion = "13" - - ContinuationFrame = 0 - TextFrame = 1 - BinaryFrame = 2 - CloseFrame = 8 - PingFrame = 9 - PongFrame = 10 - UnknownFrame = 255 -) - -// ProtocolError represents WebSocket protocol errors. -type ProtocolError struct { - ErrorString string -} - -func (err *ProtocolError) Error() string { return err.ErrorString } - -var ( - ErrBadProtocolVersion = &ProtocolError{"bad protocol version"} - ErrBadScheme = &ProtocolError{"bad scheme"} - ErrBadStatus = &ProtocolError{"bad status"} - ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"} - ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"} - ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"} - ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"} - ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"} - ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"} - ErrBadFrame = &ProtocolError{"bad frame"} - ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"} - ErrNotWebSocket = &ProtocolError{"not websocket protocol"} - ErrBadRequestMethod = &ProtocolError{"bad method"} - ErrNotSupported = &ProtocolError{"not supported"} -) - -// Addr is an implementation of net.Addr for WebSocket. -type Addr struct { - *url.URL -} - -// Network returns the network type for a WebSocket, "websocket". -func (addr *Addr) Network() string { return "websocket" } - -// Config is a WebSocket configuration -type Config struct { - // A WebSocket server address. - Location *url.URL - - // A Websocket client origin. - Origin *url.URL - - // WebSocket subprotocols. - Protocol []string - - // WebSocket protocol version. - Version int - - // TLS config for secure WebSocket (wss). - TlsConfig *tls.Config - - // Additional header fields to be sent in WebSocket opening handshake. - Header http.Header - - handshakeData map[string]string -} - -// serverHandshaker is an interface to handle WebSocket server side handshake. -type serverHandshaker interface { - // ReadHandshake reads handshake request message from client. - // Returns http response code and error if any. - ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) - - // AcceptHandshake accepts the client handshake request and sends - // handshake response back to client. - AcceptHandshake(buf *bufio.Writer) (err error) - - // NewServerConn creates a new WebSocket connection. - NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) -} - -// frameReader is an interface to read a WebSocket frame. -type frameReader interface { - // Reader is to read payload of the frame. - io.Reader - - // PayloadType returns payload type. - PayloadType() byte - - // HeaderReader returns a reader to read header of the frame. - HeaderReader() io.Reader - - // TrailerReader returns a reader to read trailer of the frame. - // If it returns nil, there is no trailer in the frame. - TrailerReader() io.Reader - - // Len returns total length of the frame, including header and trailer. - Len() int -} - -// frameReaderFactory is an interface to creates new frame reader. -type frameReaderFactory interface { - NewFrameReader() (r frameReader, err error) -} - -// frameWriter is an interface to write a WebSocket frame. -type frameWriter interface { - // Writer is to write payload of the frame. - io.WriteCloser -} - -// frameWriterFactory is an interface to create new frame writer. -type frameWriterFactory interface { - NewFrameWriter(payloadType byte) (w frameWriter, err error) -} - -type frameHandler interface { - HandleFrame(frame frameReader) (r frameReader, err error) - WriteClose(status int) (err error) -} - -// Conn represents a WebSocket connection. -type Conn struct { - config *Config - request *http.Request - - buf *bufio.ReadWriter - rwc io.ReadWriteCloser - - rio sync.Mutex - frameReaderFactory - frameReader - - wio sync.Mutex - frameWriterFactory - - frameHandler - PayloadType byte - defaultCloseStatus int -} - -// Read implements the io.Reader interface: -// it reads data of a frame from the WebSocket connection. -// if msg is not large enough for the frame data, it fills the msg and next Read -// will read the rest of the frame data. -// it reads Text frame or Binary frame. -func (ws *Conn) Read(msg []byte) (n int, err error) { - ws.rio.Lock() - defer ws.rio.Unlock() -again: - if ws.frameReader == nil { - frame, err := ws.frameReaderFactory.NewFrameReader() - if err != nil { - return 0, err - } - ws.frameReader, err = ws.frameHandler.HandleFrame(frame) - if err != nil { - return 0, err - } - if ws.frameReader == nil { - goto again - } - } - n, err = ws.frameReader.Read(msg) - if err == io.EOF { - if trailer := ws.frameReader.TrailerReader(); trailer != nil { - io.Copy(ioutil.Discard, trailer) - } - ws.frameReader = nil - goto again - } - return n, err -} - -// Write implements the io.Writer interface: -// it writes data as a frame to the WebSocket connection. -func (ws *Conn) Write(msg []byte) (n int, err error) { - ws.wio.Lock() - defer ws.wio.Unlock() - w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType) - if err != nil { - return 0, err - } - n, err = w.Write(msg) - w.Close() - if err != nil { - return n, err - } - return n, err -} - -// Close implements the io.Closer interface. -func (ws *Conn) Close() error { - err := ws.frameHandler.WriteClose(ws.defaultCloseStatus) - if err != nil { - return err - } - return ws.rwc.Close() -} - -func (ws *Conn) IsClientConn() bool { return ws.request == nil } -func (ws *Conn) IsServerConn() bool { return ws.request != nil } - -// LocalAddr returns the WebSocket Origin for the connection for client, or -// the WebSocket location for server. -func (ws *Conn) LocalAddr() net.Addr { - if ws.IsClientConn() { - return &Addr{ws.config.Origin} - } - return &Addr{ws.config.Location} -} - -// RemoteAddr returns the WebSocket location for the connection for client, or -// the Websocket Origin for server. -func (ws *Conn) RemoteAddr() net.Addr { - if ws.IsClientConn() { - return &Addr{ws.config.Location} - } - return &Addr{ws.config.Origin} -} - -var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn") - -// SetDeadline sets the connection's network read & write deadlines. -func (ws *Conn) SetDeadline(t time.Time) error { - if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetDeadline(t) - } - return errSetDeadline -} - -// SetReadDeadline sets the connection's network read deadline. -func (ws *Conn) SetReadDeadline(t time.Time) error { - if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetReadDeadline(t) - } - return errSetDeadline -} - -// SetWriteDeadline sets the connection's network write deadline. -func (ws *Conn) SetWriteDeadline(t time.Time) error { - if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetWriteDeadline(t) - } - return errSetDeadline -} - -// Config returns the WebSocket config. -func (ws *Conn) Config() *Config { return ws.config } - -// Request returns the http request upgraded to the WebSocket. -// It is nil for client side. -func (ws *Conn) Request() *http.Request { return ws.request } - -// Codec represents a symmetric pair of functions that implement a codec. -type Codec struct { - Marshal func(v interface{}) (data []byte, payloadType byte, err error) - Unmarshal func(data []byte, payloadType byte, v interface{}) (err error) -} - -// Send sends v marshaled by cd.Marshal as single frame to ws. -func (cd Codec) Send(ws *Conn, v interface{}) (err error) { - data, payloadType, err := cd.Marshal(v) - if err != nil { - return err - } - ws.wio.Lock() - defer ws.wio.Unlock() - w, err := ws.frameWriterFactory.NewFrameWriter(payloadType) - if err != nil { - return err - } - _, err = w.Write(data) - w.Close() - return err -} - -// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores in v. -func (cd Codec) Receive(ws *Conn, v interface{}) (err error) { - ws.rio.Lock() - defer ws.rio.Unlock() - if ws.frameReader != nil { - _, err = io.Copy(ioutil.Discard, ws.frameReader) - if err != nil { - return err - } - ws.frameReader = nil - } -again: - frame, err := ws.frameReaderFactory.NewFrameReader() - if err != nil { - return err - } - frame, err = ws.frameHandler.HandleFrame(frame) - if err != nil { - return err - } - if frame == nil { - goto again - } - payloadType := frame.PayloadType() - data, err := ioutil.ReadAll(frame) - if err != nil { - return err - } - return cd.Unmarshal(data, payloadType, v) -} - -func marshal(v interface{}) (msg []byte, payloadType byte, err error) { - switch data := v.(type) { - case string: - return []byte(data), TextFrame, nil - case []byte: - return data, BinaryFrame, nil - } - return nil, UnknownFrame, ErrNotSupported -} - -func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) { - switch data := v.(type) { - case *string: - *data = string(msg) - return nil - case *[]byte: - *data = msg - return nil - } - return ErrNotSupported -} - -/* -Message is a codec to send/receive text/binary data in a frame on WebSocket connection. -To send/receive text frame, use string type. -To send/receive binary frame, use []byte type. - -Trivial usage: - - import "websocket" - - // receive text frame - var message string - websocket.Message.Receive(ws, &message) - - // send text frame - message = "hello" - websocket.Message.Send(ws, message) - - // receive binary frame - var data []byte - websocket.Message.Receive(ws, &data) - - // send binary frame - data = []byte{0, 1, 2} - websocket.Message.Send(ws, data) - -*/ -var Message = Codec{marshal, unmarshal} - -func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) { - msg, err = json.Marshal(v) - return msg, TextFrame, err -} - -func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) { - return json.Unmarshal(msg, v) -} - -/* -JSON is a codec to send/receive JSON data in a frame from a WebSocket connection. - -Trivial usage: - - import "websocket" - - type T struct { - Msg string - Count int - } - - // receive JSON type T - var data T - websocket.JSON.Receive(ws, &data) - - // send JSON type T - websocket.JSON.Send(ws, data) -*/ -var JSON = Codec{jsonMarshal, jsonUnmarshal} diff --git a/Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go b/Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go deleted file mode 100644 index a376abacf..000000000 --- a/Godeps/_workspace/src/golang.org/x/net/websocket/websocket_test.go +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package websocket - -import ( - "bytes" - "fmt" - "io" - "log" - "net" - "net/http" - "net/http/httptest" - "net/url" - "strings" - "sync" - "testing" -) - -var serverAddr string -var once sync.Once - -func echoServer(ws *Conn) { io.Copy(ws, ws) } - -type Count struct { - S string - N int -} - -func countServer(ws *Conn) { - for { - var count Count - err := JSON.Receive(ws, &count) - if err != nil { - return - } - count.N++ - count.S = strings.Repeat(count.S, count.N) - err = JSON.Send(ws, count) - if err != nil { - return - } - } -} - -func subProtocolHandshake(config *Config, req *http.Request) error { - for _, proto := range config.Protocol { - if proto == "chat" { - config.Protocol = []string{proto} - return nil - } - } - return ErrBadWebSocketProtocol -} - -func subProtoServer(ws *Conn) { - for _, proto := range ws.Config().Protocol { - io.WriteString(ws, proto) - } -} - -func startServer() { - http.Handle("/echo", Handler(echoServer)) - http.Handle("/count", Handler(countServer)) - subproto := Server{ - Handshake: subProtocolHandshake, - Handler: Handler(subProtoServer), - } - http.Handle("/subproto", subproto) - server := httptest.NewServer(nil) - serverAddr = server.Listener.Addr().String() - log.Print("Test WebSocket server listening on ", serverAddr) -} - -func newConfig(t *testing.T, path string) *Config { - config, _ := NewConfig(fmt.Sprintf("ws://%s%s", serverAddr, path), "http://localhost") - return config -} - -func TestEcho(t *testing.T) { - once.Do(startServer) - - // websocket.Dial() - client, err := net.Dial("tcp", serverAddr) - if err != nil { - t.Fatal("dialing", err) - } - conn, err := NewClient(newConfig(t, "/echo"), client) - if err != nil { - t.Errorf("WebSocket handshake error: %v", err) - return - } - - msg := []byte("hello, world\n") - if _, err := conn.Write(msg); err != nil { - t.Errorf("Write: %v", err) - } - var actual_msg = make([]byte, 512) - n, err := conn.Read(actual_msg) - if err != nil { - t.Errorf("Read: %v", err) - } - actual_msg = actual_msg[0:n] - if !bytes.Equal(msg, actual_msg) { - t.Errorf("Echo: expected %q got %q", msg, actual_msg) - } - conn.Close() -} - -func TestAddr(t *testing.T) { - once.Do(startServer) - - // websocket.Dial() - client, err := net.Dial("tcp", serverAddr) - if err != nil { - t.Fatal("dialing", err) - } - conn, err := NewClient(newConfig(t, "/echo"), client) - if err != nil { - t.Errorf("WebSocket handshake error: %v", err) - return - } - - ra := conn.RemoteAddr().String() - if !strings.HasPrefix(ra, "ws://") || !strings.HasSuffix(ra, "/echo") { - t.Errorf("Bad remote addr: %v", ra) - } - la := conn.LocalAddr().String() - if !strings.HasPrefix(la, "http://") { - t.Errorf("Bad local addr: %v", la) - } - conn.Close() -} - -func TestCount(t *testing.T) { - once.Do(startServer) - - // websocket.Dial() - client, err := net.Dial("tcp", serverAddr) - if err != nil { - t.Fatal("dialing", err) - } - conn, err := NewClient(newConfig(t, "/count"), client) - if err != nil { - t.Errorf("WebSocket handshake error: %v", err) - return - } - - var count Count - count.S = "hello" - if err := JSON.Send(conn, count); err != nil { - t.Errorf("Write: %v", err) - } - if err := JSON.Receive(conn, &count); err != nil { - t.Errorf("Read: %v", err) - } - if count.N != 1 { - t.Errorf("count: expected %d got %d", 1, count.N) - } - if count.S != "hello" { - t.Errorf("count: expected %q got %q", "hello", count.S) - } - if err := JSON.Send(conn, count); err != nil { - t.Errorf("Write: %v", err) - } - if err := JSON.Receive(conn, &count); err != nil { - t.Errorf("Read: %v", err) - } - if count.N != 2 { - t.Errorf("count: expected %d got %d", 2, count.N) - } - if count.S != "hellohello" { - t.Errorf("count: expected %q got %q", "hellohello", count.S) - } - conn.Close() -} - -func TestWithQuery(t *testing.T) { - once.Do(startServer) - - client, err := net.Dial("tcp", serverAddr) - if err != nil { - t.Fatal("dialing", err) - } - - config := newConfig(t, "/echo") - config.Location, err = url.ParseRequestURI(fmt.Sprintf("ws://%s/echo?q=v", serverAddr)) - if err != nil { - t.Fatal("location url", err) - } - - ws, err := NewClient(config, client) - if err != nil { - t.Errorf("WebSocket handshake: %v", err) - return - } - ws.Close() -} - -func testWithProtocol(t *testing.T, subproto []string) (string, error) { - once.Do(startServer) - - client, err := net.Dial("tcp", serverAddr) - if err != nil { - t.Fatal("dialing", err) - } - - config := newConfig(t, "/subproto") - config.Protocol = subproto - - ws, err := NewClient(config, client) - if err != nil { - return "", err - } - msg := make([]byte, 16) - n, err := ws.Read(msg) - if err != nil { - return "", err - } - ws.Close() - return string(msg[:n]), nil -} - -func TestWithProtocol(t *testing.T) { - proto, err := testWithProtocol(t, []string{"chat"}) - if err != nil { - t.Errorf("SubProto: unexpected error: %v", err) - } - if proto != "chat" { - t.Errorf("SubProto: expected %q, got %q", "chat", proto) - } -} - -func TestWithTwoProtocol(t *testing.T) { - proto, err := testWithProtocol(t, []string{"test", "chat"}) - if err != nil { - t.Errorf("SubProto: unexpected error: %v", err) - } - if proto != "chat" { - t.Errorf("SubProto: expected %q, got %q", "chat", proto) - } -} - -func TestWithBadProtocol(t *testing.T) { - _, err := testWithProtocol(t, []string{"test"}) - if err != ErrBadStatus { - t.Errorf("SubProto: expected %v, got %v", ErrBadStatus, err) - } -} - -func TestHTTP(t *testing.T) { - once.Do(startServer) - - // If the client did not send a handshake that matches the protocol - // specification, the server MUST return an HTTP response with an - // appropriate error code (such as 400 Bad Request) - resp, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr)) - if err != nil { - t.Errorf("Get: error %#v", err) - return - } - if resp == nil { - t.Error("Get: resp is null") - return - } - if resp.StatusCode != http.StatusBadRequest { - t.Errorf("Get: expected %q got %q", http.StatusBadRequest, resp.StatusCode) - } -} - -func TestTrailingSpaces(t *testing.T) { - // http://code.google.com/p/go/issues/detail?id=955 - // The last runs of this create keys with trailing spaces that should not be - // generated by the client. - once.Do(startServer) - config := newConfig(t, "/echo") - for i := 0; i < 30; i++ { - // body - ws, err := DialConfig(config) - if err != nil { - t.Errorf("Dial #%d failed: %v", i, err) - break - } - ws.Close() - } -} - -func TestDialConfigBadVersion(t *testing.T) { - once.Do(startServer) - config := newConfig(t, "/echo") - config.Version = 1234 - - _, err := DialConfig(config) - - if dialerr, ok := err.(*DialError); ok { - if dialerr.Err != ErrBadProtocolVersion { - t.Errorf("dial expected err %q but got %q", ErrBadProtocolVersion, dialerr.Err) - } - } -} - -func TestSmallBuffer(t *testing.T) { - // http://code.google.com/p/go/issues/detail?id=1145 - // Read should be able to handle reading a fragment of a frame. - once.Do(startServer) - - // websocket.Dial() - client, err := net.Dial("tcp", serverAddr) - if err != nil { - t.Fatal("dialing", err) - } - conn, err := NewClient(newConfig(t, "/echo"), client) - if err != nil { - t.Errorf("WebSocket handshake error: %v", err) - return - } - - msg := []byte("hello, world\n") - if _, err := conn.Write(msg); err != nil { - t.Errorf("Write: %v", err) - } - var small_msg = make([]byte, 8) - n, err := conn.Read(small_msg) - if err != nil { - t.Errorf("Read: %v", err) - } - if !bytes.Equal(msg[:len(small_msg)], small_msg) { - t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg) - } - var second_msg = make([]byte, len(msg)) - n, err = conn.Read(second_msg) - if err != nil { - t.Errorf("Read: %v", err) - } - second_msg = second_msg[0:n] - if !bytes.Equal(msg[len(small_msg):], second_msg) { - t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg) - } - conn.Close() -} - -var parseAuthorityTests = []struct { - in *url.URL - out string -}{ - { - &url.URL{ - Scheme: "ws", - Host: "www.google.com", - }, - "www.google.com:80", - }, - { - &url.URL{ - Scheme: "wss", - Host: "www.google.com", - }, - "www.google.com:443", - }, - { - &url.URL{ - Scheme: "ws", - Host: "www.google.com:80", - }, - "www.google.com:80", - }, - { - &url.URL{ - Scheme: "wss", - Host: "www.google.com:443", - }, - "www.google.com:443", - }, - // some invalid ones for parseAuthority. parseAuthority doesn't - // concern itself with the scheme unless it actually knows about it - { - &url.URL{ - Scheme: "http", - Host: "www.google.com", - }, - "www.google.com", - }, - { - &url.URL{ - Scheme: "http", - Host: "www.google.com:80", - }, - "www.google.com:80", - }, - { - &url.URL{ - Scheme: "asdf", - Host: "127.0.0.1", - }, - "127.0.0.1", - }, - { - &url.URL{ - Scheme: "asdf", - Host: "www.google.com", - }, - "www.google.com", - }, -} - -func TestParseAuthority(t *testing.T) { - for _, tt := range parseAuthorityTests { - out := parseAuthority(tt.in) - if out != tt.out { - t.Errorf("got %v; want %v", out, tt.out) - } - } -} From bae7e93a9c5af679682f89b0f475e98c1eee9e58 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Mar 2015 03:00:41 +0100 Subject: [PATCH 3/7] cmd/ethereum: improve command line interface The ethereum command line interface is now structured using subcommands. These separate the different tasks it can perform. Almost all flag names are backwards compatible. The key tasks have not been ported to subcommands since they will be replaced by the new accounts infrastructure very soon. --- Godeps/Godeps.json | 5 + .../github.com/codegangsta/cli/.travis.yml | 6 + .../src/github.com/codegangsta/cli/LICENSE | 21 + .../src/github.com/codegangsta/cli/README.md | 298 +++++++ .../src/github.com/codegangsta/cli/app.go | 296 +++++++ .../github.com/codegangsta/cli/app_test.go | 619 +++++++++++++++ .../cli/autocomplete/bash_autocomplete | 13 + .../cli/autocomplete/zsh_autocomplete | 5 + .../src/github.com/codegangsta/cli/cli.go | 19 + .../github.com/codegangsta/cli/cli_test.go | 100 +++ .../src/github.com/codegangsta/cli/command.go | 160 ++++ .../codegangsta/cli/command_test.go | 49 ++ .../src/github.com/codegangsta/cli/context.go | 339 ++++++++ .../codegangsta/cli/context_test.go | 99 +++ .../src/github.com/codegangsta/cli/flag.go | 454 +++++++++++ .../github.com/codegangsta/cli/flag_test.go | 742 ++++++++++++++++++ .../src/github.com/codegangsta/cli/help.go | 211 +++++ .../codegangsta/cli/helpers_test.go | 19 + cmd/ethereum/flags.go | 168 ---- cmd/ethereum/{cmd.go => js.go} | 13 +- cmd/ethereum/main.go | 268 ++++--- cmd/utils/cmd.go | 25 +- cmd/utils/flags.go | 178 +++++ 23 files changed, 3820 insertions(+), 287 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/README.md create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/app.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/cli.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/command.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/context.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/flag.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/help.go create mode 100644 Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go delete mode 100644 cmd/ethereum/flags.go rename cmd/ethereum/{cmd.go => js.go} (79%) create mode 100644 cmd/utils/flags.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index f0a3448c7..bf5b59c95 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -15,6 +15,11 @@ "Comment": "null-15", "Rev": "12e4b4183793ac4b061921e7980845e750679fd0" }, + { + "ImportPath": "github.com/codegangsta/cli", + "Comment": "1.2.0-74-g50c77ec", + "Rev": "50c77ecec0068c9aef9d90ae0fd0fdf410041da3" + }, { "ImportPath": "github.com/ethereum/ethash", "Comment": "v17-23-g2561e13", diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml new file mode 100644 index 000000000..baf46abc6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/.travis.yml @@ -0,0 +1,6 @@ +language: go +go: 1.1 + +script: +- go vet ./... +- go test -v ./... diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE b/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE new file mode 100644 index 000000000..5515ccfb7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/LICENSE @@ -0,0 +1,21 @@ +Copyright (C) 2013 Jeremy Saenz +All Rights Reserved. + +MIT LICENSE + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/README.md b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md new file mode 100644 index 000000000..c0bb338ab --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/README.md @@ -0,0 +1,298 @@ +[![Build Status](https://travis-ci.org/codegangsta/cli.png?branch=master)](https://travis-ci.org/codegangsta/cli) + +# cli.go +cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way. + +You can view the API docs here: +http://godoc.org/github.com/codegangsta/cli + +## Overview +Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app. + +**This is where cli.go comes into play.** cli.go makes command line programming fun, organized, and expressive! + +## Installation +Make sure you have a working Go environment (go 1.1 is *required*). [See the install instructions](http://golang.org/doc/install.html). + +To install `cli.go`, simply run: +``` +$ go get github.com/codegangsta/cli +``` + +Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used: +``` +export PATH=$PATH:$GOPATH/bin +``` + +## Getting Started +One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`. + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + cli.NewApp().Run(os.Args) +} +``` + +This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation: + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + app := cli.NewApp() + app.Name = "boom" + app.Usage = "make an explosive entrance" + app.Action = func(c *cli.Context) { + println("boom! I say!") + } + + app.Run(os.Args) +} +``` + +Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below. + +## Example + +Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness! + +Start by creating a directory named `greet`, and within it, add a file, `greet.go` with the following code in it: + +``` go +package main + +import ( + "os" + "github.com/codegangsta/cli" +) + +func main() { + app := cli.NewApp() + app.Name = "greet" + app.Usage = "fight the loneliness!" + app.Action = func(c *cli.Context) { + println("Hello friend!") + } + + app.Run(os.Args) +} +``` + +Install our command to the `$GOPATH/bin` directory: + +``` +$ go install +``` + +Finally run our new command: + +``` +$ greet +Hello friend! +``` + +cli.go also generates some bitchass help text: +``` +$ greet help +NAME: + greet - fight the loneliness! + +USAGE: + greet [global options] command [command options] [arguments...] + +VERSION: + 0.0.0 + +COMMANDS: + help, h Shows a list of commands or help for one command + +GLOBAL OPTIONS + --version Shows version information +``` + +### Arguments +You can lookup arguments by calling the `Args` function on `cli.Context`. + +``` go +... +app.Action = func(c *cli.Context) { + println("Hello", c.Args()[0]) +} +... +``` + +### Flags +Setting and querying flags is simple. +``` go +... +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, +} +app.Action = func(c *cli.Context) { + name := "someone" + if len(c.Args()) > 0 { + name = c.Args()[0] + } + if c.String("lang") == "spanish" { + println("Hola", name) + } else { + println("Hello", name) + } +} +... +``` + +#### Alternate Names + +You can set alternate (or short) names for flags by providing a comma-delimited list for the `Name`. e.g. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + }, +} +``` + +That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error. + +#### Values from the Environment + +You can also have the default value set from the environment via `EnvVar`. e.g. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "APP_LANG", + }, +} +``` + +The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default. + +``` go +app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang, l", + Value: "english", + Usage: "language for the greeting", + EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG", + }, +} +``` + +### Subcommands + +Subcommands can be defined for a more git-like command line app. +```go +... +app.Commands = []cli.Command{ + { + Name: "add", + ShortName: "a", + Usage: "add a task to the list", + Action: func(c *cli.Context) { + println("added task: ", c.Args().First()) + }, + }, + { + Name: "complete", + ShortName: "c", + Usage: "complete a task on the list", + Action: func(c *cli.Context) { + println("completed task: ", c.Args().First()) + }, + }, + { + Name: "template", + ShortName: "r", + Usage: "options for task templates", + Subcommands: []cli.Command{ + { + Name: "add", + Usage: "add a new template", + Action: func(c *cli.Context) { + println("new task template: ", c.Args().First()) + }, + }, + { + Name: "remove", + Usage: "remove an existing template", + Action: func(c *cli.Context) { + println("removed task template: ", c.Args().First()) + }, + }, + }, + }, +} +... +``` + +### Bash Completion + +You can enable completion commands by setting the `EnableBashCompletion` +flag on the `App` object. By default, this setting will only auto-complete to +show an app's subcommands, but you can write your own completion methods for +the App or its subcommands. +```go +... +var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"} +app := cli.NewApp() +app.EnableBashCompletion = true +app.Commands = []cli.Command{ + { + Name: "complete", + ShortName: "c", + Usage: "complete a task on the list", + Action: func(c *cli.Context) { + println("completed task: ", c.Args().First()) + }, + BashComplete: func(c *cli.Context) { + // This will complete if no args are passed + if len(c.Args()) > 0 { + return + } + for _, t := range tasks { + fmt.Println(t) + } + }, + } +} +... +``` + +#### To Enable + +Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while +setting the `PROG` variable to the name of your program: + +`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` + + +## Contribution Guidelines +Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch. + +If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together. + +If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out. diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/app.go b/Godeps/_workspace/src/github.com/codegangsta/cli/app.go new file mode 100644 index 000000000..928983ebd --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/app.go @@ -0,0 +1,296 @@ +package cli + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "text/tabwriter" + "text/template" + "time" +) + +// App is the main structure of a cli application. It is recomended that +// and app be created with the cli.NewApp() function +type App struct { + // The name of the program. Defaults to os.Args[0] + Name string + // Description of the program. + Usage string + // Version of the program + Version string + // List of commands to execute + Commands []Command + // List of flags to parse + Flags []Flag + // Boolean to enable bash completion commands + EnableBashCompletion bool + // Boolean to hide built-in help command + HideHelp bool + // Boolean to hide built-in version flag + HideVersion bool + // An action to execute when the bash-completion flag is set + BashComplete func(context *Context) + // An action to execute before any subcommands are run, but after the context is ready + // If a non-nil error is returned, no subcommands are run + Before func(context *Context) error + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After func(context *Context) error + // The action to execute when no subcommands are specified + Action func(context *Context) + // Execute this function if the proper command cannot be found + CommandNotFound func(context *Context, command string) + // Compilation date + Compiled time.Time + // Author + Author string + // Author e-mail + Email string + // Writer writer to write output to + Writer io.Writer +} + +// Tries to find out when this binary was compiled. +// Returns the current time if it fails to find it. +func compileTime() time.Time { + info, err := os.Stat(os.Args[0]) + if err != nil { + return time.Now() + } + return info.ModTime() +} + +// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action. +func NewApp() *App { + return &App{ + Name: os.Args[0], + Usage: "A new cli application", + Version: "0.0.0", + BashComplete: DefaultAppComplete, + Action: helpCommand.Action, + Compiled: compileTime(), + Author: "Author", + Email: "unknown@email", + Writer: os.Stdout, + } +} + +// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination +func (a *App) Run(arguments []string) (err error) { + if HelpPrinter == nil { + defer func() { + HelpPrinter = nil + }() + + HelpPrinter = func(templ string, data interface{}) { + w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0) + t := template.Must(template.New("help").Parse(templ)) + err := t.Execute(w, data) + if err != nil { + panic(err) + } + w.Flush() + } + } + + // append help to commands + if a.Command(helpCommand.Name) == nil && !a.HideHelp { + a.Commands = append(a.Commands, helpCommand) + if (HelpFlag != BoolFlag{}) { + a.appendFlag(HelpFlag) + } + } + + //append version/help flags + if a.EnableBashCompletion { + a.appendFlag(BashCompletionFlag) + } + + if !a.HideVersion { + a.appendFlag(VersionFlag) + } + + // parse flags + set := flagSet(a.Name, a.Flags) + set.SetOutput(ioutil.Discard) + err = set.Parse(arguments[1:]) + nerr := normalizeFlags(a.Flags, set) + if nerr != nil { + fmt.Fprintln(a.Writer, nerr) + context := NewContext(a, set, set) + ShowAppHelp(context) + fmt.Fprintln(a.Writer) + return nerr + } + context := NewContext(a, set, set) + + if err != nil { + fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n") + ShowAppHelp(context) + fmt.Fprintln(a.Writer) + return err + } + + if checkCompletions(context) { + return nil + } + + if checkHelp(context) { + return nil + } + + if checkVersion(context) { + return nil + } + + if a.After != nil { + defer func() { + // err is always nil here. + // There is a check to see if it is non-nil + // just few lines before. + err = a.After(context) + }() + } + + if a.Before != nil { + err := a.Before(context) + if err != nil { + return err + } + } + + args := context.Args() + if args.Present() { + name := args.First() + c := a.Command(name) + if c != nil { + return c.Run(context) + } + } + + // Run default Action + a.Action(context) + return nil +} + +// Another entry point to the cli app, takes care of passing arguments and error handling +func (a *App) RunAndExitOnError() { + if err := a.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags +func (a *App) RunAsSubcommand(ctx *Context) (err error) { + // append help to commands + if len(a.Commands) > 0 { + if a.Command(helpCommand.Name) == nil && !a.HideHelp { + a.Commands = append(a.Commands, helpCommand) + if (HelpFlag != BoolFlag{}) { + a.appendFlag(HelpFlag) + } + } + } + + // append flags + if a.EnableBashCompletion { + a.appendFlag(BashCompletionFlag) + } + + // parse flags + set := flagSet(a.Name, a.Flags) + set.SetOutput(ioutil.Discard) + err = set.Parse(ctx.Args().Tail()) + nerr := normalizeFlags(a.Flags, set) + context := NewContext(a, set, ctx.globalSet) + + if nerr != nil { + fmt.Fprintln(a.Writer, nerr) + if len(a.Commands) > 0 { + ShowSubcommandHelp(context) + } else { + ShowCommandHelp(ctx, context.Args().First()) + } + fmt.Fprintln(a.Writer) + return nerr + } + + if err != nil { + fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n") + ShowSubcommandHelp(context) + return err + } + + if checkCompletions(context) { + return nil + } + + if len(a.Commands) > 0 { + if checkSubcommandHelp(context) { + return nil + } + } else { + if checkCommandHelp(ctx, context.Args().First()) { + return nil + } + } + + if a.After != nil { + defer func() { + // err is always nil here. + // There is a check to see if it is non-nil + // just few lines before. + err = a.After(context) + }() + } + + if a.Before != nil { + err := a.Before(context) + if err != nil { + return err + } + } + + args := context.Args() + if args.Present() { + name := args.First() + c := a.Command(name) + if c != nil { + return c.Run(context) + } + } + + // Run default Action + a.Action(context) + + return nil +} + +// Returns the named command on App. Returns nil if the command does not exist +func (a *App) Command(name string) *Command { + for _, c := range a.Commands { + if c.HasName(name) { + return &c + } + } + + return nil +} + +func (a *App) hasFlag(flag Flag) bool { + for _, f := range a.Flags { + if flag == f { + return true + } + } + + return false +} + +func (a *App) appendFlag(flag Flag) { + if !a.hasFlag(flag) { + a.Flags = append(a.Flags, flag) + } +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go new file mode 100644 index 000000000..fd2b0e826 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/app_test.go @@ -0,0 +1,619 @@ +package cli_test + +import ( + "flag" + "fmt" + "os" + "testing" + + "github.com/codegangsta/cli" +) + +func ExampleApp() { + // set args for examples sake + os.Args = []string{"greet", "--name", "Jeremy"} + + app := cli.NewApp() + app.Name = "greet" + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + } + app.Action = func(c *cli.Context) { + fmt.Printf("Hello %v\n", c.String("name")) + } + app.Run(os.Args) + // Output: + // Hello Jeremy +} + +func ExampleAppSubcommand() { + // set args for examples sake + os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} + app := cli.NewApp() + app.Name = "say" + app.Commands = []cli.Command{ + { + Name: "hello", + ShortName: "hi", + Usage: "use it to see a description", + Description: "This is how we describe hello the function", + Subcommands: []cli.Command{ + { + Name: "english", + ShortName: "en", + Usage: "sends a greeting in english", + Description: "greets someone in english", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, + }, + Action: func(c *cli.Context) { + fmt.Println("Hello,", c.String("name")) + }, + }, + }, + }, + } + + app.Run(os.Args) + // Output: + // Hello, Jeremy +} + +func ExampleAppHelp() { + // set args for examples sake + os.Args = []string{"greet", "h", "describeit"} + + app := cli.NewApp() + app.Name = "greet" + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + } + app.Commands = []cli.Command{ + { + Name: "describeit", + ShortName: "d", + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(c *cli.Context) { + fmt.Printf("i like to describe things") + }, + }, + } + app.Run(os.Args) + // Output: + // NAME: + // describeit - use it to see a description + // + // USAGE: + // command describeit [arguments...] + // + // DESCRIPTION: + // This is how we describe describeit the function +} + +func ExampleAppBashComplete() { + // set args for examples sake + os.Args = []string{"greet", "--generate-bash-completion"} + + app := cli.NewApp() + app.Name = "greet" + app.EnableBashCompletion = true + app.Commands = []cli.Command{ + { + Name: "describeit", + ShortName: "d", + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(c *cli.Context) { + fmt.Printf("i like to describe things") + }, + }, { + Name: "next", + Usage: "next example", + Description: "more stuff to see when generating bash completion", + Action: func(c *cli.Context) { + fmt.Printf("the next example") + }, + }, + } + + app.Run(os.Args) + // Output: + // describeit + // d + // next + // help + // h +} + +func TestApp_Run(t *testing.T) { + s := "" + + app := cli.NewApp() + app.Action = func(c *cli.Context) { + s = s + c.Args().First() + } + + err := app.Run([]string{"command", "foo"}) + expect(t, err, nil) + err = app.Run([]string{"command", "bar"}) + expect(t, err, nil) + expect(t, s, "foobar") +} + +var commandAppTests = []struct { + name string + expected bool +}{ + {"foobar", true}, + {"batbaz", true}, + {"b", true}, + {"f", true}, + {"bat", false}, + {"nothing", false}, +} + +func TestApp_Command(t *testing.T) { + app := cli.NewApp() + fooCommand := cli.Command{Name: "foobar", ShortName: "f"} + batCommand := cli.Command{Name: "batbaz", ShortName: "b"} + app.Commands = []cli.Command{ + fooCommand, + batCommand, + } + + for _, test := range commandAppTests { + expect(t, app.Command(test.name) != nil, test.expected) + } +} + +func TestApp_CommandWithArgBeforeFlags(t *testing.T) { + var parsedOption, firstArg string + + app := cli.NewApp() + command := cli.Command{ + Name: "cmd", + Flags: []cli.Flag{ + cli.StringFlag{Name: "option", Value: "", Usage: "some option"}, + }, + Action: func(c *cli.Context) { + parsedOption = c.String("option") + firstArg = c.Args().First() + }, + } + app.Commands = []cli.Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"}) + + expect(t, parsedOption, "my-option") + expect(t, firstArg, "my-arg") +} + +func TestApp_RunAsSubcommandParseFlags(t *testing.T) { + var context *cli.Context + + a := cli.NewApp() + a.Commands = []cli.Command{ + { + Name: "foo", + Action: func(c *cli.Context) { + context = c + }, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, + }, + Before: func(_ *cli.Context) error { return nil }, + }, + } + a.Run([]string{"", "foo", "--lang", "spanish", "abcd"}) + + expect(t, context.Args().Get(0), "abcd") + expect(t, context.String("lang"), "spanish") +} + +func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) { + var parsedOption string + var args []string + + app := cli.NewApp() + command := cli.Command{ + Name: "cmd", + Flags: []cli.Flag{ + cli.StringFlag{Name: "option", Value: "", Usage: "some option"}, + }, + Action: func(c *cli.Context) { + parsedOption = c.String("option") + args = c.Args() + }, + } + app.Commands = []cli.Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"}) + + expect(t, parsedOption, "my-option") + expect(t, args[0], "my-arg") + expect(t, args[1], "--") + expect(t, args[2], "--notARealFlag") +} + +func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) { + var args []string + + app := cli.NewApp() + command := cli.Command{ + Name: "cmd", + Action: func(c *cli.Context) { + args = c.Args() + }, + } + app.Commands = []cli.Command{command} + + app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"}) + + expect(t, args[0], "my-arg") + expect(t, args[1], "--") + expect(t, args[2], "notAFlagAtAll") +} + +func TestApp_Float64Flag(t *testing.T) { + var meters float64 + + app := cli.NewApp() + app.Flags = []cli.Flag{ + cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"}, + } + app.Action = func(c *cli.Context) { + meters = c.Float64("height") + } + + app.Run([]string{"", "--height", "1.93"}) + expect(t, meters, 1.93) +} + +func TestApp_ParseSliceFlags(t *testing.T) { + var parsedOption, firstArg string + var parsedIntSlice []int + var parsedStringSlice []string + + app := cli.NewApp() + command := cli.Command{ + Name: "cmd", + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"}, + cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"}, + }, + Action: func(c *cli.Context) { + parsedIntSlice = c.IntSlice("p") + parsedStringSlice = c.StringSlice("ip") + parsedOption = c.String("option") + firstArg = c.Args().First() + }, + } + app.Commands = []cli.Command{command} + + app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"}) + + IntsEquals := func(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true + } + + StrsEquals := func(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true + } + var expectedIntSlice = []int{22, 80} + var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"} + + if !IntsEquals(parsedIntSlice, expectedIntSlice) { + t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice) + } + + if !StrsEquals(parsedStringSlice, expectedStringSlice) { + t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice) + } +} + +func TestApp_DefaultStdout(t *testing.T) { + app := cli.NewApp() + + if app.Writer != os.Stdout { + t.Error("Default output writer not set.") + } +} + +type mockWriter struct { + written []byte +} + +func (fw *mockWriter) Write(p []byte) (n int, err error) { + if fw.written == nil { + fw.written = p + } else { + fw.written = append(fw.written, p...) + } + + return len(p), nil +} + +func (fw *mockWriter) GetWritten() (b []byte) { + return fw.written +} + +func TestApp_SetStdout(t *testing.T) { + w := &mockWriter{} + + app := cli.NewApp() + app.Name = "test" + app.Writer = w + + err := app.Run([]string{"help"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if len(w.written) == 0 { + t.Error("App did not write output to desired writer.") + } +} + +func TestApp_BeforeFunc(t *testing.T) { + beforeRun, subcommandRun := false, false + beforeError := fmt.Errorf("fail") + var err error + + app := cli.NewApp() + + app.Before = func(c *cli.Context) error { + beforeRun = true + s := c.String("opt") + if s == "fail" { + return beforeError + } + + return nil + } + + app.Commands = []cli.Command{ + cli.Command{ + Name: "sub", + Action: func(c *cli.Context) { + subcommandRun = true + }, + }, + } + + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "opt"}, + } + + // run with the Before() func succeeding + err = app.Run([]string{"command", "--opt", "succeed", "sub"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if beforeRun == false { + t.Errorf("Before() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } + + // reset + beforeRun, subcommandRun = false, false + + // run with the Before() func failing + err = app.Run([]string{"command", "--opt", "fail", "sub"}) + + // should be the same error produced by the Before func + if err != beforeError { + t.Errorf("Run error expected, but not received") + } + + if beforeRun == false { + t.Errorf("Before() not executed when expected") + } + + if subcommandRun == true { + t.Errorf("Subcommand executed when NOT expected") + } + +} + +func TestApp_AfterFunc(t *testing.T) { + afterRun, subcommandRun := false, false + afterError := fmt.Errorf("fail") + var err error + + app := cli.NewApp() + + app.After = func(c *cli.Context) error { + afterRun = true + s := c.String("opt") + if s == "fail" { + return afterError + } + + return nil + } + + app.Commands = []cli.Command{ + cli.Command{ + Name: "sub", + Action: func(c *cli.Context) { + subcommandRun = true + }, + }, + } + + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "opt"}, + } + + // run with the After() func succeeding + err = app.Run([]string{"command", "--opt", "succeed", "sub"}) + + if err != nil { + t.Fatalf("Run error: %s", err) + } + + if afterRun == false { + t.Errorf("After() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } + + // reset + afterRun, subcommandRun = false, false + + // run with the Before() func failing + err = app.Run([]string{"command", "--opt", "fail", "sub"}) + + // should be the same error produced by the Before func + if err != afterError { + t.Errorf("Run error expected, but not received") + } + + if afterRun == false { + t.Errorf("After() not executed when expected") + } + + if subcommandRun == false { + t.Errorf("Subcommand not executed when expected") + } +} + +func TestAppNoHelpFlag(t *testing.T) { + oldFlag := cli.HelpFlag + defer func() { + cli.HelpFlag = oldFlag + }() + + cli.HelpFlag = cli.BoolFlag{} + + app := cli.NewApp() + err := app.Run([]string{"test", "-h"}) + + if err != flag.ErrHelp { + t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err) + } +} + +func TestAppHelpPrinter(t *testing.T) { + oldPrinter := cli.HelpPrinter + defer func() { + cli.HelpPrinter = oldPrinter + }() + + var wasCalled = false + cli.HelpPrinter = func(template string, data interface{}) { + wasCalled = true + } + + app := cli.NewApp() + app.Run([]string{"-h"}) + + if wasCalled == false { + t.Errorf("Help printer expected to be called, but was not") + } +} + +func TestAppVersionPrinter(t *testing.T) { + oldPrinter := cli.VersionPrinter + defer func() { + cli.VersionPrinter = oldPrinter + }() + + var wasCalled = false + cli.VersionPrinter = func(c *cli.Context) { + wasCalled = true + } + + app := cli.NewApp() + ctx := cli.NewContext(app, nil, nil) + cli.ShowVersion(ctx) + + if wasCalled == false { + t.Errorf("Version printer expected to be called, but was not") + } +} + +func TestAppCommandNotFound(t *testing.T) { + beforeRun, subcommandRun := false, false + app := cli.NewApp() + + app.CommandNotFound = func(c *cli.Context, command string) { + beforeRun = true + } + + app.Commands = []cli.Command{ + cli.Command{ + Name: "bar", + Action: func(c *cli.Context) { + subcommandRun = true + }, + }, + } + + app.Run([]string{"command", "foo"}) + + expect(t, beforeRun, true) + expect(t, subcommandRun, false) +} + +func TestGlobalFlagsInSubcommands(t *testing.T) { + subcommandRun := false + app := cli.NewApp() + + app.Flags = []cli.Flag{ + cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"}, + } + + app.Commands = []cli.Command{ + cli.Command{ + Name: "foo", + Subcommands: []cli.Command{ + { + Name: "bar", + Action: func(c *cli.Context) { + if c.GlobalBool("debug") { + subcommandRun = true + } + }, + }, + }, + }, + } + + app.Run([]string{"command", "-d", "foo", "bar"}) + + expect(t, subcommandRun, true) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete new file mode 100644 index 000000000..9b55dd990 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete @@ -0,0 +1,13 @@ +#! /bin/bash + +_cli_bash_autocomplete() { + local cur prev opts base + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + } + + complete -F _cli_bash_autocomplete $PROG \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete new file mode 100644 index 000000000..5430a18f9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/autocomplete/zsh_autocomplete @@ -0,0 +1,5 @@ +autoload -U compinit && compinit +autoload -U bashcompinit && bashcompinit + +script_dir=$(dirname $0) +source ${script_dir}/bash_autocomplete diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go b/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go new file mode 100644 index 000000000..b74254581 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/cli.go @@ -0,0 +1,19 @@ +// Package cli provides a minimal framework for creating and organizing command line +// Go applications. cli is designed to be easy to understand and write, the most simple +// cli application can be written as follows: +// func main() { +// cli.NewApp().Run(os.Args) +// } +// +// Of course this application does not do much, so let's make this an actual application: +// func main() { +// app := cli.NewApp() +// app.Name = "greet" +// app.Usage = "say a greeting" +// app.Action = func(c *cli.Context) { +// println("Greetings") +// } +// +// app.Run(os.Args) +// } +package cli diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go new file mode 100644 index 000000000..879a793dc --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/cli_test.go @@ -0,0 +1,100 @@ +package cli_test + +import ( + "os" + + "github.com/codegangsta/cli" +) + +func Example() { + app := cli.NewApp() + app.Name = "todo" + app.Usage = "task list on the command line" + app.Commands = []cli.Command{ + { + Name: "add", + ShortName: "a", + Usage: "add a task to the list", + Action: func(c *cli.Context) { + println("added task: ", c.Args().First()) + }, + }, + { + Name: "complete", + ShortName: "c", + Usage: "complete a task on the list", + Action: func(c *cli.Context) { + println("completed task: ", c.Args().First()) + }, + }, + } + + app.Run(os.Args) +} + +func ExampleSubcommand() { + app := cli.NewApp() + app.Name = "say" + app.Commands = []cli.Command{ + { + Name: "hello", + ShortName: "hi", + Usage: "use it to see a description", + Description: "This is how we describe hello the function", + Subcommands: []cli.Command{ + { + Name: "english", + ShortName: "en", + Usage: "sends a greeting in english", + Description: "greets someone in english", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, + }, + Action: func(c *cli.Context) { + println("Hello, ", c.String("name")) + }, + }, { + Name: "spanish", + ShortName: "sp", + Usage: "sends a greeting in spanish", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "surname", + Value: "Jones", + Usage: "Surname of the person to greet", + }, + }, + Action: func(c *cli.Context) { + println("Hola, ", c.String("surname")) + }, + }, { + Name: "french", + ShortName: "fr", + Usage: "sends a greeting in french", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "nickname", + Value: "Stevie", + Usage: "Nickname of the person to greet", + }, + }, + Action: func(c *cli.Context) { + println("Bonjour, ", c.String("nickname")) + }, + }, + }, + }, { + Name: "bye", + Usage: "says goodbye", + Action: func(c *cli.Context) { + println("bye") + }, + }, + } + + app.Run(os.Args) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/command.go b/Godeps/_workspace/src/github.com/codegangsta/cli/command.go new file mode 100644 index 000000000..5747e52e8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/command.go @@ -0,0 +1,160 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "strings" +) + +// Command is a subcommand for a cli.App. +type Command struct { + // The name of the command + Name string + // short name of the command. Typically one character + ShortName string + // A short description of the usage of this command + Usage string + // A longer explanation of how the command works + Description string + // The function to call when checking for bash command completions + BashComplete func(context *Context) + // An action to execute before any sub-subcommands are run, but after the context is ready + // If a non-nil error is returned, no sub-subcommands are run + Before func(context *Context) error + // An action to execute after any subcommands are run, but after the subcommand has finished + // It is run even if Action() panics + After func(context *Context) error + // The function to call when this command is invoked + Action func(context *Context) + // List of child commands + Subcommands []Command + // List of flags to parse + Flags []Flag + // Treat all flags as normal arguments if true + SkipFlagParsing bool + // Boolean to hide built-in help command + HideHelp bool +} + +// Invokes the command given the context, parses ctx.Args() to generate command-specific flags +func (c Command) Run(ctx *Context) error { + + if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil { + return c.startApp(ctx) + } + + if !c.HideHelp && (HelpFlag != BoolFlag{}) { + // append help to flags + c.Flags = append( + c.Flags, + HelpFlag, + ) + } + + if ctx.App.EnableBashCompletion { + c.Flags = append(c.Flags, BashCompletionFlag) + } + + set := flagSet(c.Name, c.Flags) + set.SetOutput(ioutil.Discard) + + firstFlagIndex := -1 + terminatorIndex := -1 + for index, arg := range ctx.Args() { + if arg == "--" { + terminatorIndex = index + break + } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { + firstFlagIndex = index + } + } + + var err error + if firstFlagIndex > -1 && !c.SkipFlagParsing { + args := ctx.Args() + regularArgs := make([]string, len(args[1:firstFlagIndex])) + copy(regularArgs, args[1:firstFlagIndex]) + + var flagArgs []string + if terminatorIndex > -1 { + flagArgs = args[firstFlagIndex:terminatorIndex] + regularArgs = append(regularArgs, args[terminatorIndex:]...) + } else { + flagArgs = args[firstFlagIndex:] + } + + err = set.Parse(append(flagArgs, regularArgs...)) + } else { + err = set.Parse(ctx.Args().Tail()) + } + + if err != nil { + fmt.Fprint(ctx.App.Writer, "Incorrect Usage.\n\n") + ShowCommandHelp(ctx, c.Name) + fmt.Fprintln(ctx.App.Writer) + return err + } + + nerr := normalizeFlags(c.Flags, set) + if nerr != nil { + fmt.Fprintln(ctx.App.Writer, nerr) + fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) + fmt.Fprintln(ctx.App.Writer) + return nerr + } + context := NewContext(ctx.App, set, ctx.globalSet) + + if checkCommandCompletions(context, c.Name) { + return nil + } + + if checkCommandHelp(context, c.Name) { + return nil + } + context.Command = c + c.Action(context) + return nil +} + +// Returns true if Command.Name or Command.ShortName matches given name +func (c Command) HasName(name string) bool { + return c.Name == name || c.ShortName == name +} + +func (c Command) startApp(ctx *Context) error { + app := NewApp() + + // set the name and usage + app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) + if c.Description != "" { + app.Usage = c.Description + } else { + app.Usage = c.Usage + } + + // set CommandNotFound + app.CommandNotFound = ctx.App.CommandNotFound + + // set the flags and commands + app.Commands = c.Subcommands + app.Flags = c.Flags + app.HideHelp = c.HideHelp + + // bash completion + app.EnableBashCompletion = ctx.App.EnableBashCompletion + if c.BashComplete != nil { + app.BashComplete = c.BashComplete + } + + // set the actions + app.Before = c.Before + app.After = c.After + if c.Action != nil { + app.Action = c.Action + } else { + app.Action = helpSubcommand.Action + } + + return app.RunAsSubcommand(ctx) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go new file mode 100644 index 000000000..c0f556ad2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/command_test.go @@ -0,0 +1,49 @@ +package cli_test + +import ( + "flag" + "testing" + + "github.com/codegangsta/cli" +) + +func TestCommandDoNotIgnoreFlags(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + test := []string{"blah", "blah", "-break"} + set.Parse(test) + + c := cli.NewContext(app, set, set) + + command := cli.Command{ + Name: "test-cmd", + ShortName: "tc", + Usage: "this is for testing", + Description: "testing", + Action: func(_ *cli.Context) {}, + } + err := command.Run(c) + + expect(t, err.Error(), "flag provided but not defined: -break") +} + +func TestCommandIgnoreFlags(t *testing.T) { + app := cli.NewApp() + set := flag.NewFlagSet("test", 0) + test := []string{"blah", "blah"} + set.Parse(test) + + c := cli.NewContext(app, set, set) + + command := cli.Command{ + Name: "test-cmd", + ShortName: "tc", + Usage: "this is for testing", + Description: "testing", + Action: func(_ *cli.Context) {}, + SkipFlagParsing: true, + } + err := command.Run(c) + + expect(t, err, nil) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/context.go b/Godeps/_workspace/src/github.com/codegangsta/cli/context.go new file mode 100644 index 000000000..c9f645b18 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/context.go @@ -0,0 +1,339 @@ +package cli + +import ( + "errors" + "flag" + "strconv" + "strings" + "time" +) + +// Context is a type that is passed through to +// each Handler action in a cli application. Context +// can be used to retrieve context-specific Args and +// parsed command-line options. +type Context struct { + App *App + Command Command + flagSet *flag.FlagSet + globalSet *flag.FlagSet + setFlags map[string]bool + globalSetFlags map[string]bool +} + +// Creates a new context. For use in when invoking an App or Command action. +func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context { + return &Context{App: app, flagSet: set, globalSet: globalSet} +} + +// Looks up the value of a local int flag, returns 0 if no int flag exists +func (c *Context) Int(name string) int { + return lookupInt(name, c.flagSet) +} + +// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists +func (c *Context) Duration(name string) time.Duration { + return lookupDuration(name, c.flagSet) +} + +// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists +func (c *Context) Float64(name string) float64 { + return lookupFloat64(name, c.flagSet) +} + +// Looks up the value of a local bool flag, returns false if no bool flag exists +func (c *Context) Bool(name string) bool { + return lookupBool(name, c.flagSet) +} + +// Looks up the value of a local boolT flag, returns false if no bool flag exists +func (c *Context) BoolT(name string) bool { + return lookupBoolT(name, c.flagSet) +} + +// Looks up the value of a local string flag, returns "" if no string flag exists +func (c *Context) String(name string) string { + return lookupString(name, c.flagSet) +} + +// Looks up the value of a local string slice flag, returns nil if no string slice flag exists +func (c *Context) StringSlice(name string) []string { + return lookupStringSlice(name, c.flagSet) +} + +// Looks up the value of a local int slice flag, returns nil if no int slice flag exists +func (c *Context) IntSlice(name string) []int { + return lookupIntSlice(name, c.flagSet) +} + +// Looks up the value of a local generic flag, returns nil if no generic flag exists +func (c *Context) Generic(name string) interface{} { + return lookupGeneric(name, c.flagSet) +} + +// Looks up the value of a global int flag, returns 0 if no int flag exists +func (c *Context) GlobalInt(name string) int { + return lookupInt(name, c.globalSet) +} + +// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists +func (c *Context) GlobalDuration(name string) time.Duration { + return lookupDuration(name, c.globalSet) +} + +// Looks up the value of a global bool flag, returns false if no bool flag exists +func (c *Context) GlobalBool(name string) bool { + return lookupBool(name, c.globalSet) +} + +// Looks up the value of a global string flag, returns "" if no string flag exists +func (c *Context) GlobalString(name string) string { + return lookupString(name, c.globalSet) +} + +// Looks up the value of a global string slice flag, returns nil if no string slice flag exists +func (c *Context) GlobalStringSlice(name string) []string { + return lookupStringSlice(name, c.globalSet) +} + +// Looks up the value of a global int slice flag, returns nil if no int slice flag exists +func (c *Context) GlobalIntSlice(name string) []int { + return lookupIntSlice(name, c.globalSet) +} + +// Looks up the value of a global generic flag, returns nil if no generic flag exists +func (c *Context) GlobalGeneric(name string) interface{} { + return lookupGeneric(name, c.globalSet) +} + +// Determines if the flag was actually set +func (c *Context) IsSet(name string) bool { + if c.setFlags == nil { + c.setFlags = make(map[string]bool) + c.flagSet.Visit(func(f *flag.Flag) { + c.setFlags[f.Name] = true + }) + } + return c.setFlags[name] == true +} + +// Determines if the global flag was actually set +func (c *Context) GlobalIsSet(name string) bool { + if c.globalSetFlags == nil { + c.globalSetFlags = make(map[string]bool) + c.globalSet.Visit(func(f *flag.Flag) { + c.globalSetFlags[f.Name] = true + }) + } + return c.globalSetFlags[name] == true +} + +// Returns a slice of flag names used in this context. +func (c *Context) FlagNames() (names []string) { + for _, flag := range c.Command.Flags { + name := strings.Split(flag.getName(), ",")[0] + if name == "help" { + continue + } + names = append(names, name) + } + return +} + +// Returns a slice of global flag names used by the app. +func (c *Context) GlobalFlagNames() (names []string) { + for _, flag := range c.App.Flags { + name := strings.Split(flag.getName(), ",")[0] + if name == "help" || name == "version" { + continue + } + names = append(names, name) + } + return +} + +type Args []string + +// Returns the command line arguments associated with the context. +func (c *Context) Args() Args { + args := Args(c.flagSet.Args()) + return args +} + +// Returns the nth argument, or else a blank string +func (a Args) Get(n int) string { + if len(a) > n { + return a[n] + } + return "" +} + +// Returns the first argument, or else a blank string +func (a Args) First() string { + return a.Get(0) +} + +// Return the rest of the arguments (not the first one) +// or else an empty string slice +func (a Args) Tail() []string { + if len(a) >= 2 { + return []string(a)[1:] + } + return []string{} +} + +// Checks if there are any arguments present +func (a Args) Present() bool { + return len(a) != 0 +} + +// Swaps arguments at the given indexes +func (a Args) Swap(from, to int) error { + if from >= len(a) || to >= len(a) { + return errors.New("index out of range") + } + a[from], a[to] = a[to], a[from] + return nil +} + +func lookupInt(name string, set *flag.FlagSet) int { + f := set.Lookup(name) + if f != nil { + val, err := strconv.Atoi(f.Value.String()) + if err != nil { + return 0 + } + return val + } + + return 0 +} + +func lookupDuration(name string, set *flag.FlagSet) time.Duration { + f := set.Lookup(name) + if f != nil { + val, err := time.ParseDuration(f.Value.String()) + if err == nil { + return val + } + } + + return 0 +} + +func lookupFloat64(name string, set *flag.FlagSet) float64 { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseFloat(f.Value.String(), 64) + if err != nil { + return 0 + } + return val + } + + return 0 +} + +func lookupString(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + return f.Value.String() + } + + return "" +} + +func lookupStringSlice(name string, set *flag.FlagSet) []string { + f := set.Lookup(name) + if f != nil { + return (f.Value.(*StringSlice)).Value() + + } + + return nil +} + +func lookupIntSlice(name string, set *flag.FlagSet) []int { + f := set.Lookup(name) + if f != nil { + return (f.Value.(*IntSlice)).Value() + + } + + return nil +} + +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + return f.Value + } + return nil +} + +func lookupBool(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return val + } + + return false +} + +func lookupBoolT(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + val, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return true + } + return val + } + + return false +} + +func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { + switch ff.Value.(type) { + case *StringSlice: + default: + set.Set(name, ff.Value.String()) + } +} + +func normalizeFlags(flags []Flag, set *flag.FlagSet) error { + visited := make(map[string]bool) + set.Visit(func(f *flag.Flag) { + visited[f.Name] = true + }) + for _, f := range flags { + parts := strings.Split(f.getName(), ",") + if len(parts) == 1 { + continue + } + var ff *flag.Flag + for _, name := range parts { + name = strings.Trim(name, " ") + if visited[name] { + if ff != nil { + return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) + } + ff = set.Lookup(name) + } + } + if ff == nil { + continue + } + for _, name := range parts { + name = strings.Trim(name, " ") + if !visited[name] { + copyFlag(name, ff, set) + } + } + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go new file mode 100644 index 000000000..7c9a4436f --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/context_test.go @@ -0,0 +1,99 @@ +package cli_test + +import ( + "flag" + "testing" + "time" + + "github.com/codegangsta/cli" +) + +func TestNewContext(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Int("myflag", 12, "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Int("myflag", 42, "doc") + command := cli.Command{Name: "mycommand"} + c := cli.NewContext(nil, set, globalSet) + c.Command = command + expect(t, c.Int("myflag"), 12) + expect(t, c.GlobalInt("myflag"), 42) + expect(t, c.Command.Name, "mycommand") +} + +func TestContext_Int(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Int("myflag", 12, "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.Int("myflag"), 12) +} + +func TestContext_Duration(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Duration("myflag", time.Duration(12*time.Second), "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.Duration("myflag"), time.Duration(12*time.Second)) +} + +func TestContext_String(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.String("myflag", "hello world", "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.String("myflag"), "hello world") +} + +func TestContext_Bool(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.Bool("myflag"), false) +} + +func TestContext_BoolT(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", true, "doc") + c := cli.NewContext(nil, set, set) + expect(t, c.BoolT("myflag"), true) +} + +func TestContext_Args(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + c := cli.NewContext(nil, set, set) + set.Parse([]string{"--myflag", "bat", "baz"}) + expect(t, len(c.Args()), 2) + expect(t, c.Bool("myflag"), true) +} + +func TestContext_IsSet(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + set.String("otherflag", "hello world", "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Bool("myflagGlobal", true, "doc") + c := cli.NewContext(nil, set, globalSet) + set.Parse([]string{"--myflag", "bat", "baz"}) + globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"}) + expect(t, c.IsSet("myflag"), true) + expect(t, c.IsSet("otherflag"), false) + expect(t, c.IsSet("bogusflag"), false) + expect(t, c.IsSet("myflagGlobal"), false) +} + +func TestContext_GlobalIsSet(t *testing.T) { + set := flag.NewFlagSet("test", 0) + set.Bool("myflag", false, "doc") + set.String("otherflag", "hello world", "doc") + globalSet := flag.NewFlagSet("test", 0) + globalSet.Bool("myflagGlobal", true, "doc") + globalSet.Bool("myflagGlobalUnset", true, "doc") + c := cli.NewContext(nil, set, globalSet) + set.Parse([]string{"--myflag", "bat", "baz"}) + globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"}) + expect(t, c.GlobalIsSet("myflag"), false) + expect(t, c.GlobalIsSet("otherflag"), false) + expect(t, c.GlobalIsSet("bogusflag"), false) + expect(t, c.GlobalIsSet("myflagGlobal"), true) + expect(t, c.GlobalIsSet("myflagGlobalUnset"), false) + expect(t, c.GlobalIsSet("bogusGlobal"), false) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go b/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go new file mode 100644 index 000000000..251158667 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/flag.go @@ -0,0 +1,454 @@ +package cli + +import ( + "flag" + "fmt" + "os" + "strconv" + "strings" + "time" +) + +// This flag enables bash-completion for all commands and subcommands +var BashCompletionFlag = BoolFlag{ + Name: "generate-bash-completion", +} + +// This flag prints the version for the application +var VersionFlag = BoolFlag{ + Name: "version, v", + Usage: "print the version", +} + +// This flag prints the help for all commands and subcommands +// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand +// unless HideHelp is set to true) +var HelpFlag = BoolFlag{ + Name: "help, h", + Usage: "show help", +} + +// Flag is a common interface related to parsing flags in cli. +// For more advanced flag parsing techniques, it is recomended that +// this interface be implemented. +type Flag interface { + fmt.Stringer + // Apply Flag settings to the given flag set + Apply(*flag.FlagSet) + getName() string +} + +func flagSet(name string, flags []Flag) *flag.FlagSet { + set := flag.NewFlagSet(name, flag.ContinueOnError) + + for _, f := range flags { + f.Apply(set) + } + return set +} + +func eachName(longName string, fn func(string)) { + parts := strings.Split(longName, ",") + for _, name := range parts { + name = strings.Trim(name, " ") + fn(name) + } +} + +// Generic is a generic parseable type identified by a specific flag +type Generic interface { + Set(value string) error + String() string +} + +// GenericFlag is the flag type for types implementing Generic +type GenericFlag struct { + Name string + Value Generic + Usage string + EnvVar string +} + +// String returns the string representation of the generic flag to display the +// help text to the user (uses the String() method of the generic flag to show +// the value) +func (f GenericFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage)) +} + +// Apply takes the flagset and calls Set on the generic flag with the value +// provided by the user for parsing by the flag +func (f GenericFlag) Apply(set *flag.FlagSet) { + val := f.Value + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + val.Set(envVal) + break + } + } + } + + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) +} + +func (f GenericFlag) getName() string { + return f.Name +} + +type StringSlice []string + +func (f *StringSlice) Set(value string) error { + *f = append(*f, value) + return nil +} + +func (f *StringSlice) String() string { + return fmt.Sprintf("%s", *f) +} + +func (f *StringSlice) Value() []string { + return *f +} + +type StringSliceFlag struct { + Name string + Value *StringSlice + Usage string + EnvVar string +} + +func (f StringSliceFlag) String() string { + firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") + pref := prefixFor(firstName) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) +} + +func (f StringSliceFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + newVal := &StringSlice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + newVal.Set(s) + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) +} + +func (f StringSliceFlag) getName() string { + return f.Name +} + +type IntSlice []int + +func (f *IntSlice) Set(value string) error { + + tmp, err := strconv.Atoi(value) + if err != nil { + return err + } else { + *f = append(*f, tmp) + } + return nil +} + +func (f *IntSlice) String() string { + return fmt.Sprintf("%d", *f) +} + +func (f *IntSlice) Value() []int { + return *f +} + +type IntSliceFlag struct { + Name string + Value *IntSlice + Usage string + EnvVar string +} + +func (f IntSliceFlag) String() string { + firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") + pref := prefixFor(firstName) + return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) +} + +func (f IntSliceFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + newVal := &IntSlice{} + for _, s := range strings.Split(envVal, ",") { + s = strings.TrimSpace(s) + err := newVal.Set(s) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + } + } + f.Value = newVal + break + } + } + } + + eachName(f.Name, func(name string) { + set.Var(f.Value, name, f.Usage) + }) +} + +func (f IntSliceFlag) getName() string { + return f.Name +} + +type BoolFlag struct { + Name string + Usage string + EnvVar string +} + +func (f BoolFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) +} + +func (f BoolFlag) Apply(set *flag.FlagSet) { + val := false + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValBool, err := strconv.ParseBool(envVal) + if err == nil { + val = envValBool + } + break + } + } + } + + eachName(f.Name, func(name string) { + set.Bool(name, val, f.Usage) + }) +} + +func (f BoolFlag) getName() string { + return f.Name +} + +type BoolTFlag struct { + Name string + Usage string + EnvVar string +} + +func (f BoolTFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)) +} + +func (f BoolTFlag) Apply(set *flag.FlagSet) { + val := true + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValBool, err := strconv.ParseBool(envVal) + if err == nil { + val = envValBool + break + } + } + } + } + + eachName(f.Name, func(name string) { + set.Bool(name, val, f.Usage) + }) +} + +func (f BoolTFlag) getName() string { + return f.Name +} + +type StringFlag struct { + Name string + Value string + Usage string + EnvVar string +} + +func (f StringFlag) String() string { + var fmtString string + fmtString = "%s %v\t%v" + + if len(f.Value) > 0 { + fmtString = "%s \"%v\"\t%v" + } else { + fmtString = "%s %v\t%v" + } + + return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)) +} + +func (f StringFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + f.Value = envVal + break + } + } + } + + eachName(f.Name, func(name string) { + set.String(name, f.Value, f.Usage) + }) +} + +func (f StringFlag) getName() string { + return f.Name +} + +type IntFlag struct { + Name string + Value int + Usage string + EnvVar string +} + +func (f IntFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +func (f IntFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValInt, err := strconv.ParseInt(envVal, 0, 64) + if err == nil { + f.Value = int(envValInt) + break + } + } + } + } + + eachName(f.Name, func(name string) { + set.Int(name, f.Value, f.Usage) + }) +} + +func (f IntFlag) getName() string { + return f.Name +} + +type DurationFlag struct { + Name string + Value time.Duration + Usage string + EnvVar string +} + +func (f DurationFlag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +func (f DurationFlag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValDuration, err := time.ParseDuration(envVal) + if err == nil { + f.Value = envValDuration + break + } + } + } + } + + eachName(f.Name, func(name string) { + set.Duration(name, f.Value, f.Usage) + }) +} + +func (f DurationFlag) getName() string { + return f.Name +} + +type Float64Flag struct { + Name string + Value float64 + Usage string + EnvVar string +} + +func (f Float64Flag) String() string { + return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage)) +} + +func (f Float64Flag) Apply(set *flag.FlagSet) { + if f.EnvVar != "" { + for _, envVar := range strings.Split(f.EnvVar, ",") { + envVar = strings.TrimSpace(envVar) + if envVal := os.Getenv(envVar); envVal != "" { + envValFloat, err := strconv.ParseFloat(envVal, 10) + if err == nil { + f.Value = float64(envValFloat) + } + } + } + } + + eachName(f.Name, func(name string) { + set.Float64(name, f.Value, f.Usage) + }) +} + +func (f Float64Flag) getName() string { + return f.Name +} + +func prefixFor(name string) (prefix string) { + if len(name) == 1 { + prefix = "-" + } else { + prefix = "--" + } + + return +} + +func prefixedNames(fullName string) (prefixed string) { + parts := strings.Split(fullName, ",") + for i, name := range parts { + name = strings.Trim(name, " ") + prefixed += prefixFor(name) + name + if i < len(parts)-1 { + prefixed += ", " + } + } + return +} + +func withEnvHint(envVar, str string) string { + envText := "" + if envVar != "" { + envText = fmt.Sprintf(" [$%s]", strings.Join(strings.Split(envVar, ","), ", $")) + } + return str + envText +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go new file mode 100644 index 000000000..f0f096a2d --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/flag_test.go @@ -0,0 +1,742 @@ +package cli_test + +import ( + "fmt" + "os" + "reflect" + "strings" + "testing" + + "github.com/codegangsta/cli" +) + +var boolFlagTests = []struct { + name string + expected string +}{ + {"help", "--help\t"}, + {"h", "-h\t"}, +} + +func TestBoolFlagHelpOutput(t *testing.T) { + + for _, test := range boolFlagTests { + flag := cli.BoolFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +var stringFlagTests = []struct { + name string + value string + expected string +}{ + {"help", "", "--help \t"}, + {"h", "", "-h \t"}, + {"h", "", "-h \t"}, + {"test", "Something", "--test \"Something\"\t"}, +} + +func TestStringFlagHelpOutput(t *testing.T) { + + for _, test := range stringFlagTests { + flag := cli.StringFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestStringFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_FOO", "derp") + for _, test := range stringFlagTests { + flag := cli.StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_FOO]") { + t.Errorf("%s does not end with [$APP_FOO]", output) + } + } +} + +var stringSliceFlagTests = []struct { + name string + value *cli.StringSlice + expected string +}{ + {"help", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "--help [--help option --help option]\t"}, + {"h", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "-h [-h option -h option]\t"}, + {"h", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("") + return s + }(), "-h [-h option -h option]\t"}, + {"test", func() *cli.StringSlice { + s := &cli.StringSlice{} + s.Set("Something") + return s + }(), "--test [--test option --test option]\t"}, +} + +func TestStringSliceFlagHelpOutput(t *testing.T) { + + for _, test := range stringSliceFlagTests { + flag := cli.StringSliceFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_QWWX", "11,4") + for _, test := range stringSliceFlagTests { + flag := cli.StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_QWWX]") { + t.Errorf("%q does not end with [$APP_QWWX]", output) + } + } +} + +var intFlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestIntFlagHelpOutput(t *testing.T) { + + for _, test := range intFlagTests { + flag := cli.IntFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestIntFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAR", "2") + for _, test := range intFlagTests { + flag := cli.IntFlag{Name: test.name, EnvVar: "APP_BAR"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_BAR]") { + t.Errorf("%s does not end with [$APP_BAR]", output) + } + } +} + +var durationFlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestDurationFlagHelpOutput(t *testing.T) { + + for _, test := range durationFlagTests { + flag := cli.DurationFlag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAR", "2h3m6s") + for _, test := range durationFlagTests { + flag := cli.DurationFlag{Name: test.name, EnvVar: "APP_BAR"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_BAR]") { + t.Errorf("%s does not end with [$APP_BAR]", output) + } + } +} + +var intSliceFlagTests = []struct { + name string + value *cli.IntSlice + expected string +}{ + {"help", &cli.IntSlice{}, "--help [--help option --help option]\t"}, + {"h", &cli.IntSlice{}, "-h [-h option -h option]\t"}, + {"h", &cli.IntSlice{}, "-h [-h option -h option]\t"}, + {"test", func() *cli.IntSlice { + i := &cli.IntSlice{} + i.Set("9") + return i + }(), "--test [--test option --test option]\t"}, +} + +func TestIntSliceFlagHelpOutput(t *testing.T) { + + for _, test := range intSliceFlagTests { + flag := cli.IntSliceFlag{Name: test.name, Value: test.value} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_SMURF", "42,3") + for _, test := range intSliceFlagTests { + flag := cli.IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_SMURF]") { + t.Errorf("%q does not end with [$APP_SMURF]", output) + } + } +} + +var float64FlagTests = []struct { + name string + expected string +}{ + {"help", "--help \"0\"\t"}, + {"h", "-h \"0\"\t"}, +} + +func TestFloat64FlagHelpOutput(t *testing.T) { + + for _, test := range float64FlagTests { + flag := cli.Float64Flag{Name: test.name} + output := flag.String() + + if output != test.expected { + t.Errorf("%s does not match %s", output, test.expected) + } + } +} + +func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_BAZ", "99.4") + for _, test := range float64FlagTests { + flag := cli.Float64Flag{Name: test.name, EnvVar: "APP_BAZ"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_BAZ]") { + t.Errorf("%s does not end with [$APP_BAZ]", output) + } + } +} + +var genericFlagTests = []struct { + name string + value cli.Generic + expected string +}{ + {"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"}, + {"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"}, +} + +func TestGenericFlagHelpOutput(t *testing.T) { + + for _, test := range genericFlagTests { + flag := cli.GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"} + output := flag.String() + + if output != test.expected { + t.Errorf("%q does not match %q", output, test.expected) + } + } +} + +func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) { + os.Clearenv() + os.Setenv("APP_ZAP", "3") + for _, test := range genericFlagTests { + flag := cli.GenericFlag{Name: test.name, EnvVar: "APP_ZAP"} + output := flag.String() + + if !strings.HasSuffix(output, " [$APP_ZAP]") { + t.Errorf("%s does not end with [$APP_ZAP]", output) + } + } +} + +func TestParseMultiString(t *testing.T) { + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("serve") != "10" { + t.Errorf("main name not set") + } + if ctx.String("s") != "10" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10"}) +} + +func TestParseMultiStringFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_COUNT", "20") + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "count, c", EnvVar: "APP_COUNT"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("count") != "20" { + t.Errorf("main name not set") + } + if ctx.String("c") != "20" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_COUNT", "20") + (&cli.App{ + Flags: []cli.Flag{ + cli.StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"}, + }, + Action: func(ctx *cli.Context) { + if ctx.String("count") != "20" { + t.Errorf("main name not set") + } + if ctx.String("c") != "20" { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringSlice(t *testing.T) { + (&cli.App{ + Flags: []cli.Flag{ + cli.StringSliceFlag{Name: "serve, s", Value: &cli.StringSlice{}}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10", "-s", "20"}) +} + +func TestParseMultiStringSliceFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiStringSliceFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.StringSliceFlag{Name: "intervals, i", Value: &cli.StringSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiInt(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.IntFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Int("serve") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("s") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10"}) +} + +func TestParseMultiIntFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "10") + a := cli.App{ + Flags: []cli.Flag{ + cli.IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Int("timeout") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("t") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiIntFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "10") + a := cli.App{ + Flags: []cli.Flag{ + cli.IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Int("timeout") != 10 { + t.Errorf("main name not set") + } + if ctx.Int("t") != 10 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiIntSlice(t *testing.T) { + (&cli.App{ + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "serve, s", Value: &cli.IntSlice{}}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) { + t.Errorf("short name not set") + } + }, + }).Run([]string{"run", "-s", "10", "-s", "20"}) +} + +func TestParseMultiIntSliceFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiIntSliceFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_INTERVALS", "20,30,40") + + (&cli.App{ + Flags: []cli.Flag{ + cli.IntSliceFlag{Name: "intervals, i", Value: &cli.IntSlice{}, EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) { + t.Errorf("short name not set from env") + } + }, + }).Run([]string{"run"}) +} + +func TestParseMultiFloat64(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.Float64Flag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Float64("serve") != 10.2 { + t.Errorf("main name not set") + } + if ctx.Float64("s") != 10.2 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10.2"}) +} + +func TestParseMultiFloat64FromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "15.5") + a := cli.App{ + Flags: []cli.Flag{ + cli.Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Float64("timeout") != 15.5 { + t.Errorf("main name not set") + } + if ctx.Float64("t") != 15.5 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiFloat64FromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_TIMEOUT_SECONDS", "15.5") + a := cli.App{ + Flags: []cli.Flag{ + cli.Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Float64("timeout") != 15.5 { + t.Errorf("main name not set") + } + if ctx.Float64("t") != 15.5 { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBool(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Bool("serve") != true { + t.Errorf("main name not set") + } + if ctx.Bool("s") != true { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve"}) +} + +func TestParseMultiBoolFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "1") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Bool("debug") != true { + t.Errorf("main name not set from env") + } + if ctx.Bool("d") != true { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "1") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.Bool("debug") != true { + t.Errorf("main name not set from env") + } + if ctx.Bool("d") != true { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolT(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolTFlag{Name: "serve, s"}, + }, + Action: func(ctx *cli.Context) { + if ctx.BoolT("serve") != true { + t.Errorf("main name not set") + } + if ctx.BoolT("s") != true { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "--serve"}) +} + +func TestParseMultiBoolTFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "0") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolTFlag{Name: "debug, d", EnvVar: "APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.BoolT("debug") != false { + t.Errorf("main name not set from env") + } + if ctx.BoolT("d") != false { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseMultiBoolTFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_DEBUG", "0") + a := cli.App{ + Flags: []cli.Flag{ + cli.BoolTFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"}, + }, + Action: func(ctx *cli.Context) { + if ctx.BoolT("debug") != false { + t.Errorf("main name not set from env") + } + if ctx.BoolT("d") != false { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +type Parser [2]string + +func (p *Parser) Set(value string) error { + parts := strings.Split(value, ",") + if len(parts) != 2 { + return fmt.Errorf("invalid format") + } + + (*p)[0] = parts[0] + (*p)[1] = parts[1] + + return nil +} + +func (p *Parser) String() string { + return fmt.Sprintf("%s,%s", p[0], p[1]) +} + +func TestParseGeneric(t *testing.T) { + a := cli.App{ + Flags: []cli.Flag{ + cli.GenericFlag{Name: "serve, s", Value: &Parser{}}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) { + t.Errorf("main name not set") + } + if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) { + t.Errorf("short name not set") + } + }, + } + a.Run([]string{"run", "-s", "10,20"}) +} + +func TestParseGenericFromEnv(t *testing.T) { + os.Clearenv() + os.Setenv("APP_SERVE", "20,30") + a := cli.App{ + Flags: []cli.Flag{ + cli.GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) { + t.Errorf("main name not set from env") + } + if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"20", "30"}) { + t.Errorf("short name not set from env") + } + }, + } + a.Run([]string{"run"}) +} + +func TestParseGenericFromEnvCascade(t *testing.T) { + os.Clearenv() + os.Setenv("APP_FOO", "99,2000") + a := cli.App{ + Flags: []cli.Flag{ + cli.GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"}, + }, + Action: func(ctx *cli.Context) { + if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) { + t.Errorf("value not set from env") + } + }, + } + a.Run([]string{"run"}) +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/help.go b/Godeps/_workspace/src/github.com/codegangsta/cli/help.go new file mode 100644 index 000000000..bfb278851 --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/help.go @@ -0,0 +1,211 @@ +package cli + +import "fmt" + +// The text template for the Default help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var AppHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} + +USAGE: + {{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] + +VERSION: + {{.Version}}{{if or .Author .Email}} + +AUTHOR:{{if .Author}} + {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}} + {{.Email}}{{end}}{{end}} + +COMMANDS: + {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} + {{end}}{{if .Flags}} +GLOBAL OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{end}} +` + +// The text template for the command help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var CommandHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} + +USAGE: + command {{.Name}}{{if .Flags}} [command options]{{end}} [arguments...]{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if .Flags}} + +OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{ end }} +` + +// The text template for the subcommand help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var SubcommandHelpTemplate = `NAME: + {{.Name}} - {{.Usage}} + +USAGE: + {{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...] + +COMMANDS: + {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} + {{end}}{{if .Flags}} +OPTIONS: + {{range .Flags}}{{.}} + {{end}}{{end}} +` + +var helpCommand = Command{ + Name: "help", + ShortName: "h", + Usage: "Shows a list of commands or help for one command", + Action: func(c *Context) { + args := c.Args() + if args.Present() { + ShowCommandHelp(c, args.First()) + } else { + ShowAppHelp(c) + } + }, +} + +var helpSubcommand = Command{ + Name: "help", + ShortName: "h", + Usage: "Shows a list of commands or help for one command", + Action: func(c *Context) { + args := c.Args() + if args.Present() { + ShowCommandHelp(c, args.First()) + } else { + ShowSubcommandHelp(c) + } + }, +} + +// Prints help for the App +type helpPrinter func(templ string, data interface{}) + +var HelpPrinter helpPrinter = nil + +// Prints version for the App +var VersionPrinter = printVersion + +func ShowAppHelp(c *Context) { + HelpPrinter(AppHelpTemplate, c.App) +} + +// Prints the list of subcommands as the default app completion method +func DefaultAppComplete(c *Context) { + for _, command := range c.App.Commands { + fmt.Fprintln(c.App.Writer, command.Name) + if command.ShortName != "" { + fmt.Fprintln(c.App.Writer, command.ShortName) + } + } +} + +// Prints help for the given command +func ShowCommandHelp(c *Context, command string) { + for _, c := range c.App.Commands { + if c.HasName(command) { + HelpPrinter(CommandHelpTemplate, c) + return + } + } + + if c.App.CommandNotFound != nil { + c.App.CommandNotFound(c, command) + } else { + fmt.Fprintf(c.App.Writer, "No help topic for '%v'\n", command) + } +} + +// Prints help for the given subcommand +func ShowSubcommandHelp(c *Context) { + ShowCommandHelp(c, c.Command.Name) +} + +// Prints the version number of the App +func ShowVersion(c *Context) { + VersionPrinter(c) +} + +func printVersion(c *Context) { + fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) +} + +// Prints the lists of commands within a given context +func ShowCompletions(c *Context) { + a := c.App + if a != nil && a.BashComplete != nil { + a.BashComplete(c) + } +} + +// Prints the custom completions for a given command +func ShowCommandCompletions(ctx *Context, command string) { + c := ctx.App.Command(command) + if c != nil && c.BashComplete != nil { + c.BashComplete(ctx) + } +} + +func checkVersion(c *Context) bool { + if c.GlobalBool("version") { + ShowVersion(c) + return true + } + + return false +} + +func checkHelp(c *Context) bool { + if c.GlobalBool("h") || c.GlobalBool("help") { + ShowAppHelp(c) + return true + } + + return false +} + +func checkCommandHelp(c *Context, name string) bool { + if c.Bool("h") || c.Bool("help") { + ShowCommandHelp(c, name) + return true + } + + return false +} + +func checkSubcommandHelp(c *Context) bool { + if c.GlobalBool("h") || c.GlobalBool("help") { + ShowSubcommandHelp(c) + return true + } + + return false +} + +func checkCompletions(c *Context) bool { + if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion { + ShowCompletions(c) + return true + } + + return false +} + +func checkCommandCompletions(c *Context, name string) bool { + if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { + ShowCommandCompletions(c, name) + return true + } + + return false +} diff --git a/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go b/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go new file mode 100644 index 000000000..cdc4feb2f --- /dev/null +++ b/Godeps/_workspace/src/github.com/codegangsta/cli/helpers_test.go @@ -0,0 +1,19 @@ +package cli_test + +import ( + "reflect" + "testing" +) + +/* Test Helpers */ +func expect(t *testing.T, a interface{}, b interface{}) { + if a != b { + t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} + +func refute(t *testing.T, a interface{}, b interface{}) { + if a == b { + t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) + } +} diff --git a/cmd/ethereum/flags.go b/cmd/ethereum/flags.go deleted file mode 100644 index a3004f503..000000000 --- a/cmd/ethereum/flags.go +++ /dev/null @@ -1,168 +0,0 @@ -/* - 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 . -*/ -/** - * @authors - * Jeffrey Wilcke - */ -package main - -import ( - "crypto/ecdsa" - "flag" - "fmt" - "log" - "os" - "path" - "runtime" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/p2p/nat" - "github.com/ethereum/go-ethereum/vm" -) - -var ( - Identifier string - KeyRing string - DiffTool bool - DiffType string - KeyStore string - StartRpc bool - StartWebSockets bool - RpcListenAddress string - RpcPort int - OutboundPort string - ShowGenesis bool - AddPeer string - MaxPeer int - GenAddr bool - BootNodes string - NodeKey *ecdsa.PrivateKey - NAT nat.Interface - SecretFile string - ExportDir string - NonInteractive bool - Datadir string - LogFile string - ConfigFile string - DebugFile string - LogLevel int - LogFormat string - Dump bool - DumpHash string - DumpNumber int - VmType int - ImportChain string - SHH bool - Dial bool - PrintVersion bool - MinerThreads int -) - -// flags specific to cli client -var ( - StartMining bool - StartJsConsole bool - InputFile string -) - -var defaultConfigFile = path.Join(ethutil.DefaultDataDir(), "conf.ini") - -func Init() { - // TODO: move common flag processing to cmd/util - flag.Usage = func() { - fmt.Fprintf(os.Stderr, "%s [options] [filename]:\noptions precedence: default < config file < environment variables < command line\n", os.Args[0]) - flag.PrintDefaults() - } - - flag.IntVar(&VmType, "vm", 0, "Virtual Machine type: 0-1: standard, debug") - flag.StringVar(&Identifier, "id", "", "Custom client identifier") - flag.StringVar(&KeyRing, "keyring", "", "identifier for keyring to use") - flag.StringVar(&KeyStore, "keystore", "db", "system to store keyrings: db|file") - - flag.StringVar(&RpcListenAddress, "rpcaddr", "127.0.0.1", "address for json-rpc server to listen on") - flag.IntVar(&RpcPort, "rpcport", 8545, "port to start json-rpc server on") - flag.BoolVar(&StartRpc, "rpc", false, "start rpc server") - flag.BoolVar(&NonInteractive, "y", false, "non-interactive mode (say yes to confirmations)") - flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") - flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)") - flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given") - flag.StringVar(&LogFile, "logfile", "", "log file (defaults to standard output)") - flag.StringVar(&Datadir, "datadir", ethutil.DefaultDataDir(), "specifies the datadir to use") - flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") - flag.StringVar(&DebugFile, "debug", "", "debug file (no debugging if not set)") - flag.IntVar(&LogLevel, "loglevel", int(logger.InfoLevel), "loglevel: 0-5 (= silent,error,warn,info,debug,debug detail)") - flag.StringVar(&LogFormat, "logformat", "std", "logformat: std,raw") - flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0") - flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false") - flag.BoolVar(&ShowGenesis, "genesis", false, "Dump the genesis block") - flag.StringVar(&ImportChain, "chain", "", "Imports given chain") - - flag.BoolVar(&Dump, "dump", false, "output the ethereum state in JSON format. Sub args [number, hash]") - flag.StringVar(&DumpHash, "hash", "", "specify arg in hex") - flag.IntVar(&DumpNumber, "number", -1, "specify arg in number") - - flag.BoolVar(&StartMining, "mine", false, "start mining") - flag.BoolVar(&StartJsConsole, "js", false, "launches javascript console") - flag.BoolVar(&PrintVersion, "version", false, "prints version number") - flag.IntVar(&MinerThreads, "minerthreads", runtime.NumCPU(), "number of miner threads") - - // Network stuff - var ( - nodeKeyFile = flag.String("nodekey", "", "network private key file") - nodeKeyHex = flag.String("nodekeyhex", "", "network private key (for testing)") - natstr = flag.String("nat", "any", "port mapping mechanism (any|none|upnp|pmp|extip:)") - ) - flag.BoolVar(&Dial, "dial", true, "dial out connections (default on)") - //flag.BoolVar(&SHH, "shh", true, "run whisper protocol (default on)") - flag.StringVar(&OutboundPort, "port", "30303", "listening port") - - flag.StringVar(&BootNodes, "bootnodes", "", "space-separated node URLs for discovery bootstrap") - flag.IntVar(&MaxPeer, "maxpeer", 30, "maximum desired peers") - - flag.Parse() - - // When the javascript console is started log to a file instead - // of stdout - if StartJsConsole { - LogFile = path.Join(Datadir, "ethereum.log") - } - - var err error - if NAT, err = nat.Parse(*natstr); err != nil { - log.Fatalf("-nat: %v", err) - } - switch { - case *nodeKeyFile != "" && *nodeKeyHex != "": - log.Fatal("Options -nodekey and -nodekeyhex are mutually exclusive") - case *nodeKeyFile != "": - if NodeKey, err = crypto.LoadECDSA(*nodeKeyFile); err != nil { - log.Fatalf("-nodekey: %v", err) - } - case *nodeKeyHex != "": - if NodeKey, err = crypto.HexToECDSA(*nodeKeyHex); err != nil { - log.Fatalf("-nodekeyhex: %v", err) - } - } - - if VmType >= int(vm.MaxVmTy) { - log.Fatal("Invalid VM type ", VmType) - } - - InputFile = flag.Arg(0) -} diff --git a/cmd/ethereum/cmd.go b/cmd/ethereum/js.go similarity index 79% rename from cmd/ethereum/cmd.go rename to cmd/ethereum/js.go index 7bb7c3ef7..f0aeb45f5 100644 --- a/cmd/ethereum/cmd.go +++ b/cmd/ethereum/js.go @@ -21,20 +21,23 @@ import ( "io/ioutil" "os" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/javascript" "github.com/ethereum/go-ethereum/xeth" ) -func ExecJsFile(ethereum *eth.Ethereum, InputFile string) { - file, err := os.Open(InputFile) +func execJsFile(ethereum *eth.Ethereum, filename string) { + file, err := os.Open(filename) if err != nil { - clilogger.Fatalln(err) + utils.Fatalf("%v", err) } content, err := ioutil.ReadAll(file) if err != nil { - clilogger.Fatalln(err) + utils.Fatalf("%v", err) } re := javascript.NewJSRE(xeth.New(ethereum)) - re.Run(string(content)) + if _, err := re.Run(string(content)); err != nil { + utils.Fatalf("Javascript Error: %v", err) + } } diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index b9e69f700..a38e012c2 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -24,15 +24,16 @@ import ( "fmt" "os" "runtime" + "strconv" "time" + "github.com/codegangsta/cli" "github.com/ethereum/go-ethereum/cmd/ethereum/repl" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/state" ) @@ -41,117 +42,174 @@ const ( Version = "0.8.6" ) -var clilogger = logger.NewLogger("CLI") +var ( + clilogger = logger.NewLogger("CLI") + app = cli.NewApp() +) + +func init() { + app.Version = Version + app.Usage = "the go-ethereum command-line client" + app.Action = run + app.HideVersion = true // we have a command to print the version + app.Commands = []cli.Command{ + { + Action: version, + Name: "version", + Usage: "print ethereum version numbers", + Description: ` +The output of this command is supposed to be machine-readable. +`, + }, + { + Action: dump, + Name: "dump", + Usage: `dump a specific block from storage`, + Description: ` +The arguments are interpreted as block numbers or hashes. +Use "ethereum dump 0" to dump the genesis block. +`, + }, + { + Action: runjs, + Name: "js", + Usage: `interactive JavaScript console`, + Description: ` +In the console, you can use the eth object to interact +with the running ethereum stack. The API does not match +ethereum.js. + +A JavaScript file can be provided as the argument. The +runtime will execute the file and exit. +`, + }, + { + Action: importchain, + Name: "import", + Usage: `import a blockchain file`, + }, + } + app.Author = "" + app.Email = "" + app.Flags = []cli.Flag{ + utils.BootnodesFlag, + utils.DataDirFlag, + utils.KeyRingFlag, + utils.KeyStoreFlag, + utils.ListenPortFlag, + utils.LogFileFlag, + utils.LogFormatFlag, + utils.LogLevelFlag, + utils.MaxPeersFlag, + utils.MinerThreadsFlag, + utils.MiningEnabledFlag, + utils.NATFlag, + utils.NodeKeyFileFlag, + utils.NodeKeyHexFlag, + utils.RPCEnabledFlag, + utils.RPCListenAddrFlag, + utils.RPCPortFlag, + utils.VMTypeFlag, + } + + // missing: + // flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file") + // flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0") + // flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false") + + // potential subcommands: + // flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)") + // flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given") + // flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") +} func main() { runtime.GOMAXPROCS(runtime.NumCPU()) - - defer func() { - logger.Flush() - }() - + defer logger.Flush() utils.HandleInterrupt() - - // precedence: code-internal flag default < config file < environment variables < command line - Init() // parsing command line - - if PrintVersion { - printVersion() - return + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) } - - utils.InitConfig(VmType, ConfigFile, Datadir, "ETH") - - ethereum, err := eth.New(ð.Config{ - Name: p2p.MakeName(ClientIdentifier, Version), - KeyStore: KeyStore, - DataDir: Datadir, - LogFile: LogFile, - LogLevel: LogLevel, - LogFormat: LogFormat, - MaxPeers: MaxPeer, - Port: OutboundPort, - NAT: NAT, - KeyRing: KeyRing, - Shh: true, - Dial: Dial, - BootNodes: BootNodes, - NodeKey: NodeKey, - MinerThreads: MinerThreads, - }) - - if err != nil { - clilogger.Fatalln(err) - } - - utils.KeyTasks(ethereum.KeyManager(), KeyRing, GenAddr, SecretFile, ExportDir, NonInteractive) - - if Dump { - var block *types.Block - - if len(DumpHash) == 0 && DumpNumber == -1 { - block = ethereum.ChainManager().CurrentBlock() - } else if len(DumpHash) > 0 { - block = ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(DumpHash)) - } else { - block = ethereum.ChainManager().GetBlockByNumber(uint64(DumpNumber)) - } - - if block == nil { - fmt.Fprintln(os.Stderr, "block not found") - - // We want to output valid JSON - fmt.Println("{}") - - os.Exit(1) - } - - // Leave the Println. This needs clean output for piping - statedb := state.New(block.Root(), ethereum.Db()) - fmt.Printf("%s\n", statedb.Dump()) - - fmt.Println(block) - - return - } - - if len(ImportChain) > 0 { - start := time.Now() - err := utils.ImportChain(ethereum, ImportChain) - if err != nil { - clilogger.Infoln(err) - } - clilogger.Infoln("import done in", time.Since(start)) - return - } - - if StartRpc { - utils.StartRpc(ethereum, RpcListenAddress, RpcPort) - } - - utils.StartEthereum(ethereum) - - fmt.Printf("Welcome to the FRONTIER\n") - - if StartMining { - ethereum.Miner().Start() - } - - if StartJsConsole { - repl := ethrepl.NewJSRepl(ethereum) - repl.Start() - utils.RegisterInterrupt(func(os.Signal) { - repl.Stop() - }) - - } else if len(InputFile) > 0 { - ExecJsFile(ethereum, InputFile) - } - // this blocks the thread - ethereum.WaitForShutdown() } -func printVersion() { +func run(ctx *cli.Context) { + fmt.Printf("Welcome to the FRONTIER\n") + eth := utils.GetEthereum(ClientIdentifier, Version, ctx) + startEth(ctx, eth) + // this blocks the thread + eth.WaitForShutdown() +} + +func runjs(ctx *cli.Context) { + eth := utils.GetEthereum(ClientIdentifier, Version, ctx) + startEth(ctx, eth) + if len(ctx.Args()) == 0 { + repl := ethrepl.NewJSRepl(eth) + repl.Start() + utils.RegisterInterrupt(func(os.Signal) { repl.Stop() }) + eth.WaitForShutdown() + } else if len(ctx.Args()) == 1 { + execJsFile(eth, ctx.Args()[0]) + } else { + utils.Fatalf("This command can handle at most one argument.") + } +} + +func startEth(ctx *cli.Context, eth *eth.Ethereum) { + utils.StartEthereum(eth) + if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { + addr := ctx.GlobalString(utils.RPCListenAddrFlag.Name) + port := ctx.GlobalInt(utils.RPCPortFlag.Name) + utils.StartRpc(eth, addr, port) + } + if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { + eth.Miner().Start() + } +} + +func importchain(ctx *cli.Context) { + if len(ctx.Args()) != 1 { + utils.Fatalf("This command requires an argument.") + } + chain, _ := utils.GetChain(ctx) + start := time.Now() + err := utils.ImportChain(chain, ctx.Args().First()) + if err != nil { + utils.Fatalf("Import error: %v\n", err) + } + fmt.Printf("Import done in", time.Since(start)) + return +} + +func dump(ctx *cli.Context) { + chain, db := utils.GetChain(ctx) + for _, arg := range ctx.Args() { + var block *types.Block + if hashish(arg) { + block = chain.GetBlock(ethutil.Hex2Bytes(arg)) + } else { + num, _ := strconv.Atoi(arg) + block = chain.GetBlockByNumber(uint64(num)) + } + if block == nil { + fmt.Println("{}") + utils.Fatalf("block not found") + } else { + statedb := state.New(block.Root(), db) + fmt.Printf("%s\n", statedb.Dump()) + // fmt.Println(block) + } + } +} + +// hashish returns true for strings that look like hashes. +func hashish(x string) bool { + _, err := strconv.Atoi(x) + return err != nil +} + +func version(c *cli.Context) { fmt.Printf(`%v %v PV=%d GOOS=%s diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 2bd34d792..3c3d3955d 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -27,6 +27,7 @@ import ( "os/signal" "regexp" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" @@ -108,13 +109,20 @@ func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) func exit(err error) { status := 0 if err != nil { - clilogger.Errorln("Fatal: ", err) + fmt.Fprintln(os.Stderr, "Fatal: ", err) status = 1 } logger.Flush() os.Exit(status) } +// Fatalf formats a message to standard output and exits the program. +func Fatalf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, "Fatal: "+format+"\n", args...) + logger.Flush() + os.Exit(1) +} + func StartEthereum(ethereum *eth.Ethereum) { clilogger.Infoln("Starting ", ethereum.Name()) if err := ethereum.Start(); err != nil { @@ -127,7 +135,6 @@ func StartEthereum(ethereum *eth.Ethereum) { } func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) { - var err error switch { case GenAddr: @@ -200,24 +207,24 @@ func BlockDo(ethereum *eth.Ethereum, hash []byte) error { } -func ImportChain(ethereum *eth.Ethereum, fn string) error { - clilogger.Infof("importing chain '%s'\n", fn) +func ImportChain(chain *core.ChainManager, fn string) error { + fmt.Printf("importing chain '%s'\n", fn) fh, err := os.OpenFile(fn, os.O_RDONLY, os.ModePerm) if err != nil { return err } defer fh.Close() - var chain types.Blocks - if err := rlp.Decode(fh, &chain); err != nil { + var blocks types.Blocks + if err := rlp.Decode(fh, &blocks); err != nil { return err } - ethereum.ChainManager().Reset() - if err := ethereum.ChainManager().InsertChain(chain); err != nil { + chain.Reset() + if err := chain.InsertChain(blocks); err != nil { return err } - clilogger.Infof("imported %d blocks\n", len(chain)) + fmt.Printf("imported %d blocks\n", len(blocks)) return nil } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go new file mode 100644 index 000000000..fb80ac708 --- /dev/null +++ b/cmd/utils/flags.go @@ -0,0 +1,178 @@ +package utils + +import ( + "crypto/ecdsa" + "path" + "runtime" + + "github.com/codegangsta/cli" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/nat" +) + +// These are all the command line flags we support. +// If you add to this list, please remember to include the +// flag in the appropriate command definition. +// +// The flags are defined here so their names and help texts +// are the same for all commands. + +var ( + // General settings + VMTypeFlag = cli.IntFlag{ + Name: "vm", + Usage: "Virtual Machine type: 0 is standard VM, 1 is debug VM", + } + KeyRingFlag = cli.StringFlag{ + Name: "keyring", + Usage: "Name of keyring to be used", + Value: "", + } + KeyStoreFlag = cli.StringFlag{ + Name: "keystore", + Usage: `Where to store keyrings: "db" or "file"`, + Value: "db", + } + DataDirFlag = cli.StringFlag{ + Name: "datadir", + Usage: "Data directory to be used", + Value: ethutil.DefaultDataDir(), + } + MinerThreadsFlag = cli.IntFlag{ + Name: "minerthreads", + Usage: "Number of miner threads", + Value: runtime.NumCPU(), + } + MiningEnabledFlag = cli.BoolFlag{ + Name: "mine", + Usage: "Enable mining", + } + + LogFileFlag = cli.StringFlag{ + Name: "logfile", + Usage: "Send log output to a file", + } + LogLevelFlag = cli.IntFlag{ + Name: "loglevel", + Usage: "0-5 (silent, error, warn, info, debug, debug detail)", + Value: int(logger.InfoLevel), + } + LogFormatFlag = cli.StringFlag{ + Name: "logformat", + Usage: `"std" or "raw"`, + Value: "std", + } + + // RPC settings + RPCEnabledFlag = cli.BoolFlag{ + Name: "rpc", + Usage: "Whether RPC server is enabled", + } + RPCListenAddrFlag = cli.StringFlag{ + Name: "rpcaddr", + Usage: "Listening address for the JSON-RPC server", + Value: "127.0.0.1", + } + RPCPortFlag = cli.IntFlag{ + Name: "rpcport", + Usage: "Port on which the JSON-RPC server should listen", + Value: 8545, + } + + // Network Settings + MaxPeersFlag = cli.IntFlag{ + Name: "maxpeers", + Usage: "Maximum number of network peers", + Value: 16, + } + ListenPortFlag = cli.IntFlag{ + Name: "port", + Usage: "Network listening port", + Value: 30303, + } + BootnodesFlag = cli.StringFlag{ + Name: "bootnodes", + Usage: "Space-separated enode URLs for discovery bootstrap", + Value: "", + } + NodeKeyFileFlag = cli.StringFlag{ + Name: "nodekey", + Usage: "P2P node key file", + } + NodeKeyHexFlag = cli.StringFlag{ + Name: "nodekeyhex", + Usage: "P2P node key as hex (for testing)", + } + NATFlag = cli.StringFlag{ + Name: "nat", + Usage: "Port mapping mechanism (any|none|upnp|pmp|extip:)", + Value: "any", + } +) + +func GetNAT(ctx *cli.Context) nat.Interface { + natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) + if err != nil { + Fatalf("Option %s: %v", NATFlag.Name, err) + } + return natif +} + +func GetNodeKey(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) + } + } + return key +} + +func GetEthereum(clientID, version string, ctx *cli.Context) *eth.Ethereum { + ethereum, err := eth.New(ð.Config{ + Name: p2p.MakeName(clientID, version), + KeyStore: ctx.GlobalString(KeyStoreFlag.Name), + DataDir: ctx.GlobalString(DataDirFlag.Name), + LogFile: ctx.GlobalString(LogFileFlag.Name), + LogLevel: ctx.GlobalInt(LogLevelFlag.Name), + LogFormat: ctx.GlobalString(LogFormatFlag.Name), + MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name), + + MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name), + Port: ctx.GlobalString(ListenPortFlag.Name), + NAT: GetNAT(ctx), + NodeKey: GetNodeKey(ctx), + KeyRing: ctx.GlobalString(KeyRingFlag.Name), + Shh: true, + Dial: true, + BootNodes: ctx.GlobalString(BootnodesFlag.Name), + }) + if err != nil { + exit(err) + } + return ethereum +} + +func GetChain(ctx *cli.Context) (*core.ChainManager, ethutil.Database) { + dataDir := ctx.GlobalString(DataDirFlag.Name) + db, err := ethdb.NewLDBDatabase(path.Join(dataDir, "blockchain")) + if err != nil { + Fatalf("Could not open database: %v", err) + } + return core.NewChainManager(db, new(event.TypeMux)), db +} From 38f6d60e6e699db24b7a850b5999823b9e36d5bb Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Mar 2015 03:38:19 +0100 Subject: [PATCH 4/7] cmd/ethereum: new JS repl with cross-platform line editing --- cmd/ethereum/js.go | 207 ++++++++++++++++++++ cmd/ethereum/main.go | 5 +- cmd/ethereum/repl/console_colors_windows.go | 97 --------- cmd/ethereum/repl/repl.go | 201 ------------------- cmd/ethereum/repl/repl_darwin.go | 144 -------------- cmd/ethereum/repl/repl_linux.go | 1 - cmd/ethereum/repl/repl_windows.go | 92 --------- 7 files changed, 209 insertions(+), 538 deletions(-) delete mode 100644 cmd/ethereum/repl/console_colors_windows.go delete mode 100644 cmd/ethereum/repl/repl.go delete mode 100644 cmd/ethereum/repl/repl_darwin.go delete mode 120000 cmd/ethereum/repl/repl_linux.go delete mode 100644 cmd/ethereum/repl/repl_windows.go diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go index f0aeb45f5..e16ee171e 100644 --- a/cmd/ethereum/js.go +++ b/cmd/ethereum/js.go @@ -18,13 +18,21 @@ package main import ( + "fmt" "io/ioutil" "os" + "path" + "strings" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/javascript" + "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/xeth" + "github.com/obscuren/otto" + "github.com/peterh/liner" ) func execJsFile(ethereum *eth.Ethereum, filename string) { @@ -41,3 +49,202 @@ func execJsFile(ethereum *eth.Ethereum, filename string) { utils.Fatalf("Javascript Error: %v", err) } } + +type repl struct { + re *javascript.JSRE + ethereum *eth.Ethereum + xeth *xeth.XEth + prompt string + histfile *os.File + lr *liner.State + running bool +} + +func newREPL(ethereum *eth.Ethereum) *repl { + hist, err := os.OpenFile(path.Join(ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) + if err != nil { + panic(err) + } + xeth := xeth.New(ethereum) + repl := &repl{ + re: javascript.NewJSRE(xeth), + xeth: xeth, + ethereum: ethereum, + prompt: "> ", + histfile: hist, + lr: liner.NewLiner(), + } + repl.initStdFuncs() + return repl +} + +func (self *repl) Start() { + if !self.running { + self.running = true + self.lr.ReadHistory(self.histfile) + go self.read() + } +} + +func (self *repl) Stop() { + if self.running { + self.running = false + self.histfile.Truncate(0) + self.lr.WriteHistory(self.histfile) + self.histfile.Close() + } +} + +func (self *repl) parseInput(code string) { + defer func() { + if r := recover(); r != nil { + fmt.Println("[native] error", r) + } + }() + value, err := self.re.Run(code) + if err != nil { + fmt.Println(err) + return + } + self.printValue(value) +} + +var indentCount = 0 +var str = "" + +func (self *repl) setIndent() { + open := strings.Count(str, "{") + open += strings.Count(str, "(") + closed := strings.Count(str, "}") + closed += strings.Count(str, ")") + indentCount = open - closed + if indentCount <= 0 { + self.prompt = "> " + } else { + self.prompt = strings.Join(make([]string, indentCount*2), "..") + self.prompt += " " + } +} + +func (self *repl) read() { + for { + input, err := self.lr.Prompt(self.prompt) + if err != nil { + return + } + if input == "" { + continue + } + str += input + "\n" + self.setIndent() + if indentCount <= 0 { + if input == "exit" { + self.Stop() + return + } + hist := str[:len(str)-1] + self.lr.AppendHistory(hist) + self.parseInput(str) + str = "" + } + } +} + +func (self *repl) printValue(v interface{}) { + method, _ := self.re.Vm.Get("prettyPrint") + v, err := self.re.Vm.ToValue(v) + if err == nil { + val, err := method.Call(method, v) + if err == nil { + fmt.Printf("%v", val) + } + } +} + +func (self *repl) initStdFuncs() { + t, _ := self.re.Vm.Get("eth") + eth := t.Object() + eth.Set("connect", self.connect) + eth.Set("stopMining", self.stopMining) + eth.Set("startMining", self.startMining) + eth.Set("dump", self.dump) + eth.Set("export", self.export) +} + +/* + * The following methods are natively implemented javascript functions. + */ + +func (self *repl) dump(call otto.FunctionCall) otto.Value { + var block *types.Block + + if len(call.ArgumentList) > 0 { + if call.Argument(0).IsNumber() { + num, _ := call.Argument(0).ToInteger() + block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num)) + } else if call.Argument(0).IsString() { + hash, _ := call.Argument(0).ToString() + block = self.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash)) + } else { + fmt.Println("invalid argument for dump. Either hex string or number") + } + + if block == nil { + fmt.Println("block not found") + + return otto.UndefinedValue() + } + + } else { + block = self.ethereum.ChainManager().CurrentBlock() + } + + statedb := state.New(block.Root(), self.ethereum.Db()) + + v, _ := self.re.Vm.ToValue(statedb.RawDump()) + + return v +} + +func (self *repl) stopMining(call otto.FunctionCall) otto.Value { + self.xeth.Miner().Stop() + return otto.TrueValue() +} + +func (self *repl) startMining(call otto.FunctionCall) otto.Value { + self.xeth.Miner().Start() + return otto.TrueValue() +} + +func (self *repl) connect(call otto.FunctionCall) otto.Value { + nodeURL, err := call.Argument(0).ToString() + if err != nil { + return otto.FalseValue() + } + if err := self.ethereum.SuggestPeer(nodeURL); err != nil { + return otto.FalseValue() + } + return otto.TrueValue() +} + +func (self *repl) export(call otto.FunctionCall) otto.Value { + if len(call.ArgumentList) == 0 { + fmt.Println("err: require file name") + return otto.FalseValue() + } + + fn, err := call.Argument(0).ToString() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + + data := self.ethereum.ChainManager().Export() + + if err := ethutil.WriteFile(fn, data); err != nil { + fmt.Println(err) + return otto.FalseValue() + } + + return otto.TrueValue() +} diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index a38e012c2..c85caf229 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -28,7 +28,6 @@ import ( "time" "github.com/codegangsta/cli" - "github.com/ethereum/go-ethereum/cmd/ethereum/repl" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth" @@ -145,9 +144,9 @@ func runjs(ctx *cli.Context) { eth := utils.GetEthereum(ClientIdentifier, Version, ctx) startEth(ctx, eth) if len(ctx.Args()) == 0 { - repl := ethrepl.NewJSRepl(eth) - repl.Start() + repl := newREPL(eth) utils.RegisterInterrupt(func(os.Signal) { repl.Stop() }) + repl.Start() eth.WaitForShutdown() } else if len(ctx.Args()) == 1 { execJsFile(eth, ctx.Args()[0]) diff --git a/cmd/ethereum/repl/console_colors_windows.go b/cmd/ethereum/repl/console_colors_windows.go deleted file mode 100644 index 8062746fb..000000000 --- a/cmd/ethereum/repl/console_colors_windows.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. -// -// This library 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 2.1 of the License, or (at your option) any later version. -// -// This 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 -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -// MA 02110-1301 USA - -/* Inspired by https://github.com/xuyu/logging/blob/master/colorful_win.go */ - -package ethrepl - -import ( - "syscall" - "unsafe" -) - -type color uint16 - -const ( - green = color(0x0002) - red = color(0x0004) - yellow = color(0x000E) -) - -const ( - mask = uint16(yellow | green | red) -) - -var ( - kernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetStdHandle = kernel32.NewProc("GetStdHandle") - procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") - procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") - hStdout uintptr - initScreenInfo *consoleScreenBufferInfo -) - -func setConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool { - ret, _, _ := procSetConsoleTextAttribute.Call(hConsoleOutput, uintptr(wAttributes)) - return ret != 0 -} - -type coord struct { - X, Y int16 -} - -type smallRect struct { - Left, Top, Right, Bottom int16 -} - -type consoleScreenBufferInfo struct { - DwSize coord - DwCursorPosition coord - WAttributes uint16 - SrWindow smallRect - DwMaximumWindowSize coord -} - -func getConsoleScreenBufferInfo(hConsoleOutput uintptr) *consoleScreenBufferInfo { - var csbi consoleScreenBufferInfo - ret, _, _ := procGetConsoleScreenBufferInfo.Call(hConsoleOutput, uintptr(unsafe.Pointer(&csbi))) - if ret == 0 { - return nil - } - return &csbi -} - -const ( - stdOutputHandle = uint32(-11 & 0xFFFFFFFF) -) - -func init() { - hStdout, _, _ = procGetStdHandle.Call(uintptr(stdOutputHandle)) - initScreenInfo = getConsoleScreenBufferInfo(hStdout) -} - -func resetColorful() { - if initScreenInfo == nil { - return - } - setConsoleTextAttribute(hStdout, initScreenInfo.WAttributes) -} - -func changeColor(c color) { - attr := uint16(0) & ^mask | uint16(c) - setConsoleTextAttribute(hStdout, attr) -} diff --git a/cmd/ethereum/repl/repl.go b/cmd/ethereum/repl/repl.go deleted file mode 100644 index 05ea71e79..000000000 --- a/cmd/ethereum/repl/repl.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. -// -// This library 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 2.1 of the License, or (at your option) any later version. -// -// This 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 -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -// MA 02110-1301 USA - -package ethrepl - -import ( - "bufio" - "fmt" - "io" - "os" - "path" - - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/javascript" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/state" - "github.com/ethereum/go-ethereum/xeth" - "github.com/obscuren/otto" -) - -var repllogger = logger.NewLogger("REPL") - -type Repl interface { - Start() - Stop() -} - -type JSRepl struct { - re *javascript.JSRE - ethereum *eth.Ethereum - xeth *xeth.XEth - - prompt string - - history *os.File - - running bool -} - -func NewJSRepl(ethereum *eth.Ethereum) *JSRepl { - hist, err := os.OpenFile(path.Join(ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) - if err != nil { - panic(err) - } - - xeth := xeth.New(ethereum) - repl := &JSRepl{re: javascript.NewJSRE(xeth), xeth: xeth, ethereum: ethereum, prompt: "> ", history: hist} - repl.initStdFuncs() - - return repl -} - -func (self *JSRepl) Start() { - if !self.running { - self.running = true - repllogger.Infoln("init JS Console") - - reader := bufio.NewReader(self.history) - for { - line, err := reader.ReadString('\n') - if err != nil && err == io.EOF { - break - } else if err != nil { - fmt.Println("error reading history", err) - break - } - - addHistory(line[:len(line)-1]) - } - self.read() - } -} - -func (self *JSRepl) Stop() { - if self.running { - self.running = false - repllogger.Infoln("exit JS Console") - self.history.Close() - } -} - -func (self *JSRepl) parseInput(code string) { - defer func() { - if r := recover(); r != nil { - fmt.Println("[native] error", r) - } - }() - - value, err := self.re.Run(code) - if err != nil { - fmt.Println(err) - return - } - - self.PrintValue(value) -} - -func (self *JSRepl) initStdFuncs() { - t, _ := self.re.Vm.Get("eth") - eth := t.Object() - eth.Set("connect", self.connect) - eth.Set("stopMining", self.stopMining) - eth.Set("startMining", self.startMining) - eth.Set("dump", self.dump) - eth.Set("export", self.export) -} - -/* - * The following methods are natively implemented javascript functions - */ - -func (self *JSRepl) dump(call otto.FunctionCall) otto.Value { - var block *types.Block - - if len(call.ArgumentList) > 0 { - if call.Argument(0).IsNumber() { - num, _ := call.Argument(0).ToInteger() - block = self.ethereum.ChainManager().GetBlockByNumber(uint64(num)) - } else if call.Argument(0).IsString() { - hash, _ := call.Argument(0).ToString() - block = self.ethereum.ChainManager().GetBlock(ethutil.Hex2Bytes(hash)) - } else { - fmt.Println("invalid argument for dump. Either hex string or number") - } - - if block == nil { - fmt.Println("block not found") - - return otto.UndefinedValue() - } - - } else { - block = self.ethereum.ChainManager().CurrentBlock() - } - - statedb := state.New(block.Root(), self.ethereum.Db()) - - v, _ := self.re.Vm.ToValue(statedb.RawDump()) - - return v -} - -func (self *JSRepl) stopMining(call otto.FunctionCall) otto.Value { - self.xeth.Miner().Stop() - - return otto.TrueValue() -} - -func (self *JSRepl) startMining(call otto.FunctionCall) otto.Value { - self.xeth.Miner().Start() - return otto.TrueValue() -} - -func (self *JSRepl) connect(call otto.FunctionCall) otto.Value { - nodeURL, err := call.Argument(0).ToString() - if err != nil { - return otto.FalseValue() - } - if err := self.ethereum.SuggestPeer(nodeURL); err != nil { - return otto.FalseValue() - } - return otto.TrueValue() -} - -func (self *JSRepl) export(call otto.FunctionCall) otto.Value { - if len(call.ArgumentList) == 0 { - fmt.Println("err: require file name") - return otto.FalseValue() - } - - fn, err := call.Argument(0).ToString() - if err != nil { - fmt.Println(err) - return otto.FalseValue() - } - - data := self.ethereum.ChainManager().Export() - - if err := ethutil.WriteFile(fn, data); err != nil { - fmt.Println(err) - return otto.FalseValue() - } - - return otto.TrueValue() -} diff --git a/cmd/ethereum/repl/repl_darwin.go b/cmd/ethereum/repl/repl_darwin.go deleted file mode 100644 index 3710150cc..000000000 --- a/cmd/ethereum/repl/repl_darwin.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. -// -// This library 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 2.1 of the License, or (at your option) any later version. -// -// This 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 -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -// MA 02110-1301 USA - -package ethrepl - -// #cgo darwin CFLAGS: -I/usr/local/opt/readline/include -// #cgo darwin LDFLAGS: -L/usr/local/opt/readline/lib -// #cgo LDFLAGS: -lreadline -// #include -// #include -// #include -// #include -import "C" -import ( - "fmt" - "os" - "os/signal" - "strings" - "syscall" - "unsafe" -) - -func initReadLine() { - C.rl_catch_sigwinch = 0 - C.rl_catch_signals = 0 - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGWINCH) - signal.Notify(c, os.Interrupt) - go func() { - for sig := range c { - switch sig { - case syscall.SIGWINCH: - C.rl_resize_terminal() - - case os.Interrupt: - C.rl_cleanup_after_signal() - default: - - } - } - }() -} - -func readLine(prompt *string) *string { - var p *C.char - - //readline allows an empty prompt(NULL) - if prompt != nil { - p = C.CString(*prompt) - } - - ret := C.readline(p) - - if p != nil { - C.free(unsafe.Pointer(p)) - } - - if ret == nil { - return nil - } //EOF - - s := C.GoString(ret) - C.free(unsafe.Pointer(ret)) - return &s -} - -func addHistory(s string) { - p := C.CString(s) - C.add_history(p) - C.free(unsafe.Pointer(p)) -} - -var indentCount = 0 -var str = "" - -func (self *JSRepl) setIndent() { - open := strings.Count(str, "{") - open += strings.Count(str, "(") - closed := strings.Count(str, "}") - closed += strings.Count(str, ")") - indentCount = open - closed - if indentCount <= 0 { - self.prompt = "> " - } else { - self.prompt = strings.Join(make([]string, indentCount*2), "..") - self.prompt += " " - } -} - -func (self *JSRepl) read() { - initReadLine() -L: - for { - switch result := readLine(&self.prompt); true { - case result == nil: - break L - - case *result != "": - str += *result + "\n" - - self.setIndent() - - if indentCount <= 0 { - if *result == "exit" { - self.Stop() - break L - } - - hist := str[:len(str)-1] - addHistory(hist) //allow user to recall this line - self.history.WriteString(str) - - self.parseInput(str) - - str = "" - } - } - } -} - -func (self *JSRepl) PrintValue(v interface{}) { - method, _ := self.re.Vm.Get("prettyPrint") - v, err := self.re.Vm.ToValue(v) - if err == nil { - val, err := method.Call(method, v) - if err == nil { - fmt.Printf("%v", val) - } - } -} diff --git a/cmd/ethereum/repl/repl_linux.go b/cmd/ethereum/repl/repl_linux.go deleted file mode 120000 index 276f135d7..000000000 --- a/cmd/ethereum/repl/repl_linux.go +++ /dev/null @@ -1 +0,0 @@ -repl_darwin.go \ No newline at end of file diff --git a/cmd/ethereum/repl/repl_windows.go b/cmd/ethereum/repl/repl_windows.go deleted file mode 100644 index d2c405ee9..000000000 --- a/cmd/ethereum/repl/repl_windows.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2013-2014, Jeffrey Wilcke. All rights reserved. -// -// This library 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 2.1 of the License, or (at your option) any later version. -// -// This 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 -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -// MA 02110-1301 USA - -package ethrepl - -import ( - "bufio" - "fmt" - "os" - "strings" -) - -func (self *JSRepl) read() { - reader := bufio.NewReader(os.Stdin) - for { - fmt.Printf(self.prompt) - str, _, err := reader.ReadLine() - if err != nil { - fmt.Println("Error reading input", err) - } else { - if string(str) == "exit" { - self.Stop() - break - } else { - self.parseInput(string(str)) - } - } - } -} - -func addHistory(s string) { -} - -func printColored(outputVal string) { - for outputVal != "" { - codePart := "" - if strings.HasPrefix(outputVal, "\033[32m") { - codePart = "\033[32m" - changeColor(2) - } - if strings.HasPrefix(outputVal, "\033[1m\033[30m") { - codePart = "\033[1m\033[30m" - changeColor(8) - } - if strings.HasPrefix(outputVal, "\033[31m") { - codePart = "\033[31m" - changeColor(red) - } - if strings.HasPrefix(outputVal, "\033[35m") { - codePart = "\033[35m" - changeColor(5) - } - if strings.HasPrefix(outputVal, "\033[0m") { - codePart = "\033[0m" - resetColorful() - } - textPart := outputVal[len(codePart):len(outputVal)] - index := strings.Index(textPart, "\033") - if index == -1 { - outputVal = "" - } else { - outputVal = textPart[index:len(textPart)] - textPart = textPart[0:index] - } - fmt.Printf("%v", textPart) - } -} - -func (self *JSRepl) PrintValue(v interface{}) { - method, _ := self.re.Vm.Get("prettyPrint") - v, err := self.re.Vm.ToValue(v) - if err == nil { - val, err := method.Call(method, v) - if err == nil { - printColored(fmt.Sprintf("%v", val)) - } - } -} From 2393de5d6b535a850e8b5d510aa2ae4f940f3d23 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Mar 2015 10:39:31 +0100 Subject: [PATCH 5/7] Godeps: add github.com/peterh/liner --- Godeps/Godeps.json | 4 + .../src/github.com/peterh/liner/COPYING | 21 + .../src/github.com/peterh/liner/README.md | 95 ++ .../src/github.com/peterh/liner/bsdinput.go | 39 + .../src/github.com/peterh/liner/common.go | 219 +++++ .../github.com/peterh/liner/fallbackinput.go | 57 ++ .../src/github.com/peterh/liner/input.go | 359 ++++++++ .../github.com/peterh/liner/input_darwin.go | 39 + .../github.com/peterh/liner/input_linux.go | 26 + .../src/github.com/peterh/liner/input_test.go | 61 ++ .../github.com/peterh/liner/input_windows.go | 313 +++++++ .../src/github.com/peterh/liner/line.go | 864 ++++++++++++++++++ .../src/github.com/peterh/liner/line_test.go | 90 ++ .../src/github.com/peterh/liner/output.go | 63 ++ .../github.com/peterh/liner/output_windows.go | 54 ++ .../github.com/peterh/liner/prefix_test.go | 37 + .../src/github.com/peterh/liner/race_test.go | 44 + .../src/github.com/peterh/liner/signal.go | 12 + .../github.com/peterh/liner/signal_legacy.go | 11 + .../src/github.com/peterh/liner/unixmode.go | 37 + .../src/github.com/peterh/liner/width.go | 47 + .../src/github.com/peterh/liner/width_test.go | 87 ++ 22 files changed, 2579 insertions(+) create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/COPYING create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/README.md create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/common.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input_linux.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input_test.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/input_windows.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/line.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/line_test.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/output.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/output_windows.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/race_test.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/signal.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/unixmode.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/width.go create mode 100644 Godeps/_workspace/src/github.com/peterh/liner/width_test.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index bf5b59c95..00c6584a9 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -54,6 +54,10 @@ "ImportPath": "github.com/obscuren/qml", "Rev": "c288002b52e905973b131089a8a7c761d4a2c36a" }, + { + "ImportPath": "github.com/peterh/liner", + "Rev": "29f6a646557d83e2b6e9ba05c45fbea9c006dbe8" + }, { "ImportPath": "github.com/rakyll/globalconf", "Rev": "415abc325023f1a00cd2d9fa512e0e71745791a2" diff --git a/Godeps/_workspace/src/github.com/peterh/liner/COPYING b/Godeps/_workspace/src/github.com/peterh/liner/COPYING new file mode 100644 index 000000000..9e8c9f206 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/COPYING @@ -0,0 +1,21 @@ +Copyright © 2012 Peter Harris + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/Godeps/_workspace/src/github.com/peterh/liner/README.md b/Godeps/_workspace/src/github.com/peterh/liner/README.md new file mode 100644 index 000000000..99027c6e2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/README.md @@ -0,0 +1,95 @@ +Liner +===== + +Liner is a command line editor with history. It was inspired by linenoise; +everything Unix-like is a VT100 (or is trying very hard to be). If your +terminal is not pretending to be a VT100, change it. Liner also support +Windows. + +Liner is released under the X11 license (which is similar to the new BSD +license). + +Line Editing +------------ + +The following line editing commands are supported on platforms and terminals +that Liner supports: + +Keystroke | Action +--------- | ------ +Ctrl-A, Home | Move cursor to beginning of line +Ctrl-E, End | Move cursor to end of line +Ctrl-B, Left | Move cursor one character left +Ctrl-F, Right| Move cursor one character right +Ctrl-Left | Move cursor to previous word +Ctrl-Right | Move cursor to next word +Ctrl-D, Del | (if line is *not* empty) Delete character under cursor +Ctrl-D | (if line *is* empty) End of File - usually quits application +Ctrl-C | Reset input (create new empty prompt) +Ctrl-L | Clear screen (line is unmodified) +Ctrl-T | Transpose previous character with current character +Ctrl-H, BackSpace | Delete character before cursor +Ctrl-W | Delete word leading up to cursor +Ctrl-K | Delete from cursor to end of line +Ctrl-U | Delete from start of line to cursor +Ctrl-P, Up | Previous match from history +Ctrl-N, Down | Next match from history +Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel) +Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead) +Tab | Next completion +Shift-Tab | (after Tab) Previous completion + +Getting started +----------------- + +```go +package main + +import ( + "log" + "os" + "strings" + + "github.com/peterh/liner" +) + +var ( + history_fn = "/tmp/.liner_history" + names = []string{"john", "james", "mary", "nancy"} +) + +func main() { + line := liner.NewLiner() + defer line.Close() + + line.SetCompleter(func(line string) (c []string) { + for _, n := range names { + if strings.HasPrefix(n, strings.ToLower(line)) { + c = append(c, n) + } + } + return + }) + + if f, err := os.Open(history_fn); err == nil { + line.ReadHistory(f) + f.Close() + } + + if name, err := line.Prompt("What is your name? "); err != nil { + log.Print("Error reading line: ", err) + } else { + log.Print("Got: ", name) + line.AppendHistory(name) + } + + if f, err := os.Create(history_fn); err != nil { + log.Print("Error writing history file: ", err) + } else { + line.WriteHistory(f) + f.Close() + } +} +``` + +For documentation, see http://godoc.org/github.com/peterh/liner diff --git a/Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go b/Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go new file mode 100644 index 000000000..4b552d44d --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/bsdinput.go @@ -0,0 +1,39 @@ +// +build openbsd freebsd netbsd + +package liner + +import "syscall" + +const ( + getTermios = syscall.TIOCGETA + setTermios = syscall.TIOCSETA +) + +const ( + // Input flags + inpck = 0x010 + istrip = 0x020 + icrnl = 0x100 + ixon = 0x200 + + // Output flags + opost = 0x1 + + // Control flags + cs8 = 0x300 + + // Local flags + isig = 0x080 + icanon = 0x100 + iexten = 0x400 +) + +type termios struct { + Iflag uint32 + Oflag uint32 + Cflag uint32 + Lflag uint32 + Cc [20]byte + Ispeed int32 + Ospeed int32 +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/common.go b/Godeps/_workspace/src/github.com/peterh/liner/common.go new file mode 100644 index 000000000..f8753a195 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/common.go @@ -0,0 +1,219 @@ +/* +Package liner implements a simple command line editor, inspired by linenoise +(https://github.com/antirez/linenoise/). This package supports WIN32 in +addition to the xterm codes supported by everything else. +*/ +package liner + +import ( + "bufio" + "bytes" + "container/ring" + "errors" + "fmt" + "io" + "strings" + "sync" + "unicode/utf8" +) + +type commonState struct { + terminalSupported bool + outputRedirected bool + inputRedirected bool + history []string + historyMutex sync.RWMutex + completer WordCompleter + columns int + killRing *ring.Ring + ctrlCAborts bool + r *bufio.Reader + tabStyle TabStyle +} + +// TabStyle is used to select how tab completions are displayed. +type TabStyle int + +// Two tab styles are currently available: +// +// TabCircular cycles through each completion item and displays it directly on +// the prompt +// +// TabPrints prints the list of completion items to the screen after a second +// tab key is pressed. This behaves similar to GNU readline and BASH (which +// uses readline) +const ( + TabCircular TabStyle = iota + TabPrints +) + +// ErrPromptAborted is returned from Prompt or PasswordPrompt when the user presses Ctrl-C +// if SetCtrlCAborts(true) has been called on the State +var ErrPromptAborted = errors.New("prompt aborted") + +// ErrNotTerminalOutput is returned from Prompt or PasswordPrompt if the +// platform is normally supported, but stdout has been redirected +var ErrNotTerminalOutput = errors.New("standard output is not a terminal") + +// Max elements to save on the killring +const KillRingMax = 60 + +// HistoryLimit is the maximum number of entries saved in the scrollback history. +const HistoryLimit = 1000 + +// ReadHistory reads scrollback history from r. Returns the number of lines +// read, and any read error (except io.EOF). +func (s *State) ReadHistory(r io.Reader) (num int, err error) { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + + in := bufio.NewReader(r) + num = 0 + for { + line, part, err := in.ReadLine() + if err == io.EOF { + break + } + if err != nil { + return num, err + } + if part { + return num, fmt.Errorf("line %d is too long", num+1) + } + if !utf8.Valid(line) { + return num, fmt.Errorf("invalid string at line %d", num+1) + } + num++ + s.history = append(s.history, string(line)) + if len(s.history) > HistoryLimit { + s.history = s.history[1:] + } + } + return num, nil +} + +// WriteHistory writes scrollback history to w. Returns the number of lines +// successfully written, and any write error. +// +// Unlike the rest of liner's API, WriteHistory is safe to call +// from another goroutine while Prompt is in progress. +// This exception is to facilitate the saving of the history buffer +// during an unexpected exit (for example, due to Ctrl-C being invoked) +func (s *State) WriteHistory(w io.Writer) (num int, err error) { + s.historyMutex.RLock() + defer s.historyMutex.RUnlock() + + for _, item := range s.history { + _, err := fmt.Fprintln(w, item) + if err != nil { + return num, err + } + num++ + } + return num, nil +} + +// AppendHistory appends an entry to the scrollback history. AppendHistory +// should be called iff Prompt returns a valid command. +func (s *State) AppendHistory(item string) { + s.historyMutex.Lock() + defer s.historyMutex.Unlock() + + if len(s.history) > 0 { + if item == s.history[len(s.history)-1] { + return + } + } + s.history = append(s.history, item) + if len(s.history) > HistoryLimit { + s.history = s.history[1:] + } +} + +// Returns the history lines starting with prefix +func (s *State) getHistoryByPrefix(prefix string) (ph []string) { + for _, h := range s.history { + if strings.HasPrefix(h, prefix) { + ph = append(ph, h) + } + } + return +} + +// Returns the history lines matching the inteligent search +func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) { + if pattern == "" { + return + } + for _, h := range s.history { + if i := strings.Index(h, pattern); i >= 0 { + ph = append(ph, h) + pos = append(pos, i) + } + } + return +} + +// Completer takes the currently edited line content at the left of the cursor +// and returns a list of completion candidates. +// If the line is "Hello, wo!!!" and the cursor is before the first '!', "Hello, wo" is passed +// to the completer which may return {"Hello, world", "Hello, Word"} to have "Hello, world!!!". +type Completer func(line string) []string + +// WordCompleter takes the currently edited line with the cursor position and +// returns the completion candidates for the partial word to be completed. +// If the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, wo!!!", 9) is passed +// to the completer which may returns ("Hello, ", {"world", "Word"}, "!!!") to have "Hello, world!!!". +type WordCompleter func(line string, pos int) (head string, completions []string, tail string) + +// SetCompleter sets the completion function that Liner will call to +// fetch completion candidates when the user presses tab. +func (s *State) SetCompleter(f Completer) { + if f == nil { + s.completer = nil + return + } + s.completer = func(line string, pos int) (string, []string, string) { + return "", f(line[:pos]), line[pos:] + } +} + +// SetWordCompleter sets the completion function that Liner will call to +// fetch completion candidates when the user presses tab. +func (s *State) SetWordCompleter(f WordCompleter) { + s.completer = f +} + +// SetTabCompletionStyle sets the behvavior when the Tab key is pressed +// for auto-completion. TabCircular is the default behavior and cycles +// through the list of candidates at the prompt. TabPrints will print +// the available completion candidates to the screen similar to BASH +// and GNU Readline +func (s *State) SetTabCompletionStyle(tabStyle TabStyle) { + s.tabStyle = tabStyle +} + +// ModeApplier is the interface that wraps a representation of the terminal +// mode. ApplyMode sets the terminal to this mode. +type ModeApplier interface { + ApplyMode() error +} + +// SetCtrlCAborts sets whether Prompt on a supported terminal will return an +// ErrPromptAborted when Ctrl-C is pressed. The default is false (will not +// return when Ctrl-C is pressed). Unsupported terminals typically raise SIGINT +// (and Prompt does not return) regardless of the value passed to SetCtrlCAborts. +func (s *State) SetCtrlCAborts(aborts bool) { + s.ctrlCAborts = aborts +} + +func (s *State) promptUnsupported(p string) (string, error) { + if !s.inputRedirected { + fmt.Print(p) + } + linebuf, _, err := s.r.ReadLine() + if err != nil { + return "", err + } + return string(bytes.TrimSpace(linebuf)), nil +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go b/Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go new file mode 100644 index 000000000..d9eb79d9e --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/fallbackinput.go @@ -0,0 +1,57 @@ +// +build !windows,!linux,!darwin,!openbsd,!freebsd,!netbsd + +package liner + +import ( + "bufio" + "errors" + "os" +) + +// State represents an open terminal +type State struct { + commonState +} + +// Prompt displays p, and then waits for user input. Prompt does not support +// line editing on this operating system. +func (s *State) Prompt(p string) (string, error) { + return s.promptUnsupported(p) +} + +// PasswordPrompt is not supported in this OS. +func (s *State) PasswordPrompt(p string) (string, error) { + return "", errors.New("liner: function not supported in this terminal") +} + +// NewLiner initializes a new *State +// +// Note that this operating system uses a fallback mode without line +// editing. Patches welcome. +func NewLiner() *State { + var s State + s.r = bufio.NewReader(os.Stdin) + return &s +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + return nil +} + +// TerminalSupported returns false because line editing is not +// supported on this platform. +func TerminalSupported() bool { + return false +} + +type noopMode struct{} + +func (n noopMode) ApplyMode() error { + return nil +} + +// TerminalMode returns a noop InputModeSetter on this platform. +func TerminalMode() (ModeApplier, error) { + return noopMode{}, nil +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input.go b/Godeps/_workspace/src/github.com/peterh/liner/input.go new file mode 100644 index 000000000..cf71d2bce --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input.go @@ -0,0 +1,359 @@ +// +build linux darwin openbsd freebsd netbsd + +package liner + +import ( + "bufio" + "errors" + "os" + "os/signal" + "strconv" + "strings" + "syscall" + "time" +) + +type nexter struct { + r rune + err error +} + +// State represents an open terminal +type State struct { + commonState + origMode termios + defaultMode termios + next <-chan nexter + winch chan os.Signal + pending []rune + useCHA bool +} + +// NewLiner initializes a new *State, and sets the terminal into raw mode. To +// restore the terminal to its previous state, call State.Close(). +// +// Note if you are still using Go 1.0: NewLiner handles SIGWINCH, so it will +// leak a channel every time you call it. Therefore, it is recommened that you +// upgrade to a newer release of Go, or ensure that NewLiner is only called +// once. +func NewLiner() *State { + var s State + s.r = bufio.NewReader(os.Stdin) + + s.terminalSupported = TerminalSupported() + if m, err := TerminalMode(); err == nil { + s.origMode = *m.(*termios) + } else { + s.terminalSupported = false + s.inputRedirected = true + } + if _, err := getMode(syscall.Stdout); err != 0 { + s.terminalSupported = false + s.outputRedirected = true + } + if s.terminalSupported { + mode := s.origMode + mode.Iflag &^= icrnl | inpck | istrip | ixon + mode.Cflag |= cs8 + mode.Lflag &^= syscall.ECHO | icanon | iexten + mode.ApplyMode() + + winch := make(chan os.Signal, 1) + signal.Notify(winch, syscall.SIGWINCH) + s.winch = winch + + s.checkOutput() + } + + if !s.outputRedirected { + s.getColumns() + s.outputRedirected = s.columns <= 0 + } + + return &s +} + +var errTimedOut = errors.New("timeout") + +func (s *State) startPrompt() { + if s.terminalSupported { + if m, err := TerminalMode(); err == nil { + s.defaultMode = *m.(*termios) + mode := s.defaultMode + mode.Lflag &^= isig + mode.ApplyMode() + } + } + s.restartPrompt() +} + +func (s *State) restartPrompt() { + next := make(chan nexter) + go func() { + for { + var n nexter + n.r, _, n.err = s.r.ReadRune() + next <- n + // Shut down nexter loop when an end condition has been reached + if n.err != nil || n.r == '\n' || n.r == '\r' || n.r == ctrlC || n.r == ctrlD { + close(next) + return + } + } + }() + s.next = next +} + +func (s *State) stopPrompt() { + if s.terminalSupported { + s.defaultMode.ApplyMode() + } +} + +func (s *State) nextPending(timeout <-chan time.Time) (rune, error) { + select { + case thing, ok := <-s.next: + if !ok { + return 0, errors.New("liner: internal error") + } + if thing.err != nil { + return 0, thing.err + } + s.pending = append(s.pending, thing.r) + return thing.r, nil + case <-timeout: + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, errTimedOut + } + // not reached + return 0, nil +} + +func (s *State) readNext() (interface{}, error) { + if len(s.pending) > 0 { + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + var r rune + select { + case thing, ok := <-s.next: + if !ok { + return 0, errors.New("liner: internal error") + } + if thing.err != nil { + return nil, thing.err + } + r = thing.r + case <-s.winch: + s.getColumns() + return winch, nil + } + if r != esc { + return r, nil + } + s.pending = append(s.pending, r) + + // Wait at most 50 ms for the rest of the escape sequence + // If nothing else arrives, it was an actual press of the esc key + timeout := time.After(50 * time.Millisecond) + flag, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return flag, nil + } + return unknown, err + } + + switch flag { + case '[': + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return unknown, err + } + switch code { + case 'A': + s.pending = s.pending[:0] // escape code complete + return up, nil + case 'B': + s.pending = s.pending[:0] // escape code complete + return down, nil + case 'C': + s.pending = s.pending[:0] // escape code complete + return right, nil + case 'D': + s.pending = s.pending[:0] // escape code complete + return left, nil + case 'F': + s.pending = s.pending[:0] // escape code complete + return end, nil + case 'H': + s.pending = s.pending[:0] // escape code complete + return home, nil + case 'Z': + s.pending = s.pending[:0] // escape code complete + return shiftTab, nil + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num := []rune{code} + for { + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return nil, err + } + switch code { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num = append(num, code) + case ';': + // Modifier code to follow + // This only supports Ctrl-left and Ctrl-right for now + x, _ := strconv.ParseInt(string(num), 10, 32) + if x != 1 { + // Can't be left or right + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + num = num[:0] + for { + code, err = s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + return nil, err + } + switch code { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + num = append(num, code) + case 'C', 'D': + // right, left + mod, _ := strconv.ParseInt(string(num), 10, 32) + if mod != 5 { + // Not bare Ctrl + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + s.pending = s.pending[:0] // escape code complete + if code == 'C' { + return wordRight, nil + } + return wordLeft, nil + default: + // Not left or right + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + } + case '~': + s.pending = s.pending[:0] // escape code complete + x, _ := strconv.ParseInt(string(num), 10, 32) + switch x { + case 2: + return insert, nil + case 3: + return del, nil + case 5: + return pageUp, nil + case 6: + return pageDown, nil + case 7: + return home, nil + case 8: + return end, nil + case 15: + return f5, nil + case 17: + return f6, nil + case 18: + return f7, nil + case 19: + return f8, nil + case 20: + return f9, nil + case 21: + return f10, nil + case 23: + return f11, nil + case 24: + return f12, nil + default: + return unknown, nil + } + default: + // unrecognized escape code + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + } + } + + case 'O': + code, err := s.nextPending(timeout) + if err != nil { + if err == errTimedOut { + return code, nil + } + return nil, err + } + s.pending = s.pending[:0] // escape code complete + switch code { + case 'c': + return wordRight, nil + case 'd': + return wordLeft, nil + case 'H': + return home, nil + case 'F': + return end, nil + case 'P': + return f1, nil + case 'Q': + return f2, nil + case 'R': + return f3, nil + case 'S': + return f4, nil + default: + return unknown, nil + } + case 'y': + s.pending = s.pending[:0] // escape code complete + return altY, nil + default: + rv := s.pending[0] + s.pending = s.pending[1:] + return rv, nil + } + + // not reached + return r, nil +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + stopSignal(s.winch) + if s.terminalSupported { + s.origMode.ApplyMode() + } + return nil +} + +// TerminalSupported returns true if the current terminal supports +// line editing features, and false if liner will use the 'dumb' +// fallback for input. +func TerminalSupported() bool { + bad := map[string]bool{"": true, "dumb": true, "cons25": true} + return !bad[strings.ToLower(os.Getenv("TERM"))] +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go b/Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go new file mode 100644 index 000000000..23c9c5da0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input_darwin.go @@ -0,0 +1,39 @@ +// +build darwin + +package liner + +import "syscall" + +const ( + getTermios = syscall.TIOCGETA + setTermios = syscall.TIOCSETA +) + +const ( + // Input flags + inpck = 0x010 + istrip = 0x020 + icrnl = 0x100 + ixon = 0x200 + + // Output flags + opost = 0x1 + + // Control flags + cs8 = 0x300 + + // Local flags + isig = 0x080 + icanon = 0x100 + iexten = 0x400 +) + +type termios struct { + Iflag uintptr + Oflag uintptr + Cflag uintptr + Lflag uintptr + Cc [20]byte + Ispeed uintptr + Ospeed uintptr +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_linux.go b/Godeps/_workspace/src/github.com/peterh/liner/input_linux.go new file mode 100644 index 000000000..6ca87124e --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input_linux.go @@ -0,0 +1,26 @@ +// +build linux + +package liner + +import "syscall" + +const ( + getTermios = syscall.TCGETS + setTermios = syscall.TCSETS +) + +const ( + icrnl = syscall.ICRNL + inpck = syscall.INPCK + istrip = syscall.ISTRIP + ixon = syscall.IXON + opost = syscall.OPOST + cs8 = syscall.CS8 + isig = syscall.ISIG + icanon = syscall.ICANON + iexten = syscall.IEXTEN +) + +type termios struct { + syscall.Termios +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_test.go b/Godeps/_workspace/src/github.com/peterh/liner/input_test.go new file mode 100644 index 000000000..e515a4894 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input_test.go @@ -0,0 +1,61 @@ +// +build !windows + +package liner + +import ( + "bufio" + "bytes" + "testing" +) + +func (s *State) expectRune(t *testing.T, r rune) { + item, err := s.readNext() + if err != nil { + t.Fatalf("Expected rune '%c', got error %s\n", r, err) + } + if v, ok := item.(rune); !ok { + t.Fatalf("Expected rune '%c', got non-rune %v\n", r, v) + } else { + if v != r { + t.Fatalf("Expected rune '%c', got rune '%c'\n", r, v) + } + } +} + +func (s *State) expectAction(t *testing.T, a action) { + item, err := s.readNext() + if err != nil { + t.Fatalf("Expected Action %d, got error %s\n", a, err) + } + if v, ok := item.(action); !ok { + t.Fatalf("Expected Action %d, got non-Action %v\n", a, v) + } else { + if v != a { + t.Fatalf("Expected Action %d, got Action %d\n", a, v) + } + } +} + +func TestTypes(t *testing.T) { + input := []byte{'A', 27, 'B', 27, 91, 68, 27, '[', '1', ';', '5', 'D', 'e'} + var s State + s.r = bufio.NewReader(bytes.NewBuffer(input)) + + next := make(chan nexter) + go func() { + for { + var n nexter + n.r, _, n.err = s.r.ReadRune() + next <- n + } + }() + s.next = next + + s.expectRune(t, 'A') + s.expectRune(t, 27) + s.expectRune(t, 'B') + s.expectAction(t, left) + s.expectAction(t, wordLeft) + + s.expectRune(t, 'e') +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go b/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go new file mode 100644 index 000000000..cc98719c1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/input_windows.go @@ -0,0 +1,313 @@ +package liner + +import ( + "bufio" + "os" + "syscall" + "unsafe" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32.dll") + + procGetStdHandle = kernel32.NewProc("GetStdHandle") + procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW") + procGetConsoleMode = kernel32.NewProc("GetConsoleMode") + procSetConsoleMode = kernel32.NewProc("SetConsoleMode") + procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition") + procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") + procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW") +) + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + std_input_handle = uint32(-10 & 0xFFFFFFFF) + std_output_handle = uint32(-11 & 0xFFFFFFFF) + std_error_handle = uint32(-12 & 0xFFFFFFFF) + invalid_handle_value = ^uintptr(0) +) + +type inputMode uint32 + +// State represents an open terminal +type State struct { + commonState + handle syscall.Handle + hOut syscall.Handle + origMode inputMode + defaultMode inputMode + key interface{} + repeat uint16 +} + +const ( + enableEchoInput = 0x4 + enableInsertMode = 0x20 + enableLineInput = 0x2 + enableMouseInput = 0x10 + enableProcessedInput = 0x1 + enableQuickEditMode = 0x40 + enableWindowInput = 0x8 +) + +// NewLiner initializes a new *State, and sets the terminal into raw mode. To +// restore the terminal to its previous state, call State.Close(). +func NewLiner() *State { + var s State + hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle)) + s.handle = syscall.Handle(hIn) + hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle)) + s.hOut = syscall.Handle(hOut) + + s.terminalSupported = true + if m, err := TerminalMode(); err == nil { + s.origMode = m.(inputMode) + mode := s.origMode + mode &^= enableEchoInput + mode &^= enableInsertMode + mode &^= enableLineInput + mode &^= enableMouseInput + mode |= enableWindowInput + mode.ApplyMode() + } else { + s.inputRedirected = true + s.r = bufio.NewReader(os.Stdin) + } + + s.getColumns() + s.outputRedirected = s.columns <= 0 + + return &s +} + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + focus_event = 0x0010 + key_event = 0x0001 + menu_event = 0x0008 + mouse_event = 0x0002 + window_buffer_size_event = 0x0004 +) + +type input_record struct { + eventType uint16 + pad uint16 + blob [16]byte +} + +type key_event_record struct { + KeyDown int32 + RepeatCount uint16 + VirtualKeyCode uint16 + VirtualScanCode uint16 + Char int16 + ControlKeyState uint32 +} + +// These names are from the Win32 api, so they use underscores (contrary to +// what golint suggests) +const ( + vk_tab = 0x09 + vk_prior = 0x21 + vk_next = 0x22 + vk_end = 0x23 + vk_home = 0x24 + vk_left = 0x25 + vk_up = 0x26 + vk_right = 0x27 + vk_down = 0x28 + vk_insert = 0x2d + vk_delete = 0x2e + vk_f1 = 0x70 + vk_f2 = 0x71 + vk_f3 = 0x72 + vk_f4 = 0x73 + vk_f5 = 0x74 + vk_f6 = 0x75 + vk_f7 = 0x76 + vk_f8 = 0x77 + vk_f9 = 0x78 + vk_f10 = 0x79 + vk_f11 = 0x7a + vk_f12 = 0x7b + yKey = 0x59 +) + +const ( + shiftPressed = 0x0010 + leftAltPressed = 0x0002 + leftCtrlPressed = 0x0008 + rightAltPressed = 0x0001 + rightCtrlPressed = 0x0004 + + modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed +) + +func (s *State) readNext() (interface{}, error) { + if s.repeat > 0 { + s.repeat-- + return s.key, nil + } + + var input input_record + pbuf := uintptr(unsafe.Pointer(&input)) + var rv uint32 + prv := uintptr(unsafe.Pointer(&rv)) + + for { + ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv) + + if ok == 0 { + return nil, err + } + + if input.eventType == window_buffer_size_event { + xy := (*coord)(unsafe.Pointer(&input.blob[0])) + s.columns = int(xy.x) + return winch, nil + } + if input.eventType != key_event { + continue + } + ke := (*key_event_record)(unsafe.Pointer(&input.blob[0])) + if ke.KeyDown == 0 { + continue + } + + if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed { + s.key = shiftTab + } else if ke.VirtualKeyCode == yKey && (ke.ControlKeyState&modKeys == leftAltPressed || + ke.ControlKeyState&modKeys == rightAltPressed) { + s.key = altY + } else if ke.Char > 0 { + s.key = rune(ke.Char) + } else { + switch ke.VirtualKeyCode { + case vk_prior: + s.key = pageUp + case vk_next: + s.key = pageDown + case vk_end: + s.key = end + case vk_home: + s.key = home + case vk_left: + s.key = left + if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 { + if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) { + s.key = wordLeft + } + } + case vk_right: + s.key = right + if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 { + if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) { + s.key = wordRight + } + } + case vk_up: + s.key = up + case vk_down: + s.key = down + case vk_insert: + s.key = insert + case vk_delete: + s.key = del + case vk_f1: + s.key = f1 + case vk_f2: + s.key = f2 + case vk_f3: + s.key = f3 + case vk_f4: + s.key = f4 + case vk_f5: + s.key = f5 + case vk_f6: + s.key = f6 + case vk_f7: + s.key = f7 + case vk_f8: + s.key = f8 + case vk_f9: + s.key = f9 + case vk_f10: + s.key = f10 + case vk_f11: + s.key = f11 + case vk_f12: + s.key = f12 + default: + // Eat modifier keys + // TODO: return Action(Unknown) if the key isn't a + // modifier. + continue + } + } + + if ke.RepeatCount > 1 { + s.repeat = ke.RepeatCount - 1 + } + return s.key, nil + } + return unknown, nil +} + +// Close returns the terminal to its previous mode +func (s *State) Close() error { + s.origMode.ApplyMode() + return nil +} + +func (s *State) startPrompt() { + if m, err := TerminalMode(); err == nil { + s.defaultMode = m.(inputMode) + mode := s.defaultMode + mode &^= enableProcessedInput + mode.ApplyMode() + } +} + +func (s *State) restartPrompt() { +} + +func (s *State) stopPrompt() { + s.defaultMode.ApplyMode() +} + +// TerminalSupported returns true because line editing is always +// supported on Windows. +func TerminalSupported() bool { + return true +} + +func (mode inputMode) ApplyMode() error { + hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle)) + if hIn == invalid_handle_value || hIn == 0 { + return err + } + ok, _, err := procSetConsoleMode.Call(hIn, uintptr(mode)) + if ok != 0 { + err = nil + } + return err +} + +// TerminalMode returns the current terminal input mode as an InputModeSetter. +// +// This function is provided for convenience, and should +// not be necessary for most users of liner. +func TerminalMode() (ModeApplier, error) { + var mode inputMode + hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle)) + if hIn == invalid_handle_value || hIn == 0 { + return nil, err + } + ok, _, err := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&mode))) + if ok != 0 { + err = nil + } + return mode, err +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/line.go b/Godeps/_workspace/src/github.com/peterh/liner/line.go new file mode 100644 index 000000000..a70fb59e5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/line.go @@ -0,0 +1,864 @@ +// +build windows linux darwin openbsd freebsd netbsd + +package liner + +import ( + "container/ring" + "errors" + "fmt" + "io" + "strings" + "unicode" + "unicode/utf8" +) + +type action int + +const ( + left action = iota + right + up + down + home + end + insert + del + pageUp + pageDown + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + altY + shiftTab + wordLeft + wordRight + winch + unknown +) + +const ( + ctrlA = 1 + ctrlB = 2 + ctrlC = 3 + ctrlD = 4 + ctrlE = 5 + ctrlF = 6 + ctrlG = 7 + ctrlH = 8 + tab = 9 + lf = 10 + ctrlK = 11 + ctrlL = 12 + cr = 13 + ctrlN = 14 + ctrlO = 15 + ctrlP = 16 + ctrlQ = 17 + ctrlR = 18 + ctrlS = 19 + ctrlT = 20 + ctrlU = 21 + ctrlV = 22 + ctrlW = 23 + ctrlX = 24 + ctrlY = 25 + ctrlZ = 26 + esc = 27 + bs = 127 +) + +const ( + beep = "\a" +) + +type tabDirection int + +const ( + tabForward tabDirection = iota + tabReverse +) + +func (s *State) refresh(prompt []rune, buf []rune, pos int) error { + s.cursorPos(0) + _, err := fmt.Print(string(prompt)) + if err != nil { + return err + } + + pLen := countGlyphs(prompt) + bLen := countGlyphs(buf) + pos = countGlyphs(buf[:pos]) + if pLen+bLen < s.columns { + _, err = fmt.Print(string(buf)) + s.eraseLine() + s.cursorPos(pLen + pos) + } else { + // Find space available + space := s.columns - pLen + space-- // space for cursor + start := pos - space/2 + end := start + space + if end > bLen { + end = bLen + start = end - space + } + if start < 0 { + start = 0 + end = space + } + pos -= start + + // Leave space for markers + if start > 0 { + start++ + } + if end < bLen { + end-- + } + startRune := len(getPrefixGlyphs(buf, start)) + line := getPrefixGlyphs(buf[startRune:], end-start) + + // Output + if start > 0 { + fmt.Print("{") + } + fmt.Print(string(line)) + if end < bLen { + fmt.Print("}") + } + + // Set cursor position + s.eraseLine() + s.cursorPos(pLen + pos) + } + return err +} + +func longestCommonPrefix(strs []string) string { + if len(strs) == 0 { + return "" + } + longest := strs[0] + + for _, str := range strs[1:] { + for !strings.HasPrefix(str, longest) { + longest = longest[:len(longest)-1] + } + } + // Remove trailing partial runes + longest = strings.TrimRight(longest, "\uFFFD") + return longest +} + +func (s *State) circularTabs(items []string) func(tabDirection) (string, error) { + item := -1 + return func(direction tabDirection) (string, error) { + if direction == tabForward { + if item < len(items)-1 { + item++ + } else { + item = 0 + } + } else if direction == tabReverse { + if item > 0 { + item-- + } else { + item = len(items) - 1 + } + } + return items[item], nil + } +} + +func (s *State) printedTabs(items []string) func(tabDirection) (string, error) { + numTabs := 1 + prefix := longestCommonPrefix(items) + return func(direction tabDirection) (string, error) { + if len(items) == 1 { + return items[0], nil + } + + if numTabs == 2 { + if len(items) > 100 { + fmt.Printf("\nDisplay all %d possibilities? (y or n) ", len(items)) + for { + next, err := s.readNext() + if err != nil { + return prefix, err + } + + if key, ok := next.(rune); ok { + if unicode.ToLower(key) == 'n' { + return prefix, nil + } else if unicode.ToLower(key) == 'y' { + break + } + } + } + } + fmt.Println("") + maxWidth := 0 + for _, item := range items { + if len(item) >= maxWidth { + maxWidth = len(item) + 1 + } + } + + numColumns := s.columns / maxWidth + numRows := len(items) / numColumns + if len(items)%numColumns > 0 { + numRows++ + } + + if len(items) <= numColumns { + maxWidth = 0 + } + for i := 0; i < numRows; i++ { + for j := 0; j < numColumns*numRows; j += numRows { + if i+j < len(items) { + if maxWidth > 0 { + fmt.Printf("%-*s", maxWidth, items[i+j]) + } else { + fmt.Printf("%v ", items[i+j]) + } + } + } + fmt.Println("") + } + } else { + numTabs++ + } + return prefix, nil + } +} + +func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interface{}, error) { + if s.completer == nil { + return line, pos, rune(esc), nil + } + head, list, tail := s.completer(string(line), pos) + if len(list) <= 0 { + return line, pos, rune(esc), nil + } + hl := utf8.RuneCountInString(head) + if len(list) == 1 { + s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0])) + return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), nil + } + + direction := tabForward + tabPrinter := s.circularTabs(list) + if s.tabStyle == TabPrints { + tabPrinter = s.printedTabs(list) + } + + for { + pick, err := tabPrinter(direction) + if err != nil { + return line, pos, rune(esc), err + } + s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick)) + + next, err := s.readNext() + if err != nil { + return line, pos, rune(esc), err + } + if key, ok := next.(rune); ok { + if key == tab { + direction = tabForward + continue + } + if key == esc { + return line, pos, rune(esc), nil + } + } + if a, ok := next.(action); ok && a == shiftTab { + direction = tabReverse + continue + } + return []rune(head + pick + tail), hl + utf8.RuneCountInString(pick), next, nil + } + // Not reached + return line, pos, rune(esc), nil +} + +// reverse intelligent search, implements a bash-like history search. +func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) { + p := "(reverse-i-search)`': " + s.refresh([]rune(p), origLine, origPos) + + line := []rune{} + pos := 0 + foundLine := string(origLine) + foundPos := origPos + + getLine := func() ([]rune, []rune, int) { + search := string(line) + prompt := "(reverse-i-search)`%s': " + return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos + } + + history, positions := s.getHistoryByPattern(string(line)) + historyPos := len(history) - 1 + + for { + next, err := s.readNext() + if err != nil { + return []rune(foundLine), foundPos, rune(esc), err + } + + switch v := next.(type) { + case rune: + switch v { + case ctrlR: // Search backwards + if historyPos > 0 && historyPos < len(history) { + historyPos-- + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + fmt.Print(beep) + } + case ctrlS: // Search forward + if historyPos < len(history)-1 && historyPos >= 0 { + historyPos++ + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + fmt.Print(beep) + } + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + + // For each char deleted, display the last matching line of history + history, positions := s.getHistoryByPattern(string(line)) + historyPos = len(history) - 1 + if len(history) > 0 { + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + foundLine = "" + foundPos = 0 + } + } + case ctrlG: // Cancel + return origLine, origPos, rune(esc), err + + case tab, cr, lf, ctrlA, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK, + ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: + fallthrough + case 0, ctrlC, esc, 28, 29, 30, 31: + return []rune(foundLine), foundPos, next, err + default: + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + + // For each keystroke typed, display the last matching line of history + history, positions = s.getHistoryByPattern(string(line)) + historyPos = len(history) - 1 + if len(history) > 0 { + foundLine = history[historyPos] + foundPos = positions[historyPos] + } else { + foundLine = "" + foundPos = 0 + } + } + case action: + return []rune(foundLine), foundPos, next, err + } + s.refresh(getLine()) + } +} + +// addToKillRing adds some text to the kill ring. If mode is 0 it adds it to a +// new node in the end of the kill ring, and move the current pointer to the new +// node. If mode is 1 or 2 it appends or prepends the text to the current entry +// of the killRing. +func (s *State) addToKillRing(text []rune, mode int) { + // Don't use the same underlying array as text + killLine := make([]rune, len(text)) + copy(killLine, text) + + // Point killRing to a newNode, procedure depends on the killring state and + // append mode. + if mode == 0 { // Add new node to killRing + if s.killRing == nil { // if killring is empty, create a new one + s.killRing = ring.New(1) + } else if s.killRing.Len() >= KillRingMax { // if killring is "full" + s.killRing = s.killRing.Next() + } else { // Normal case + s.killRing.Link(ring.New(1)) + s.killRing = s.killRing.Next() + } + } else { + if s.killRing == nil { // if killring is empty, create a new one + s.killRing = ring.New(1) + s.killRing.Value = []rune{} + } + if mode == 1 { // Append to last entry + killLine = append(s.killRing.Value.([]rune), killLine...) + } else if mode == 2 { // Prepend to last entry + killLine = append(killLine, s.killRing.Value.([]rune)...) + } + } + + // Save text in the current killring node + s.killRing.Value = killLine +} + +func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{}, error) { + if s.killRing == nil { + return text, pos, rune(esc), nil + } + + lineStart := text[:pos] + lineEnd := text[pos:] + var line []rune + + for { + value := s.killRing.Value.([]rune) + line = make([]rune, 0) + line = append(line, lineStart...) + line = append(line, value...) + line = append(line, lineEnd...) + + pos = len(lineStart) + len(value) + s.refresh(p, line, pos) + + next, err := s.readNext() + if err != nil { + return line, pos, next, err + } + + switch v := next.(type) { + case rune: + return line, pos, next, nil + case action: + switch v { + case altY: + s.killRing = s.killRing.Prev() + default: + return line, pos, next, nil + } + } + } + + return line, pos, esc, nil +} + +// Prompt displays p, and then waits for user input. Prompt allows line editing +// if the terminal supports it. +func (s *State) Prompt(prompt string) (string, error) { + if s.inputRedirected { + return s.promptUnsupported(prompt) + } + if s.outputRedirected { + return "", ErrNotTerminalOutput + } + if !s.terminalSupported { + return s.promptUnsupported(prompt) + } + + s.historyMutex.RLock() + defer s.historyMutex.RUnlock() + + s.startPrompt() + defer s.stopPrompt() + s.getColumns() + + fmt.Print(prompt) + p := []rune(prompt) + var line []rune + pos := 0 + historyEnd := "" + prefixHistory := s.getHistoryByPrefix(string(line)) + historyPos := len(prefixHistory) + historyAction := false // used to mark history related actions + killAction := 0 // used to mark kill related actions +mainLoop: + for { + next, err := s.readNext() + haveNext: + if err != nil { + return "", err + } + + historyAction = false + switch v := next.(type) { + case rune: + switch v { + case cr, lf: + fmt.Println() + break mainLoop + case ctrlA: // Start of line + pos = 0 + s.refresh(p, line, pos) + case ctrlE: // End of line + pos = len(line) + s.refresh(p, line, pos) + case ctrlB: // left + if pos > 0 { + pos -= len(getSuffixGlyphs(line[:pos], 1)) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlF: // right + if pos < len(line) { + pos += len(getPrefixGlyphs(line[pos:], 1)) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlD: // del + if pos == 0 && len(line) == 0 { + // exit + return "", io.EOF + } + + // ctrlD is a potential EOF, so the rune reader shuts down. + // Therefore, if it isn't actually an EOF, we must re-startPrompt. + s.restartPrompt() + + if pos >= len(line) { + fmt.Print(beep) + } else { + n := len(getPrefixGlyphs(line[pos:], 1)) + line = append(line[:pos], line[pos+n:]...) + s.refresh(p, line, pos) + } + case ctrlK: // delete remainder of line + if pos >= len(line) { + fmt.Print(beep) + } else { + if killAction > 0 { + s.addToKillRing(line[pos:], 1) // Add in apend mode + } else { + s.addToKillRing(line[pos:], 0) // Add in normal mode + } + + killAction = 2 // Mark that there was a kill action + line = line[:pos] + s.refresh(p, line, pos) + } + case ctrlP: // up + historyAction = true + if historyPos > 0 { + if historyPos == len(prefixHistory) { + historyEnd = string(line) + } + historyPos-- + line = []rune(prefixHistory[historyPos]) + pos = len(line) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlN: // down + historyAction = true + if historyPos < len(prefixHistory) { + historyPos++ + if historyPos == len(prefixHistory) { + line = []rune(historyEnd) + } else { + line = []rune(prefixHistory[historyPos]) + } + pos = len(line) + s.refresh(p, line, pos) + } else { + fmt.Print(beep) + } + case ctrlT: // transpose prev glyph with glyph under cursor + if len(line) < 2 || pos < 1 { + fmt.Print(beep) + } else { + if pos == len(line) { + pos -= len(getSuffixGlyphs(line, 1)) + } + prev := getSuffixGlyphs(line[:pos], 1) + next := getPrefixGlyphs(line[pos:], 1) + scratch := make([]rune, len(prev)) + copy(scratch, prev) + copy(line[pos-len(prev):], next) + copy(line[pos-len(prev)+len(next):], scratch) + pos += len(next) + s.refresh(p, line, pos) + } + case ctrlL: // clear screen + s.eraseScreen() + s.refresh(p, line, pos) + case ctrlC: // reset + fmt.Println("^C") + if s.ctrlCAborts { + return "", ErrPromptAborted + } + line = line[:0] + pos = 0 + fmt.Print(prompt) + s.restartPrompt() + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + s.refresh(p, line, pos) + } + case ctrlU: // Erase line before cursor + if killAction > 0 { + s.addToKillRing(line[:pos], 2) // Add in prepend mode + } else { + s.addToKillRing(line[:pos], 0) // Add in normal mode + } + + killAction = 2 // Mark that there was some killing + line = line[pos:] + pos = 0 + s.refresh(p, line, pos) + case ctrlW: // Erase word + if pos == 0 { + fmt.Print(beep) + break + } + // Remove whitespace to the left + var buf []rune // Store the deleted chars in a buffer + for { + if pos == 0 || !unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Remove non-whitespace to the left + for { + if pos == 0 || unicode.IsSpace(line[pos-1]) { + break + } + buf = append(buf, line[pos-1]) + line = append(line[:pos-1], line[pos:]...) + pos-- + } + // Invert the buffer and save the result on the killRing + var newBuf []rune + for i := len(buf) - 1; i >= 0; i-- { + newBuf = append(newBuf, buf[i]) + } + if killAction > 0 { + s.addToKillRing(newBuf, 2) // Add in prepend mode + } else { + s.addToKillRing(newBuf, 0) // Add in normal mode + } + killAction = 2 // Mark that there was some killing + + s.refresh(p, line, pos) + case ctrlY: // Paste from Yank buffer + line, pos, next, err = s.yank(p, line, pos) + goto haveNext + case ctrlR: // Reverse Search + line, pos, next, err = s.reverseISearch(line, pos) + s.refresh(p, line, pos) + goto haveNext + case tab: // Tab completion + line, pos, next, err = s.tabComplete(p, line, pos) + goto haveNext + // Catch keys that do nothing, but you don't want them to beep + case esc: + // DO NOTHING + // Unused keys + case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX, ctrlZ: + fallthrough + // Catch unhandled control codes (anything <= 31) + case 0, 28, 29, 30, 31: + fmt.Print(beep) + default: + if pos == len(line) && len(p)+len(line) < s.columns-1 { + line = append(line, v) + fmt.Printf("%c", v) + pos++ + } else { + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + s.refresh(p, line, pos) + } + } + case action: + switch v { + case del: + if pos >= len(line) { + fmt.Print(beep) + } else { + n := len(getPrefixGlyphs(line[pos:], 1)) + line = append(line[:pos], line[pos+n:]...) + } + case left: + if pos > 0 { + pos -= len(getSuffixGlyphs(line[:pos], 1)) + } else { + fmt.Print(beep) + } + case wordLeft: + if pos > 0 { + for { + pos-- + if pos == 0 || unicode.IsSpace(line[pos-1]) { + break + } + } + } else { + fmt.Print(beep) + } + case right: + if pos < len(line) { + pos += len(getPrefixGlyphs(line[pos:], 1)) + } else { + fmt.Print(beep) + } + case wordRight: + if pos < len(line) { + for { + pos++ + if pos == len(line) || unicode.IsSpace(line[pos]) { + break + } + } + } else { + fmt.Print(beep) + } + case up: + historyAction = true + if historyPos > 0 { + if historyPos == len(prefixHistory) { + historyEnd = string(line) + } + historyPos-- + line = []rune(prefixHistory[historyPos]) + pos = len(line) + } else { + fmt.Print(beep) + } + case down: + historyAction = true + if historyPos < len(prefixHistory) { + historyPos++ + if historyPos == len(prefixHistory) { + line = []rune(historyEnd) + } else { + line = []rune(prefixHistory[historyPos]) + } + pos = len(line) + } else { + fmt.Print(beep) + } + case home: // Start of line + pos = 0 + case end: // End of line + pos = len(line) + } + s.refresh(p, line, pos) + } + if !historyAction { + prefixHistory = s.getHistoryByPrefix(string(line)) + historyPos = len(prefixHistory) + } + if killAction > 0 { + killAction-- + } + } + return string(line), nil +} + +// PasswordPrompt displays p, and then waits for user input. The input typed by +// the user is not displayed in the terminal. +func (s *State) PasswordPrompt(prompt string) (string, error) { + if s.inputRedirected { + return s.promptUnsupported(prompt) + } + if s.outputRedirected { + return "", ErrNotTerminalOutput + } + if !s.terminalSupported { + return "", errors.New("liner: function not supported in this terminal") + } + + s.startPrompt() + defer s.stopPrompt() + s.getColumns() + + fmt.Print(prompt) + p := []rune(prompt) + var line []rune + pos := 0 + +mainLoop: + for { + next, err := s.readNext() + if err != nil { + return "", err + } + + switch v := next.(type) { + case rune: + switch v { + case cr, lf: + fmt.Println() + break mainLoop + case ctrlD: // del + if pos == 0 && len(line) == 0 { + // exit + return "", io.EOF + } + + // ctrlD is a potential EOF, so the rune reader shuts down. + // Therefore, if it isn't actually an EOF, we must re-startPrompt. + s.restartPrompt() + case ctrlL: // clear screen + s.eraseScreen() + s.refresh(p, []rune{}, 0) + case ctrlH, bs: // Backspace + if pos <= 0 { + fmt.Print(beep) + } else { + n := len(getSuffixGlyphs(line[:pos], 1)) + line = append(line[:pos-n], line[pos:]...) + pos -= n + } + case ctrlC: + fmt.Println("^C") + if s.ctrlCAborts { + return "", ErrPromptAborted + } + line = line[:0] + pos = 0 + fmt.Print(prompt) + s.restartPrompt() + // Unused keys + case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS, + ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ: + fallthrough + // Catch unhandled control codes (anything <= 31) + case 0, 28, 29, 30, 31: + fmt.Print(beep) + default: + line = append(line[:pos], append([]rune{v}, line[pos:]...)...) + pos++ + } + } + } + return string(line), nil +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/line_test.go b/Godeps/_workspace/src/github.com/peterh/liner/line_test.go new file mode 100644 index 000000000..727da6ce7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/line_test.go @@ -0,0 +1,90 @@ +package liner + +import ( + "bytes" + "strings" + "testing" +) + +func TestAppend(t *testing.T) { + var s State + s.AppendHistory("foo") + s.AppendHistory("bar") + + var out bytes.Buffer + num, err := s.WriteHistory(&out) + if err != nil { + t.Fatal("Unexpected error writing history", err) + } + if num != 2 { + t.Fatalf("Expected 2 history entries, got %d", num) + } + + s.AppendHistory("baz") + num, err = s.WriteHistory(&out) + if err != nil { + t.Fatal("Unexpected error writing history", err) + } + if num != 3 { + t.Fatalf("Expected 3 history entries, got %d", num) + } + + s.AppendHistory("baz") + num, err = s.WriteHistory(&out) + if err != nil { + t.Fatal("Unexpected error writing history", err) + } + if num != 3 { + t.Fatalf("Expected 3 history entries after duplicate append, got %d", num) + } + + s.AppendHistory("baz") + +} + +func TestHistory(t *testing.T) { + input := `foo +bar +baz +quux +dingle` + + var s State + num, err := s.ReadHistory(strings.NewReader(input)) + if err != nil { + t.Fatal("Unexpected error reading history", err) + } + if num != 5 { + t.Fatal("Wrong number of history entries read") + } + + var out bytes.Buffer + num, err = s.WriteHistory(&out) + if err != nil { + t.Fatal("Unexpected error writing history", err) + } + if num != 5 { + t.Fatal("Wrong number of history entries written") + } + if strings.TrimSpace(out.String()) != input { + t.Fatal("Round-trip failure") + } + + // Test reading with a trailing newline present + var s2 State + num, err = s2.ReadHistory(&out) + if err != nil { + t.Fatal("Unexpected error reading history the 2nd time", err) + } + if num != 5 { + t.Fatal("Wrong number of history entries read the 2nd time") + } + + num, err = s.ReadHistory(strings.NewReader(input + "\n\xff")) + if err == nil { + t.Fatal("Unexpected success reading corrupted history", err) + } + if num != 5 { + t.Fatal("Wrong number of history entries read the 3rd time") + } +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/output.go b/Godeps/_workspace/src/github.com/peterh/liner/output.go new file mode 100644 index 000000000..e91f4ea81 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/output.go @@ -0,0 +1,63 @@ +// +build linux darwin openbsd freebsd netbsd + +package liner + +import ( + "fmt" + "os" + "strings" + "syscall" + "unsafe" +) + +func (s *State) cursorPos(x int) { + if s.useCHA { + // 'G' is "Cursor Character Absolute (CHA)" + fmt.Printf("\x1b[%dG", x+1) + } else { + // 'C' is "Cursor Forward (CUF)" + fmt.Print("\r") + if x > 0 { + fmt.Printf("\x1b[%dC", x) + } + } +} + +func (s *State) eraseLine() { + fmt.Print("\x1b[0K") +} + +func (s *State) eraseScreen() { + fmt.Print("\x1b[H\x1b[2J") +} + +type winSize struct { + row, col uint16 + xpixel, ypixel uint16 +} + +func (s *State) getColumns() { + var ws winSize + ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout), + syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws))) + if ok < 0 { + s.columns = 80 + } + s.columns = int(ws.col) +} + +func (s *State) checkOutput() { + // xterm is known to support CHA + if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") { + s.useCHA = true + return + } + + // The test for functional ANSI CHA is unreliable (eg the Windows + // telnet command does not support reading the cursor position with + // an ANSI DSR request, despite setting TERM=ansi) + + // Assume CHA isn't supported (which should be safe, although it + // does result in occasional visible cursor jitter) + s.useCHA = false +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go b/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go new file mode 100644 index 000000000..27ae55a14 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/output_windows.go @@ -0,0 +1,54 @@ +package liner + +import ( + "unsafe" +) + +type coord struct { + x, y int16 +} +type smallRect struct { + left, top, right, bottom int16 +} + +type consoleScreenBufferInfo struct { + dwSize coord + dwCursorPosition coord + wAttributes int16 + srWindow smallRect + dwMaximumWindowSize coord +} + +func (s *State) cursorPos(x int) { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), + uintptr(int(x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16)) +} + +func (s *State) eraseLine() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + var numWritten uint32 + procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '), + uintptr(sbi.dwSize.x-sbi.dwCursorPosition.x), + uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16), + uintptr(unsafe.Pointer(&numWritten))) +} + +func (s *State) eraseScreen() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + var numWritten uint32 + procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '), + uintptr(sbi.dwSize.x)*uintptr(sbi.dwSize.y), + 0, + uintptr(unsafe.Pointer(&numWritten))) + procSetConsoleCursorPosition.Call(uintptr(s.hOut), 0) +} + +func (s *State) getColumns() { + var sbi consoleScreenBufferInfo + procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi))) + s.columns = int(sbi.dwSize.x) +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go b/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go new file mode 100644 index 000000000..c826d6c3b --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/prefix_test.go @@ -0,0 +1,37 @@ +// +build windows linux darwin openbsd freebsd netbsd + +package liner + +import "testing" + +type testItem struct { + list []string + prefix string +} + +func TestPrefix(t *testing.T) { + list := []testItem{ + {[]string{"food", "foot"}, "foo"}, + {[]string{"foo", "foot"}, "foo"}, + {[]string{"food", "foo"}, "foo"}, + {[]string{"food", "foe", "foot"}, "fo"}, + {[]string{"food", "foot", "barbeque"}, ""}, + {[]string{"cafeteria", "café"}, "caf"}, + {[]string{"cafe", "café"}, "caf"}, + {[]string{"cafè", "café"}, "caf"}, + {[]string{"cafés", "café"}, "café"}, + {[]string{"áéíóú", "áéíóú"}, "áéíóú"}, + {[]string{"éclairs", "éclairs"}, "éclairs"}, + {[]string{"éclairs are the best", "éclairs are great", "éclairs"}, "éclairs"}, + {[]string{"éclair", "éclairs"}, "éclair"}, + {[]string{"éclairs", "éclair"}, "éclair"}, + {[]string{"éclair", "élan"}, "é"}, + } + + for _, test := range list { + lcp := longestCommonPrefix(test.list) + if lcp != test.prefix { + t.Errorf("%s != %s for %+v", lcp, test.prefix, test.list) + } + } +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/race_test.go b/Godeps/_workspace/src/github.com/peterh/liner/race_test.go new file mode 100644 index 000000000..e320849c7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/race_test.go @@ -0,0 +1,44 @@ +// +build race + +package liner + +import ( + "io/ioutil" + "os" + "sync" + "testing" +) + +func TestWriteHistory(t *testing.T) { + oldout := os.Stdout + defer func() { os.Stdout = oldout }() + oldin := os.Stdout + defer func() { os.Stdin = oldin }() + + newinr, newinw, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + os.Stdin = newinr + newoutr, newoutw, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + defer newoutr.Close() + os.Stdout = newoutw + + var wait sync.WaitGroup + wait.Add(1) + s := NewLiner() + go func() { + s.AppendHistory("foo") + s.AppendHistory("bar") + s.Prompt("") + wait.Done() + }() + + s.WriteHistory(ioutil.Discard) + + newinw.Close() + wait.Wait() +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/signal.go b/Godeps/_workspace/src/github.com/peterh/liner/signal.go new file mode 100644 index 000000000..0cba79e7f --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/signal.go @@ -0,0 +1,12 @@ +// +build go1.1,!windows + +package liner + +import ( + "os" + "os/signal" +) + +func stopSignal(c chan<- os.Signal) { + signal.Stop(c) +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go b/Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go new file mode 100644 index 000000000..fa3672daa --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/signal_legacy.go @@ -0,0 +1,11 @@ +// +build !go1.1,!windows + +package liner + +import ( + "os" +) + +func stopSignal(c chan<- os.Signal) { + // signal.Stop does not exist before Go 1.1 +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/unixmode.go b/Godeps/_workspace/src/github.com/peterh/liner/unixmode.go new file mode 100644 index 000000000..9838923f5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/unixmode.go @@ -0,0 +1,37 @@ +// +build linux darwin freebsd openbsd netbsd + +package liner + +import ( + "syscall" + "unsafe" +) + +func (mode *termios) ApplyMode() error { + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), setTermios, uintptr(unsafe.Pointer(mode))) + + if errno != 0 { + return errno + } + return nil +} + +// TerminalMode returns the current terminal input mode as an InputModeSetter. +// +// This function is provided for convenience, and should +// not be necessary for most users of liner. +func TerminalMode() (ModeApplier, error) { + mode, errno := getMode(syscall.Stdin) + + if errno != 0 { + return nil, errno + } + return mode, nil +} + +func getMode(handle int) (*termios, syscall.Errno) { + var mode termios + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(handle), getTermios, uintptr(unsafe.Pointer(&mode))) + + return &mode, errno +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/width.go b/Godeps/_workspace/src/github.com/peterh/liner/width.go new file mode 100644 index 000000000..02cfb5e1b --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/width.go @@ -0,0 +1,47 @@ +package liner + +import "unicode" + +// These character classes are mostly zero width (when combined). +// A few might not be, depending on the user's font. Fixing this +// is non-trivial, given that some terminals don't support +// ANSI DSR/CPR +var zeroWidth = []*unicode.RangeTable{ + unicode.Mn, + unicode.Me, + unicode.Cc, + unicode.Cf, +} + +func countGlyphs(s []rune) int { + n := 0 + for _, r := range s { + if !unicode.IsOneOf(zeroWidth, r) { + n++ + } + } + return n +} + +func getPrefixGlyphs(s []rune, num int) []rune { + p := 0 + for n := 0; n < num && p < len(s); p++ { + if !unicode.IsOneOf(zeroWidth, s[p]) { + n++ + } + } + for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) { + p++ + } + return s[:p] +} + +func getSuffixGlyphs(s []rune, num int) []rune { + p := len(s) + for n := 0; n < num && p > 0; p-- { + if !unicode.IsOneOf(zeroWidth, s[p-1]) { + n++ + } + } + return s[p:] +} diff --git a/Godeps/_workspace/src/github.com/peterh/liner/width_test.go b/Godeps/_workspace/src/github.com/peterh/liner/width_test.go new file mode 100644 index 000000000..134920a4b --- /dev/null +++ b/Godeps/_workspace/src/github.com/peterh/liner/width_test.go @@ -0,0 +1,87 @@ +package liner + +import ( + "strconv" + "testing" +) + +func accent(in []rune) []rune { + var out []rune + for _, r := range in { + out = append(out, r) + out = append(out, '\u0301') + } + return out +} + +var testString = []rune("query") + +func TestCountGlyphs(t *testing.T) { + count := countGlyphs(testString) + if count != len(testString) { + t.Errorf("ASCII count incorrect. %d != %d", count, len(testString)) + } + count = countGlyphs(accent(testString)) + if count != len(testString) { + t.Errorf("Accent count incorrect. %d != %d", count, len(testString)) + } +} + +func compare(a, b []rune, name string, t *testing.T) { + if len(a) != len(b) { + t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name) + return + } + for i := range a { + if a[i] != b[i] { + t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name) + return + } + } +} + +func TestPrefixGlyphs(t *testing.T) { + for i := 0; i <= len(testString); i++ { + iter := strconv.Itoa(i) + out := getPrefixGlyphs(testString, i) + compare(out, testString[:i], "ascii prefix "+iter, t) + out = getPrefixGlyphs(accent(testString), i) + compare(out, accent(testString[:i]), "accent prefix "+iter, t) + } + out := getPrefixGlyphs(testString, 999) + compare(out, testString, "ascii prefix overflow", t) + out = getPrefixGlyphs(accent(testString), 999) + compare(out, accent(testString), "accent prefix overflow", t) + + out = getPrefixGlyphs(testString, -3) + if len(out) != 0 { + t.Error("ascii prefix negative") + } + out = getPrefixGlyphs(accent(testString), -3) + if len(out) != 0 { + t.Error("accent prefix negative") + } +} + +func TestSuffixGlyphs(t *testing.T) { + for i := 0; i <= len(testString); i++ { + iter := strconv.Itoa(i) + out := getSuffixGlyphs(testString, i) + compare(out, testString[len(testString)-i:], "ascii suffix "+iter, t) + out = getSuffixGlyphs(accent(testString), i) + compare(out, accent(testString[len(testString)-i:]), "accent suffix "+iter, t) + } + out := getSuffixGlyphs(testString, 999) + compare(out, testString, "ascii suffix overflow", t) + out = getSuffixGlyphs(accent(testString), 999) + compare(out, accent(testString), "accent suffix overflow", t) + + out = getSuffixGlyphs(testString, -3) + if len(out) != 0 { + t.Error("ascii suffix negative") + } + out = getSuffixGlyphs(accent(testString), -3) + if len(out) != 0 { + t.Error("accent suffix negative") + } +} From de86403f330e68df8fc4aee00df98374b7842d0d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Mar 2015 12:18:44 +0100 Subject: [PATCH 6/7] cmd/ethereum: fix JS REPL exit and add support for dumb terminals It is now possible to exit the REPL using Ctrl-C, Ctrl-D or by typing "exit". --- cmd/ethereum/js.go | 84 ++++++++++++++++++++++++++++++-------------- cmd/ethereum/main.go | 7 ++-- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go index e16ee171e..9125ccbba 100644 --- a/cmd/ethereum/js.go +++ b/cmd/ethereum/js.go @@ -18,9 +18,11 @@ package main import ( + "bufio" "fmt" "io/ioutil" "os" + "os/signal" "path" "strings" @@ -55,44 +57,38 @@ type repl struct { ethereum *eth.Ethereum xeth *xeth.XEth prompt string - histfile *os.File lr *liner.State - running bool } -func newREPL(ethereum *eth.Ethereum) *repl { - hist, err := os.OpenFile(path.Join(ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) - if err != nil { - panic(err) - } +func runREPL(ethereum *eth.Ethereum) { xeth := xeth.New(ethereum) repl := &repl{ re: javascript.NewJSRE(xeth), xeth: xeth, ethereum: ethereum, prompt: "> ", - histfile: hist, - lr: liner.NewLiner(), } repl.initStdFuncs() - return repl -} - -func (self *repl) Start() { - if !self.running { - self.running = true - self.lr.ReadHistory(self.histfile) - go self.read() + if !liner.TerminalSupported() { + repl.dumbRead() + } else { + lr := liner.NewLiner() + defer lr.Close() + lr.SetCtrlCAborts(true) + repl.withHistory(func(hist *os.File) { lr.ReadHistory(hist) }) + repl.read(lr) + repl.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) } } -func (self *repl) Stop() { - if self.running { - self.running = false - self.histfile.Truncate(0) - self.lr.WriteHistory(self.histfile) - self.histfile.Close() +func (self *repl) withHistory(op func(*os.File)) { + hist, err := os.OpenFile(path.Join(self.ethereum.DataDir, "history"), os.O_RDWR|os.O_CREATE, os.ModePerm) + if err != nil { + fmt.Printf("unable to open history file: %v\n", err) + return } + op(hist) + hist.Close() } func (self *repl) parseInput(code string) { @@ -126,9 +122,9 @@ func (self *repl) setIndent() { } } -func (self *repl) read() { +func (self *repl) read(lr *liner.State) { for { - input, err := self.lr.Prompt(self.prompt) + input, err := lr.Prompt(self.prompt) if err != nil { return } @@ -139,17 +135,51 @@ func (self *repl) read() { self.setIndent() if indentCount <= 0 { if input == "exit" { - self.Stop() return } hist := str[:len(str)-1] - self.lr.AppendHistory(hist) + lr.AppendHistory(hist) self.parseInput(str) str = "" } } } +func (self *repl) dumbRead() { + fmt.Println("Unsupported terminal, line editing will not work.") + + // process lines + readDone := make(chan struct{}) + go func() { + r := bufio.NewReader(os.Stdin) + loop: + for { + fmt.Print(self.prompt) + line, err := r.ReadString('\n') + switch { + case err != nil || line == "exit": + break loop + case line == "": + continue + default: + self.parseInput(line + "\n") + } + } + close(readDone) + }() + + // wait for Ctrl-C + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, os.Interrupt, os.Kill) + defer signal.Stop(sigc) + + select { + case <-readDone: + case <-sigc: + os.Stdin.Close() // terminate read + } +} + func (self *repl) printValue(v interface{}) { method, _ := self.re.Vm.Get("prettyPrint") v, err := self.re.Vm.ToValue(v) diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index c85caf229..1133bd6f7 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -125,7 +125,6 @@ runtime will execute the file and exit. func main() { runtime.GOMAXPROCS(runtime.NumCPU()) defer logger.Flush() - utils.HandleInterrupt() if err := app.Run(os.Args); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) @@ -134,6 +133,7 @@ func main() { func run(ctx *cli.Context) { fmt.Printf("Welcome to the FRONTIER\n") + utils.HandleInterrupt() eth := utils.GetEthereum(ClientIdentifier, Version, ctx) startEth(ctx, eth) // this blocks the thread @@ -144,9 +144,8 @@ func runjs(ctx *cli.Context) { eth := utils.GetEthereum(ClientIdentifier, Version, ctx) startEth(ctx, eth) if len(ctx.Args()) == 0 { - repl := newREPL(eth) - utils.RegisterInterrupt(func(os.Signal) { repl.Stop() }) - repl.Start() + runREPL(eth) + eth.Stop() eth.WaitForShutdown() } else if len(ctx.Args()) == 1 { execJsFile(eth, ctx.Args()[0]) From 71e510540e817550f6e28ca0acc8136313160095 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 6 Mar 2015 12:27:11 +0000 Subject: [PATCH 7/7] Godeps: bump github.com/ethereum/ethash This fixes the build. --- Godeps/Godeps.json | 4 +- .../src/github.com/ethereum/ethash/.gitignore | 7 +- .../github.com/ethereum/ethash/.travis.yml | 6 + .../github.com/ethereum/ethash/CMakeLists.txt | 11 +- .../src/github.com/ethereum/ethash/Makefile | 3 + .../src/github.com/ethereum/ethash/README.md | 7 + .../github.com/ethereum/ethash/Vagrantfile | 7 + .../cmake/modules/CMakeParseArguments.cmake | 161 ++++ .../ethash/cmake/modules/FindOpenCL.cmake | 197 ++-- .../FindPackageHandleStandardArgs.cmake | 382 ++++++++ .../cmake/modules/FindPackageMessage.cmake | 57 ++ .../src/github.com/ethereum/ethash/ethash.go | 215 +++-- .../src/github.com/ethereum/ethash/js/LICENSE | 22 + .../github.com/ethereum/ethash/js/ethash.js | 190 ++++ .../github.com/ethereum/ethash/js/keccak.js | 404 ++++++++ .../ethereum/ethash/js/makekeccak.js | 201 ++++ .../src/github.com/ethereum/ethash/js/test.js | 53 ++ .../src/github.com/ethereum/ethash/js/util.js | 100 ++ .../ethash/libethash-cl/CMakeLists.txt | 12 - .../ethash/libethash-cuda/CMakeLists.txt | 15 - .../ethash/libethash-cuda/cuPrintf.cu | 879 ------------------ .../ethash/libethash-cuda/cuPrintf.cuh | 162 ---- .../ethash/libethash-cuda/libethash.cu | 27 - .../ethereum/ethash/libethash/data_sizes.h | 248 ----- .../ethereum/ethash/node-ethash/binding.gyp | 29 - .../ethereum/ethash/node-ethash/ethash.cc | 587 ------------ .../ethereum/ethash/node-ethash/package.json | 13 - .../ethereum/ethash/node-ethash/readme.md | 12 - .../ethereum/ethash/pyethash/.gitignore | 2 + .../ethereum/ethash/pyethash/__init__.py | 3 + .../src/github.com/ethereum/ethash/setup.py | 21 + .../ethash/{ => src}/benchmark/CMakeLists.txt | 0 .../ethash/{ => src}/benchmark/benchmark.cpp | 0 .../ethash/src/libethash-cl/CMakeLists.txt | 15 + .../ethash/src/libethash-cl/bin2h.cmake | 87 ++ .../ethash/{ => src}/libethash-cl/cl.hpp | 0 .../src/libethash-cl/ethash_cl_miner.cpp | 289 ++++++ .../{ => src}/libethash-cl/ethash_cl_miner.h | 0 .../libethash-cl/ethash_cl_miner_kernel.cl} | 293 ------ .../ethash/{ => src}/libethash/CMakeLists.txt | 8 +- .../ethash/{ => src}/libethash/compiler.h | 0 .../ethash/src/libethash/data_sizes.h | 779 ++++++++++++++++ .../ethash/{ => src}/libethash/endian.h | 0 .../ethash/{ => src}/libethash/ethash.h | 19 +- .../ethereum/ethash/{ => src}/libethash/fnv.h | 0 .../ethash/{ => src}/libethash/internal.c | 7 +- .../ethash/{ => src}/libethash/internal.h | 0 .../ethash/{ => src}/libethash/sha3.c | 0 .../ethash/{ => src}/libethash/sha3.h | 0 .../{ => src}/libethash/sha3_cryptopp.cpp | 0 .../{ => src}/libethash/sha3_cryptopp.h | 0 .../ethash/{ => src}/libethash/util.c | 0 .../ethash/{ => src}/libethash/util.h | 0 .../ethereum/ethash/src/python/core.c | 64 ++ .../ethash/test/{ => c}/CMakeLists.txt | 2 +- .../ethereum/ethash/test/{ => c}/test.cpp | 19 - .../github.com/ethereum/ethash/test/c/test.sh | 19 + .../ethereum/ethash/test/go/ethash_test.go | 54 -- .../ethereum/ethash/test/python/.gitignore | 1 + .../ethash/test/python/requirements.txt | 2 + .../ethereum/ethash/test/python/test.sh | 19 + .../ethash/test/python/test_pyethash.py | 45 + .../github.com/ethereum/ethash/test/test.sh | 26 + 63 files changed, 3261 insertions(+), 2524 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/Makefile create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/README.md create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/CMakeLists.txt delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/CMakeLists.txt delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/cuPrintf.cu delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/cuPrintf.cuh delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/libethash.cu delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/libethash/data_sizes.h delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/binding.gyp delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/ethash.cc delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/package.json delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/readme.md create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/.gitignore create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/__init__.py create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/setup.py rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/benchmark/CMakeLists.txt (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/benchmark/benchmark.cpp (100%) create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/CMakeLists.txt create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/bin2h.cmake rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash-cl/cl.hpp (100%) create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.cpp rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash-cl/ethash_cl_miner.h (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{libethash-cl/ethash_cl_miner.cpp => src/libethash-cl/ethash_cl_miner_kernel.cl} (61%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/CMakeLists.txt (88%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/compiler.h (100%) create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/endian.h (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/ethash.h (70%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/fnv.h (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/internal.c (98%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/internal.h (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/sha3.c (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/sha3.h (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/sha3_cryptopp.cpp (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/sha3_cryptopp.h (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/util.c (100%) rename Godeps/_workspace/src/github.com/ethereum/ethash/{ => src}/libethash/util.h (100%) create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c rename Godeps/_workspace/src/github.com/ethereum/ethash/test/{ => c}/CMakeLists.txt (95%) rename Godeps/_workspace/src/github.com/ethereum/ethash/test/{ => c}/test.cpp (90%) create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh delete mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/go/ethash_test.go create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py create mode 100644 Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index a1025c85d..3c1769529 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -17,8 +17,8 @@ }, { "ImportPath": "github.com/ethereum/ethash", - "Comment": "v17-23-g2561e13", - "Rev": "2561e1322a7e8e3d4a2cc903c44b1e96340bcb27" + "Comment": "v17-63-gbca024b", + "Rev": "bca024b0b30d83ec6798a5d4fa8c5fc6f937009a" }, { "ImportPath": "github.com/ethereum/serpent-go", diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore b/Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore index 6bb36ed15..3162bd828 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/.gitignore @@ -2,4 +2,9 @@ .DS_Store */**/*un~ .vagrant/ -cpp-build/ +*.pyc +build/ +pyethash.egg-info/ +*.so +*~ +*.swp diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml b/Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml new file mode 100644 index 000000000..4b929eb69 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/.travis.yml @@ -0,0 +1,6 @@ +before_install: + - sudo apt-get update -qq + - sudo apt-get install -qq wget cmake gcc bash libboost-test-dev nodejs python-pip python-dev + - sudo pip install virtualenv -q + +script: "./test/test.sh" diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt index ac189457f..c93395bf8 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.2) +cmake_minimum_required(VERSION 2.8.7) project(ethash) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") @@ -8,7 +8,8 @@ if (WIN32 AND WANT_CRYPTOPP) add_subdirectory(cryptopp) endif() -add_subdirectory(libethash) -add_subdirectory(libethash-cl EXCLUDE_FROM_ALL) -add_subdirectory(benchmark EXCLUDE_FROM_ALL) -add_subdirectory(test EXCLUDE_FROM_ALL) +add_subdirectory(src/libethash) +# bin2h.cmake doesn't work +#add_subdirectory(src/libethash-cl EXCLUDE_FROM_ALL) +add_subdirectory(src/benchmark EXCLUDE_FROM_ALL) +add_subdirectory(test/c EXCLUDE_FROM_ALL) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/Makefile b/Godeps/_workspace/src/github.com/ethereum/ethash/Makefile new file mode 100644 index 000000000..e2630581e --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/Makefile @@ -0,0 +1,3 @@ +.PHONY: clean +clean: + rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash/*.{so,pyc} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/README.md b/Godeps/_workspace/src/github.com/ethereum/ethash/README.md new file mode 100644 index 000000000..8b9e015cf --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/README.md @@ -0,0 +1,7 @@ +[![Build Status](https://travis-ci.org/ethereum/ethash.svg?branch=master)](https://travis-ci.org/ethereum/ethash) + + +# Ethash + +For details on this project, please see the Ethereum wiki: +https://github.com/ethereum/wiki/wiki/Ethash diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile b/Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile new file mode 100644 index 000000000..03891653f --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/Vagrantfile @@ -0,0 +1,7 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure(2) do |config| + config.vm.box = "Ubuntu 12.04" + config.vm.box_url = "https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box" +end diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake new file mode 100644 index 000000000..8553f38f5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/CMakeParseArguments.cmake @@ -0,0 +1,161 @@ +#.rst: +# CMakeParseArguments +# ------------------- +# +# +# +# CMAKE_PARSE_ARGUMENTS( +# args...) +# +# CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions +# for parsing the arguments given to that macro or function. It +# processes the arguments and defines a set of variables which hold the +# values of the respective options. +# +# The argument contains all options for the respective macro, +# i.e. keywords which can be used when calling the macro without any +# value following, like e.g. the OPTIONAL keyword of the install() +# command. +# +# The argument contains all keywords for this macro +# which are followed by one value, like e.g. DESTINATION keyword of the +# install() command. +# +# The argument contains all keywords for this +# macro which can be followed by more than one value, like e.g. the +# TARGETS or FILES keywords of the install() command. +# +# When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the +# keywords listed in , and +# a variable composed of the given +# followed by "_" and the name of the respective keyword. These +# variables will then hold the respective value from the argument list. +# For the keywords this will be TRUE or FALSE. +# +# All remaining arguments are collected in a variable +# _UNPARSED_ARGUMENTS, this can be checked afterwards to see +# whether your macro was called with unrecognized parameters. +# +# As an example here a my_install() macro, which takes similar arguments +# as the real install() command: +# +# :: +# +# function(MY_INSTALL) +# set(options OPTIONAL FAST) +# set(oneValueArgs DESTINATION RENAME) +# set(multiValueArgs TARGETS CONFIGURATIONS) +# cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" +# "${multiValueArgs}" ${ARGN} ) +# ... +# +# +# +# Assume my_install() has been called like this: +# +# :: +# +# my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) +# +# +# +# After the cmake_parse_arguments() call the macro will have set the +# following variables: +# +# :: +# +# MY_INSTALL_OPTIONAL = TRUE +# MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() +# MY_INSTALL_DESTINATION = "bin" +# MY_INSTALL_RENAME = "" (was not used) +# MY_INSTALL_TARGETS = "foo;bar" +# MY_INSTALL_CONFIGURATIONS = "" (was not used) +# MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" +# +# +# +# You can then continue and process these variables. +# +# Keywords terminate lists of values, e.g. if directly after a +# one_value_keyword another recognized keyword follows, this is +# interpreted as the beginning of the new option. E.g. +# my_install(TARGETS foo DESTINATION OPTIONAL) would result in +# MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION +# would be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefor. + +#============================================================================= +# Copyright 2010 Alexander Neundorf +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + + +if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) + return() +endif() +set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) + + +function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) + # first set all result variables to empty/FALSE + foreach(arg_name ${_singleArgNames} ${_multiArgNames}) + set(${prefix}_${arg_name}) + endforeach() + + foreach(option ${_optionNames}) + set(${prefix}_${option} FALSE) + endforeach() + + set(${prefix}_UNPARSED_ARGUMENTS) + + set(insideValues FALSE) + set(currentArgName) + + # now iterate over all arguments and fill the result variables + foreach(currentArg ${ARGN}) + list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword + list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword + + if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) + if(insideValues) + if("${insideValues}" STREQUAL "SINGLE") + set(${prefix}_${currentArgName} ${currentArg}) + set(insideValues FALSE) + elseif("${insideValues}" STREQUAL "MULTI") + list(APPEND ${prefix}_${currentArgName} ${currentArg}) + endif() + else() + list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) + endif() + else() + if(NOT ${optionIndex} EQUAL -1) + set(${prefix}_${currentArg} TRUE) + set(insideValues FALSE) + elseif(NOT ${singleArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "SINGLE") + elseif(NOT ${multiArgIndex} EQUAL -1) + set(currentArgName ${currentArg}) + set(${prefix}_${currentArgName}) + set(insideValues "MULTI") + endif() + endif() + + endforeach() + + # propagate the result variables to the caller: + foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) + set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) + endforeach() + set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) + +endfunction() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake index cc567c95e..4d3ed842c 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindOpenCL.cmake @@ -1,91 +1,136 @@ +#.rst: +# FindOpenCL +# ---------- # -# This file taken from FindOpenCL project @ http://gitorious.com/findopencl +# Try to find OpenCL # -# - Try to find OpenCL -# This module tries to find an OpenCL implementation on your system. It supports -# AMD / ATI, Apple and NVIDIA implementations, but shoudl work, too. +# Once done this will define:: # -# Once done this will define -# OPENCL_FOUND - system has OpenCL -# OPENCL_INCLUDE_DIRS - the OpenCL include directory -# OPENCL_LIBRARIES - link these to use OpenCL +# OpenCL_FOUND - True if OpenCL was found +# OpenCL_INCLUDE_DIRS - include directories for OpenCL +# OpenCL_LIBRARIES - link against this library to use OpenCL +# OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2) +# OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation +# OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation +# +# The module will also define two cache variables:: +# +# OpenCL_INCLUDE_DIR - the OpenCL include directory +# OpenCL_LIBRARY - the path to the OpenCL library # -# WIN32 should work, but is untested -FIND_PACKAGE( PackageHandleStandardArgs ) +#============================================================================= +# Copyright 2014 Matthaeus G. Chajdas +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) -SET (OPENCL_VERSION_STRING "0.1.0") -SET (OPENCL_VERSION_MAJOR 0) -SET (OPENCL_VERSION_MINOR 1) -SET (OPENCL_VERSION_PATCH 0) +function(_FIND_OPENCL_VERSION) + include(CheckSymbolExists) + include(CMakePushCheckState) + set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY}) -IF (APPLE) + CMAKE_PUSH_CHECK_STATE() + foreach(VERSION "2_0" "1_2" "1_1" "1_0") + set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}") - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL DOC "OpenCL lib for OSX") - FIND_PATH(OPENCL_INCLUDE_DIRS OpenCL/cl.h DOC "Include for OpenCL on OSX") - FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS OpenCL/cl.hpp DOC "Include for OpenCL CPP bindings on OSX") + if(APPLE) + CHECK_SYMBOL_EXISTS( + CL_VERSION_${VERSION} + "${OpenCL_INCLUDE_DIR}/OpenCL/cl.h" + OPENCL_VERSION_${VERSION}) + else() + CHECK_SYMBOL_EXISTS( + CL_VERSION_${VERSION} + "${OpenCL_INCLUDE_DIR}/CL/cl.h" + OPENCL_VERSION_${VERSION}) + endif() -ELSE (APPLE) + if(OPENCL_VERSION_${VERSION}) + string(REPLACE "_" "." VERSION "${VERSION}") + set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE) + string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}") + list(GET version_components 0 major_version) + list(GET version_components 1 minor_version) + set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE) + set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE) + break() + endif() + endforeach() + CMAKE_POP_CHECK_STATE() +endfunction() - IF (WIN32) - - FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h) - FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp) - - # The AMD SDK currently installs both x86 and x86_64 libraries - # This is only a hack to find out architecture - IF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" ) - SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86_64") - SET(OPENCL_LIB_DIR "$ENV{ATIINTERNALSTREAMSDKROOT}/lib/x86_64") - ELSE (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64") - SET(OPENCL_LIB_DIR "$ENV{ATISTREAMSDKROOT}/lib/x86") - SET(OPENCL_LIB_DIR "$ENV{ATIINTERNALSTREAMSDKROOT}/lib/x86") - ENDIF( ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64" ) +find_path(OpenCL_INCLUDE_DIR + NAMES + CL/cl.h OpenCL/cl.h + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV NVSDKCOMPUTE_ROOT + ENV CUDA_PATH + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + include + OpenCL/common/inc + "AMD APP/include") - # find out if the user asked for a 64-bit build, and use the corresponding - # 64 or 32 bit NVIDIA library paths to the search: - STRING(REGEX MATCH "Win64" ISWIN64 ${CMAKE_GENERATOR}) - IF("${ISWIN64}" STREQUAL "Win64") - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib ${OPENCL_LIB_DIR} $ENV{CUDA_LIB_PATH} $ENV{CUDA_PATH}/lib/x64) - ELSE("${ISWIN64}" STREQUAL "Win64") - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL.lib ${OPENCL_LIB_DIR} $ENV{CUDA_LIB_PATH} $ENV{CUDA_PATH}/lib/Win32) - ENDIF("${ISWIN64}" STREQUAL "Win64") +_FIND_OPENCL_VERSION() - GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) - - # On Win32 search relative to the library - FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS "${_OPENCL_INC_CAND}" $ENV{CUDA_INC_PATH} $ENV{CUDA_PATH}/include) - FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS "${_OPENCL_INC_CAND}" $ENV{CUDA_INC_PATH} $ENV{CUDA_PATH}/include) - - ELSE (WIN32) +if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 4) + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86" + lib/x86 + lib/Win32 + OpenCL/common/lib/Win32) + elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + find_library(OpenCL_LIBRARY + NAMES OpenCL + PATHS + ENV "PROGRAMFILES(X86)" + ENV AMDAPPSDKROOT + ENV INTELOCLSDKROOT + ENV CUDA_PATH + ENV NVSDKCOMPUTE_ROOT + ENV ATISTREAMSDKROOT + PATH_SUFFIXES + "AMD APP/lib/x86_64" + lib/x86_64 + lib/x64 + OpenCL/common/lib/x64) + endif() +else() + find_library(OpenCL_LIBRARY + NAMES OpenCL) +endif() - # Unix style platforms - FIND_LIBRARY(OPENCL_LIBRARIES OpenCL - ENV LD_LIBRARY_PATH - ) +set(OpenCL_LIBRARIES ${OpenCL_LIBRARY}) +set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR}) - GET_FILENAME_COMPONENT(OPENCL_LIB_DIR ${OPENCL_LIBRARIES} PATH) - GET_FILENAME_COMPONENT(_OPENCL_INC_CAND ${OPENCL_LIB_DIR}/../../include ABSOLUTE) +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +find_package_handle_standard_args( + OpenCL + FOUND_VAR OpenCL_FOUND + REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR + VERSION_VAR OpenCL_VERSION_STRING) - # The AMD SDK currently does not place its headers - # in /usr/include, therefore also search relative - # to the library - FIND_PATH(OPENCL_INCLUDE_DIRS CL/cl.h PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include") - FIND_PATH(_OPENCL_CPP_INCLUDE_DIRS CL/cl.hpp PATHS ${_OPENCL_INC_CAND} "/usr/local/cuda/include") - - ENDIF (WIN32) - -ENDIF (APPLE) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS( OpenCL DEFAULT_MSG OPENCL_LIBRARIES OPENCL_INCLUDE_DIRS ) - -IF( _OPENCL_CPP_INCLUDE_DIRS ) - SET( OPENCL_HAS_CPP_BINDINGS TRUE ) - LIST( APPEND OPENCL_INCLUDE_DIRS ${_OPENCL_CPP_INCLUDE_DIRS} ) - # This is often the same, so clean up - LIST( REMOVE_DUPLICATES OPENCL_INCLUDE_DIRS ) -ENDIF( _OPENCL_CPP_INCLUDE_DIRS ) - -MARK_AS_ADVANCED( - OPENCL_INCLUDE_DIRS -) \ No newline at end of file +mark_as_advanced( + OpenCL_INCLUDE_DIR + OpenCL_LIBRARY) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake new file mode 100644 index 000000000..6bcf1e788 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageHandleStandardArgs.cmake @@ -0,0 +1,382 @@ +#.rst: +# FindPackageHandleStandardArgs +# ----------------------------- +# +# +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( ... ) +# +# This function is intended to be used in FindXXX.cmake modules files. +# It handles the REQUIRED, QUIET and version-related arguments to +# find_package(). It also sets the _FOUND variable. The +# package is considered found if all variables ... listed contain +# valid results, e.g. valid filepaths. +# +# There are two modes of this function. The first argument in both +# modes is the name of the Find-module where it is called (in original +# casing). +# +# The first simple mode looks like this: +# +# :: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS( +# (DEFAULT_MSG|"Custom failure message") ... ) +# +# If the variables to are all valid, then +# _FOUND will be set to TRUE. If DEFAULT_MSG is given +# as second argument, then the function will generate itself useful +# success and error messages. You can also supply a custom error +# message for the failure case. This is not recommended. +# +# The second mode is more powerful and also supports version checking: +# +# :: +# +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(NAME +# [FOUND_VAR ] +# [REQUIRED_VARS ...] +# [VERSION_VAR ] +# [HANDLE_COMPONENTS] +# [CONFIG_MODE] +# [FAIL_MESSAGE "Custom failure message"] ) +# +# In this mode, the name of the result-variable can be set either to +# either _FOUND or _FOUND using the +# FOUND_VAR option. Other names for the result-variable are not +# allowed. So for a Find-module named FindFooBar.cmake, the two +# possible names are FooBar_FOUND and FOOBAR_FOUND. It is recommended +# to use the original case version. If the FOUND_VAR option is not +# used, the default is _FOUND. +# +# As in the simple mode, if through are all valid, +# _FOUND will be set to TRUE. After REQUIRED_VARS the +# variables which are required for this package are listed. Following +# VERSION_VAR the name of the variable can be specified which holds the +# version of the package which has been found. If this is done, this +# version will be checked against the (potentially) specified required +# version used in the find_package() call. The EXACT keyword is also +# handled. The default messages include information about the required +# version and the version which has been actually found, both if the +# version is ok or not. If the package supports components, use the +# HANDLE_COMPONENTS option to enable handling them. In this case, +# find_package_handle_standard_args() will report which components have +# been found and which are missing, and the _FOUND variable +# will be set to FALSE if any of the required components (i.e. not the +# ones listed after OPTIONAL_COMPONENTS) are missing. Use the option +# CONFIG_MODE if your FindXXX.cmake module is a wrapper for a +# find_package(... NO_MODULE) call. In this case VERSION_VAR will be +# set to _VERSION and the macro will automatically check whether +# the Config module was found. Via FAIL_MESSAGE a custom failure +# message can be specified, if this is not used, the default message +# will be displayed. +# +# Example for mode 1: +# +# :: +# +# find_package_handle_standard_args(LibXml2 DEFAULT_MSG +# LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) +# +# +# +# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and +# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to +# TRUE. If it is not found and REQUIRED was used, it fails with +# FATAL_ERROR, independent whether QUIET was used or not. If it is +# found, success will be reported, including the content of . On +# repeated Cmake runs, the same message won't be printed again. +# +# Example for mode 2: +# +# :: +# +# find_package_handle_standard_args(LibXslt +# FOUND_VAR LibXslt_FOUND +# REQUIRED_VARS LibXslt_LIBRARIES LibXslt_INCLUDE_DIRS +# VERSION_VAR LibXslt_VERSION_STRING) +# +# In this case, LibXslt is considered to be found if the variable(s) +# listed after REQUIRED_VAR are all valid, i.e. LibXslt_LIBRARIES and +# LibXslt_INCLUDE_DIRS in this case. The result will then be stored in +# LibXslt_FOUND . Also the version of LibXslt will be checked by using +# the version contained in LibXslt_VERSION_STRING. Since no +# FAIL_MESSAGE is given, the default messages will be printed. +# +# Another example for mode 2: +# +# :: +# +# find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4) +# find_package_handle_standard_args(Automoc4 CONFIG_MODE) +# +# In this case, FindAutmoc4.cmake wraps a call to find_package(Automoc4 +# NO_MODULE) and adds an additional search directory for automoc4. Here +# the result will be stored in AUTOMOC4_FOUND. The following +# FIND_PACKAGE_HANDLE_STANDARD_ARGS() call produces a proper +# success/error message. + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake) + +# internal helper macro +macro(_FPHSA_FAILURE_MESSAGE _msg) + if (${_NAME}_FIND_REQUIRED) + message(FATAL_ERROR "${_msg}") + else () + if (NOT ${_NAME}_FIND_QUIETLY) + message(STATUS "${_msg}") + endif () + endif () +endmacro() + + +# internal helper macro to generate the failure message when used in CONFIG_MODE: +macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) + # _CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found: + if(${_NAME}_CONFIG) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing: ${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})") + else() + # If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version. + # List them all in the error message: + if(${_NAME}_CONSIDERED_CONFIGS) + set(configsText "") + list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount) + math(EXPR configsCount "${configsCount} - 1") + foreach(currentConfigIndex RANGE ${configsCount}) + list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) + list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) + set(configsText "${configsText} ${filename} (version ${version})\n") + endforeach() + if (${_NAME}_NOT_FOUND_MESSAGE) + set(configsText "${configsText} Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") + endif() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") + + else() + # Simple case: No Config-file was found at all: + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}") + endif() + endif() +endmacro() + + +function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) + +# set up the arguments for CMAKE_PARSE_ARGUMENTS and check whether we are in +# new extended or in the "old" mode: + set(options CONFIG_MODE HANDLE_COMPONENTS) + set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR) + set(multiValueArgs REQUIRED_VARS) + set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} ) + list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX) + + if(${INDEX} EQUAL -1) + set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG}) + set(FPHSA_REQUIRED_VARS ${ARGN}) + set(FPHSA_VERSION_VAR) + else() + + CMAKE_PARSE_ARGUMENTS(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN}) + + if(FPHSA_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT FPHSA_FAIL_MESSAGE) + set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG") + endif() + endif() + +# now that we collected all arguments, process them + + if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG") + set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}") + endif() + + # In config-mode, we rely on the variable _CONFIG, which is set by find_package() + # when it successfully found the config-file, including version checking: + if(FPHSA_CONFIG_MODE) + list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG) + list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS) + set(FPHSA_VERSION_VAR ${_NAME}_VERSION) + endif() + + if(NOT FPHSA_REQUIRED_VARS) + message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()") + endif() + + list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR) + + string(TOUPPER ${_NAME} _NAME_UPPER) + string(TOLOWER ${_NAME} _NAME_LOWER) + + if(FPHSA_FOUND_VAR) + if(FPHSA_FOUND_VAR MATCHES "^${_NAME}_FOUND$" OR FPHSA_FOUND_VAR MATCHES "^${_NAME_UPPER}_FOUND$") + set(_FOUND_VAR ${FPHSA_FOUND_VAR}) + else() + message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_NAME}_FOUND\" and \"${_NAME_UPPER}_FOUND\" are valid names.") + endif() + else() + set(_FOUND_VAR ${_NAME_UPPER}_FOUND) + endif() + + # collect all variables which were not found, so they can be printed, so the + # user knows better what went wrong (#6375) + set(MISSING_VARS "") + set(DETAILS "") + # check if all passed variables are valid + unset(${_FOUND_VAR}) + foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS}) + if(NOT ${_CURRENT_VAR}) + set(${_FOUND_VAR} FALSE) + set(MISSING_VARS "${MISSING_VARS} ${_CURRENT_VAR}") + else() + set(DETAILS "${DETAILS}[${${_CURRENT_VAR}}]") + endif() + endforeach() + if(NOT "${${_FOUND_VAR}}" STREQUAL "FALSE") + set(${_FOUND_VAR} TRUE) + endif() + + # component handling + unset(FOUND_COMPONENTS_MSG) + unset(MISSING_COMPONENTS_MSG) + + if(FPHSA_HANDLE_COMPONENTS) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(${_NAME}_${comp}_FOUND) + + if(NOT DEFINED FOUND_COMPONENTS_MSG) + set(FOUND_COMPONENTS_MSG "found components: ") + endif() + set(FOUND_COMPONENTS_MSG "${FOUND_COMPONENTS_MSG} ${comp}") + + else() + + if(NOT DEFINED MISSING_COMPONENTS_MSG) + set(MISSING_COMPONENTS_MSG "missing components: ") + endif() + set(MISSING_COMPONENTS_MSG "${MISSING_COMPONENTS_MSG} ${comp}") + + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_FOUND_VAR} FALSE) + set(MISSING_VARS "${MISSING_VARS} ${comp}") + endif() + + endif() + endforeach() + set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}") + set(DETAILS "${DETAILS}[c${COMPONENT_MSG}]") + endif() + + # version handling: + set(VERSION_MSG "") + set(VERSION_OK TRUE) + set(VERSION ${${FPHSA_VERSION_VAR}}) + + # check with DEFINED here as the requested or found version may be "0" + if (DEFINED ${_NAME}_FIND_VERSION) + if(DEFINED ${FPHSA_VERSION_VAR}) + + if(${_NAME}_FIND_VERSION_EXACT) # exact version required + # count the dots in the version string + string(REGEX REPLACE "[^.]" "" _VERSION_DOTS "${VERSION}") + # add one dot because there is one dot more than there are components + string(LENGTH "${_VERSION_DOTS}." _VERSION_DOTS) + if (_VERSION_DOTS GREATER ${_NAME}_FIND_VERSION_COUNT) + # Because of the C++ implementation of find_package() ${_NAME}_FIND_VERSION_COUNT + # is at most 4 here. Therefore a simple lookup table is used. + if (${_NAME}_FIND_VERSION_COUNT EQUAL 1) + set(_VERSION_REGEX "[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 2) + set(_VERSION_REGEX "[^.]*\\.[^.]*") + elseif (${_NAME}_FIND_VERSION_COUNT EQUAL 3) + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*") + else () + set(_VERSION_REGEX "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*") + endif () + string(REGEX REPLACE "^(${_VERSION_REGEX})\\..*" "\\1" _VERSION_HEAD "${VERSION}") + unset(_VERSION_REGEX) + if (NOT ${_NAME}_FIND_VERSION VERSION_EQUAL _VERSION_HEAD) + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + unset(_VERSION_HEAD) + else () + if (NOT "${${_NAME}_FIND_VERSION}" VERSION_EQUAL "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is exact version \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable exact version \"${VERSION}\")") + endif () + endif () + unset(_VERSION_DOTS) + + else() # minimum version specified: + if ("${${_NAME}_FIND_VERSION}" VERSION_GREATER "${VERSION}") + set(VERSION_MSG "Found unsuitable version \"${VERSION}\", but required is at least \"${${_NAME}_FIND_VERSION}\"") + set(VERSION_OK FALSE) + else () + set(VERSION_MSG "(found suitable version \"${VERSION}\", minimum required is \"${${_NAME}_FIND_VERSION}\")") + endif () + endif() + + else() + + # if the package was not found, but a version was given, add that to the output: + if(${_NAME}_FIND_VERSION_EXACT) + set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")") + else() + set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")") + endif() + + endif() + else () + if(VERSION) + set(VERSION_MSG "(found version \"${VERSION}\")") + endif() + endif () + + if(VERSION_OK) + set(DETAILS "${DETAILS}[v${VERSION}(${${_NAME}_FIND_VERSION})]") + else() + set(${_FOUND_VAR} FALSE) + endif() + + + # print the result: + if (${_FOUND_VAR}) + FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}") + else () + + if(FPHSA_CONFIG_MODE) + _FPHSA_HANDLE_FAILURE_CONFIG_MODE() + else() + if(NOT VERSION_OK) + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (found ${${_FIRST_REQUIRED_VAR}})") + else() + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing: ${MISSING_VARS}) ${VERSION_MSG}") + endif() + endif() + + endif () + + set(${_FOUND_VAR} ${${_FOUND_VAR}} PARENT_SCOPE) + +endfunction() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake new file mode 100644 index 000000000..a0349d3db --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/cmake/modules/FindPackageMessage.cmake @@ -0,0 +1,57 @@ +#.rst: +# FindPackageMessage +# ------------------ +# +# +# +# FIND_PACKAGE_MESSAGE( "message for user" "find result details") +# +# This macro is intended to be used in FindXXX.cmake modules files. It +# will print a message once for each unique find result. This is useful +# for telling the user where a package was found. The first argument +# specifies the name (XXX) of the package. The second argument +# specifies the message to display. The third argument lists details +# about the find result so that if they change the message will be +# displayed again. The macro also obeys the QUIET argument to the +# find_package command. +# +# Example: +# +# :: +# +# if(X11_FOUND) +# FIND_PACKAGE_MESSAGE(X11 "Found X11: ${X11_X11_LIB}" +# "[${X11_X11_LIB}][${X11_INCLUDE_DIR}]") +# else() +# ... +# endif() + +#============================================================================= +# Copyright 2008-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +function(FIND_PACKAGE_MESSAGE pkg msg details) + # Avoid printing a message repeatedly for the same find result. + if(NOT ${pkg}_FIND_QUIETLY) + string(REPLACE "\n" "" details "${details}") + set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg}) + if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}") + # The message has not yet been printed. + message(STATUS "${msg}") + + # Save the find details in the cache to avoid printing the same + # message again. + set("${DETAILS_VAR}" "${details}" + CACHE INTERNAL "Details about finding ${pkg}") + endif() + endif() +endfunction() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go index 32d3f0264..e50a3a834 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/ethash.go @@ -2,32 +2,39 @@ package ethash /* #cgo CFLAGS: -std=gnu99 -Wall -#include "libethash/ethash.h" -#include "libethash/util.c" -#include "libethash/internal.c" -#include "libethash/sha3.c" +#include "src/libethash/util.c" +#include "src/libethash/internal.c" +#include "src/libethash/sha3.c" */ import "C" import ( "bytes" "encoding/binary" + "fmt" + "io/ioutil" "log" "math/big" "math/rand" + "os" + "path" "sync" "time" "unsafe" + "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/pow" ) +var tt256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) + var powlogger = logger.NewLogger("POW") type DAG struct { SeedBlockNum uint64 dag unsafe.Pointer // full GB of memory for dag + file bool } type ParamsAndCache struct { @@ -59,16 +66,28 @@ func parseNonce(nonce []byte) (uint64, error) { const epochLength uint64 = 30000 -func getSeedBlockNum(blockNum uint64) uint64 { +func GetSeedBlockNum(blockNum uint64) uint64 { var seedBlockNum uint64 = 0 - if blockNum >= 2*epochLength { - seedBlockNum = ((blockNum / epochLength) - 1) * epochLength + if blockNum > epochLength { + seedBlockNum = ((blockNum - 1) / epochLength) * epochLength } return seedBlockNum } +/* +XXX THIS DOESN'T WORK!! NEEDS FIXING +blockEpoch will underflow and wrap around causing massive issues +func GetSeedBlockNum(blockNum uint64) uint64 { + var seedBlockNum uint64 = 0 + if blockNum > epochLength { + seedBlockNum = ((blockNum - 1) / epochLength) * epochLength + } + return seedBlockNum +} +*/ + func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) *ParamsAndCache { - seedBlockNum := getSeedBlockNum(blockNum) + seedBlockNum := GetSeedBlockNum(blockNum) paramsAndCache := &ParamsAndCache{ params: new(C.ethash_params), cache: new(C.ethash_cache), @@ -76,19 +95,19 @@ func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) *ParamsA } C.ethash_params_init(paramsAndCache.params, C.uint32_t(seedBlockNum)) paramsAndCache.cache.mem = C.malloc(paramsAndCache.params.cache_size) - seedHash := chainManager.GetBlockByNumber(seedBlockNum).Header().Hash() - log.Println("Params", paramsAndCache.params) + seedHash := chainManager.GetBlockByNumber(seedBlockNum).SeedHash() log.Println("Making Cache") start := time.Now() - C.ethash_mkcache(paramsAndCache.cache, paramsAndCache.params, (*C.uint8_t)((unsafe.Pointer)(&seedHash[0]))) + C.ethash_mkcache(paramsAndCache.cache, paramsAndCache.params, (*C.uint8_t)(unsafe.Pointer(&seedHash[0]))) log.Println("Took:", time.Since(start)) + return paramsAndCache } func (pow *Ethash) updateCache() { pow.cacheMutex.Lock() - seedNum := getSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64()) + seedNum := GetSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64()) if pow.paramsAndCache.SeedBlockNum != seedNum { pow.paramsAndCache = makeParamsAndCache(pow.chainManager, pow.chainManager.CurrentBlock().NumberU64()) } @@ -104,17 +123,66 @@ func makeDAG(p *ParamsAndCache) *DAG { return d } -func (pow *Ethash) updateDAG() { +func (pow *Ethash) writeDagToDisk(dag *DAG, seedNum uint64) *os.File { + data := C.GoBytes(unsafe.Pointer(dag.dag), C.int(pow.paramsAndCache.params.full_size)) + file, err := os.Create("/tmp/dag") + if err != nil { + panic(err) + } + + num := make([]byte, 8) + binary.BigEndian.PutUint64(num, seedNum) + + file.Write(num) + file.Write(data) + + return file +} + +func (pow *Ethash) UpdateDAG() { pow.cacheMutex.Lock() pow.dagMutex.Lock() - seedNum := getSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64()) + seedNum := GetSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64()) if pow.dag == nil || pow.dag.SeedBlockNum != seedNum { + if pow.dag != nil && pow.dag.dag != nil { + C.free(pow.dag.dag) + pow.dag.dag = nil + } + + path := path.Join("/", "tmp", "dag") pow.dag = nil - log.Println("Making Dag") + log.Println("Generating dag") start := time.Now() - pow.dag = makeDAG(pow.paramsAndCache) + + file, err := os.Open(path) + if err != nil { + log.Printf("No dag found in '%s'. Generating new dago(takes a while)...", path) + pow.dag = makeDAG(pow.paramsAndCache) + file = pow.writeDagToDisk(pow.dag, seedNum) + } else { + data, err := ioutil.ReadAll(file) + if err != nil { + panic(err) + } + + num := binary.BigEndian.Uint64(data[0:8]) + if num < seedNum { + log.Printf("Old found. Generating new dag (takes a while)...") + pow.dag = makeDAG(pow.paramsAndCache) + file = pow.writeDagToDisk(pow.dag, seedNum) + } else { + data = data[8:] + pow.dag = &DAG{ + dag: unsafe.Pointer(&data[0]), + file: true, + SeedBlockNum: pow.paramsAndCache.SeedBlockNum, + } + } + } log.Println("Took:", time.Since(start)) + + file.Close() } pow.dagMutex.Unlock() @@ -123,11 +191,10 @@ func (pow *Ethash) updateDAG() { func New(chainManager pow.ChainManager) *Ethash { return &Ethash{ - turbo: false, + turbo: true, paramsAndCache: makeParamsAndCache(chainManager, chainManager.CurrentBlock().NumberU64()), chainManager: chainManager, dag: nil, - ret: new(C.ethash_return_value), cacheMutex: new(sync.Mutex), dagMutex: new(sync.Mutex), } @@ -142,73 +209,70 @@ func (pow *Ethash) CacheSize() uint64 { } func (pow *Ethash) GetSeedHash(blockNum uint64) []byte { - return pow.chainManager.GetBlockByNumber(getSeedBlockNum(blockNum)).Header().Hash() + seednum := GetSeedBlockNum(blockNum) + return pow.chainManager.GetBlockByNumber(seednum).SeedHash() } func (pow *Ethash) Stop() { pow.cacheMutex.Lock() pow.dagMutex.Lock() + defer pow.dagMutex.Unlock() + defer pow.cacheMutex.Unlock() + if pow.paramsAndCache.cache != nil { C.free(pow.paramsAndCache.cache.mem) } - if pow.dag != nil { + if pow.dag.dag != nil && !pow.dag.file { C.free(pow.dag.dag) } - pow.dagMutex.Unlock() - pow.cacheMutex.Unlock() + pow.dag.dag = nil } -func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) ([]byte, []byte, []byte) { - pow.updateDAG() +func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte, []byte) { + //pow.UpdateDAG() // Not very elegant, multiple mining instances are not supported - pow.dagMutex.Lock() - pow.cacheMutex.Lock() - defer pow.cacheMutex.Unlock() - defer pow.dagMutex.Unlock() + //pow.dagMutex.Lock() + //pow.cacheMutex.Lock() + //defer pow.cacheMutex.Unlock() + //defer pow.dagMutex.Unlock() r := rand.New(rand.NewSource(time.Now().UnixNano())) miningHash := block.HashNoNonce() diff := block.Difficulty() - log.Println("difficulty", diff) + i := int64(0) + starti := i start := time.Now().UnixNano() - t := time.Now() nonce := uint64(r.Int63()) + cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0])) + target := new(big.Int).Div(tt256, diff) + var ret C.ethash_return_value for { select { case <-stop: powlogger.Infoln("Breaking from mining") pow.HashRate = 0 - pow.dagMutex.Unlock() - return nil, nil, nil + return 0, nil, nil default: i++ - if time.Since(t) > (1 * time.Second) { - elapsed := time.Now().UnixNano() - start - hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 - pow.HashRate = int64(hashes) - powlogger.Infoln("Hashing @", pow.HashRate, "khash") + elapsed := time.Now().UnixNano() - start + hashes := ((float64(1e9) / float64(elapsed)) * float64(i-starti)) / 1000 + pow.HashRate = int64(hashes) + + C.ethash_full(&ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, C.uint64_t(nonce)) + result := ethutil.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32))) + + if result.Cmp(target) <= 0 { + mixDigest := C.GoBytes(unsafe.Pointer(&ret.mix_hash[0]), C.int(32)) + + return nonce, mixDigest, pow.GetSeedHash(block.NumberU64()) - t = time.Now() } - cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash)) - cnonce := C.uint64_t(nonce) - log.Printf("seed hash, nonce: %x %x\n", miningHash, nonce) - // pow.hash is the output/return of ethash_full - C.ethash_full(pow.ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, cnonce) - res := C.ethash_check_difficulty((*C.uint8_t)(&pow.ret.result[0]), (*C.uint8_t)(unsafe.Pointer(&diff.Bytes()[0]))) - if res == 1 { - mixDigest := C.GoBytes(unsafe.Pointer(&pow.ret.mix_hash[0]), 32) - // We don't really nead 32 bytes here - buf := make([]byte, 32) - binary.PutUvarint(buf, nonce) - return buf, mixDigest, pow.GetSeedHash(block.NumberU64()) - } nonce += 1 } @@ -216,43 +280,32 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) ([]byte, []byte time.Sleep(20 * time.Microsecond) } } + } func (pow *Ethash) Verify(block pow.Block) bool { // Make sure the SeedHash is set correctly if bytes.Compare(block.SeedHash(), pow.GetSeedHash(block.NumberU64())) != 0 { - log.Println("Block had wrong SeedHash") - log.Println("Expected: ", pow.GetSeedHash(block.NumberU64())) - log.Println("Actual: ", block.SeedHash()) return false } - nonceInt, err := parseNonce(block.Nonce()) - if err != nil { - log.Println("nonce to int err:", err) - return false - } - return pow.verify(block.HashNoNonce(), block.MixDigest(), block.Difficulty(), block.NumberU64(), nonceInt) + return pow.verify(block.HashNoNonce(), block.MixDigest(), block.Difficulty(), block.NumberU64(), block.Nonce()) } func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, blockNum uint64, nonce uint64) bool { + fmt.Printf("%x\n%d\n%x\n%x\n", hash, nonce, mixDigest, difficulty.Bytes()) // First check: make sure header, mixDigest, nonce are correct without hitting the DAG // This is to prevent DOS attacks - chash := (*C.uint8_t)(unsafe.Pointer(&hash)) + chash := (*C.uint8_t)(unsafe.Pointer(&hash[0])) cnonce := C.uint64_t(nonce) - cmixDigest := (*C.uint8_t)(unsafe.Pointer(&mixDigest)) - cdifficulty := (*C.uint8_t)(unsafe.Pointer(&difficulty.Bytes()[0])) - if C.ethash_quick_check_difficulty(chash, cnonce, cmixDigest, cdifficulty) != 1 { - log.Println("Failed to pass quick check. Are you sure that the mix digest is correct?") - return false - } + target := new(big.Int).Div(tt256, difficulty) var pAc *ParamsAndCache // If its an old block (doesn't use the current cache) // get the cache for it but don't update (so we don't need the mutex) // Otherwise, it's the current block or a future. // If current, updateCache will do nothing. - if getSeedBlockNum(blockNum) < pow.paramsAndCache.SeedBlockNum { + if GetSeedBlockNum(blockNum) < pow.paramsAndCache.SeedBlockNum { pAc = makeParamsAndCache(pow.chainManager, blockNum) } else { pow.updateCache() @@ -261,9 +314,12 @@ func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, bl pAc = pow.paramsAndCache } - C.ethash_light(pow.ret, pAc.cache, pAc.params, chash, cnonce) - res := C.ethash_check_difficulty((*C.uint8_t)(unsafe.Pointer(&pow.ret.result[0])), cdifficulty) - return res == 1 + ret := new(C.ethash_return_value) + + C.ethash_light(ret, pAc.cache, pAc.params, chash, cnonce) + + result := ethutil.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32))) + return result.Cmp(target) <= 0 } func (pow *Ethash) GetHashrate() int64 { @@ -275,22 +331,23 @@ func (pow *Ethash) Turbo(on bool) { } func (pow *Ethash) FullHash(nonce uint64, miningHash []byte) []byte { - pow.updateDAG() + pow.UpdateDAG() pow.dagMutex.Lock() defer pow.dagMutex.Unlock() - cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash)) + cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0])) cnonce := C.uint64_t(nonce) - log.Println("seed hash, nonce:", miningHash, nonce) + ret := new(C.ethash_return_value) // pow.hash is the output/return of ethash_full - C.ethash_full(pow.ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, cnonce) - ghash_full := C.GoBytes(unsafe.Pointer(&pow.ret.result[0]), 32) + C.ethash_full(ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, cnonce) + ghash_full := C.GoBytes(unsafe.Pointer(&ret.result), 32) return ghash_full } func (pow *Ethash) LightHash(nonce uint64, miningHash []byte) []byte { - cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash)) + cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0])) cnonce := C.uint64_t(nonce) - C.ethash_light(pow.ret, pow.paramsAndCache.cache, pow.paramsAndCache.params, cMiningHash, cnonce) - ghash_light := C.GoBytes(unsafe.Pointer(&pow.ret.result[0]), 32) + ret := new(C.ethash_return_value) + C.ethash_light(ret, pow.paramsAndCache.cache, pow.paramsAndCache.params, cMiningHash, cnonce) + ghash_light := C.GoBytes(unsafe.Pointer(&ret.result), 32) return ghash_light } diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE b/Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE new file mode 100644 index 000000000..070be633d --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Tim Hughes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js new file mode 100644 index 000000000..bec1284f6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/ethash.js @@ -0,0 +1,190 @@ +// ethash.js +// Tim Hughes +// Revision 19 + +/*jslint node: true, shadow:true */ +"use strict"; + +var Keccak = require('./keccak'); +var util = require('./util'); + +// 32-bit unsigned modulo +function mod32(x, n) +{ + return (x>>>0) % (n>>>0); +} + +function fnv(x, y) +{ + // js integer multiply by 0x01000193 will lose precision + return ((x*0x01000000 | 0) + (x*0x193 | 0)) ^ y; +} + +function computeCache(params, seedWords) +{ + var cache = new Uint32Array(params.cacheSize >> 2); + var cacheNodeCount = params.cacheSize >> 6; + + // Initialize cache + var keccak = new Keccak(); + keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length); + for (var n = 1; n < cacheNodeCount; ++n) + { + keccak.digestWords(cache, n<<4, 16, cache, (n-1)<<4, 16); + } + + var tmp = new Uint32Array(16); + + // Do randmemohash passes + for (var r = 0; r < params.cacheRounds; ++r) + { + for (var n = 0; n < cacheNodeCount; ++n) + { + var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4; + var p1 = mod32(cache[n<<4|0], cacheNodeCount) << 4; + + for (var w = 0; w < 16; w=(w+1)|0) + { + tmp[w] = cache[p0 | w] ^ cache[p1 | w]; + } + + keccak.digestWords(cache, n<<4, 16, tmp, 0, tmp.length); + } + } + return cache; +} + +function computeDagNode(o_node, params, cache, keccak, nodeIndex) +{ + var cacheNodeCount = params.cacheSize >> 6; + var dagParents = params.dagParents; + + var c = (nodeIndex % cacheNodeCount) << 4; + var mix = o_node; + for (var w = 0; w < 16; ++w) + { + mix[w] = cache[c|w]; + } + mix[0] ^= nodeIndex; + keccak.digestWords(mix, 0, 16, mix, 0, 16); + + for (var p = 0; p < dagParents; ++p) + { + // compute cache node (word) index + c = mod32(fnv(nodeIndex ^ p, mix[p&15]), cacheNodeCount) << 4; + + for (var w = 0; w < 16; ++w) + { + mix[w] = fnv(mix[w], cache[c|w]); + } + } + + keccak.digestWords(mix, 0, 16, mix, 0, 16); +} + +function computeHashInner(mix, params, cache, keccak, tempNode) +{ + var mixParents = params.mixParents|0; + var mixWordCount = params.mixSize >> 2; + var mixNodeCount = mixWordCount >> 4; + var dagPageCount = (params.dagSize / params.mixSize) >> 0; + + // grab initial first word + var s0 = mix[0]; + + // initialise mix from initial 64 bytes + for (var w = 16; w < mixWordCount; ++w) + { + mix[w] = mix[w & 15]; + } + + for (var a = 0; a < mixParents; ++a) + { + var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount-1)]), dagPageCount); + var d = (p * mixNodeCount)|0; + + for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16) + { + computeDagNode(tempNode, params, cache, keccak, (d + n)|0); + + for (var v = 0; v < 16; ++v) + { + mix[w|v] = fnv(mix[w|v], tempNode[v]); + } + } + } +} + +function convertSeed(seed) +{ + // todo, reconcile with spec, byte ordering? + // todo, big-endian conversion + var newSeed = util.toWords(seed); + if (newSeed === null) + throw Error("Invalid seed '" + seed + "'"); + return newSeed; +} + +exports.defaultParams = function() +{ + return { + cacheSize: 1048384, + cacheRounds: 3, + dagSize: 1073739904, + dagParents: 256, + mixSize: 128, + mixParents: 64, + }; +}; + +exports.Ethash = function(params, seed) +{ + // precompute cache and related values + seed = convertSeed(seed); + var cache = computeCache(params, seed); + + // preallocate buffers/etc + var initBuf = new ArrayBuffer(96); + var initBytes = new Uint8Array(initBuf); + var initWords = new Uint32Array(initBuf); + var mixWords = new Uint32Array(params.mixSize / 4); + var tempNode = new Uint32Array(16); + var keccak = new Keccak(); + + var retWords = new Uint32Array(8); + var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only + + this.hash = function(header, nonce) + { + // compute initial hash + initBytes.set(header, 0); + initBytes.set(nonce, 32); + keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length/4); + + // compute mix + for (var i = 0; i != 16; ++i) + { + mixWords[i] = initWords[i]; + } + computeHashInner(mixWords, params, cache, keccak, tempNode); + + // compress mix and append to initWords + for (var i = 0; i != mixWords.length; i += 4) + { + initWords[16 + i/4] = fnv(fnv(fnv(mixWords[i], mixWords[i+1]), mixWords[i+2]), mixWords[i+3]); + } + + // final Keccak hashes + keccak.digestWords(retWords, 0, 8, initWords, 0, 24); // Keccak-256(s + cmix) + return retBytes; + }; + + this.cacheDigest = function() + { + return keccak.digest(32, new Uint8Array(cache.buffer)); + }; +}; + + + + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js new file mode 100644 index 000000000..84ddde645 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/keccak.js @@ -0,0 +1,404 @@ +// keccak.js +// Tim Hughes +// derived from Markku-Juhani O. Saarinen's C code (http://keccak.noekeon.org/readable_code.html) + +/*jslint node: true, shadow:true */ +"use strict"; + +var Keccak_f1600_RC = new Uint32Array([ + 0x00000001, 0x00000000, + 0x00008082, 0x00000000, + 0x0000808a, 0x80000000, + 0x80008000, 0x80000000, + 0x0000808b, 0x00000000, + 0x80000001, 0x00000000, + 0x80008081, 0x80000000, + 0x00008009, 0x80000000, + 0x0000008a, 0x00000000, + 0x00000088, 0x00000000, + 0x80008009, 0x00000000, + 0x8000000a, 0x00000000, + 0x8000808b, 0x00000000, + 0x0000008b, 0x80000000, + 0x00008089, 0x80000000, + 0x00008003, 0x80000000, + 0x00008002, 0x80000000, + 0x00000080, 0x80000000, + 0x0000800a, 0x00000000, + 0x8000000a, 0x80000000, + 0x80008081, 0x80000000, + 0x00008080, 0x80000000, + 0x80000001, 0x00000000, + 0x80008008, 0x80000000 +]); + +function keccak_f1600(outState, outOffset, outSize, inState) +{ + // todo, handle big endian loads + var a00l = inState[0]|0; + var a00h = inState[1]|0; + var a01l = inState[2]|0; + var a01h = inState[3]|0; + var a02l = inState[4]|0; + var a02h = inState[5]|0; + var a03l = inState[6]|0; + var a03h = inState[7]|0; + var a04l = inState[8]|0; + var a04h = inState[9]|0; + var a05l = inState[10]|0; + var a05h = inState[11]|0; + var a06l = inState[12]|0; + var a06h = inState[13]|0; + var a07l = inState[14]|0; + var a07h = inState[15]|0; + var a08l = inState[16]|0; + var a08h = inState[17]|0; + var a09l = inState[18]|0; + var a09h = inState[19]|0; + var a10l = inState[20]|0; + var a10h = inState[21]|0; + var a11l = inState[22]|0; + var a11h = inState[23]|0; + var a12l = inState[24]|0; + var a12h = inState[25]|0; + var a13l = inState[26]|0; + var a13h = inState[27]|0; + var a14l = inState[28]|0; + var a14h = inState[29]|0; + var a15l = inState[30]|0; + var a15h = inState[31]|0; + var a16l = inState[32]|0; + var a16h = inState[33]|0; + var a17l = inState[34]|0; + var a17h = inState[35]|0; + var a18l = inState[36]|0; + var a18h = inState[37]|0; + var a19l = inState[38]|0; + var a19h = inState[39]|0; + var a20l = inState[40]|0; + var a20h = inState[41]|0; + var a21l = inState[42]|0; + var a21h = inState[43]|0; + var a22l = inState[44]|0; + var a22h = inState[45]|0; + var a23l = inState[46]|0; + var a23h = inState[47]|0; + var a24l = inState[48]|0; + var a24h = inState[49]|0; + var b00l, b00h, b01l, b01h, b02l, b02h, b03l, b03h, b04l, b04h; + var b05l, b05h, b06l, b06h, b07l, b07h, b08l, b08h, b09l, b09h; + var b10l, b10h, b11l, b11h, b12l, b12h, b13l, b13h, b14l, b14h; + var b15l, b15h, b16l, b16h, b17l, b17h, b18l, b18h, b19l, b19h; + var b20l, b20h, b21l, b21h, b22l, b22h, b23l, b23h, b24l, b24h; + var tl, nl; + var th, nh; + + for (var r = 0; r < 48; r = (r+2)|0) + { + // Theta + b00l = a00l ^ a05l ^ a10l ^ a15l ^ a20l; + b00h = a00h ^ a05h ^ a10h ^ a15h ^ a20h; + b01l = a01l ^ a06l ^ a11l ^ a16l ^ a21l; + b01h = a01h ^ a06h ^ a11h ^ a16h ^ a21h; + b02l = a02l ^ a07l ^ a12l ^ a17l ^ a22l; + b02h = a02h ^ a07h ^ a12h ^ a17h ^ a22h; + b03l = a03l ^ a08l ^ a13l ^ a18l ^ a23l; + b03h = a03h ^ a08h ^ a13h ^ a18h ^ a23h; + b04l = a04l ^ a09l ^ a14l ^ a19l ^ a24l; + b04h = a04h ^ a09h ^ a14h ^ a19h ^ a24h; + tl = b04l ^ (b01l << 1 | b01h >>> 31); + th = b04h ^ (b01h << 1 | b01l >>> 31); + a00l ^= tl; + a00h ^= th; + a05l ^= tl; + a05h ^= th; + a10l ^= tl; + a10h ^= th; + a15l ^= tl; + a15h ^= th; + a20l ^= tl; + a20h ^= th; + tl = b00l ^ (b02l << 1 | b02h >>> 31); + th = b00h ^ (b02h << 1 | b02l >>> 31); + a01l ^= tl; + a01h ^= th; + a06l ^= tl; + a06h ^= th; + a11l ^= tl; + a11h ^= th; + a16l ^= tl; + a16h ^= th; + a21l ^= tl; + a21h ^= th; + tl = b01l ^ (b03l << 1 | b03h >>> 31); + th = b01h ^ (b03h << 1 | b03l >>> 31); + a02l ^= tl; + a02h ^= th; + a07l ^= tl; + a07h ^= th; + a12l ^= tl; + a12h ^= th; + a17l ^= tl; + a17h ^= th; + a22l ^= tl; + a22h ^= th; + tl = b02l ^ (b04l << 1 | b04h >>> 31); + th = b02h ^ (b04h << 1 | b04l >>> 31); + a03l ^= tl; + a03h ^= th; + a08l ^= tl; + a08h ^= th; + a13l ^= tl; + a13h ^= th; + a18l ^= tl; + a18h ^= th; + a23l ^= tl; + a23h ^= th; + tl = b03l ^ (b00l << 1 | b00h >>> 31); + th = b03h ^ (b00h << 1 | b00l >>> 31); + a04l ^= tl; + a04h ^= th; + a09l ^= tl; + a09h ^= th; + a14l ^= tl; + a14h ^= th; + a19l ^= tl; + a19h ^= th; + a24l ^= tl; + a24h ^= th; + + // Rho Pi + b00l = a00l; + b00h = a00h; + b10l = a01l << 1 | a01h >>> 31; + b10h = a01h << 1 | a01l >>> 31; + b07l = a10l << 3 | a10h >>> 29; + b07h = a10h << 3 | a10l >>> 29; + b11l = a07l << 6 | a07h >>> 26; + b11h = a07h << 6 | a07l >>> 26; + b17l = a11l << 10 | a11h >>> 22; + b17h = a11h << 10 | a11l >>> 22; + b18l = a17l << 15 | a17h >>> 17; + b18h = a17h << 15 | a17l >>> 17; + b03l = a18l << 21 | a18h >>> 11; + b03h = a18h << 21 | a18l >>> 11; + b05l = a03l << 28 | a03h >>> 4; + b05h = a03h << 28 | a03l >>> 4; + b16l = a05h << 4 | a05l >>> 28; + b16h = a05l << 4 | a05h >>> 28; + b08l = a16h << 13 | a16l >>> 19; + b08h = a16l << 13 | a16h >>> 19; + b21l = a08h << 23 | a08l >>> 9; + b21h = a08l << 23 | a08h >>> 9; + b24l = a21l << 2 | a21h >>> 30; + b24h = a21h << 2 | a21l >>> 30; + b04l = a24l << 14 | a24h >>> 18; + b04h = a24h << 14 | a24l >>> 18; + b15l = a04l << 27 | a04h >>> 5; + b15h = a04h << 27 | a04l >>> 5; + b23l = a15h << 9 | a15l >>> 23; + b23h = a15l << 9 | a15h >>> 23; + b19l = a23h << 24 | a23l >>> 8; + b19h = a23l << 24 | a23h >>> 8; + b13l = a19l << 8 | a19h >>> 24; + b13h = a19h << 8 | a19l >>> 24; + b12l = a13l << 25 | a13h >>> 7; + b12h = a13h << 25 | a13l >>> 7; + b02l = a12h << 11 | a12l >>> 21; + b02h = a12l << 11 | a12h >>> 21; + b20l = a02h << 30 | a02l >>> 2; + b20h = a02l << 30 | a02h >>> 2; + b14l = a20l << 18 | a20h >>> 14; + b14h = a20h << 18 | a20l >>> 14; + b22l = a14h << 7 | a14l >>> 25; + b22h = a14l << 7 | a14h >>> 25; + b09l = a22h << 29 | a22l >>> 3; + b09h = a22l << 29 | a22h >>> 3; + b06l = a09l << 20 | a09h >>> 12; + b06h = a09h << 20 | a09l >>> 12; + b01l = a06h << 12 | a06l >>> 20; + b01h = a06l << 12 | a06h >>> 20; + + // Chi + a00l = b00l ^ ~b01l & b02l; + a00h = b00h ^ ~b01h & b02h; + a01l = b01l ^ ~b02l & b03l; + a01h = b01h ^ ~b02h & b03h; + a02l = b02l ^ ~b03l & b04l; + a02h = b02h ^ ~b03h & b04h; + a03l = b03l ^ ~b04l & b00l; + a03h = b03h ^ ~b04h & b00h; + a04l = b04l ^ ~b00l & b01l; + a04h = b04h ^ ~b00h & b01h; + a05l = b05l ^ ~b06l & b07l; + a05h = b05h ^ ~b06h & b07h; + a06l = b06l ^ ~b07l & b08l; + a06h = b06h ^ ~b07h & b08h; + a07l = b07l ^ ~b08l & b09l; + a07h = b07h ^ ~b08h & b09h; + a08l = b08l ^ ~b09l & b05l; + a08h = b08h ^ ~b09h & b05h; + a09l = b09l ^ ~b05l & b06l; + a09h = b09h ^ ~b05h & b06h; + a10l = b10l ^ ~b11l & b12l; + a10h = b10h ^ ~b11h & b12h; + a11l = b11l ^ ~b12l & b13l; + a11h = b11h ^ ~b12h & b13h; + a12l = b12l ^ ~b13l & b14l; + a12h = b12h ^ ~b13h & b14h; + a13l = b13l ^ ~b14l & b10l; + a13h = b13h ^ ~b14h & b10h; + a14l = b14l ^ ~b10l & b11l; + a14h = b14h ^ ~b10h & b11h; + a15l = b15l ^ ~b16l & b17l; + a15h = b15h ^ ~b16h & b17h; + a16l = b16l ^ ~b17l & b18l; + a16h = b16h ^ ~b17h & b18h; + a17l = b17l ^ ~b18l & b19l; + a17h = b17h ^ ~b18h & b19h; + a18l = b18l ^ ~b19l & b15l; + a18h = b18h ^ ~b19h & b15h; + a19l = b19l ^ ~b15l & b16l; + a19h = b19h ^ ~b15h & b16h; + a20l = b20l ^ ~b21l & b22l; + a20h = b20h ^ ~b21h & b22h; + a21l = b21l ^ ~b22l & b23l; + a21h = b21h ^ ~b22h & b23h; + a22l = b22l ^ ~b23l & b24l; + a22h = b22h ^ ~b23h & b24h; + a23l = b23l ^ ~b24l & b20l; + a23h = b23h ^ ~b24h & b20h; + a24l = b24l ^ ~b20l & b21l; + a24h = b24h ^ ~b20h & b21h; + + // Iota + a00l ^= Keccak_f1600_RC[r|0]; + a00h ^= Keccak_f1600_RC[r|1]; + } + + // todo, handle big-endian stores + outState[outOffset|0] = a00l; + outState[outOffset|1] = a00h; + outState[outOffset|2] = a01l; + outState[outOffset|3] = a01h; + outState[outOffset|4] = a02l; + outState[outOffset|5] = a02h; + outState[outOffset|6] = a03l; + outState[outOffset|7] = a03h; + if (outSize == 8) + return; + outState[outOffset|8] = a04l; + outState[outOffset|9] = a04h; + outState[outOffset|10] = a05l; + outState[outOffset|11] = a05h; + outState[outOffset|12] = a06l; + outState[outOffset|13] = a06h; + outState[outOffset|14] = a07l; + outState[outOffset|15] = a07h; + if (outSize == 16) + return; + outState[outOffset|16] = a08l; + outState[outOffset|17] = a08h; + outState[outOffset|18] = a09l; + outState[outOffset|19] = a09h; + outState[outOffset|20] = a10l; + outState[outOffset|21] = a10h; + outState[outOffset|22] = a11l; + outState[outOffset|23] = a11h; + outState[outOffset|24] = a12l; + outState[outOffset|25] = a12h; + outState[outOffset|26] = a13l; + outState[outOffset|27] = a13h; + outState[outOffset|28] = a14l; + outState[outOffset|29] = a14h; + outState[outOffset|30] = a15l; + outState[outOffset|31] = a15h; + outState[outOffset|32] = a16l; + outState[outOffset|33] = a16h; + outState[outOffset|34] = a17l; + outState[outOffset|35] = a17h; + outState[outOffset|36] = a18l; + outState[outOffset|37] = a18h; + outState[outOffset|38] = a19l; + outState[outOffset|39] = a19h; + outState[outOffset|40] = a20l; + outState[outOffset|41] = a20h; + outState[outOffset|42] = a21l; + outState[outOffset|43] = a21h; + outState[outOffset|44] = a22l; + outState[outOffset|45] = a22h; + outState[outOffset|46] = a23l; + outState[outOffset|47] = a23h; + outState[outOffset|48] = a24l; + outState[outOffset|49] = a24h; +} + +var Keccak = function() +{ + var stateBuf = new ArrayBuffer(200); + var stateBytes = new Uint8Array(stateBuf); + var stateWords = new Uint32Array(stateBuf); + + this.digest = function(oSize, iBytes) + { + for (var i = 0; i < 50; ++i) + { + stateWords[i] = 0; + } + + var r = 200 - oSize*2; + var iLength = iBytes.length; + var iOffset = 0; + for ( ; ;) + { + var len = iLength < r ? iLength : r; + for (i = 0; i < len; ++i, ++iOffset) + { + stateBytes[i] ^= iBytes[iOffset]; + } + + if (iLength < r) + break; + iLength -= len; + + keccak_f1600(stateWords, 0, 50, stateWords); + } + + stateBytes[iLength] ^= 1; + stateBytes[r-1] ^= 0x80; + keccak_f1600(stateWords, 0, 50, stateWords); + return stateBytes.subarray(0, oSize); + }; + + this.digestWords = function(oWords, oOffset, oLength, iWords, iOffset, iLength) + { + for (var i = 0; i < 50; ++i) + { + stateWords[i] = 0; + } + + var r = 50 - oLength*2; + for (; ; ) + { + var len = iLength < r ? iLength : r; + for (i = 0; i < len; ++i, ++iOffset) + { + stateWords[i] ^= iWords[iOffset]; + } + + if (iLength < r) + break; + iLength -= len; + + keccak_f1600(stateWords, 0, 50, stateWords); + } + + stateBytes[iLength<<2] ^= 1; + stateBytes[(r<<2) - 1] ^= 0x80; + keccak_f1600(oWords, oOffset, oLength, stateWords); + }; +}; + +module.exports = Keccak; + + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js new file mode 100644 index 000000000..c4db2b80a --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/makekeccak.js @@ -0,0 +1,201 @@ +#!/usr/bin/env node +// makekeccak.js +// Tim Hughes + +/*jslint node: true, shadow:true */ +"use strict"; + +var Keccak_f1600_Rho = [ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 +]; + +var Keccak_f1600_Pi= [ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 +]; + +var Keccak_f1600_RC = [ + 0x00000001, 0x00000000, + 0x00008082, 0x00000000, + 0x0000808a, 0x80000000, + 0x80008000, 0x80000000, + 0x0000808b, 0x00000000, + 0x80000001, 0x00000000, + 0x80008081, 0x80000000, + 0x00008009, 0x80000000, + 0x0000008a, 0x00000000, + 0x00000088, 0x00000000, + 0x80008009, 0x00000000, + 0x8000000a, 0x00000000, + 0x8000808b, 0x00000000, + 0x0000008b, 0x80000000, + 0x00008089, 0x80000000, + 0x00008003, 0x80000000, + 0x00008002, 0x80000000, + 0x00000080, 0x80000000, + 0x0000800a, 0x00000000, + 0x8000000a, 0x80000000, + 0x80008081, 0x80000000, + 0x00008080, 0x80000000, + 0x80000001, 0x00000000, + 0x80008008, 0x80000000, +]; + +function makeRotLow(lo, hi, n) +{ + if (n === 0 || n === 32) throw Error("unsupported"); + if ((n & 0x20) !== 0) + { + n &= ~0x20; + var t = hi; + hi = lo; + lo = t; + } + var hir = hi + " >>> " + (32 - n); + var los = lo + " << " + n; + return los + " | " + hir; +} + +function makeRotHigh(lo, hi, n) +{ + if (n === 0 || n === 32) throw Error("unsupported"); + if ((n & 0x20) !== 0) + { + n &= ~0x20; + var t = hi; + hi = lo; + lo = t; + } + var his = hi + " << " + n; + var lor = lo + " >>> " + (32 - n); + return his + " | " + lor; +} + +function makeKeccak_f1600() +{ + var format = function(n) + { + return n < 10 ? "0"+n : ""+n; + }; + + var a = function(n, w) + { + return "a" + format(n) + (w !== 0?'h':'l'); + }; + + var b = function(n, w) + { + return "b" + format(n) + (w !== 0?'h':'l'); + }; + + var str = ""; + str += "function keccak_f1600(outState, outOffset, outSize, inState)\n"; + str += "{\n"; + + for (var i = 0; i < 25; ++i) + { + for (var w = 0; w <= 1; ++w) + { + str += "\tvar " + a(i,w) + " = inState["+(i<<1|w)+"]|0;\n"; + } + } + + for (var j = 0; j < 5; ++j) + { + str += "\tvar "; + for (var i = 0; i < 5; ++i) + { + if (i !== 0) + str += ", "; + str += b(j*5+i,0) + ", " + b(j*5+i,1); + } + str += ";\n"; + } + + str += "\tvar tl, th;\n"; + str += "\n"; + str += "\tfor (var r = 0; r < 48; r = (r+2)|0)\n"; + str += "\t{\n"; + + + // Theta + str += "\t\t// Theta\n"; + for (var i = 0; i < 5; ++i) + { + for (var w = 0; w <= 1; ++w) + { + str += "\t\t" + b(i,w) + " = " + a(i,w) + " ^ " + a(i+5,w) + " ^ " + a(i+10,w) + " ^ " + a(i+15,w) + " ^ " + a(i+20,w) + ";\n"; + } + } + + for (var i = 0; i < 5; ++i) + { + var i4 = (i + 4) % 5; + var i1 = (i + 1) % 5; + str += "\t\ttl = " + b(i4,0) + " ^ (" + b(i1,0) + " << 1 | " + b(i1,1) + " >>> 31);\n"; + str += "\t\tth = " + b(i4,1) + " ^ (" + b(i1,1) + " << 1 | " + b(i1,0) + " >>> 31);\n"; + + for (var j = 0; j < 25; j = (j+5)|0) + { + str += "\t\t" + a((j+i),0) + " ^= tl;\n"; + str += "\t\t" + a((j+i),1) + " ^= th;\n"; + } + } + + + // Rho Pi + str += "\n\t\t// Rho Pi\n"; + for (var w = 0; w <= 1; ++w) + { + str += "\t\t" + b(0,w) + " = " + a(0,w) + ";\n"; + } + var opi = 1; + for (var i = 0; i < 24; ++i) + { + var pi = Keccak_f1600_Pi[i]; + str += "\t\t" + b(pi,0) + " = " + makeRotLow(a(opi,0), a(opi,1), Keccak_f1600_Rho[i]) + ";\n"; + str += "\t\t" + b(pi,1) + " = " + makeRotHigh(a(opi,0), a(opi,1), Keccak_f1600_Rho[i]) + ";\n"; + opi = pi; + } + + // Chi + str += "\n\t\t// Chi\n"; + for (var j = 0; j < 25; j += 5) + { + for (var i = 0; i < 5; ++i) + { + for (var w = 0; w <= 1; ++w) + { + str += "\t\t" + a(j+i,w) + " = " + b(j+i,w) + " ^ ~" + b(j+(i+1)%5,w) + " & " + b(j+(i+2)%5,w) + ";\n"; + } + } + } + + // Iota + str += "\n\t\t// Iota\n"; + for (var w = 0; w <= 1; ++w) + { + str += "\t\t" + a(0,w) + " ^= Keccak_f1600_RC[r|" + w + "];\n"; + } + + + str += "\t}\n"; + + for (var i = 0; i < 25; ++i) + { + if (i == 4 || i == 8) + { + str += "\tif (outSize == " + i*2 + ")\n\t\treturn;\n"; + } + for (var w = 0; w <= 1; ++w) + { + str += "\toutState[outOffset|"+(i<<1|w)+"] = " + a(i,w) + ";\n"; + } + } + str += "}\n"; + + return str; +} + +console.log(makeKeccak_f1600()); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js new file mode 100644 index 000000000..7ebb733ff --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/test.js @@ -0,0 +1,53 @@ +// test.js +// Tim Hughes + +/*jslint node: true, shadow:true */ +"use strict"; + +var ethash = require('./ethash'); +var util = require('./util'); +var Keccak = require('./keccak'); + +// sanity check hash functions +var src = util.stringToBytes(""); +if (util.bytesToHexString(new Keccak().digest(32, src)) != "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") throw Error("Keccak-256 failed"); +if (util.bytesToHexString(new Keccak().digest(64, src)) != "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") throw Error("Keccak-512 failed"); + +src = new Uint32Array(src.buffer); +var dst = new Uint32Array(8); +new Keccak().digestWords(dst, 0, dst.length, src, 0, src.length); +if (util.wordsToHexString(dst) != "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") throw Error("Keccak-256 Fast failed"); + +var dst = new Uint32Array(16); +new Keccak().digestWords(dst, 0, dst.length, src, 0, src.length); +if (util.wordsToHexString(dst) != "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") throw Error("Keccak-512 Fast failed"); + + +// init params +var ethashParams = ethash.defaultParams(); +//ethashParams.cacheRounds = 0; + +// create hasher +var seed = util.hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466") +var startTime = new Date().getTime(); +var hasher = new ethash.Ethash(ethashParams, seed); +console.log('Ethash startup took: '+(new Date().getTime() - startTime) + "ms"); +console.log('Ethash cache hash: ' + util.bytesToHexString(hasher.cacheDigest())); + +var testHexString = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; +if (testHexString != util.bytesToHexString(util.hexStringToBytes(testHexString))) + throw Error("bytesToHexString or hexStringToBytes broken"); + + +var header = util.hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); +var nonce = util.hexStringToBytes("0000000000000000"); +var hash; + +startTime = new Date().getTime(); +var trials = 10; +for (var i = 0; i < trials; ++i) +{ + hash = hasher.hash(header, nonce); +} +console.log("Light client hashes averaged: " + (new Date().getTime() - startTime)/trials + "ms"); +console.log("Hash = " + util.bytesToHexString(hash)); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js b/Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js new file mode 100644 index 000000000..79743cd91 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/js/util.js @@ -0,0 +1,100 @@ +// util.js +// Tim Hughes + +/*jslint node: true, shadow:true */ +"use strict"; + +function nibbleToChar(nibble) +{ + return String.fromCharCode((nibble < 10 ? 48 : 87) + nibble); +} + +function charToNibble(chr) +{ + if (chr >= 48 && chr <= 57) + { + return chr - 48; + } + if (chr >= 65 && chr <= 70) + { + return chr - 65 + 10; + } + if (chr >= 97 && chr <= 102) + { + return chr - 97 + 10; + } + return 0; +} + +function stringToBytes(str) +{ + var bytes = new Uint8Array(str.length); + for (var i = 0; i != str.length; ++i) + { + bytes[i] = str.charCodeAt(i); + } + return bytes; +} + +function hexStringToBytes(str) +{ + var bytes = new Uint8Array(str.length>>>1); + for (var i = 0; i != bytes.length; ++i) + { + bytes[i] = charToNibble(str.charCodeAt(i<<1 | 0)) << 4; + bytes[i] |= charToNibble(str.charCodeAt(i<<1 | 1)); + } + return bytes; +} + +function bytesToHexString(bytes) +{ + var str = ""; + for (var i = 0; i != bytes.length; ++i) + { + str += nibbleToChar(bytes[i] >>> 4); + str += nibbleToChar(bytes[i] & 0xf); + } + return str; +} + +function wordsToHexString(words) +{ + return bytesToHexString(new Uint8Array(words.buffer)); +} + +function uint32ToHexString(num) +{ + var buf = new Uint8Array(4); + buf[0] = (num >> 24) & 0xff; + buf[1] = (num >> 16) & 0xff; + buf[2] = (num >> 8) & 0xff; + buf[3] = (num >> 0) & 0xff; + return bytesToHexString(buf); +} + +function toWords(input) +{ + if (input instanceof Uint32Array) + { + return input; + } + else if (input instanceof Uint8Array) + { + var tmp = new Uint8Array((input.length + 3) & ~3); + tmp.set(input); + return new Uint32Array(tmp.buffer); + } + else if (typeof input === typeof "") + { + return toWords(stringToBytes(input)); + } + return null; +} + +exports.stringToBytes = stringToBytes; +exports.hexStringToBytes = hexStringToBytes; +exports.bytesToHexString = bytesToHexString; +exports.wordsToHexString = wordsToHexString; +exports.uint32ToHexString = uint32ToHexString; +exports.toWords = toWords; \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/CMakeLists.txt deleted file mode 100644 index 19d2fecbf..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -set(LIBRARY ethash-cl) -set(CMAKE_BUILD_TYPE Release) - -if (NOT OPENCL_FOUND) - find_package(OpenCL) -endif() -if (OPENCL_FOUND) - include_directories(${OPENCL_INCLUDE_DIRS}) - include_directories(..) - add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h) - TARGET_LINK_LIBRARIES(${LIBRARY} ${OPENCL_LIBRARIES} ethash) -endif() \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/CMakeLists.txt deleted file mode 100644 index b30ed3e2d..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -find_package(CUDA) - -# Pass options to NVCC - - -if (CUDA_FOUND) -set(CUDA_NVCC_FLAGS " -gencode;arch=compute_30,code=sm_30; - -gencode;arch=compute_20,code=sm_20; - -gencode;arch=compute_11,code=sm_11; - -gencode;arch=compute_12,code=sm_12; - -gencode;arch=compute_13,code=sm_13;") -cuda_add_executable( - ethash-cuda - libethash.cu) -endif() \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/cuPrintf.cu b/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/cuPrintf.cu deleted file mode 100644 index f06653f2d..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/cuPrintf.cu +++ /dev/null @@ -1,879 +0,0 @@ -/* - Copyright 2009 NVIDIA Corporation. All rights reserved. - - NOTICE TO LICENSEE: - - This source code and/or documentation ("Licensed Deliverables") are subject - to NVIDIA intellectual property rights under U.S. and international Copyright - laws. - - These Licensed Deliverables contained herein is PROPRIETARY and CONFIDENTIAL - to NVIDIA and is being provided under the terms and conditions of a form of - NVIDIA software license agreement by and between NVIDIA and Licensee ("License - Agreement") or electronically accepted by Licensee. Notwithstanding any terms - or conditions to the contrary in the License Agreement, reproduction or - disclosure of the Licensed Deliverables to any third party without the express - written consent of NVIDIA is prohibited. - - NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE LICENSE AGREEMENT, - NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THESE LICENSED - DELIVERABLES FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED - WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE - LICENSED DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, - NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. NOTWITHSTANDING ANY - TERMS OR CONDITIONS TO THE CONTRARY IN THE LICENSE AGREEMENT, IN NO EVENT SHALL - NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THESE LICENSED DELIVERABLES. - - U.S. Government End Users. These Licensed Deliverables are a "commercial item" - as that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of - "commercial computer software" and "commercial computer software documentation" - as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) and is provided to the - U.S. Government only as a commercial end item. Consistent with 48 C.F.R.12.212 - and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all U.S. Government - End Users acquire the Licensed Deliverables with only those rights set forth - herein. - - Any use of the Licensed Deliverables in individual and commercial software must - include, in the user documentation and internal comments to the code, the above - Disclaimer and U.S. Government End Users Notice. - */ - -/* - * cuPrintf.cu - * - * This is a printf command callable from within a kernel. It is set - * up so that output is sent to a memory buffer, which is emptied from - * the host side - but only after a cudaThreadSynchronize() on the host. - * - * Currently, there is a limitation of around 200 characters of output - * and no more than 10 arguments to a single cuPrintf() call. Issue - * multiple calls if longer format strings are required. - * - * It requires minimal setup, and is *NOT* optimised for performance. - * For example, writes are not coalesced - this is because there is an - * assumption that people will not want to printf from every single one - * of thousands of threads, but only from individual threads at a time. - * - * Using this is simple - it requires one host-side call to initialise - * everything, and then kernels can call cuPrintf at will. Sample code - * is the easiest way to demonstrate: - * - #include "cuPrintf.cu" - - __global__ void testKernel(int val) - { - cuPrintf("Value is: %d\n", val); - } - - int main() - { - cudaPrintfInit(); - testKernel<<< 2, 3 >>>(10); - cudaPrintfDisplay(stdout, true); - cudaPrintfEnd(); - return 0; - } - * - * See the header file, "cuPrintf.cuh" for more info, especially - * arguments to cudaPrintfInit() and cudaPrintfDisplay(); - */ - -#ifndef CUPRINTF_CU -#define CUPRINTF_CU - -#include "cuPrintf.cuh" -#if __CUDA_ARCH__ > 100 // Atomics only used with > sm_10 architecture -#include -#endif - -// This is the smallest amount of memory, per-thread, which is allowed. -// It is also the largest amount of space a single printf() can take up -const static int CUPRINTF_MAX_LEN = 256; - -// This structure is used internally to track block/thread output restrictions. -typedef struct __align__(8) { - int threadid; // CUPRINTF_UNRESTRICTED for unrestricted - int blockid; // CUPRINTF_UNRESTRICTED for unrestricted -} cuPrintfRestriction; - -// The main storage is in a global print buffer, which has a known -// start/end/length. These are atomically updated so it works as a -// circular buffer. -// Since the only control primitive that can be used is atomicAdd(), -// we cannot wrap the pointer as such. The actual address must be -// calculated from printfBufferPtr by mod-ing with printfBufferLength. -// For sm_10 architecture, we must subdivide the buffer per-thread -// since we do not even have an atomic primitive. -__constant__ static char *globalPrintfBuffer = NULL; // Start of circular buffer (set up by host) -__constant__ static int printfBufferLength = 0; // Size of circular buffer (set up by host) -__device__ static cuPrintfRestriction restrictRules; // Output restrictions -__device__ volatile static char *printfBufferPtr = NULL; // Current atomically-incremented non-wrapped offset - -// This is the header preceeding all printf entries. -// NOTE: It *must* be size-aligned to the maximum entity size (size_t) -typedef struct __align__(8) { - unsigned short magic; // Magic number says we're valid - unsigned short fmtoffset; // Offset of fmt string into buffer - unsigned short blockid; // Block ID of author - unsigned short threadid; // Thread ID of author -} cuPrintfHeader; - -// Special header for sm_10 architecture -#define CUPRINTF_SM10_MAGIC 0xC810 // Not a valid ascii character -typedef struct __align__(16) { - unsigned short magic; // sm_10 specific magic number - unsigned short unused; - unsigned int thread_index; // thread ID for this buffer - unsigned int thread_buf_len; // per-thread buffer length - unsigned int offset; // most recent printf's offset -} cuPrintfHeaderSM10; - - -// Because we can't write an element which is not aligned to its bit-size, -// we have to align all sizes and variables on maximum-size boundaries. -// That means sizeof(double) in this case, but we'll use (long long) for -// better arch<1.3 support -#define CUPRINTF_ALIGN_SIZE sizeof(long long) - -// All our headers are prefixed with a magic number so we know they're ready -#define CUPRINTF_SM11_MAGIC (unsigned short)0xC811 // Not a valid ascii character - - -// -// getNextPrintfBufPtr -// -// Grabs a block of space in the general circular buffer, using an -// atomic function to ensure that it's ours. We handle wrapping -// around the circular buffer and return a pointer to a place which -// can be written to. -// -// Important notes: -// 1. We always grab CUPRINTF_MAX_LEN bytes -// 2. Because of 1, we never worry about wrapping around the end -// 3. Because of 1, printfBufferLength *must* be a factor of CUPRINTF_MAX_LEN -// -// This returns a pointer to the place where we own. -// -__device__ static char *getNextPrintfBufPtr() -{ - // Initialisation check - if(!printfBufferPtr) - return NULL; - - // Thread/block restriction check - if((restrictRules.blockid != CUPRINTF_UNRESTRICTED) && (restrictRules.blockid != (blockIdx.x + gridDim.x*blockIdx.y))) - return NULL; - if((restrictRules.threadid != CUPRINTF_UNRESTRICTED) && (restrictRules.threadid != (threadIdx.x + blockDim.x*threadIdx.y + blockDim.x*blockDim.y*threadIdx.z))) - return NULL; - - // Conditional section, dependent on architecture -#if __CUDA_ARCH__ == 100 - // For sm_10 architectures, we have no atomic add - this means we must split the - // entire available buffer into per-thread blocks. Inefficient, but what can you do. - int thread_count = (gridDim.x * gridDim.y) * (blockDim.x * blockDim.y * blockDim.z); - int thread_index = threadIdx.x + blockDim.x*threadIdx.y + blockDim.x*blockDim.y*threadIdx.z + - (blockIdx.x + gridDim.x*blockIdx.y) * (blockDim.x * blockDim.y * blockDim.z); - - // Find our own block of data and go to it. Make sure the per-thread length - // is a precise multiple of CUPRINTF_MAX_LEN, otherwise we risk size and - // alignment issues! We must round down, of course. - unsigned int thread_buf_len = printfBufferLength / thread_count; - thread_buf_len &= ~(CUPRINTF_MAX_LEN-1); - - // We *must* have a thread buffer length able to fit at least two printfs (one header, one real) - if(thread_buf_len < (CUPRINTF_MAX_LEN * 2)) - return NULL; - - // Now address our section of the buffer. The first item is a header. - char *myPrintfBuffer = globalPrintfBuffer + (thread_buf_len * thread_index); - cuPrintfHeaderSM10 hdr = *(cuPrintfHeaderSM10 *)(void *)myPrintfBuffer; - if(hdr.magic != CUPRINTF_SM10_MAGIC) - { - // If our header is not set up, initialise it - hdr.magic = CUPRINTF_SM10_MAGIC; - hdr.thread_index = thread_index; - hdr.thread_buf_len = thread_buf_len; - hdr.offset = 0; // Note we start at 0! We pre-increment below. - *(cuPrintfHeaderSM10 *)(void *)myPrintfBuffer = hdr; // Write back the header - - // For initial setup purposes, we might need to init thread0's header too - // (so that cudaPrintfDisplay() below will work). This is only run once. - cuPrintfHeaderSM10 *tophdr = (cuPrintfHeaderSM10 *)(void *)globalPrintfBuffer; - tophdr->thread_buf_len = thread_buf_len; - } - - // Adjust the offset by the right amount, and wrap it if need be - unsigned int offset = hdr.offset + CUPRINTF_MAX_LEN; - if(offset >= hdr.thread_buf_len) - offset = CUPRINTF_MAX_LEN; - - // Write back the new offset for next time and return a pointer to it - ((cuPrintfHeaderSM10 *)(void *)myPrintfBuffer)->offset = offset; - return myPrintfBuffer + offset; -#else - // Much easier with an atomic operation! - size_t offset = atomicAdd((unsigned int *)&printfBufferPtr, CUPRINTF_MAX_LEN) - (size_t)globalPrintfBuffer; - offset %= printfBufferLength; - return globalPrintfBuffer + offset; -#endif -} - - -// -// writePrintfHeader -// -// Inserts the header for containing our UID, fmt position and -// block/thread number. We generate it dynamically to avoid -// issues arising from requiring pre-initialisation. -// -__device__ static void writePrintfHeader(char *ptr, char *fmtptr) -{ - if(ptr) - { - cuPrintfHeader header; - header.magic = CUPRINTF_SM11_MAGIC; - header.fmtoffset = (unsigned short)(fmtptr - ptr); - header.blockid = blockIdx.x + gridDim.x*blockIdx.y; - header.threadid = threadIdx.x + blockDim.x*threadIdx.y + blockDim.x*blockDim.y*threadIdx.z; - *(cuPrintfHeader *)(void *)ptr = header; - } -} - - -// -// cuPrintfStrncpy -// -// This special strncpy outputs an aligned length value, followed by the -// string. It then zero-pads the rest of the string until a 64-aligned -// boundary. The length *includes* the padding. A pointer to the byte -// just after the \0 is returned. -// -// This function could overflow CUPRINTF_MAX_LEN characters in our buffer. -// To avoid it, we must count as we output and truncate where necessary. -// -__device__ static char *cuPrintfStrncpy(char *dest, const char *src, int n, char *end) -{ - // Initialisation and overflow check - if(!dest || !src || (dest >= end)) - return NULL; - - // Prepare to write the length specifier. We're guaranteed to have - // at least "CUPRINTF_ALIGN_SIZE" bytes left because we only write out in - // chunks that size, and CUPRINTF_MAX_LEN is aligned with CUPRINTF_ALIGN_SIZE. - int *lenptr = (int *)(void *)dest; - int len = 0; - dest += CUPRINTF_ALIGN_SIZE; - - // Now copy the string - while(n--) - { - if(dest >= end) // Overflow check - break; - - len++; - *dest++ = *src; - if(*src++ == '\0') - break; - } - - // Now write out the padding bytes, and we have our length. - while((dest < end) && (((long)dest & (CUPRINTF_ALIGN_SIZE-1)) != 0)) - { - len++; - *dest++ = 0; - } - *lenptr = len; - return (dest < end) ? dest : NULL; // Overflow means return NULL -} - - -// -// copyArg -// -// This copies a length specifier and then the argument out to the -// data buffer. Templates let the compiler figure all this out at -// compile-time, making life much simpler from the programming -// point of view. I'm assuimg all (const char *) is a string, and -// everything else is the variable it points at. I'd love to see -// a better way of doing it, but aside from parsing the format -// string I can't think of one. -// -// The length of the data type is inserted at the beginning (so that -// the display can distinguish between float and double), and the -// pointer to the end of the entry is returned. -// -__device__ static char *copyArg(char *ptr, const char *arg, char *end) -{ - // Initialisation check - if(!ptr || !arg) - return NULL; - - // strncpy does all our work. We just terminate. - if((ptr = cuPrintfStrncpy(ptr, arg, CUPRINTF_MAX_LEN, end)) != NULL) - *ptr = 0; - - return ptr; -} - -template -__device__ static char *copyArg(char *ptr, T &arg, char *end) -{ - // Initisalisation and overflow check. Alignment rules mean that - // we're at least CUPRINTF_ALIGN_SIZE away from "end", so we only need - // to check that one offset. - if(!ptr || ((ptr+CUPRINTF_ALIGN_SIZE) >= end)) - return NULL; - - // Write the length and argument - *(int *)(void *)ptr = sizeof(arg); - ptr += CUPRINTF_ALIGN_SIZE; - *(T *)(void *)ptr = arg; - ptr += CUPRINTF_ALIGN_SIZE; - *ptr = 0; - - return ptr; -} - - -// -// cuPrintf -// -// Templated printf functions to handle multiple arguments. -// Note we return the total amount of data copied, not the number -// of characters output. But then again, who ever looks at the -// return from printf() anyway? -// -// The format is to grab a block of circular buffer space, the -// start of which will hold a header and a pointer to the format -// string. We then write in all the arguments, and finally the -// format string itself. This is to make it easy to prevent -// overflow of our buffer (we support up to 10 arguments, each of -// which can be 12 bytes in length - that means that only the -// format string (or a %s) can actually overflow; so the overflow -// check need only be in the strcpy function. -// -// The header is written at the very last because that's what -// makes it look like we're done. -// -// Errors, which are basically lack-of-initialisation, are ignored -// in the called functions because NULL pointers are passed around -// - -// All printf variants basically do the same thing, setting up the -// buffer, writing all arguments, then finalising the header. For -// clarity, we'll pack the code into some big macros. -#define CUPRINTF_PREAMBLE \ - char *start, *end, *bufptr, *fmtstart; \ - if((start = getNextPrintfBufPtr()) == NULL) return 0; \ - end = start + CUPRINTF_MAX_LEN; \ - bufptr = start + sizeof(cuPrintfHeader); - -// Posting an argument is easy -#define CUPRINTF_ARG(argname) \ - bufptr = copyArg(bufptr, argname, end); - -// After args are done, record start-of-fmt and write the fmt and header -#define CUPRINTF_POSTAMBLE \ - fmtstart = bufptr; \ - end = cuPrintfStrncpy(bufptr, fmt, CUPRINTF_MAX_LEN, end); \ - writePrintfHeader(start, end ? fmtstart : NULL); \ - return end ? (int)(end - start) : 0; - -__device__ int cuPrintf(const char *fmt) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - CUPRINTF_ARG(arg3); - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - CUPRINTF_ARG(arg3); - CUPRINTF_ARG(arg4); - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - CUPRINTF_ARG(arg3); - CUPRINTF_ARG(arg4); - CUPRINTF_ARG(arg5); - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - CUPRINTF_ARG(arg3); - CUPRINTF_ARG(arg4); - CUPRINTF_ARG(arg5); - CUPRINTF_ARG(arg6); - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - CUPRINTF_ARG(arg3); - CUPRINTF_ARG(arg4); - CUPRINTF_ARG(arg5); - CUPRINTF_ARG(arg6); - CUPRINTF_ARG(arg7); - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - CUPRINTF_ARG(arg3); - CUPRINTF_ARG(arg4); - CUPRINTF_ARG(arg5); - CUPRINTF_ARG(arg6); - CUPRINTF_ARG(arg7); - CUPRINTF_ARG(arg8); - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - CUPRINTF_ARG(arg3); - CUPRINTF_ARG(arg4); - CUPRINTF_ARG(arg5); - CUPRINTF_ARG(arg6); - CUPRINTF_ARG(arg7); - CUPRINTF_ARG(arg8); - CUPRINTF_ARG(arg9); - - CUPRINTF_POSTAMBLE; -} -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10) -{ - CUPRINTF_PREAMBLE; - - CUPRINTF_ARG(arg1); - CUPRINTF_ARG(arg2); - CUPRINTF_ARG(arg3); - CUPRINTF_ARG(arg4); - CUPRINTF_ARG(arg5); - CUPRINTF_ARG(arg6); - CUPRINTF_ARG(arg7); - CUPRINTF_ARG(arg8); - CUPRINTF_ARG(arg9); - CUPRINTF_ARG(arg10); - - CUPRINTF_POSTAMBLE; -} -#undef CUPRINTF_PREAMBLE -#undef CUPRINTF_ARG -#undef CUPRINTF_POSTAMBLE - - -// -// cuPrintfRestrict -// -// Called to restrict output to a given thread/block. -// We store the info in "restrictRules", which is set up at -// init time by the host. It's not the cleanest way to do this -// because it means restrictions will last between -// invocations, but given the output-pointer continuity, -// I feel this is reasonable. -// -__device__ void cuPrintfRestrict(int threadid, int blockid) -{ - int thread_count = blockDim.x * blockDim.y * blockDim.z; - if(((threadid < thread_count) && (threadid >= 0)) || (threadid == CUPRINTF_UNRESTRICTED)) - restrictRules.threadid = threadid; - - int block_count = gridDim.x * gridDim.y; - if(((blockid < block_count) && (blockid >= 0)) || (blockid == CUPRINTF_UNRESTRICTED)) - restrictRules.blockid = blockid; -} - - -/////////////////////////////////////////////////////////////////////////////// -// HOST SIDE - -#include -static FILE *printf_fp; - -static char *printfbuf_start=NULL; -static char *printfbuf_device=NULL; -static int printfbuf_len=0; - - -// -// outputPrintfData -// -// Our own internal function, which takes a pointer to a data buffer -// and passes it through libc's printf for output. -// -// We receive the formate string and a pointer to where the data is -// held. We then run through and print it out. -// -// Returns 0 on failure, 1 on success -// -static int outputPrintfData(char *fmt, char *data) -{ - // Format string is prefixed by a length that we don't need - fmt += CUPRINTF_ALIGN_SIZE; - - // Now run through it, printing everything we can. We must - // run to every % character, extract only that, and use printf - // to format it. - char *p = strchr(fmt, '%'); - while(p != NULL) - { - // Print up to the % character - *p = '\0'; - fputs(fmt, printf_fp); - *p = '%'; // Put back the % - - // Now handle the format specifier - char *format = p++; // Points to the '%' - p += strcspn(p, "%cdiouxXeEfgGaAnps"); - if(*p == '\0') // If no format specifier, print the whole thing - { - fmt = format; - break; - } - - // Cut out the format bit and use printf to print it. It's prefixed - // by its length. - int arglen = *(int *)data; - if(arglen > CUPRINTF_MAX_LEN) - { - fputs("Corrupt printf buffer data - aborting\n", printf_fp); - return 0; - } - - data += CUPRINTF_ALIGN_SIZE; - - char specifier = *p++; - char c = *p; // Store for later - *p = '\0'; - switch(specifier) - { - // These all take integer arguments - case 'c': - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - case 'p': - fprintf(printf_fp, format, *((int *)data)); - break; - - // These all take double arguments - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - case 'a': - case 'A': - if(arglen == 4) // Float vs. Double thing - fprintf(printf_fp, format, *((float *)data)); - else - fprintf(printf_fp, format, *((double *)data)); - break; - - // Strings are handled in a special way - case 's': - fprintf(printf_fp, format, (char *)data); - break; - - // % is special - case '%': - fprintf(printf_fp, "%%"); - break; - - // Everything else is just printed out as-is - default: - fprintf(printf_fp, format); - break; - } - data += CUPRINTF_ALIGN_SIZE; // Move on to next argument - *p = c; // Restore what we removed - fmt = p; // Adjust fmt string to be past the specifier - p = strchr(fmt, '%'); // and get the next specifier - } - - // Print out the last of the string - fputs(fmt, printf_fp); - return 1; -} - - -// -// doPrintfDisplay -// -// This runs through the blocks of CUPRINTF_MAX_LEN-sized data, calling the -// print function above to display them. We've got this separate from -// cudaPrintfDisplay() below so we can handle the SM_10 architecture -// partitioning. -// -static int doPrintfDisplay(int headings, int clear, char *bufstart, char *bufend, char *bufptr, char *endptr) -{ - // Grab, piece-by-piece, each output element until we catch - // up with the circular buffer end pointer - int printf_count=0; - char printfbuf_local[CUPRINTF_MAX_LEN+1]; - printfbuf_local[CUPRINTF_MAX_LEN] = '\0'; - - while(bufptr != endptr) - { - // Wrap ourselves at the end-of-buffer - if(bufptr == bufend) - bufptr = bufstart; - - // Adjust our start pointer to within the circular buffer and copy a block. - cudaMemcpy(printfbuf_local, bufptr, CUPRINTF_MAX_LEN, cudaMemcpyDeviceToHost); - - // If the magic number isn't valid, then this write hasn't gone through - // yet and we'll wait until it does (or we're past the end for non-async printfs). - cuPrintfHeader *hdr = (cuPrintfHeader *)printfbuf_local; - if((hdr->magic != CUPRINTF_SM11_MAGIC) || (hdr->fmtoffset >= CUPRINTF_MAX_LEN)) - { - //fprintf(printf_fp, "Bad magic number in printf header\n"); - break; - } - - // Extract all the info and get this printf done - if(headings) - fprintf(printf_fp, "[%d, %d]: ", hdr->blockid, hdr->threadid); - if(hdr->fmtoffset == 0) - fprintf(printf_fp, "printf buffer overflow\n"); - else if(!outputPrintfData(printfbuf_local+hdr->fmtoffset, printfbuf_local+sizeof(cuPrintfHeader))) - break; - printf_count++; - - // Clear if asked - if(clear) - cudaMemset(bufptr, 0, CUPRINTF_MAX_LEN); - - // Now advance our start location, because we're done, and keep copying - bufptr += CUPRINTF_MAX_LEN; - } - - return printf_count; -} - - -// -// cudaPrintfInit -// -// Takes a buffer length to allocate, creates the memory on the device and -// returns a pointer to it for when a kernel is called. It's up to the caller -// to free it. -// -extern "C" cudaError_t cudaPrintfInit(size_t bufferLen) -{ - // Fix up bufferlen to be a multiple of CUPRINTF_MAX_LEN - bufferLen = (bufferLen < CUPRINTF_MAX_LEN) ? CUPRINTF_MAX_LEN : bufferLen; - if((bufferLen % CUPRINTF_MAX_LEN) > 0) - bufferLen += (CUPRINTF_MAX_LEN - (bufferLen % CUPRINTF_MAX_LEN)); - printfbuf_len = (int)bufferLen; - - // Allocate a print buffer on the device and zero it - if(cudaMalloc((void **)&printfbuf_device, printfbuf_len) != cudaSuccess) - return cudaErrorInitializationError; - cudaMemset(printfbuf_device, 0, printfbuf_len); - printfbuf_start = printfbuf_device; // Where we start reading from - - // No restrictions to begin with - cuPrintfRestriction restrict; - restrict.threadid = restrict.blockid = CUPRINTF_UNRESTRICTED; - cudaMemcpyToSymbol(restrictRules, &restrict, sizeof(restrict)); - - // Initialise the buffer and the respective lengths/pointers. - cudaMemcpyToSymbol(globalPrintfBuffer, &printfbuf_device, sizeof(char *)); - cudaMemcpyToSymbol(printfBufferPtr, &printfbuf_device, sizeof(char *)); - cudaMemcpyToSymbol(printfBufferLength, &printfbuf_len, sizeof(printfbuf_len)); - - return cudaSuccess; -} - - -// -// cudaPrintfEnd -// -// Frees up the memory which we allocated -// -extern "C" void cudaPrintfEnd() -{ - if(!printfbuf_start || !printfbuf_device) - return; - - cudaFree(printfbuf_device); - printfbuf_start = printfbuf_device = NULL; -} - - -// -// cudaPrintfDisplay -// -// Each call to this function dumps the entire current contents -// of the printf buffer to the pre-specified FILE pointer. The -// circular "start" pointer is advanced so that subsequent calls -// dumps only new stuff. -// -// In the case of async memory access (via streams), call this -// repeatedly to keep trying to empty the buffer. If it's a sync -// access, then the whole buffer should empty in one go. -// -// Arguments: -// outputFP - File descriptor to output to (NULL => stdout) -// showThreadID - If true, prints [block,thread] before each line -// -extern "C" cudaError_t cudaPrintfDisplay(void *outputFP, bool showThreadID) -{ - printf_fp = (FILE *)((outputFP == NULL) ? stdout : outputFP); - - // For now, we force "synchronous" mode which means we're not concurrent - // with kernel execution. This also means we don't need clearOnPrint. - // If you're patching it for async operation, here's where you want it. - bool sync_printfs = true; - bool clearOnPrint = false; - - // Initialisation check - if(!printfbuf_start || !printfbuf_device || !printf_fp) - return cudaErrorMissingConfiguration; - - // To determine which architecture we're using, we read the - // first short from the buffer - it'll be the magic number - // relating to the version. - unsigned short magic; - cudaMemcpy(&magic, printfbuf_device, sizeof(unsigned short), cudaMemcpyDeviceToHost); - - // For SM_10 architecture, we've split our buffer into one-per-thread. - // That means we must do each thread block separately. It'll require - // extra reading. We also, for now, don't support async printfs because - // that requires tracking one start pointer per thread. - if(magic == CUPRINTF_SM10_MAGIC) - { - sync_printfs = true; - clearOnPrint = false; - int blocklen = 0; - char *blockptr = printfbuf_device; - while(blockptr < (printfbuf_device + printfbuf_len)) - { - cuPrintfHeaderSM10 hdr; - cudaMemcpy(&hdr, blockptr, sizeof(hdr), cudaMemcpyDeviceToHost); - - // We get our block-size-step from the very first header - if(hdr.thread_buf_len != 0) - blocklen = hdr.thread_buf_len; - - // No magic number means no printfs from this thread - if(hdr.magic != CUPRINTF_SM10_MAGIC) - { - if(blocklen == 0) - { - fprintf(printf_fp, "No printf headers found at all!\n"); - break; // No valid headers! - } - blockptr += blocklen; - continue; - } - - // "offset" is non-zero then we can print the block contents - if(hdr.offset > 0) - { - // For synchronous printfs, we must print from endptr->bufend, then from start->end - if(sync_printfs) - doPrintfDisplay(showThreadID, clearOnPrint, blockptr+CUPRINTF_MAX_LEN, blockptr+hdr.thread_buf_len, blockptr+hdr.offset+CUPRINTF_MAX_LEN, blockptr+hdr.thread_buf_len); - doPrintfDisplay(showThreadID, clearOnPrint, blockptr+CUPRINTF_MAX_LEN, blockptr+hdr.thread_buf_len, blockptr+CUPRINTF_MAX_LEN, blockptr+hdr.offset+CUPRINTF_MAX_LEN); - } - - // Move on to the next block and loop again - blockptr += hdr.thread_buf_len; - } - } - // For SM_11 and up, everything is a single buffer and it's simple - else if(magic == CUPRINTF_SM11_MAGIC) - { - // Grab the current "end of circular buffer" pointer. - char *printfbuf_end = NULL; - cudaMemcpyFromSymbol(&printfbuf_end, printfBufferPtr, sizeof(char *)); - - // Adjust our starting and ending pointers to within the block - char *bufptr = ((printfbuf_start - printfbuf_device) % printfbuf_len) + printfbuf_device; - char *endptr = ((printfbuf_end - printfbuf_device) % printfbuf_len) + printfbuf_device; - - // For synchronous (i.e. after-kernel-exit) printf display, we have to handle circular - // buffer wrap carefully because we could miss those past "end". - if(sync_printfs) - doPrintfDisplay(showThreadID, clearOnPrint, printfbuf_device, printfbuf_device+printfbuf_len, endptr, printfbuf_device+printfbuf_len); - doPrintfDisplay(showThreadID, clearOnPrint, printfbuf_device, printfbuf_device+printfbuf_len, bufptr, endptr); - - printfbuf_start = printfbuf_end; - } - else - ;//printf("Bad magic number in cuPrintf buffer header\n"); - - // If we were synchronous, then we must ensure that the memory is cleared on exit - // otherwise another kernel launch with a different grid size could conflict. - if(sync_printfs) - cudaMemset(printfbuf_device, 0, printfbuf_len); - - return cudaSuccess; -} - -// Cleanup -#undef CUPRINTF_MAX_LEN -#undef CUPRINTF_ALIGN_SIZE -#undef CUPRINTF_SM10_MAGIC -#undef CUPRINTF_SM11_MAGIC - -#endif diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/cuPrintf.cuh b/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/cuPrintf.cuh deleted file mode 100644 index cf3fe4868..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/cuPrintf.cuh +++ /dev/null @@ -1,162 +0,0 @@ -/* - Copyright 2009 NVIDIA Corporation. All rights reserved. - - NOTICE TO LICENSEE: - - This source code and/or documentation ("Licensed Deliverables") are subject - to NVIDIA intellectual property rights under U.S. and international Copyright - laws. - - These Licensed Deliverables contained herein is PROPRIETARY and CONFIDENTIAL - to NVIDIA and is being provided under the terms and conditions of a form of - NVIDIA software license agreement by and between NVIDIA and Licensee ("License - Agreement") or electronically accepted by Licensee. Notwithstanding any terms - or conditions to the contrary in the License Agreement, reproduction or - disclosure of the Licensed Deliverables to any third party without the express - written consent of NVIDIA is prohibited. - - NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE LICENSE AGREEMENT, - NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THESE LICENSED - DELIVERABLES FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED - WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE - LICENSED DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, - NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. NOTWITHSTANDING ANY - TERMS OR CONDITIONS TO THE CONTRARY IN THE LICENSE AGREEMENT, IN NO EVENT SHALL - NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, - OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER - IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THESE LICENSED DELIVERABLES. - - U.S. Government End Users. These Licensed Deliverables are a "commercial item" - as that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of - "commercial computer software" and "commercial computer software documentation" - as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) and is provided to the - U.S. Government only as a commercial end item. Consistent with 48 C.F.R.12.212 - and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all U.S. Government - End Users acquire the Licensed Deliverables with only those rights set forth - herein. - - Any use of the Licensed Deliverables in individual and commercial software must - include, in the user documentation and internal comments to the code, the above - Disclaimer and U.S. Government End Users Notice. - */ - -#ifndef CUPRINTF_H -#define CUPRINTF_H - -/* - * This is the header file supporting cuPrintf.cu and defining both - * the host and device-side interfaces. See that file for some more - * explanation and sample use code. See also below for details of the - * host-side interfaces. - * - * Quick sample code: - * - #include "cuPrintf.cu" - - __global__ void testKernel(int val) - { - cuPrintf("Value is: %d\n", val); - } - - int main() - { - cudaPrintfInit(); - testKernel<<< 2, 3 >>>(10); - cudaPrintfDisplay(stdout, true); - cudaPrintfEnd(); - return 0; - } - */ - -/////////////////////////////////////////////////////////////////////////////// -// DEVICE SIDE -// External function definitions for device-side code - -// Abuse of templates to simulate varargs -__device__ int cuPrintf(const char *fmt); -template __device__ int cuPrintf(const char *fmt, T1 arg1); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9); -template __device__ int cuPrintf(const char *fmt, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10); - - -// -// cuPrintfRestrict -// -// Called to restrict output to a given thread/block. Pass -// the constant CUPRINTF_UNRESTRICTED to unrestrict output -// for thread/block IDs. Note you can therefore allow -// "all printfs from block 3" or "printfs from thread 2 -// on all blocks", or "printfs only from block 1, thread 5". -// -// Arguments: -// threadid - Thread ID to allow printfs from -// blockid - Block ID to allow printfs from -// -// NOTE: Restrictions last between invocations of -// kernels unless cudaPrintfInit() is called again. -// -#define CUPRINTF_UNRESTRICTED -1 -__device__ void cuPrintfRestrict(int threadid, int blockid); - - - -/////////////////////////////////////////////////////////////////////////////// -// HOST SIDE -// External function definitions for host-side code - -// -// cudaPrintfInit -// -// Call this once to initialise the printf system. If the output -// file or buffer size needs to be changed, call cudaPrintfEnd() -// before re-calling cudaPrintfInit(). -// -// The default size for the buffer is 1 megabyte. For CUDA -// architecture 1.1 and above, the buffer is filled linearly and -// is completely used; however for architecture 1.0, the buffer -// is divided into as many segments are there are threads, even -// if some threads do not call cuPrintf(). -// -// Arguments: -// bufferLen - Length, in bytes, of total space to reserve -// (in device global memory) for output. -// -// Returns: -// cudaSuccess if all is well. -// -extern "C" cudaError_t cudaPrintfInit(size_t bufferLen=1048576); // 1-meg - that's enough for 4096 printfs by all threads put together - -// -// cudaPrintfEnd -// -// Cleans up all memories allocated by cudaPrintfInit(). -// Call this at exit, or before calling cudaPrintfInit() again. -// -extern "C" void cudaPrintfEnd(); - -// -// cudaPrintfDisplay -// -// Dumps the contents of the output buffer to the specified -// file pointer. If the output pointer is not specified, -// the default "stdout" is used. -// -// Arguments: -// outputFP - A file pointer to an output stream. -// showThreadID - If "true", output strings are prefixed -// by "[blockid, threadid] " at output. -// -// Returns: -// cudaSuccess if all is well. -// -extern "C" cudaError_t cudaPrintfDisplay(void *outputFP=NULL, bool showThreadID=false); - -#endif // CUPRINTF_H diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/libethash.cu b/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/libethash.cu deleted file mode 100644 index 3e53c8853..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cuda/libethash.cu +++ /dev/null @@ -1,27 +0,0 @@ -#include "cuPrintf.cu" -#include - -__global__ void device_greetings(void) -{ - cuPrintf("Hello, world from the device!\n"); -} - -int main(void) -{ - // greet from the host - printf("Hello, world from the host!\n"); - - // initialize cuPrintf - cudaPrintfInit(); - - // launch a kernel with a single thread to greet from the device - device_greetings<<<1,1>>>(); - - // display the device's greeting - cudaPrintfDisplay(); - - // clean up after cuPrintf - cudaPrintfEnd(); - - return 0; -} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/data_sizes.h b/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/data_sizes.h deleted file mode 100644 index 40417cb71..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/data_sizes.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-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 FoundationUUU,either version 3 of the LicenseUUU,or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be usefulU, - 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 cpp-ethereum. If notUUU,see . -*/ - -/** @file nth_prime.h -* @author Matthew Wampler-Doty -* @date 2015 -*/ - -// TODO: Update this after ~7 years - -#pragma once - -#include -//#include -#include "compiler.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -// 500 Epochs worth of tabulated DAG sizes (~3.5 Years) - -// Generated with the following Mathematica Code: -// GetDataSizes[n_] := Module[{ -// DAGSizeBytesInit = 2^30, -// MixBytes = 128, -// DAGGrowth = 113000000, -// j = 0}, -// Reap[ -// While[j < n, -// Module[{i = -// Floor[(DAGSizeBytesInit + DAGGrowth * j) / MixBytes]}, -// While[! PrimeQ[i], i--]; -// Sow[i*MixBytes]; j++]]]][[2]][[1]] - -static const size_t dag_sizes[] = { - 1073739904U, 1186739584U, 1299741568U, 1412741248U, 1525741696U, - 1638736768U, 1751741312U, 1864740736U, 1977740672U, 2090740864U, - 2203740544U, 2316741248U, 2429739392U, 2542740352U, 2655741824U, - 2768739712U, 2881740416U, 2994741632U, 3107740544U, 3220741504U, - 3333738112U, 3446741632U, 3559741312U, 3672740224U, 3785740928U, - 3898738304U, 4011741824U, 4124739712U, 4237735808U, 4350740864U, - 4463741824U, 4576741504U, 4689741184U, 4802739328U, 4915741568U, - 5028740224U, 5141740672U, 5254738304U, 5367741824U, 5480737664U, - 5593738112U, 5706741632U, 5819740544U, 5932734592U, 6045739904U, - 6158740096U, 6271740032U, 6384731776U, 6497732992U, 6610740352U, - 6723741056U, 6836741504U, 6949740416U, 7062740096U, 7175741824U, - 7288740224U, 7401741184U, 7514741632U, 7627741568U, 7740739712U, - 7853739136U, 7966740352U, 8079741568U, 8192739712U, 8305738624U, - 8418740864U, 8531740288U, 8644740736U, 8757735808U, 8870738816U, - 8983739264U, 9096740992U, 9209740928U, 9322739584U, 9435741824U, - 9548741504U, 9661739392U, 9774738304U, 9887741312U, 10000738688U, - 10113739136U, 10226741632U, 10339739776U, 10452741248U, 10565740928U, - 10678736512U, 10791734656U, 10904741248U, 11017738112U, 11130741632U, - 11243741312U, 11356739456U, 11469740416U, 11582734976U, 11695739008U, - 11808741248U, 11921734784U, 12034739072U, 12147741568U, 12260737408U, - 12373741696U, 12486738304U, 12599740544U, 12712740224U, 12825741184U, - 12938736256U, 13051741312U, 13164737408U, 13277738368U, 13390738048U, - 13503741824U, 13616741504U, 13729737088U, 13842740096U, 13955741312U, - 14068741504U, 14181740416U, 14294741632U, 14407739776U, 14520740224U, - 14633740928U, 14746736512U, 14859741824U, 14972740736U, 15085740928U, - 15198738304U, 15311732096U, 15424740736U, 15537739904U, 15650741632U, - 15763741568U, 15876737152U, 15989741696U, 16102740608U, 16215741056U, - 16328741248U, 16441740416U, 16554737792U, 16667740288U, 16780740992U, - 16893738112U, 17006741632U, 17119739008U, 17232735616U, 17345739392U, - 17458740352U, 17571736192U, 17684739712U, 17797739392U, 17910740096U, - 18023741312U, 18136740736U, 18249738112U, 18362738816U, 18475735424U, - 18588740224U, 18701738368U, 18814736768U, 18927737216U, 19040739968U, - 19153739648U, 19266736768U, 19379737984U, 19492739456U, 19605738368U, - 19718740352U, 19831741312U, 19944736384U, 20057741696U, 20170741376U, - 20283741824U, 20396737408U, 20509741696U, 20622741376U, 20735739008U, - 20848741504U, 20961740672U, 21074739328U, 21187740032U, 21300739456U, - 21413741696U, 21526740608U, 21639741824U, 21752737408U, 21865741696U, - 21978741376U, 22091741824U, 22204738432U, 22317740672U, 22430740096U, - 22543736704U, 22656741248U, 22769739904U, 22882739584U, 22995740288U, - 23108740736U, 23221740928U, 23334741376U, 23447737216U, 23560740992U, - 23673741184U, 23786740864U, 23899737728U, 24012741248U, 24125734784U, - 24238736512U, 24351741824U, 24464740736U, 24577737088U, 24690741632U, - 24803739776U, 24916740736U, 25029740416U, 25142740864U, 25255741568U, - 25368741248U, 25481740672U, 25594741376U, 25707741568U, 25820741504U, - 25933730432U, 26046739072U, 26159741824U, 26272741504U, 26385740672U, - 26498740096U, 26611741568U, 26724740992U, 26837739904U, 26950735232U, - 27063738496U, 27176741248U, 27289741184U, 27402740864U, 27515740544U, - 27628737152U, 27741740672U, 27854741632U, 27967740544U, 28080739712U, - 28193738368U, 28306741376U, 28419737728U, 28532739968U, 28645739648U, - 28758740096U, 28871741312U, 28984739456U, 29097740416U, 29210740864U, - 29323741312U, 29436740224U, 29549741696U, 29662738304U, 29775741568U, - 29888741504U, 30001740928U, 30114737024U, 30227735168U, 30340737664U, - 30453738368U, 30566737024U, 30679733632U, 30792740224U, 30905740928U, - 31018740352U, 31131740032U, 31244738944U, 31357737344U, 31470741376U, - 31583740544U, 31696740224U, 31809738112U, 31922739328U, 32035737472U, - 32148740992U, 32261741696U, 32374740352U, 32487741824U, 32600740736U, - 32713739648U, 32826740608U, 32939729792U, 33052740992U, 33165740672U, - 33278739584U, 33391741312U, 33504739712U, 33617740928U, 33730740608U, - 33843738496U, 33956739968U, 34069741696U, 34182739328U, 34295741824U, - 34408739968U, 34521740672U, 34634736512U, 34747741568U, 34860741248U, - 34973739392U, 35086738304U, 35199741056U, 35312736896U, 35425741184U, - 35538741376U, 35651740288U, 35764737152U, 35877741184U, 35990739584U, - 36103740544U, 36216740992U, 36329739392U, 36442737536U, 36555741568U, - 36668740736U, 36781741184U, 36894737024U, 37007741312U, 37120739456U, - 37233741184U, 37346736256U, 37459736192U, 37572734336U, 37685739904U, - 37798740352U, 37911737728U, 38024741504U, 38137739648U, 38250740608U, - 38363741824U, 38476740992U, 38589741184U, 38702740096U, 38815741312U, - 38928741248U, 39041738368U, 39154739584U, 39267741824U, 39380739712U, - 39493735808U, 39606741632U, 39719741312U, 39832741504U, 39945739648U, - 40058740352U, 40171740032U, 40284740992U, 40397740672U, 40510740352U, - 40623740288U, 40736738176U, 40849737856U, 40962741376U, 41075739776U, - 41188737664U, 41301735808U, 41414738048U, 41527741312U, 41640740992U, - 41753739904U, 41866739072U, 41979738496U, 42092740736U, 42205739648U, - 42318740608U, 42431741312U, 42544738688U, 42657741184U, 42770738048U, - 42883741568U, 42996741248U, 43109740928U, 43222736512U, 43335741056U, - 43448730496U, 43561740416U, 43674741632U, 43787740544U, 43900741504U, - 44013739648U, 44126740864U, 44239740544U, 44352741248U, 44465738368U, - 44578735232U, 44691739264U, 44804741504U, 44917741696U, 45030741376U, - 45143741824U, 45256740992U, 45369739136U, 45482740096U, 45595739776U, - 45708739712U, 45821740672U, 45934741376U, 46047741056U, 46160741248U, - 46273737088U, 46386740864U, 46499739008U, 46612739968U, 46725735296U, - 46838740864U, 46951741568U, 47064737152U, 47177741696U, 47290741376U, - 47403738752U, 47516741248U, 47629739648U, 47742741632U, 47855737984U, - 47968740224U, 48081738368U, 48194741632U, 48307739264U, 48420739712U, - 48533739136U, 48646738304U, 48759741824U, 48872741504U, 48985739392U, - 49098741376U, 49211741056U, 49324740992U, 49437738368U, 49550740864U, - 49663735424U, 49776737408U, 49889740672U, 50002738816U, 50115738752U, - 50228739712U, 50341741696U, 50454736768U, 50567738752U, 50680739968U, - 50793736832U, 50906734976U, 51019741568U, 51132739456U, 51245741696U, - 51358741376U, 51471741056U, 51584738944U, 51697734272U, 51810739072U, - 51923736448U, 52036740736U, 52149741184U, 52262737024U, 52375738496U, - 52488740992U, 52601739136U, 52714740352U, 52827736448U, 52940738176U, - 53053741696U, 53166740864U, 53279741824U, 53392741504U, 53505739136U, - 53618739584U, 53731741312U, 53844741248U, 53957741696U, 54070741376U, - 54183740288U, 54296741504U, 54409741696U, 54522739072U, 54635737472U, - 54748741504U, 54861736064U, 54974740096U, 55087741568U, 55200733568U, - 55313741696U, 55426734464U, 55539741056U, 55652741504U, 55765741184U, - 55878741376U, 55991730304U, 56104740992U, 56217740672U, 56330731648U, - 56443737472U, 56556724352U, 56669740672U, 56782739072U, 56895740032U, - 57008741248U, 57121741696U, 57234740096U, 57347741312U, 57460741504U -}; - -// 500 Epochs worth of tabulated DAG sizes (~3.5 Years) - -// Generated with the following Mathematica Code: -// GetCacheSizes[n_] := Module[{ -// DAGSizeBytesInit = 2^30, -// MixBytes = 128, -// DAGGrowth = 113000000, -// HashBytes = 64, -// DAGParents = 1024, -// j = 0}, -// Reap[ -// While[j < n, -// Module[{i = Floor[(DAGSizeBytesInit + DAGGrowth * j) / (DAGParents * HashBytes)]}, -// While[! PrimeQ[i], i--]; -// Sow[i*HashBytes]; j++]]]][[2]][[1]] - -const size_t cache_sizes[] = { - 1048384U, 1158208U, 1268416U, 1377856U, 1489856U, 1599296U, 1710656U, - 1820608U, 1930816U, 2041024U, 2151872U, 2261696U, 2371904U, 2482624U, - 2593216U, 2703296U, 2814016U, 2924224U, 3034816U, 3144896U, 3255488U, - 3365312U, 3475904U, 3586624U, 3696064U, 3806272U, 3917504U, 4027456U, - 4138304U, 4248512U, 4359104U, 4469312U, 4579264U, 4689728U, 4797376U, - 4909888U, 5020096U, 5131328U, 5241664U, 5351744U, 5461312U, 5572544U, - 5683264U, 5793472U, 5903552U, 6014144U, 6121664U, 6235072U, 6344896U, - 6454592U, 6565952U, 6675904U, 6786112U, 6896704U, 7006784U, 7117888U, - 7228096U, 7338304U, 7448768U, 7557952U, 7669184U, 7779776U, 7889216U, - 8000192U, 8110912U, 8220736U, 8331712U, 8441536U, 8552384U, 8662592U, - 8772928U, 8883136U, 8993728U, 9103168U, 9214528U, 9323968U, 9434816U, - 9545152U, 9655616U, 9766336U, 9876544U, 9986624U, 10097344U, 10207424U, - 10316864U, 10427968U, 10538432U, 10649152U, 10758976U, 10869568U, 10979776U, - 11089472U, 11200832U, 11309632U, 11420608U, 11531584U, 11641792U, 11751104U, - 11862976U, 11973184U, 12083264U, 12193856U, 12304064U, 12414656U, 12524608U, - 12635072U, 12745792U, 12855616U, 12965824U, 13076416U, 13187008U, 13297216U, - 13407808U, 13518016U, 13627072U, 13738688U, 13848256U, 13959488U, 14069696U, - 14180288U, 14290624U, 14399552U, 14511424U, 14621504U, 14732096U, 14841664U, - 14951744U, 15062336U, 15172672U, 15283264U, 15393088U, 15504448U, 15614272U, - 15723712U, 15834944U, 15945152U, 16055744U, 16165696U, 16277056U, 16387136U, - 16494784U, 16607936U, 16718272U, 16828736U, 16938176U, 17048384U, 17159872U, - 17266624U, 17380544U, 17490496U, 17600192U, 17711296U, 17821376U, 17931968U, - 18041152U, 18152896U, 18261952U, 18373568U, 18483392U, 18594112U, 18703936U, - 18814912U, 18924992U, 19034944U, 19145408U, 19256128U, 19366208U, 19477184U, - 19587136U, 19696576U, 19808192U, 19916992U, 20028352U, 20137664U, 20249024U, - 20358848U, 20470336U, 20580544U, 20689472U, 20801344U, 20911424U, 21020096U, - 21130688U, 21242176U, 21352384U, 21462208U, 21573824U, 21683392U, 21794624U, - 21904448U, 22013632U, 22125248U, 22235968U, 22344512U, 22456768U, 22566848U, - 22677056U, 22786496U, 22897984U, 23008064U, 23118272U, 23228992U, 23338816U, - 23449408U, 23560256U, 23670464U, 23780672U, 23891264U, 24001216U, 24110656U, - 24221888U, 24332608U, 24442688U, 24552512U, 24662464U, 24773696U, 24884032U, - 24994496U, 25105216U, 25215296U, 25324864U, 25435712U, 25546432U, 25655744U, - 25767232U, 25876672U, 25986368U, 26098112U, 26207936U, 26318912U, 26428736U, - 26539712U, 26650048U, 26760256U, 26869184U, 26979776U, 27091136U, 27201728U, - 27311552U, 27422272U, 27532352U, 27642304U, 27752896U, 27863744U, 27973952U, - 28082752U, 28194752U, 28305344U, 28415168U, 28524992U, 28636352U, 28746304U, - 28857152U, 28967104U, 29077184U, 29187904U, 29298496U, 29408576U, 29518912U, - 29628992U, 29739968U, 29850176U, 29960512U, 30070336U, 30180544U, 30290752U, - 30398912U, 30512192U, 30622784U, 30732992U, 30842176U, 30953536U, 31063744U, - 31174336U, 31284544U, 31395136U, 31504448U, 31615552U, 31725632U, 31835072U, - 31946176U, 32057024U, 32167232U, 32277568U, 32387008U, 32497984U, 32608832U, - 32719168U, 32829376U, 32939584U, 33050048U, 33160768U, 33271232U, 33381184U, - 33491648U, 33601856U, 33712576U, 33822016U, 33932992U, 34042816U, 34153024U, - 34263104U, 34373824U, 34485056U, 34594624U, 34704832U, 34816064U, 34926272U, - 35036224U, 35146816U, 35255104U, 35367104U, 35478208U, 35588416U, 35698496U, - 35808832U, 35918656U, 36029888U, 36139456U, 36250688U, 36360512U, 36471104U, - 36581696U, 36691136U, 36802112U, 36912448U, 37022912U, 37132864U, 37242944U, - 37354048U, 37464512U, 37574848U, 37684928U, 37794752U, 37904704U, 38015552U, - 38125888U, 38236864U, 38345792U, 38457152U, 38567744U, 38678336U, 38787776U, - 38897216U, 39009088U, 39117632U, 39230144U, 39340352U, 39450304U, 39560384U, - 39671488U, 39781312U, 39891392U, 40002112U, 40112704U, 40223168U, 40332608U, - 40443968U, 40553792U, 40664768U, 40774208U, 40884416U, 40993984U, 41105984U, - 41215424U, 41326528U, 41436992U, 41546048U, 41655872U, 41768128U, 41878336U, - 41988928U, 42098752U, 42209344U, 42319168U, 42429248U, 42540352U, 42649792U, - 42761024U, 42871616U, 42981824U, 43092032U, 43201856U, 43312832U, 43423552U, - 43533632U, 43643584U, 43753792U, 43864384U, 43974976U, 44084032U, 44195392U, - 44306368U, 44415296U, 44526016U, 44637248U, 44746816U, 44858048U, 44967872U, - 45078848U, 45188288U, 45299264U, 45409216U, 45518272U, 45630272U, 45740224U, - 45850432U, 45960896U, 46069696U, 46182208U, 46292416U, 46402624U, 46512064U, - 46623296U, 46733888U, 46843712U, 46953664U, 47065024U, 47175104U, 47285696U, - 47395904U, 47506496U, 47615296U, 47726912U, 47837632U, 47947712U, 48055232U, - 48168128U, 48277952U, 48387392U, 48499648U, 48609472U, 48720064U, 48830272U, - 48940096U, 49050944U, 49160896U, 49271744U, 49381568U, 49492288U, 49602752U, - 49712576U, 49822016U, 49934272U, 50042816U, 50154304U, 50264128U, 50374336U, - 50484416U, 50596288U, 50706752U, 50816704U, 50927168U, 51035456U, 51146944U, - 51258176U, 51366976U, 51477824U, 51589568U, 51699776U, 51809728U, 51920576U, - 52030016U, 52140736U, 52251328U, 52361152U, 52470592U, 52582592U, 52691776U, - 52803136U, 52912576U, 53020736U, 53132224U, 53242688U, 53354816U, 53465536U, - 53575232U, 53685568U, 53796544U, 53906752U, 54016832U, 54126656U, 54236992U, - 54347456U, 54457408U, 54569024U, 54679232U, 54789184U, 54899776U, 55008832U, - 55119296U, 55231168U, 55341248U, 55451584U, 55562048U, 55672256U, 55782208U, - 55893184U, 56002112U, 56113216U -}; - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/binding.gyp b/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/binding.gyp deleted file mode 100644 index 642c33cb3..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/binding.gyp +++ /dev/null @@ -1,29 +0,0 @@ -{ - "targets": - [{ - "target_name": "ethash", - "sources": [ - './ethash.cc', - '../libethash/ethash.h', - '../libethash/util.c', - '../libethash/util.h', - '../libethash/blum_blum_shub.h', - '../libethash/blum_blum_shub.c', - '../libethash/sha3.h', - '../libethash/sha3.c', - '../libethash/internal.h', - '../libethash/internal.c' - ], - "include_dirs": [ - "../", - " -#include -#include -#include -#include -#include "../libethash/ethash.h" - -using namespace v8; - -class EthashValidator : public NanAsyncWorker { - public: - // Constructor - EthashValidator(NanCallback *callback, const unsigned blocknumber, const unsigned char * seed) - : NanAsyncWorker(callback), blocknumber(blocknumber), seed(seed) {} - // Destructor - ~EthashValidator() { - free(this->cache); - free(this->params); - } - - // Executed inside the worker-thread. - // It is not safe to access V8, or V8 data structures - // here, so everything we need for input and output - // should go on `this`. - void Execute () { - - /* this->result = secp256k1_ecdsa_sign(this->msg, this->sig , &this->sig_len, this->pk, NULL, NULL); */ - } - - // Executed when the async work is complete - // this function will be run inside the main event loop - // so it is safe to use V8 again - void HandleOKCallback () { - NanScope(); - Handle argv[] = { - NanNew(this->result) - }; - callback->Call(2, argv); - } - - protected: - const unsigned blocknumber; - const unsigned char * seed; - ethash_params * params; - ethash_cache * cache; - bool result; - bool ready = 0; -}; - -/* class CompactSignWorker : public SignWorker { */ -/* public: */ -/* CompactSignWorker(NanCallback *callback, const unsigned char *msg, const unsigned char *pk ) */ -/* : SignWorker(callback, msg, pk){} */ - -/* void Execute () { */ -/* this->result = secp256k1_ecdsa_sign_compact(this->msg, this->sig , this->pk, NULL, NULL, &this->sig_len); */ -/* } */ - -/* void HandleOKCallback () { */ -/* NanScope(); */ -/* Handle argv[] = { */ -/* NanNew(this->result), */ -/* NanNewBufferHandle((char *)this->sig, 64), */ -/* NanNew(this->sig_len) */ -/* }; */ -/* callback->Call(3, argv); */ -/* } */ -/* }; */ - -/* class RecoverWorker : public NanAsyncWorker { */ -/* public: */ -/* // Constructor */ -/* RecoverWorker(NanCallback *callback, const unsigned char *msg, const unsigned char *sig, int compressed, int rec_id) */ -/* : NanAsyncWorker(callback), msg(msg), sig(sig), compressed(compressed), rec_id(rec_id) {} */ -/* // Destructor */ -/* ~RecoverWorker() {} */ - -/* void Execute () { */ -/* if(this->compressed == 1){ */ -/* this->pubkey = new unsigned char[33]; */ -/* }else{ */ -/* this->pubkey = new unsigned char[65]; */ -/* } */ - -/* this->result = secp256k1_ecdsa_recover_compact(this->msg, this->sig, this->pubkey, &this->pubkey_len, this->compressed, this->rec_id); */ -/* } */ - -/* void HandleOKCallback () { */ -/* NanScope(); */ -/* Handle argv[] = { */ -/* NanNew(this->result), */ -/* NanNewBufferHandle((char *)this->pubkey, this->pubkey_len) */ -/* }; */ -/* callback->Call(2, argv); */ -/* } */ - -/* protected: */ -/* const unsigned char * msg; */ -/* const unsigned char * sig; */ -/* int compressed; */ -/* int rec_id; */ -/* int result; */ -/* unsigned char * pubkey; */ -/* int pubkey_len; */ -/* }; */ - -/* class VerifyWorker : public NanAsyncWorker { */ -/* public: */ -/* // Constructor */ -/* VerifyWorker(NanCallback *callback, const unsigned char *msg, const unsigned char *sig, int sig_len, const unsigned char *pub_key, int pub_key_len) */ -/* : NanAsyncWorker(callback), msg(msg), sig(sig), sig_len(sig_len), pub_key(pub_key), pub_key_len(pub_key_len) {} */ -/* // Destructor */ -/* ~VerifyWorker() {} */ - -/* void Execute () { */ -/* this->result = secp256k1_ecdsa_verify(this->msg, this->sig, this->sig_len, this->pub_key, this->pub_key_len); */ -/* } */ - -/* void HandleOKCallback () { */ -/* NanScope(); */ -/* Handle argv[] = { */ -/* NanNew(this->result), */ -/* }; */ -/* callback->Call(1, argv); */ -/* } */ - -/* protected: */ -/* int result; */ -/* const unsigned char * msg; */ -/* const unsigned char * sig; */ -/* int sig_len; */ -/* const unsigned char * pub_key; */ -/* int pub_key_len; */ -/* }; */ - -/* NAN_METHOD(Verify){ */ -/* NanScope(); */ - -/* Local pub_buf = args[0].As(); */ -/* const unsigned char *pub_data = (unsigned char *) node::Buffer::Data(pub_buf); */ -/* int pub_len = node::Buffer::Length(args[0]); */ - -/* Local msg_buf = args[1].As(); */ -/* const unsigned char *msg_data = (unsigned char *) node::Buffer::Data(msg_buf); */ - -/* Local sig_buf = args[2].As(); */ -/* const unsigned char *sig_data = (unsigned char *) node::Buffer::Data(sig_buf); */ -/* int sig_len = node::Buffer::Length(args[2]); */ - -/* int result = secp256k1_ecdsa_verify(msg_data, sig_data, sig_len, pub_data, pub_len ); */ - -/* NanReturnValue(NanNew(result)); */ -/* } */ - -/* NAN_METHOD(Verify_Async){ */ -/* NanScope(); */ - -/* Local pub_buf = args[0].As(); */ -/* const unsigned char *pub_data = (unsigned char *) node::Buffer::Data(pub_buf); */ -/* int pub_len = node::Buffer::Length(args[0]); */ - -/* Local msg_buf = args[1].As(); */ -/* const unsigned char *msg_data = (unsigned char *) node::Buffer::Data(msg_buf); */ - -/* Local sig_buf = args[2].As(); */ -/* const unsigned char *sig_data = (unsigned char *) node::Buffer::Data(sig_buf); */ -/* int sig_len = node::Buffer::Length(args[2]); */ - -/* Local callback = args[3].As(); */ -/* NanCallback* nanCallback = new NanCallback(callback); */ - -/* VerifyWorker* worker = new VerifyWorker(nanCallback, msg_data, sig_data, sig_len, pub_data, pub_len); */ -/* NanAsyncQueueWorker(worker); */ - -/* NanReturnUndefined(); */ -/* } */ - -/* NAN_METHOD(Sign){ */ -/* NanScope(); */ - -/* //the first argument should be the private key as a buffer */ -/* Local pk_buf = args[0].As(); */ -/* const unsigned char *pk_data = (unsigned char *) node::Buffer::Data(pk_buf); */ -/* int sec_len = node::Buffer::Length(args[0]); */ -/* //the second argument is the message that we are signing */ -/* Local msg_buf = args[1].As(); */ -/* const unsigned char *msg_data = (unsigned char *) node::Buffer::Data(msg_buf); */ - -/* unsigned char sig[72]; */ -/* int sig_len = 72; */ -/* int msg_len = node::Buffer::Length(args[1]); */ - -/* if(sec_len != 32){ */ -/* return NanThrowError("the secret key needs tobe 32 bytes"); */ -/* } */ - -/* if(msg_len == 0){ */ -/* return NanThrowError("messgae cannot be null"); */ -/* } */ - -/* int result = secp256k1_ecdsa_sign(msg_data, sig , &sig_len, pk_data, NULL, NULL); */ - -/* if(result == 1){ */ -/* NanReturnValue(NanNewBufferHandle((char *)sig, sig_len)); */ -/* }else{ */ -/* return NanThrowError("nonce invalid, try another one"); */ -/* } */ -/* } */ - -/* NAN_METHOD(Sign_Async){ */ - -/* NanScope(); */ -/* //the first argument should be the private key as a buffer */ -/* Local sec_buf = args[0].As(); */ -/* const unsigned char *sec_data = (unsigned char *) node::Buffer::Data(sec_buf); */ -/* int sec_len = node::Buffer::Length(args[0]); */ -/* //the second argument is the message that we are signing */ -/* Local msg_buf = args[1].As(); */ -/* const unsigned char *msg_data = (unsigned char *) node::Buffer::Data(msg_buf); */ - -/* Local callback = args[2].As(); */ -/* NanCallback* nanCallback = new NanCallback(callback); */ - -/* int msg_len = node::Buffer::Length(args[1]); */ - -/* if(sec_len != 32){ */ -/* return NanThrowError("the secret key needs tobe 32 bytes"); */ -/* } */ - -/* if(msg_len == 0){ */ -/* return NanThrowError("messgae cannot be null"); */ -/* } */ - -/* SignWorker* worker = new SignWorker(nanCallback, msg_data, sec_data); */ -/* NanAsyncQueueWorker(worker); */ - -/* NanReturnUndefined(); */ -/* } */ - -/* NAN_METHOD(Sign_Compact){ */ - -/* NanScope(); */ - -/* Local seckey_buf = args[0].As(); */ -/* const unsigned char *seckey_data = (unsigned char *) node::Buffer::Data(seckey_buf); */ -/* int sec_len = node::Buffer::Length(args[0]); */ - -/* Local msg_buf = args[1].As(); */ -/* const unsigned char *msg_data = (unsigned char *) node::Buffer::Data(msg_buf); */ -/* int msg_len = node::Buffer::Length(args[1]); */ - -/* if(sec_len != 32){ */ -/* return NanThrowError("the secret key needs tobe 32 bytes"); */ -/* } */ - -/* if(msg_len == 0){ */ -/* return NanThrowError("messgae cannot be null"); */ -/* } */ - -/* unsigned char sig[64]; */ -/* int rec_id; */ - -/* //TODO: change the nonce */ -/* int valid_nonce = secp256k1_ecdsa_sign_compact(msg_data, sig, seckey_data, NULL, NULL, &rec_id ); */ - -/* Local array = NanNew(3); */ -/* array->Set(0, NanNew(valid_nonce)); */ -/* array->Set(1, NanNew(rec_id)); */ -/* array->Set(2, NanNewBufferHandle((char *)sig, 64)); */ - -/* NanReturnValue(array); */ -/* } */ - -/* NAN_METHOD(Sign_Compact_Async){ */ -/* NanScope(); */ -/* //the first argument should be the private key as a buffer */ -/* Local sec_buf = args[0].As(); */ -/* const unsigned char *sec_data = (unsigned char *) node::Buffer::Data(sec_buf); */ -/* int sec_len = node::Buffer::Length(args[0]); */ - -/* //the second argument is the message that we are signing */ -/* Local msg_buf = args[1].As(); */ -/* const unsigned char *msg_data = (unsigned char *) node::Buffer::Data(msg_buf); */ - - -/* Local callback = args[2].As(); */ -/* NanCallback* nanCallback = new NanCallback(callback); */ - -/* int msg_len = node::Buffer::Length(args[1]); */ - -/* if(sec_len != 32){ */ -/* return NanThrowError("the secret key needs tobe 32 bytes"); */ -/* } */ - -/* if(msg_len == 0){ */ -/* return NanThrowError("messgae cannot be null"); */ -/* } */ - -/* CompactSignWorker* worker = new CompactSignWorker(nanCallback, msg_data, sec_data); */ -/* NanAsyncQueueWorker(worker); */ - -/* NanReturnUndefined(); */ -/* } */ - -/* NAN_METHOD(Recover_Compact){ */ - -/* NanScope(); */ - -/* Local msg_buf = args[0].As(); */ -/* const unsigned char *msg = (unsigned char *) node::Buffer::Data(msg_buf); */ -/* int msg_len = node::Buffer::Length(args[0]); */ - -/* Local sig_buf = args[1].As(); */ -/* const unsigned char *sig = (unsigned char *) node::Buffer::Data(sig_buf); */ - -/* Local compressed = args[2].As(); */ -/* int int_compressed = compressed->IntegerValue(); */ - -/* Local rec_id = args[3].As(); */ -/* int int_rec_id = rec_id->IntegerValue(); */ - -/* if(msg_len == 0){ */ -/* return NanThrowError("messgae cannot be null"); */ -/* } */ - -/* unsigned char pubKey[65]; */ - -/* int pubKeyLen; */ - -/* int result = secp256k1_ecdsa_recover_compact(msg, sig, pubKey, &pubKeyLen, int_compressed, int_rec_id); */ -/* if(result == 1){ */ -/* NanReturnValue(NanNewBufferHandle((char *)pubKey, pubKeyLen)); */ -/* }else{ */ - -/* NanReturnValue(NanFalse()); */ -/* } */ -/* } */ - -/* NAN_METHOD(Recover_Compact_Async){ */ - -/* NanScope(); */ - -/* //the message */ -/* Local msg_buf = args[0].As(); */ -/* const unsigned char *msg = (unsigned char *) node::Buffer::Data(msg_buf); */ -/* int msg_len = node::Buffer::Length(args[0]); */ - -/* //the signature length */ -/* Local sig_buf = args[1].As(); */ -/* const unsigned char *sig = (unsigned char *) node::Buffer::Data(sig_buf); */ -/* //todo sig len needs tobe 64 */ -/* int sig_len = node::Buffer::Length(args[1]); */ - -/* //to compress or not? */ -/* Local compressed = args[2].As(); */ -/* int int_compressed = compressed->IntegerValue(); */ - -/* //the rec_id */ -/* Local rec_id = args[3].As(); */ -/* int int_rec_id = rec_id->IntegerValue(); */ - -/* //the callback */ -/* Local callback = args[4].As(); */ -/* NanCallback* nanCallback = new NanCallback(callback); */ - -/* if(sig_len != 64){ */ -/* return NanThrowError("the signature needs to be 64 bytes"); */ -/* } */ - -/* if(msg_len == 0){ */ -/* return NanThrowError("messgae cannot be null"); */ -/* } */ - -/* RecoverWorker* worker = new RecoverWorker(nanCallback, msg, sig, int_compressed, int_rec_id); */ -/* NanAsyncQueueWorker(worker); */ - -/* NanReturnUndefined(); */ -/* } */ - -/* NAN_METHOD(Seckey_Verify){ */ -/* NanScope(); */ - -/* const unsigned char *data = (const unsigned char*) node::Buffer::Data(args[0]); */ -/* int result = secp256k1_ec_seckey_verify(data); */ -/* NanReturnValue(NanNew(result)); */ -/* } */ - -/* NAN_METHOD(Pubkey_Verify){ */ - -/* NanScope(); */ - -/* Local pub_buf = args[0].As(); */ -/* const unsigned char *pub_key = (unsigned char *) node::Buffer::Data(pub_buf); */ -/* int pub_key_len = node::Buffer::Length(args[0]); */ - -/* int result = secp256k1_ec_pubkey_verify(pub_key, pub_key_len); */ - -/* NanReturnValue(NanNew(result)); */ -/* } */ - -/* NAN_METHOD(Pubkey_Create){ */ -/* NanScope(); */ - -/* Handle pk_buf = args[0].As(); */ -/* const unsigned char *pk_data = (unsigned char *) node::Buffer::Data(pk_buf); */ -/* int pk_len = node::Buffer::Length(args[0]); */ - -/* Local l_compact = args[1].As(); */ -/* int compact = l_compact->IntegerValue(); */ -/* int pubKeyLen; */ - -/* if(pk_len != 32){ */ -/* return NanThrowError("the secert key need to be 32 bytes"); */ -/* } */ - -/* unsigned char *pubKey; */ -/* if(compact == 1){ */ -/* pubKey = new unsigned char[33]; */ -/* }else{ */ -/* pubKey = new unsigned char[65]; */ -/* } */ - -/* int results = secp256k1_ec_pubkey_create(pubKey,&pubKeyLen, pk_data, compact ); */ -/* if(results == 0){ */ -/* return NanThrowError("secret was invalid, try again."); */ -/* }else{ */ -/* NanReturnValue(NanNewBufferHandle((char *)pubKey, pubKeyLen)); */ -/* } */ -/* } */ - -/* NAN_METHOD(Pubkey_Decompress){ */ -/* NanScope(); */ - -/* //the first argument should be the private key as a buffer */ -/* Local pk_buf = args[0].As(); */ -/* unsigned char *pk_data = (unsigned char *) node::Buffer::Data(pk_buf); */ - -/* int pk_len = node::Buffer::Length(args[0]); */ - -/* int results = secp256k1_ec_pubkey_decompress(pk_data, &pk_len); */ - -/* if(results == 0){ */ -/* return NanThrowError("invalid public key"); */ -/* }else{ */ -/* NanReturnValue(NanNewBufferHandle((char *)pk_data, pk_len)); */ -/* } */ -/* } */ - - -/* NAN_METHOD(Privkey_Import){ */ -/* NanScope(); */ - -/* //the first argument should be the private key as a buffer */ -/* Handle pk_buf = args[0].As(); */ -/* const unsigned char *pk_data = (unsigned char *) node::Buffer::Data(pk_buf); */ - -/* int pk_len = node::Buffer::Length(args[0]); */ - -/* unsigned char sec_key[32]; */ -/* int results = secp256k1_ec_privkey_import(sec_key, pk_data, pk_len); */ - -/* if(results == 0){ */ -/* return NanThrowError("invalid private key"); */ -/* }else{ */ -/* NanReturnValue(NanNewBufferHandle((char *)sec_key, 32)); */ -/* } */ -/* } */ - -/* NAN_METHOD(Privkey_Export){ */ -/* NanScope(); */ - -/* //the first argument should be the private key as a buffer */ -/* Handle sk_buf = args[0].As(); */ -/* const unsigned char *sk_data = (unsigned char *) node::Buffer::Data(sk_buf); */ - -/* Local l_compressed = args[1].As(); */ -/* int compressed = l_compressed->IntegerValue(); */ - -/* unsigned char *privKey; */ -/* int pk_len; */ -/* int results = secp256k1_ec_privkey_export(sk_data, privKey, &pk_len, compressed); */ -/* if(results == 0){ */ -/* return NanThrowError("invalid private key"); */ -/* }else{ */ -/* NanReturnValue(NanNewBufferHandle((char *)privKey, pk_len)); */ -/* } */ -/* } */ - -/* NAN_METHOD(Privkey_Tweak_Add){ */ -/* NanScope(); */ - -/* //the first argument should be the private key as a buffer */ -/* Handle sk_buf = args[0].As(); */ -/* unsigned char *sk = (unsigned char *) node::Buffer::Data(sk_buf); */ - -/* Handle tweak_buf = args[1].As(); */ -/* const unsigned char *tweak= (unsigned char *) node::Buffer::Data(tweak_buf); */ - -/* int results = secp256k1_ec_privkey_tweak_add(sk, tweak); */ -/* if(results == 0){ */ -/* return NanThrowError("invalid key"); */ -/* }else{ */ -/* NanReturnValue(NanNewBufferHandle((char *)sk, 32)); */ -/* } */ -/* } */ - -/* NAN_METHOD(Privkey_Tweak_Mul){ */ -/* NanScope(); */ - -/* //the first argument should be the private key as a buffer */ -/* Handle sk_buf = args[0].As(); */ -/* unsigned char *sk = (unsigned char *) node::Buffer::Data(sk_buf); */ - -/* Handle tweak_buf = args[1].As(); */ -/* const unsigned char *tweak= (unsigned char *) node::Buffer::Data(tweak_buf); */ - -/* int results = secp256k1_ec_privkey_tweak_mul(sk, tweak); */ -/* if(results == 0){ */ -/* return NanThrowError("invalid key"); */ -/* }else{ */ -/* NanReturnValue(NanNewBufferHandle((char *)sk, 32)); */ -/* } */ -/* } */ - -/* NAN_METHOD(Pubkey_Tweak_Add){ */ -/* NanScope(); */ - -/* //the first argument should be the private key as a buffer */ -/* Handle pk_buf = args[0].As(); */ -/* unsigned char *pk = (unsigned char *) node::Buffer::Data(pk_buf); */ -/* int pk_len = node::Buffer::Length(args[0]); */ - -/* Handle tweak_buf = args[1].As(); */ -/* const unsigned char *tweak= (unsigned char *) node::Buffer::Data(tweak_buf); */ - -/* int results = secp256k1_ec_pubkey_tweak_add(pk, pk_len, tweak); */ -/* if(results == 0){ */ -/* return NanThrowError("invalid key"); */ -/* }else{ */ -/* NanReturnValue(NanNewBufferHandle((char *)pk, pk_len)); */ -/* } */ -/* } */ - -/* NAN_METHOD(Pubkey_Tweak_Mul){ */ -/* NanScope(); */ - -/* //the first argument should be the private key as a buffer */ -/* Handle pk_buf = args[0].As(); */ -/* unsigned char *pk = (unsigned char *) node::Buffer::Data(pk_buf); */ -/* int pk_len = node::Buffer::Length(args[0]); */ - -/* Handle tweak_buf = args[1].As(); */ -/* const unsigned char *tweak= (unsigned char *) node::Buffer::Data(tweak_buf); */ - -/* int results = secp256k1_ec_pubkey_tweak_mul(pk, pk_len, tweak); */ -/* if(results == 0){ */ -/* return NanThrowError("invalid key"); */ -/* }else{ */ -/* NanReturnValue(NanNewBufferHandle((char *)pk, pk_len)); */ -/* } */ -/* } */ - -void Init(Handle exports) { - - /* secp256k1_start(SECP256K1_START_SIGN | SECP256K1_START_VERIFY); */ - /* exports->Set(NanNew("seckeyVerify"), NanNew(Seckey_Verify)->GetFunction()); */ - /* exports->Set(NanNew("sign"), NanNew(Sign)->GetFunction()); */ - /* exports->Set(NanNew("signAsync"), NanNew(Sign_Async)->GetFunction()); */ - /* exports->Set(NanNew("signCompact"), NanNew(Sign_Compact)->GetFunction()); */ - /* exports->Set(NanNew("signCompactAsync"), NanNew(Sign_Compact_Async)->GetFunction()); */ - /* exports->Set(NanNew("recoverCompact"), NanNew(Recover_Compact)->GetFunction()); */ - /* exports->Set(NanNew("recoverCompactAsync"), NanNew(Recover_Compact_Async)->GetFunction()); */ - /* exports->Set(NanNew("verify"), NanNew(Verify)->GetFunction()); */ - /* exports->Set(NanNew("verifyAsync"), NanNew(Verify_Async)->GetFunction()); */ - /* exports->Set(NanNew("secKeyVerify"), NanNew(Seckey_Verify)->GetFunction()); */ - /* exports->Set(NanNew("pubKeyVerify"), NanNew(Pubkey_Verify)->GetFunction()); */ - /* exports->Set(NanNew("pubKeyCreate"), NanNew(Pubkey_Create)->GetFunction()); */ - /* exports->Set(NanNew("pubKeyDecompress"), NanNew(Pubkey_Decompress)->GetFunction()); */ - /* exports->Set(NanNew("privKeyExport"), NanNew(Privkey_Export)->GetFunction()); */ - /* exports->Set(NanNew("privKeyImport"), NanNew(Privkey_Import)->GetFunction()); */ - /* exports->Set(NanNew("privKeyTweakAdd"), NanNew(Privkey_Tweak_Add)->GetFunction()); */ - /* exports->Set(NanNew("privKeyTweakMul"), NanNew(Privkey_Tweak_Mul)->GetFunction()); */ - /* exports->Set(NanNew("pubKeyTweakAdd"), NanNew(Privkey_Tweak_Add)->GetFunction()); */ - /* exports->Set(NanNew("pubKeyTweakMul"), NanNew(Privkey_Tweak_Mul)->GetFunction()); */ -} - -NODE_MODULE(secp256k1, Init) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/package.json b/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/package.json deleted file mode 100644 index 690ea3263..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "node-ethash", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "install": "node-gyp rebuild" - }, - "author": "", - "license": "ISC", - "gypfile": true -} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/readme.md b/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/readme.md deleted file mode 100644 index bb46cdd6e..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/node-ethash/readme.md +++ /dev/null @@ -1,12 +0,0 @@ -# To Develop -`npm install -g node-gyp` -`npm install .` - - -# To rebuild -`node-gyp rebuild` - - -# notes - -nan is good https://github.com/rvagg/nan diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/.gitignore b/Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/.gitignore new file mode 100644 index 000000000..e1374b866 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/.gitignore @@ -0,0 +1,2 @@ +pyethash.egg-info/ +*.so diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/__init__.py b/Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/__init__.py new file mode 100644 index 000000000..fca037dba --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/pyethash/__init__.py @@ -0,0 +1,3 @@ +import pyethash.core +core = pyethash.core +EPOCH_LENGTH = 30000 diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py b/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py new file mode 100644 index 000000000..4e27aad6c --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/setup.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +from distutils.core import setup, Extension + +pyethash_core = Extension('pyethash.core', + sources = [ + 'src/python/core.c', + 'src/libethash/util.c', + 'src/libethash/internal.c', + 'src/libethash/sha3.c' + ], + extra_compile_args = ["-std=gnu99"]) + +setup ( + name = 'pyethash', + author = "Matthew Wampler-Doty", + author_email = "matthew.wampler.doty@gmail.com", + license = 'GPL', + version = '1.0', + description = 'Python wrappers for ethash, the ethereum proof of work hashing function', + ext_modules = [pyethash_core], + ) diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/benchmark/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/benchmark/CMakeLists.txt rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/CMakeLists.txt diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/benchmark/benchmark.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/benchmark/benchmark.cpp rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/benchmark/benchmark.cpp diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/CMakeLists.txt new file mode 100644 index 000000000..fe563aae4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/CMakeLists.txt @@ -0,0 +1,15 @@ +set(LIBRARY ethash-cl) +set(CMAKE_BUILD_TYPE Release) + +include(bin2h.cmake) +bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl VARIABLE_NAME ethash_cl_miner_kernel HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) + +if (NOT OpenCL_FOUND) + find_package(OpenCL) +endif() +if (OpenCL_FOUND) + include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) + include_directories(..) + add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h) + TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash) +endif() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/bin2h.cmake b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/bin2h.cmake new file mode 100644 index 000000000..e224c1a67 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/bin2h.cmake @@ -0,0 +1,87 @@ +# https://gist.github.com/sivachandran/3a0de157dccef822a230 +include(CMakeParseArguments) + +# Function to wrap a given string into multiple lines at the given column position. +# Parameters: +# VARIABLE - The name of the CMake variable holding the string. +# AT_COLUMN - The column position at which string will be wrapped. +function(WRAP_STRING) + set(oneValueArgs VARIABLE AT_COLUMN) + cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN}) + + string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength) + math(EXPR offset "0") + + while(stringLength GREATER 0) + + if(stringLength GREATER ${WRAP_STRING_AT_COLUMN}) + math(EXPR length "${WRAP_STRING_AT_COLUMN}") + else() + math(EXPR length "${stringLength}") + endif() + + string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line) + set(lines "${lines}\n${line}") + + math(EXPR stringLength "${stringLength} - ${length}") + math(EXPR offset "${offset} + ${length}") + endwhile() + + set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE) +endfunction() + +# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file +# will contain a byte array and integer variable holding the size of the array. +# Parameters +# SOURCE_FILE - The path of source file whose contents will be embedded in the header file. +# VARIABLE_NAME - The name of the variable for the byte array. The string "_SIZE" will be append +# to this name and will be used a variable name for size variable. +# HEADER_FILE - The path of header file. +# APPEND - If specified appends to the header file instead of overwriting it +# NULL_TERMINATE - If specified a null byte(zero) will be append to the byte array. This will be +# useful if the source file is a text file and we want to use the file contents +# as string. But the size variable holds size of the byte array without this +# null byte. +# Usage: +# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG") +function(BIN2H) + set(options APPEND NULL_TERMINATE) + set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE) + cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN}) + + # reads source file contents as hex string + file(READ ${BIN2H_SOURCE_FILE} hexString HEX) + string(LENGTH ${hexString} hexStringLength) + + # appends null byte if asked + if(BIN2H_NULL_TERMINATE) + set(hexString "${hexString}00") + endif() + + # wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line) + wrap_string(VARIABLE hexString AT_COLUMN 32) + math(EXPR arraySize "${hexStringLength} / 2") + + # adds '0x' prefix and comma suffix before and after every byte respectively + string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString}) + # removes trailing comma + string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) + + # converts the variable name into proper C identifier + # TODO: fix for legacy cmake + IF (${CMAKE_VERSION} GREATER 2.8.10) + string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) + ENDIF() + string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) + + # declares byte array and the length variables + set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };") + set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};") + + set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n") + if(BIN2H_APPEND) + file(APPEND ${BIN2H_HEADER_FILE} "${declarations}") + else() + file(WRITE ${BIN2H_HEADER_FILE} "${declarations}") + endif() +endfunction() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/cl.hpp b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/cl.hpp similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/cl.hpp rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/cl.hpp diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.cpp new file mode 100644 index 000000000..c0dbea21d --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.cpp @@ -0,0 +1,289 @@ +/* + This file is part of c-ethash. + + c-ethash 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. + + c-ethash 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 cpp-ethereum. If not, see . +*/ +/** @file ethash_cl_miner.cpp +* @author Tim Hughes +* @date 2015 +*/ + + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include "ethash_cl_miner.h" +#include "ethash_cl_miner_kernel.h" +#include + +#undef min +#undef max + +#define HASH_BYTES 32 + +static void add_definition(std::string& source, char const* id, unsigned value) +{ + char buf[256]; + sprintf(buf, "#define %s %uu\n", id, value); + source.insert(source.begin(), buf, buf + strlen(buf)); +} + +ethash_cl_miner::ethash_cl_miner() +{ +} + +bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size) +{ + // store params + m_params = params; + + // get all platforms + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + debugf("No OpenCL platforms found.\n"); + return false; + } + + // use default platform + debugf("Using platform: %s\n", platforms[0].getInfo().c_str()); + + // get GPU device of the default platform + std::vector devices; + platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) + { + debugf("No OpenCL devices found.\n"); + return false; + } + + // use default device + cl::Device& device = devices[0]; + debugf("Using device: %s\n", device.getInfo().c_str()); + + // create context + m_context = cl::Context({device}); + m_queue = cl::CommandQueue(m_context, device); + + // use requested workgroup size, but we require multiple of 8 + m_workgroup_size = ((workgroup_size + 7) / 8) * 8; + + // patch source code + std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); + add_definition(code, "GROUP_SIZE", m_workgroup_size); + add_definition(code, "DAG_SIZE", (unsigned)(params.full_size / MIX_BYTES)); + add_definition(code, "ACCESSES", ACCESSES); + add_definition(code, "MAX_OUTPUTS", c_max_search_results); + //debugf("%s", code.c_str()); + + // create miner OpenCL program + cl::Program::Sources sources; + sources.push_back({code.c_str(), code.size()}); + + cl::Program program(m_context, sources); + try + { + program.build({device}); + } + catch (cl::Error err) + { + debugf("%s\n", program.getBuildInfo(device).c_str()); + return false; + } + m_hash_kernel = cl::Kernel(program, "ethash_hash"); + m_search_kernel = cl::Kernel(program, "ethash_search"); + + // create buffer for dag + m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, params.full_size); + + // create buffer for header + m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); + + // compute dag on CPU + { + void* cache_mem = malloc(params.cache_size + 63); + ethash_cache cache; + cache.mem = (void*)(((uintptr_t)cache_mem + 63) & ~63); + ethash_mkcache(&cache, ¶ms, seed); + + // if this throws then it's because we probably need to subdivide the dag uploads for compatibility + void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size); + ethash_compute_full_data(dag_ptr, ¶ms, &cache); + m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); + + free(cache_mem); + } + + // create mining buffers + for (unsigned i = 0; i != c_num_buffers; ++i) + { + m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, 32*c_hash_batch_size); + m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); + } + return true; +} + +void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count) +{ + struct pending_batch + { + unsigned base; + unsigned count; + unsigned buf; + }; + std::queue pending; + + // update header constant buffer + m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header); + + /* + __kernel void ethash_combined_hash( + __global hash32_t* g_hashes, + __constant hash32_t const* g_header, + __global hash128_t const* g_dag, + ulong start_nonce, + uint isolate + ) + */ + m_hash_kernel.setArg(1, m_header); + m_hash_kernel.setArg(2, m_dag); + m_hash_kernel.setArg(3, nonce); + m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop + + unsigned buf = 0; + for (unsigned i = 0; i < count || !pending.empty(); ) + { + // how many this batch + if (i < count) + { + unsigned const this_count = std::min(count - i, c_hash_batch_size); + unsigned const batch_count = std::max(this_count, m_workgroup_size); + + // supply output hash buffer to kernel + m_hash_kernel.setArg(0, m_hash_buf[buf]); + + // execute it! + clock_t start_time = clock(); + m_queue.enqueueNDRangeKernel( + m_hash_kernel, + cl::NullRange, + cl::NDRange(batch_count), + cl::NDRange(m_workgroup_size) + ); + m_queue.flush(); + + pending.push({i, this_count, buf}); + i += this_count; + buf = (buf + 1) % c_num_buffers; + } + + // read results + if (i == count || pending.size() == c_num_buffers) + { + pending_batch const& batch = pending.front(); + + // could use pinned host pointer instead, but this path isn't that important. + uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * HASH_BYTES); + memcpy(ret + batch.base*HASH_BYTES, hashes, batch.count*HASH_BYTES); + m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes); + + pending.pop(); + } + } +} + + +void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook) +{ + struct pending_batch + { + uint64_t start_nonce; + unsigned buf; + }; + std::queue pending; + + static uint32_t const c_zero = 0; + + // update header constant buffer + m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); + for (unsigned i = 0; i != c_num_buffers; ++i) + { + m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); + } + cl::Event pre_return_event; + m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); + + /* + __kernel void ethash_combined_search( + __global hash32_t* g_hashes, // 0 + __constant hash32_t const* g_header, // 1 + __global hash128_t const* g_dag, // 2 + ulong start_nonce, // 3 + ulong target, // 4 + uint isolate // 5 + ) + */ + m_search_kernel.setArg(1, m_header); + m_search_kernel.setArg(2, m_dag); + + // pass these to stop the compiler unrolling the loops + m_search_kernel.setArg(4, target); + m_search_kernel.setArg(5, ~0u); + + + unsigned buf = 0; + for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size) + { + // supply output buffer to kernel + m_search_kernel.setArg(0, m_search_buf[buf]); + m_search_kernel.setArg(3, start_nonce); + + // execute it! + m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); + + pending.push({start_nonce, buf}); + buf = (buf + 1) % c_num_buffers; + + // read results + if (pending.size() == c_num_buffers) + { + pending_batch const& batch = pending.front(); + + // could use pinned host pointer instead + uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t)); + unsigned num_found = std::min(results[0], c_max_search_results); + + uint64_t nonces[c_max_search_results]; + for (unsigned i = 0; i != num_found; ++i) + { + nonces[i] = batch.start_nonce + results[i+1]; + } + + m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); + + bool exit = num_found && hook.found(nonces, num_found); + exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit + if (exit) + break; + + pending.pop(); + } + } + + // not safe to return until this is ready + pre_return_event.wait(); +} + diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/ethash_cl_miner.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.h similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/ethash_cl_miner.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/ethash_cl_miner.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner_kernel.cl similarity index 61% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/ethash_cl_miner.cpp rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner_kernel.cl index 11b29333c..ee21a331e 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash-cl/ethash_cl_miner.cpp +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash-cl/ethash_cl_miner_kernel.cl @@ -1,39 +1,3 @@ -/* - This file is part of c-ethash. - - c-ethash 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. - - c-ethash 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 cpp-ethereum. If not, see . -*/ -/** @file ethash_cl_miner.cpp -* @author Tim Hughes -* @date 2015 -*/ - - -#define _CRT_SECURE_NO_WARNINGS - -#include -#include -#include "ethash_cl_miner.h" -#include - -#undef min -#undef max - -#define HASH_BYTES 32 - -static char const ethash_inner_code[] = R"( - // author Tim Hughes // Tested on Radeon HD 7850 // Hashrate: 15940347 hashes/s @@ -495,260 +459,3 @@ __kernel void ethash_search( g_output[slot] = gid; } } - -)"; - -static void add_definition(std::string& source, char const* id, unsigned value) -{ - char buf[256]; - sprintf(buf, "#define %s %uu\n", id, value); - source.insert(source.begin(), buf, buf + strlen(buf)); -} - -ethash_cl_miner::ethash_cl_miner() -{ -} - -bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32], unsigned workgroup_size) -{ - // store params - m_params = params; - - // get all platforms - std::vector platforms; - cl::Platform::get(&platforms); - if (platforms.empty()) - { - debugf("No OpenCL platforms found.\n"); - return false; - } - - // use default platform - debugf("Using platform: %s\n", platforms[0].getInfo().c_str()); - - // get GPU device of the default platform - std::vector devices; - platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devices); - if (devices.empty()) - { - debugf("No OpenCL devices found.\n"); - return false; - } - - // use default device - cl::Device& device = devices[0]; - debugf("Using device: %s\n", device.getInfo().c_str()); - - // create context - m_context = cl::Context({device}); - m_queue = cl::CommandQueue(m_context, device); - - // use requested workgroup size, but we require multiple of 8 - m_workgroup_size = ((workgroup_size + 7) / 8) * 8; - - // patch source code - std::string code = ethash_inner_code; - add_definition(code, "GROUP_SIZE", m_workgroup_size); - add_definition(code, "DAG_SIZE", (unsigned)(params.full_size / MIX_BYTES)); - add_definition(code, "ACCESSES", ACCESSES); - add_definition(code, "MAX_OUTPUTS", c_max_search_results); - //debugf("%s", code.c_str()); - - // create miner OpenCL program - cl::Program::Sources sources; - sources.push_back({code.c_str(), code.size()}); - - cl::Program program(m_context, sources); - try - { - program.build({device}); - } - catch (cl::Error err) - { - debugf("%s\n", program.getBuildInfo(device).c_str()); - return false; - } - m_hash_kernel = cl::Kernel(program, "ethash_hash"); - m_search_kernel = cl::Kernel(program, "ethash_search"); - - // create buffer for dag - m_dag = cl::Buffer(m_context, CL_MEM_READ_ONLY, params.full_size); - - // create buffer for header - m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); - - // compute dag on CPU - { - void* cache_mem = malloc(params.cache_size + 63); - ethash_cache cache; - cache.mem = (void*)(((uintptr_t)cache_mem + 63) & ~63); - ethash_mkcache(&cache, ¶ms, seed); - - // if this throws then it's because we probably need to subdivide the dag uploads for compatibility - void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size); - ethash_compute_full_data(dag_ptr, ¶ms, &cache); - m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); - - free(cache_mem); - } - - // create mining buffers - for (unsigned i = 0; i != c_num_buffers; ++i) - { - m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, 32*c_hash_batch_size); - m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); - } - return true; -} - -void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count) -{ - struct pending_batch - { - unsigned base; - unsigned count; - unsigned buf; - }; - std::queue pending; - - // update header constant buffer - m_queue.enqueueWriteBuffer(m_header, true, 0, 32, header); - - /* - __kernel void ethash_combined_hash( - __global hash32_t* g_hashes, - __constant hash32_t const* g_header, - __global hash128_t const* g_dag, - ulong start_nonce, - uint isolate - ) - */ - m_hash_kernel.setArg(1, m_header); - m_hash_kernel.setArg(2, m_dag); - m_hash_kernel.setArg(3, nonce); - m_hash_kernel.setArg(4, ~0u); // have to pass this to stop the compile unrolling the loop - - unsigned buf = 0; - for (unsigned i = 0; i < count || !pending.empty(); ) - { - // how many this batch - if (i < count) - { - unsigned const this_count = std::min(count - i, c_hash_batch_size); - unsigned const batch_count = std::max(this_count, m_workgroup_size); - - // supply output hash buffer to kernel - m_hash_kernel.setArg(0, m_hash_buf[buf]); - - // execute it! - clock_t start_time = clock(); - m_queue.enqueueNDRangeKernel( - m_hash_kernel, - cl::NullRange, - cl::NDRange(batch_count), - cl::NDRange(m_workgroup_size) - ); - m_queue.flush(); - - pending.push({i, this_count, buf}); - i += this_count; - buf = (buf + 1) % c_num_buffers; - } - - // read results - if (i == count || pending.size() == c_num_buffers) - { - pending_batch const& batch = pending.front(); - - // could use pinned host pointer instead, but this path isn't that important. - uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * HASH_BYTES); - memcpy(ret + batch.base*HASH_BYTES, hashes, batch.count*HASH_BYTES); - m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes); - - pending.pop(); - } - } -} - - -void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook) -{ - struct pending_batch - { - uint64_t start_nonce; - unsigned buf; - }; - std::queue pending; - - static uint32_t const c_zero = 0; - - // update header constant buffer - m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); - for (unsigned i = 0; i != c_num_buffers; ++i) - { - m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); - } - cl::Event pre_return_event; - m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); - - /* - __kernel void ethash_combined_search( - __global hash32_t* g_hashes, // 0 - __constant hash32_t const* g_header, // 1 - __global hash128_t const* g_dag, // 2 - ulong start_nonce, // 3 - ulong target, // 4 - uint isolate // 5 - ) - */ - m_search_kernel.setArg(1, m_header); - m_search_kernel.setArg(2, m_dag); - - // pass these to stop the compiler unrolling the loops - m_search_kernel.setArg(4, target); - m_search_kernel.setArg(5, ~0u); - - - unsigned buf = 0; - for (uint64_t start_nonce = 0; ; start_nonce += c_search_batch_size) - { - // supply output buffer to kernel - m_search_kernel.setArg(0, m_search_buf[buf]); - m_search_kernel.setArg(3, start_nonce); - - // execute it! - m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); - - pending.push({start_nonce, buf}); - buf = (buf + 1) % c_num_buffers; - - // read results - if (pending.size() == c_num_buffers) - { - pending_batch const& batch = pending.front(); - - // could use pinned host pointer instead - uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1+c_max_search_results) * sizeof(uint32_t)); - unsigned num_found = std::min(results[0], c_max_search_results); - - uint64_t nonces[c_max_search_results]; - for (unsigned i = 0; i != num_found; ++i) - { - nonces[i] = batch.start_nonce + results[i+1]; - } - - m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); - - bool exit = num_found && hook.found(nonces, num_found); - exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit - if (exit) - break; - - pending.pop(); - } - } - - // not safe to return until this is ready - pre_return_event.wait(); -} - diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt similarity index 88% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/CMakeLists.txt rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt index bef63ef0a..7bc147af7 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/CMakeLists.txt +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/CMakeLists.txt @@ -1,4 +1,10 @@ set(LIBRARY ethash) + +if (CPPETHEREUM) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") +#else () +endif () + set(CMAKE_BUILD_TYPE Release) if (NOT MSVC) @@ -30,4 +36,4 @@ add_library(${LIBRARY} ${FILES}) if (CRYPTOPP_FOUND) TARGET_LINK_LIBRARIES(${LIBRARY} ${CRYPTOPP_LIBRARIES}) -endif() \ No newline at end of file +endif() diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/compiler.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/compiler.h similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/compiler.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/compiler.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h new file mode 100644 index 000000000..a10d4c42c --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/data_sizes.h @@ -0,0 +1,779 @@ +/* + This file is part of cpp-ethereum. + + cpp-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 FoundationUUU,either version 3 of the LicenseUUU,or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be usefulU, + 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 cpp-ethereum. If notUUU,see . +*/ + +/** @file data_sizes.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +// TODO: Update this after ~3.5 years + +#pragma once + +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// 2048 Epochs worth of tabulated DAG sizes + +// Generated with the following Mathematica Code: + +// GetDataSizes[n_] := Module[{ +// DataSetSizeBytesInit = 2^30, +// MixBytes = 128, +// DataSetGrowth = 2^23, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = +// Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / MixBytes]}, +// While[! PrimeQ[i], i--]; +// Sow[i*MixBytes]; j++]]]][[2]][[1]] + +static const size_t dag_sizes[] = { + 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, + 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, + 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, + 1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U, + 1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U, + 1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U, + 1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U, + 1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U, + 1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U, + 1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U, + 1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U, + 1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U, + 1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U, + 1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U, + 1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U, + 1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U, + 1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U, + 1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U, + 1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U, + 1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U, + 1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U, + 1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U, + 1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U, + 2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U, + 2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U, + 2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U, + 2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U, + 2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U, + 2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U, + 2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U, + 2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U, + 2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U, + 2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U, + 2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U, + 2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U, + 2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U, + 2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U, + 2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U, + 2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U, + 2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U, + 2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U, + 2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U, + 2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U, + 2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U, + 2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U, + 2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U, + 3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U, + 3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U, + 3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U, + 3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U, + 3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U, + 3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U, + 3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U, + 3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U, + 3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U, + 3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U, + 3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U, + 3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U, + 3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U, + 3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U, + 3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U, + 3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U, + 3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U, + 3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U, + 3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U, + 3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U, + 3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U, + 3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U, + 3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U, + 3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U, + 4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U, + 4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U, + 4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U, + 4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U, + 4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U, + 4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U, + 4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U, + 4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U, + 4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U, + 4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U, + 4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U, + 4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U, + 4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U, + 4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U, + 4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U, + 4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U, + 4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U, + 4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U, + 4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U, + 4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U, + 4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U, + 4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U, + 4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U, + 4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U, + 5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U, + 5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U, + 5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U, + 5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U, + 5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U, + 5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U, + 5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U, + 5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U, + 5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U, + 5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U, + 5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U, + 5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U, + 5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U, + 5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U, + 5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U, + 5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U, + 5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U, + 5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U, + 5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U, + 5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U, + 5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U, + 5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U, + 5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U, + 5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U, + 6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U, + 6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U, + 6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U, + 6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U, + 6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U, + 6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U, + 6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U, + 6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U, + 6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U, + 6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U, + 6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U, + 6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U, + 6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U, + 6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U, + 6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U, + 6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U, + 6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U, + 6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U, + 6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U, + 6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U, + 6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U, + 6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U, + 6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U, + 6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U, + 7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U, + 7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U, + 7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U, + 7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U, + 7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U, + 7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U, + 7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U, + 7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U, + 7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U, + 7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U, + 7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U, + 7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U, + 7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U, + 7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U, + 7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U, + 7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U, + 7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U, + 7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U, + 7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U, + 7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U, + 7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U, + 7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U, + 7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U, + 7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U, + 8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U, + 8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U, + 8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U, + 8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U, + 8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U, + 8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U, + 8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U, + 8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U, + 8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U, + 8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U, + 8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U, + 8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U, + 8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U, + 8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U, + 8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U, + 8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U, + 8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U, + 8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U, + 8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U, + 8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U, + 8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U, + 8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U, + 8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U, + 9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U, + 9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U, + 9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U, + 9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U, + 9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U, + 9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U, + 9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U, + 9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U, + 9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U, + 9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U, + 9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U, + 9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U, + 9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U, + 9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U, + 9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U, + 9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U, + 9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U, + 9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U, + 9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U, + 9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U, + 9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U, + 9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U, + 9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U, + 9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U, + 10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U, + 10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U, + 10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U, + 10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U, + 10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U, + 10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U, + 10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U, + 10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U, + 10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U, + 10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U, + 10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U, + 10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U, + 10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U, + 10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U, + 10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U, + 10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U, + 10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U, + 10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U, + 10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U, + 10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U, + 10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U, + 10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U, + 10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U, + 10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U, + 11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U, + 11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U, + 11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U, + 11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U, + 11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U, + 11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U, + 11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U, + 11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U, + 11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U, + 11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U, + 11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U, + 11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U, + 11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U, + 11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U, + 11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U, + 11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U, + 11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U, + 11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U, + 11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U, + 11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U, + 11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U, + 11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U, + 11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U, + 11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U, + 12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U, + 12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U, + 12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U, + 12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U, + 12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U, + 12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U, + 12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U, + 12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U, + 12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U, + 12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U, + 12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U, + 12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U, + 12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U, + 12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U, + 12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U, + 12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U, + 12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U, + 12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U, + 12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U, + 12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U, + 12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U, + 12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U, + 12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U, + 12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U, + 13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U, + 13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U, + 13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U, + 13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U, + 13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U, + 13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U, + 13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U, + 13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U, + 13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U, + 13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U, + 13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U, + 13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U, + 13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U, + 13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U, + 13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U, + 13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U, + 13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U, + 13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U, + 13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U, + 13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U, + 13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U, + 13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U, + 13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U, + 13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U, + 14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U, + 14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U, + 14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U, + 14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U, + 14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U, + 14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U, + 14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U, + 14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U, + 14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U, + 14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U, + 14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U, + 14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U, + 14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U, + 14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U, + 14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U, + 14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U, + 14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U, + 14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U, + 14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U, + 14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U, + 14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U, + 14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U, + 14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U, + 14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U, + 15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U, + 15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U, + 15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U, + 15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U, + 15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U, + 15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U, + 15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U, + 15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U, + 15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U, + 15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U, + 15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U, + 15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U, + 15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U, + 15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U, + 15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U, + 15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U, + 15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U, + 15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U, + 15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U, + 15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U, + 15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U, + 15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U, + 15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U, + 16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U, + 16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U, + 16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U, + 16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U, + 16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U, + 16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U, + 16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U, + 16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U, + 16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U, + 16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U, + 16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U, + 16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U, + 16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U, + 16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U, + 16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U, + 16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U, + 16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U, + 16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U, + 16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U, + 16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U, + 16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U, + 16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U, + 16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U, + 16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U, + 17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U, + 17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U, + 17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U, + 17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U, + 17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U, + 17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U, + 17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U, + 17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U, + 17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U, + 17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U, + 17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U, + 17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U, + 17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U, + 17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U, + 17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U, + 17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U, + 17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U, + 17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U, + 17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U, + 17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U, + 17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U, + 17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U, + 17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U, + 17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U, + 18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U, + 18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U, + 18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U, + 18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U, + 18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U, + 18228444544U, 18236833408U, 18245220736U +}; + + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// DataSetSizeBytesInit = 2^30, +// MixBytes = 128, +// DataSetGrowth = 2^23, +// HashBytes = 64, +// CacheMultiplier = 1024, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + +const size_t cache_sizes[] = { + 1048384U, 1055552U, 1064512U, 1072832U, 1080896U, 1089344U, 1096768U, + 1104448U, 1113664U, 1121216U, 1130176U, 1138624U, 1146304U, 1155008U, + 1162816U, 1171264U, 1179328U, 1187392U, 1195456U, 1203392U, 1210816U, + 1220416U, 1227712U, 1236416U, 1244608U, 1253312U, 1261376U, 1268416U, + 1277632U, 1285696U, 1294016U, 1302208U, 1310656U, 1318336U, 1326784U, + 1334848U, 1342912U, 1350848U, 1359808U, 1366208U, 1376192U, 1383488U, + 1392448U, 1400384U, 1408832U, 1416512U, 1425344U, 1433408U, 1440704U, + 1449664U, 1458112U, 1466048U, 1474496U, 1482688U, 1490752U, 1498688U, + 1507136U, 1515328U, 1523264U, 1531456U, 1539904U, 1547584U, 1556288U, + 1564352U, 1572544U, 1580608U, 1588544U, 1596992U, 1605568U, 1612096U, + 1621952U, 1630144U, 1637696U, 1645888U, 1654336U, 1662784U, 1671104U, + 1679168U, 1686848U, 1695296U, 1702208U, 1711168U, 1720256U, 1727552U, + 1736128U, 1744576U, 1751488U, 1760576U, 1769408U, 1777472U, 1785664U, + 1793984U, 1801664U, 1810112U, 1818304U, 1826624U, 1834816U, 1842752U, + 1851328U, 1858112U, 1867456U, 1875904U, 1883968U, 1892288U, 1899712U, + 1908416U, 1916608U, 1924544U, 1932992U, 1940672U, 1948736U, 1956928U, + 1965632U, 1973824U, 1982144U, 1989824U, 1998784U, 2006848U, 2014784U, + 2022848U, 2031424U, 2038976U, 2047424U, 2055616U, 2064064U, 2072384U, + 2080448U, 2088512U, 2095936U, 2104768U, 2113472U, 2121664U, 2127808U, + 2137792U, 2146112U, 2153408U, 2162624U, 2170304U, 2178496U, 2186944U, + 2195392U, 2203456U, 2211136U, 2219968U, 2227648U, 2236096U, 2244416U, + 2250944U, 2260928U, 2268736U, 2276672U, 2283328U, 2293696U, 2301632U, + 2309312U, 2317888U, 2325952U, 2334656U, 2342848U, 2350144U, 2358848U, + 2366656U, 2375488U, 2383552U, 2391616U, 2400064U, 2407616U, 2415808U, + 2424256U, 2432704U, 2439616U, 2448704U, 2457152U, 2464064U, 2473792U, + 2482112U, 2489792U, 2497472U, 2506432U, 2514752U, 2522816U, 2531264U, + 2539456U, 2547136U, 2555456U, 2564032U, 2572096U, 2578496U, 2587712U, + 2595776U, 2604736U, 2613056U, 2620736U, 2629184U, 2637632U, 2645824U, + 2653888U, 2662208U, 2670016U, 2678464U, 2686912U, 2694464U, 2703296U, + 2710976U, 2719424U, 2727104U, 2736064U, 2743232U, 2752192U, 2760512U, + 2768704U, 2777024U, 2785088U, 2792512U, 2800576U, 2809024U, 2817856U, + 2826176U, 2833984U, 2840896U, 2850752U, 2858048U, 2867008U, 2875328U, + 2883392U, 2891584U, 2899648U, 2908096U, 2915648U, 2924224U, 2932672U, + 2940736U, 2948672U, 2956736U, 2964928U, 2973248U, 2981824U, 2988992U, + 2997184U, 3005248U, 3013952U, 3022144U, 3030592U, 3037376U, 3046976U, + 3055552U, 3063616U, 3070784U, 3079744U, 3087808U, 3096512U, 3103808U, + 3111872U, 3121088U, 3128896U, 3137216U, 3144896U, 3153856U, 3161152U, + 3169984U, 3178432U, 3186496U, 3194816U, 3203008U, 3210176U, 3218624U, + 3227072U, 3235264U, 3243712U, 3250496U, 3259456U, 3268544U, 3276736U, + 3283648U, 3292736U, 3301184U, 3308224U, 3317696U, 3324736U, 3333184U, + 3342272U, 3348544U, 3357248U, 3365312U, 3374912U, 3383104U, 3390784U, + 3399488U, 3407296U, 3414976U, 3424192U, 3432256U, 3440576U, 3448768U, + 3456832U, 3464896U, 3473216U, 3480128U, 3489344U, 3497408U, 3505856U, + 3514048U, 3521344U, 3530432U, 3538624U, 3546304U, 3555008U, 3563072U, + 3571648U, 3579712U, 3587392U, 3595456U, 3603904U, 3612352U, 3620416U, + 3628864U, 3636928U, 3645248U, 3652928U, 3660992U, 3669184U, 3677888U, + 3685952U, 3694528U, 3702592U, 3710528U, 3719104U, 3727168U, 3735488U, + 3742784U, 3751232U, 3759424U, 3765184U, 3775808U, 3783872U, 3792832U, + 3800768U, 3808832U, 3816256U, 3825344U, 3832768U, 3841856U, 3849536U, + 3857344U, 3866432U, 3874496U, 3882304U, 3890752U, 3899072U, 3907264U, + 3914816U, 3923008U, 3930688U, 3939904U, 3947968U, 3956416U, 3964736U, + 3972544U, 3981248U, 3988928U, 3997376U, 4005824U, 4012864U, 4020928U, + 4030144U, 4038592U, 4045504U, 4054592U, 4063168U, 4071104U, 4079552U, + 4087232U, 4095808U, 4103872U, 4111168U, 4120384U, 4127936U, 4136512U, + 4144832U, 4153024U, 4160704U, 4169408U, 4177216U, 4186048U, 4193344U, + 4202048U, 4210496U, 4217536U, 4227008U, 4235072U, 4243264U, 4251584U, + 4259392U, 4267712U, 4275776U, 4284352U, 4291904U, 4300096U, 4307648U, + 4316992U, 4325056U, 4333376U, 4341056U, 4349888U, 4357568U, 4366016U, + 4374464U, 4382528U, 4390208U, 4398656U, 4407232U, 4413632U, 4423616U, + 4431808U, 4439744U, 4447936U, 4455872U, 4463296U, 4472128U, 4480576U, + 4489024U, 4497344U, 4505152U, 4512448U, 4520896U, 4530112U, 4537664U, + 4546496U, 4554688U, 4562752U, 4570816U, 4579264U, 4586944U, 4595648U, + 4603712U, 4611392U, 4619072U, 4628032U, 4635584U, 4643776U, 4652864U, + 4660672U, 4669376U, 4677056U, 4684096U, 4693184U, 4702144U, 4710208U, + 4718528U, 4726336U, 4734272U, 4742464U, 4750784U, 4759232U, 4767296U, + 4775872U, 4783808U, 4791872U, 4797376U, 4808512U, 4816192U, 4825024U, + 4832704U, 4841024U, 4849472U, 4856512U, 4865984U, 4874176U, 4882112U, + 4889792U, 4898752U, 4906688U, 4913984U, 4922816U, 4931008U, 4938944U, + 4946624U, 4955584U, 4964032U, 4972096U, 4980032U, 4988864U, 4997056U, + 5004992U, 5012288U, 5020096U, 5029312U, 5037632U, 5045696U, 5052224U, + 5062592U, 5070784U, 5078848U, 5086784U, 5095232U, 5100736U, 5111488U, + 5119936U, 5127104U, 5136064U, 5143616U, 5151424U, 5160256U, 5168704U, + 5175232U, 5185472U, 5192384U, 5199296U, 5209664U, 5218112U, 5225536U, + 5233472U, 5242816U, 5250496U, 5258944U, 5267264U, 5274944U, 5283776U, + 5290048U, 5300032U, 5308096U, 5316544U, 5323328U, 5331904U, 5340736U, + 5349056U, 5356864U, 5365312U, 5372096U, 5381696U, 5390272U, 5398336U, + 5405888U, 5413696U, 5422784U, 5430976U, 5439424U, 5446976U, 5455808U, + 5463616U, 5471168U, 5480128U, 5488064U, 5494592U, 5504704U, 5513152U, + 5521216U, 5529536U, 5536576U, 5544256U, 5554112U, 5559616U, 5570368U, + 5577664U, 5586752U, 5594944U, 5603008U, 5611456U, 5619392U, 5627584U, + 5634368U, 5643328U, 5651264U, 5659328U, 5667008U, 5675584U, 5684416U, + 5692864U, 5701568U, 5709632U, 5717056U, 5725376U, 5734336U, 5740096U, + 5750336U, 5758912U, 5766848U, 5775296U, 5782976U, 5790784U, 5799616U, + 5807936U, 5815232U, 5823808U, 5832256U, 5840192U, 5848768U, 5856832U, + 5864896U, 5873344U, 5879872U, 5888576U, 5897792U, 5905216U, 5914432U, + 5920448U, 5930944U, 5938624U, 5947328U, 5955392U, 5963456U, 5971648U, + 5979328U, 5988032U, 5995712U, 6003904U, 6012736U, 6021056U, 6029248U, + 6037184U, 6045632U, 6053312U, 6061376U, 6070208U, 6077504U, 6086464U, + 6094784U, 6101696U, 6110912U, 6118592U, 6127168U, 6135616U, 6143296U, + 6150208U, 6158912U, 6168128U, 6175808U, 6182464U, 6192832U, 6201152U, + 6209344U, 6217664U, 6224576U, 6233408U, 6241472U, 6249664U, 6258496U, + 6266816U, 6275008U, 6281152U, 6291136U, 6299456U, 6306752U, 6314816U, + 6323776U, 6332096U, 6339392U, 6348224U, 6356288U, 6364096U, 6373184U, + 6381376U, 6389696U, 6397504U, 6404416U, 6413632U, 6421952U, 6430016U, + 6437824U, 6446912U, 6454592U, 6463168U, 6471616U, 6478144U, 6487232U, + 6496192U, 6504128U, 6511936U, 6520256U, 6528832U, 6536896U, 6544576U, + 6553408U, 6561472U, 6569792U, 6577216U, 6586304U, 6592448U, 6601024U, + 6610624U, 6619072U, 6627136U, 6634816U, 6643264U, 6650816U, 6659776U, + 6667712U, 6675904U, 6682688U, 6691904U, 6700864U, 6709184U, 6717376U, + 6724544U, 6733504U, 6741824U, 6749888U, 6756032U, 6766528U, 6773056U, + 6782912U, 6790976U, 6798016U, 6807488U, 6815168U, 6823744U, 6832064U, + 6840128U, 6847552U, 6855872U, 6864064U, 6872128U, 6880576U, 6889408U, + 6897472U, 6905792U, 6913472U, 6920896U, 6930368U, 6938432U, 6946624U, + 6953536U, 6963136U, 6971072U, 6979136U, 6986944U, 6995392U, 7003712U, + 7012288U, 7019072U, 7028416U, 7036352U, 7044416U, 7051712U, 7060672U, + 7069376U, 7077568U, 7085504U, 7092544U, 7102016U, 7110592U, 7118656U, + 7126208U, 7135168U, 7143104U, 7150912U, 7159744U, 7167808U, 7175744U, + 7184192U, 7191232U, 7200448U, 7207744U, 7216576U, 7224128U, 7233472U, + 7241536U, 7249856U, 7256512U, 7264832U, 7274048U, 7282112U, 7290176U, + 7298752U, 7306688U, 7315136U, 7322816U, 7331392U, 7339456U, 7347776U, + 7356224U, 7364288U, 7371712U, 7380928U, 7387456U, 7396544U, 7404352U, + 7413568U, 7421632U, 7429696U, 7436864U, 7446464U, 7454144U, 7461952U, + 7470784U, 7478336U, 7487296U, 7495616U, 7503424U, 7511872U, 7520192U, + 7527616U, 7536448U, 7544512U, 7551424U, 7560128U, 7568576U, 7577536U, + 7583552U, 7592512U, 7600448U, 7610048U, 7618496U, 7626176U, 7634752U, + 7642816U, 7651264U, 7659328U, 7667008U, 7675456U, 7683136U, 7691584U, + 7700416U, 7707584U, 7716416U, 7724224U, 7733056U, 7740608U, 7749184U, + 7756096U, 7765952U, 7774016U, 7781824U, 7790528U, 7798592U, 7805888U, + 7814336U, 7822784U, 7831232U, 7839296U, 7847104U, 7855552U, 7863616U, + 7872448U, 7880128U, 7888576U, 7896256U, 7905088U, 7912768U, 7920448U, + 7928768U, 7937344U, 7945792U, 7953728U, 7959488U, 7970752U, 7978816U, + 7987136U, 7994816U, 8003392U, 8011712U, 8019904U, 8027456U, 8035264U, + 8044352U, 8052544U, 8060224U, 8069056U, 8076736U, 8084672U, 8093504U, + 8101312U, 8110016U, 8117696U, 8125888U, 8134592U, 8142016U, 8149952U, + 8159168U, 8166976U, 8175296U, 8183488U, 8191808U, 8199616U, 8207296U, + 8216128U, 8224576U, 8232256U, 8241088U, 8248256U, 8257472U, 8264128U, + 8273728U, 8281792U, 8290112U, 8297152U, 8305216U, 8314816U, 8322752U, + 8330944U, 8339392U, 8347072U, 8355392U, 8363968U, 8371904U, 8379328U, + 8388544U, 8394944U, 8404544U, 8412736U, 8421184U, 8429504U, 8437696U, + 8445376U, 8452544U, 8460736U, 8470208U, 8478016U, 8486848U, 8494144U, + 8503232U, 8511296U, 8519488U, 8527424U, 8534464U, 8543936U, 8552384U, + 8558912U, 8568128U, 8575936U, 8584256U, 8593216U, 8601536U, 8608832U, + 8616896U, 8625728U, 8634176U, 8641856U, 8649664U, 8658112U, 8666176U, + 8674112U, 8682944U, 8691136U, 8699456U, 8707648U, 8716096U, 8724416U, + 8732608U, 8740672U, 8748352U, 8756032U, 8764864U, 8773568U, 8781376U, + 8789824U, 8796992U, 8806208U, 8814272U, 8822336U, 8830912U, 8838848U, + 8847296U, 8854336U, 8863552U, 8871488U, 8879296U, 8887616U, 8894528U, + 8904512U, 8911424U, 8920768U, 8928704U, 8936128U, 8944576U, 8953664U, + 8960576U, 8970176U, 8977984U, 8986304U, 8994112U, 9002432U, 9011008U, + 9018176U, 9026624U, 9035584U, 9043904U, 9052096U, 9059264U, 9068096U, + 9075904U, 9084224U, 9092288U, 9100352U, 9108928U, 9116992U, 9125824U, + 9133504U, 9141824U, 9150272U, 9157952U, 9164608U, 9174848U, 9182912U, + 9190976U, 9199552U, 9205312U, 9215936U, 9222592U, 9232192U, 9240512U, + 9248704U, 9256256U, 9264832U, 9272896U, 9281344U, 9288896U, 9297088U, + 9305536U, 9313984U, 9322304U, 9329728U, 9337792U, 9346112U, 9355072U, + 9363136U, 9371072U, 9378752U, 9387712U, 9395648U, 9404224U, 9411008U, + 9420608U, 9428416U, 9436864U, 9445312U, 9453376U, 9460928U, 9468736U, + 9477824U, 9485248U, 9493696U, 9502144U, 9509056U, 9518528U, 9527104U, + 9535424U, 9543616U, 9551296U, 9559744U, 9568192U, 9576256U, 9584576U, + 9591872U, 9600704U, 9608384U, 9615808U, 9624512U, 9633472U, 9641536U, + 9649856U, 9658048U, 9665728U, 9674432U, 9682496U, 9691072U, 9699136U, + 9707072U, 9715136U, 9722176U, 9732032U, 9740096U, 9747904U, 9756352U, + 9764288U, 9771584U, 9780544U, 9789376U, 9796928U, 9804224U, 9813952U, + 9822016U, 9829696U, 9838016U, 9845824U, 9852992U, 9863104U, 9870656U, + 9878464U, 9887552U, 9895744U, 9903808U, 9912128U, 9920192U, 9927616U, + 9936064U, 9944768U, 9952576U, 9960128U, 9969472U, 9977152U, 9985216U, + 9994048U, 10001216U, 10007744U, 10018496U, 10026944U, 10035136U, 10042432U, + 10051264U, 10059584U, 10067648U, 10075712U, 10083904U, 10091456U, 10100672U, + 10108864U, 10116928U, 10124864U, 10133056U, 10140736U, 10149824U, 10156736U, + 10165952U, 10173376U, 10182208U, 10190528U, 10198336U, 10206272U, 10213696U, + 10223296U, 10231744U, 10238656U, 10247488U, 10256192U, 10263872U, 10272448U, + 10280896U, 10288448U, 10296512U, 10305088U, 10313536U, 10321088U, 10330048U, + 10337984U, 10346176U, 10354112U, 10362304U, 10369088U, 10377152U, 10386752U, + 10394816U, 10403648U, 10411712U, 10418624U, 10427968U, 10436032U, 10444736U, + 10452928U, 10459712U, 10468672U, 10476608U, 10484416U, 10491328U, 10501952U, + 10509376U, 10517824U, 10526528U, 10534336U, 10542656U, 10549696U, 10559168U, + 10566592U, 10575808U, 10583488U, 10590656U, 10599488U, 10607936U, 10616768U, + 10624832U, 10630336U, 10640576U, 10649536U, 10655168U, 10665152U, 10674112U, + 10682176U, 10690496U, 10698176U, 10705216U, 10715072U, 10722752U, 10731328U, + 10739264U, 10746688U, 10754752U, 10761664U, 10770752U, 10779712U, 10787776U, + 10796608U, 10803392U, 10812352U, 10821056U, 10828736U, 10837952U, 10846144U, + 10853824U, 10861376U, 10869952U, 10877248U, 10887104U, 10895296U, 10903232U, + 10910912U, 10918976U, 10927936U, 10935872U, 10944448U, 10952384U, 10960832U, + 10968512U, 10977088U, 10985024U, 10992832U, 11000896U, 11009984U, 11018048U, + 11026112U, 11034304U, 11042624U, 11050432U, 11058368U, 11064512U, 11075392U, + 11083712U, 11091776U, 11099584U, 11107904U, 11115968U, 11124416U, 11131712U, + 11141056U, 11148608U, 11157184U, 11165248U, 11173312U, 11180992U, 11189056U, + 11197376U, 11206592U, 11214656U, 11222336U, 11230784U, 11238464U, 11246528U, + 11254976U, 11263552U, 11271872U, 11279552U, 11288512U, 11296576U, 11304256U, + 11312192U, 11320768U, 11329216U, 11336384U, 11345216U, 11352512U, 11362112U, + 11369408U, 11378624U, 11386688U, 11394496U, 11402816U, 11411264U, 11418688U, + 11427776U, 11435584U, 11444032U, 11452096U, 11459648U, 11467072U, 11476928U, + 11484992U, 11493184U, 11500352U, 11509312U, 11517248U, 11524928U, 11534144U, + 11542208U, 11550272U, 11556416U, 11566784U, 11574208U, 11581376U, 11589568U, + 11599552U, 11607104U, 11616064U, 11623616U, 11632576U, 11639872U, 11648704U, + 11657024U, 11664704U, 11672896U, 11681216U, 11689792U, 11697856U, 11705536U, + 11714368U, 11722688U, 11730496U, 11737408U, 11745728U, 11754304U, 11763008U, + 11770816U, 11779648U, 11788096U, 11795776U, 11804608U, 11812544U, 11820992U, + 11829184U, 11837248U, 11844928U, 11852096U, 11860928U, 11869888U, 11878336U, + 11886272U, 11894336U, 11902144U, 11910848U, 11919296U, 11925952U, 11934784U, + 11943616U, 11951552U, 11960128U, 11968192U, 11976512U, 11983168U, 11992768U, + 12000832U, 12008896U, 12016832U, 12025408U, 12033856U, 12042176U, 12049984U, + 12058048U, 12066112U, 12073792U, 12082624U, 12091328U, 12098752U, 12106816U, + 12115904U, 12124096U, 12131776U, 12140224U, 12148672U, 12156736U, 12164032U, + 12173248U, 12181184U, 12186176U, 12197824U, 12205888U, 12213952U, 12218944U, + 12230336U, 12238784U, 12246592U, 12254272U, 12262336U, 12269888U, 12279104U, + 12287936U, 12295744U, 12304064U, 12312512U, 12319936U, 12328768U, 12337088U, + 12344896U, 12352832U, 12361408U, 12368704U, 12377152U, 12384832U, 12394432U, + 12402496U, 12409024U, 12417728U, 12426688U, 12433216U, 12443584U, 12450752U, + 12459968U, 12468032U, 12475712U, 12484544U, 12492608U, 12500416U, 12508352U, + 12517184U, 12525376U, 12532288U, 12541888U, 12549568U, 12556864U, 12565568U, + 12574528U, 12582208U, 12590528U, 12598592U, 12607424U, 12615488U, 12623552U, + 12631744U, 12638656U, 12647744U, 12656576U, 12664768U, 12672832U, 12680896U, + 12688576U, 12697408U, 12704192U, 12713408U, 12721216U, 12729664U, 12738496U, + 12745792U, 12754496U, 12762688U, 12769472U, 12779456U, 12787648U, 12795712U, + 12804032U, 12812224U, 12819008U, 12828352U, 12836672U, 12844736U, 12851648U, + 12859456U, 12868672U, 12877504U, 12885568U, 12892864U, 12902336U, 12909376U, + 12918208U, 12926656U, 12934976U, 12942784U, 12951104U, 12959552U, 12967744U, + 12976064U, 12984256U, 12991936U, 12999488U, 13007936U, 13016768U, 13021504U, + 13033024U, 13041472U, 13049408U, 13057472U, 13065664U, 13072064U, 13081408U, + 13089344U, 13098688U, 13107008U, 13115072U, 13122752U, 13130944U, 13139648U, + 13147712U, 13155776U, 13162432U, 13172672U, 13180864U, 13188928U, 13196992U, + 13203392U, 13213504U, 13219264U, 13228736U, 13236928U, 13244992U, 13253056U, + 13262528U, 13269952U, 13278784U, 13285952U, 13295552U, 13303616U, 13311808U, + 13319744U, 13328192U, 13336256U, 13344704U, 13352384U, 13360576U, 13369024U, + 13377344U, 13385408U, 13393216U, 13401664U, 13410112U, 13418176U, 13426496U, + 13434688U, 13442368U, 13451072U, 13459136U, 13466944U, 13475648U, 13482944U, + 13491904U, 13500352U, 13508288U, 13516736U, 13524416U, 13532224U, 13541312U, + 13549504U, 13556288U, 13564736U, 13573184U, 13581376U, 13587008U, 13598656U, + 13605952U, 13612864U, 13622464U, 13631168U, 13639616U, 13647808U, 13655104U, + 13663424U, 13671872U, 13680064U, 13688768U, 13696576U, 13705024U, 13712576U, + 13721536U, 13729216U, 13737664U, 13746112U, 13753024U, 13759552U, 13770304U, + 13777856U, 13786688U, 13793984U, 13802176U, 13811264U, 13819328U, 13827904U, + 13835456U, 13844416U, 13851584U, 13860544U, 13868992U, 13877056U, 13884608U, + 13893184U, 13901248U, 13909696U, 13917632U, 13925056U, 13934528U, 13942336U, + 13950784U, 13959104U, 13966912U, 13975232U, 13982656U, 13991872U, 13999936U, + 14007872U, 14016064U, 14024512U, 14032064U, 14040896U, 14049088U, 14057408U, + 14065088U, 14072896U, 14081344U, 14089664U, 14097856U, 14106304U, 14114752U, + 14122688U, 14130752U, 14138816U, 14147008U, 14155072U, 14163904U, 14170432U, + 14180288U, 14187328U, 14196032U, 14204864U, 14212672U, 14220736U, 14229056U, + 14237504U, 14245568U, 14253632U, 14261824U, 14269888U, 14278592U, 14286656U, + 14293696U, 14302784U, 14309696U, 14317504U, 14326336U, 14335936U, 14343232U, + 14352064U, 14359232U, 14368064U, 14376512U, 14384576U, 14393024U, 14401472U, + 14409536U, 14416832U, 14424512U, 14433856U, 14440768U, 14449984U, 14458816U, + 14465728U, 14474816U, 14482112U, 14491328U, 14499392U, 14506816U, 14516032U, + 14524352U, 14531392U, 14540224U, 14547392U, 14556992U, 14565184U, 14573248U, + 14580928U, 14588864U, 14596928U, 14606272U, 14613824U, 14622656U, 14630464U, + 14638912U, 14646976U, 14655296U, 14661952U, 14671808U, 14679872U, 14687936U, + 14696384U, 14704576U, 14710336U, 14720192U, 14729152U, 14736448U, 14745152U, + 14752448U, 14761792U, 14769856U, 14777024U, 14785984U, 14792384U, 14802752U, + 14810816U, 14819264U, 14827328U, 14835136U, 14843072U, 14851264U, 14860096U, + 14867648U, 14876096U, 14884544U, 14892736U, 14900672U, 14907968U, 14917312U, + 14924864U, 14933824U, 14939968U, 14950336U, 14957632U, 14966464U, 14974912U, + 14982592U, 14991296U, 14999104U, 15006272U, 15015232U, 15023936U, 15031616U, + 15040448U, 15047488U, 15055552U, 15063616U, 15073216U, 15079744U, 15088064U, + 15097664U, 15105344U, 15113792U, 15122368U, 15130048U, 15137728U, 15146176U, + 15154112U, 15162688U, 15171392U, 15179456U, 15187264U, 15194176U, 15204032U, + 15212224U, 15220544U, 15227456U, 15237056U, 15245248U, 15253184U, 15261632U, + 15269824U, 15277376U, 15285824U, 15293888U, 15301568U, 15310784U, 15318848U, + 15325504U, 15335104U, 15343168U, 15350848U, 15359936U, 15367232U, 15373376U, + 15384256U, 15392576U, 15400384U, 15408832U, 15417152U, 15424832U, 15433024U, + 15441344U, 15449152U, 15457088U, 15466432U, 15474112U, 15482816U, 15488576U, + 15499072U, 15505856U, 15514816U, 15523264U, 15531584U, 15540032U, 15547328U, + 15553984U, 15564608U, 15571904U, 15579968U, 15589312U, 15597376U, 15605696U, + 15612992U, 15621824U, 15630016U, 15638464U, 15646144U, 15654592U, 15662912U, + 15671104U, 15677248U, 15686848U, 15693376U, 15701696U, 15712064U, 15720256U, + 15728576U, 15736384U, 15744704U, 15752512U, 15761344U, 15769024U, 15777728U, + 15785152U, 15793984U, 15802048U, 15809984U, 15817024U, 15825856U, 15834944U, + 15843008U, 15849664U, 15859136U, 15866432U, 15876032U, 15884096U, 15892288U, + 15900608U, 15908416U, 15916864U, 15924928U, 15930176U, 15941056U, 15949504U, + 15957824U, 15965632U, 15973952U, 15982528U, 15990592U, 15998272U, 16006976U, + 16012736U, 16023104U, 16031296U, 16039616U, 16048064U, 16055744U, 16064192U, + 16071488U, 16080832U, 16088768U, 16097216U, 16104896U, 16112704U, 16121792U, + 16129856U, 16138048U, 16146112U, 16154176U, 16162624U, 16170688U, 16177856U, + 16186816U, 16195136U, 16202176U, 16211648U, 16220096U, 16228288U, 16235584U, + 16244672U, 16252864U, 16260544U, 16269248U, 16277056U, 16285504U, 16291648U, + 16301632U, 16309312U, 16318144U, 16326208U, 16333888U, 16342336U, 16351168U, + 16359232U, 16367552U, 16375616U, 16383296U, 16391744U, 16398016U, 16407616U, + 16415936U, 16424896U, 16432448U, 16440896U, 16449088U, 16457024U, 16465472U, + 16474048U, 16481216U, 16490048U, 16498624U, 16505792U, 16513984U, 16523072U, + 16531136U, 16538944U, 16547264U, 16555328U, 16563776U, 16570816U, 16578112U, + 16587712U, 16596544U, 16604992U, 16613312U, 16620608U, 16629568U, 16637888U, + 16645696U, 16653632U, 16661696U, 16669888U, 16677568U, 16686272U, 16695232U, + 16703168U, 16710464U, 16719424U, 16726592U, 16733888U, 16744384U, 16752448U, + 16760768U, 16768448U, 16776896U, 16785344U, 16793536U, 16801216U, 16809664U, + 16818112U, 16826176U, 16833472U, 16842688U, 16850752U, 16859072U, 16866368U, + 16875328U, 16883392U, 16891712U, 16899776U, 16907456U, 16915264U, 16924352U, + 16931776U, 16940608U, 16949056U, 16957376U, 16965056U, 16973248U, 16981696U, + 16990144U, 16997056U, 17005888U, 17014208U, 17021504U, 17031104U, 17039296U, + 17046976U, 17055424U, 17062592U, 17070016U, 17079488U, 17087936U, 17096512U, + 17104576U, 17113024U, 17121088U, 17129408U, 17136832U, 17145664U, 17152832U, + 17161792U, 17170112U, 17177792U, 17186368U, 17194304U, 17202496U, 17211328U, + 17218624U, 17227712U, 17233984U, 17243584U, 17251904U, 17259712U, 17266624U, + 17276608U, 17284672U, 17292224U, 17301056U, 17309632U, 17317568U, 17326016U, + 17333824U, 17342272U, 17350208U, 17358784U, 17366848U, 17374912U, 17382592U, + 17390656U, 17399488U, 17406784U, 17413952U, 17423936U, 17432512U, 17440448U, + 17447744U, 17456704U, 17464768U, 17472064U, 17481536U, 17489344U, 17495488U, + 17505728U, 17513792U, 17522368U, 17530816U, 17538112U, 17546944U, 17555264U, + 17563072U, 17569856U, 17579456U, 17587904U, 17596352U, 17603776U, 17611712U, + 17620672U, 17628992U, 17637184U, 17645504U, 17653568U, 17661632U, 17669824U, + 17677376U, 17686208U, 17693888U, 17702336U, 17710144U, 17718208U, 17726528U, + 17734336U, 17743808U, 17751872U, 17759936U, 17766592U, 17776448U, 17784512U, + 17791936U, 17801152U, 17809216U, 17817152U +}; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/endian.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/endian.h similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/endian.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/endian.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/ethash.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h similarity index 70% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/ethash.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h index 62edd0082..82421b868 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/ethash.h +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/ethash.h @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ + /** @file ethash.h * @date 2015 */ @@ -25,9 +26,10 @@ #include #include "compiler.h" -#define REVISION 18 -#define DAGSIZE_BYTES_INIT 1073741824U -#define DAG_GROWTH 113000000U +#define REVISION 20 +#define DAGSIZE_BYTES_INIT 1073741824U // 2**30 +#define DAG_GROWTH 8388608U // 2**23 +#define CACHE_MULTIPLIER 1024 #define EPOCH_LENGTH 30000U #define MIX_BYTES 128 #define DAG_PARENTS 256 @@ -48,8 +50,8 @@ typedef struct ethash_return_value { uint8_t mix_hash[32]; } ethash_return_value; -size_t const ethash_get_datasize(const uint32_t block_number); -size_t const ethash_get_cachesize(const uint32_t block_number); +size_t ethash_get_datasize(const uint32_t block_number); +size_t ethash_get_cachesize(const uint32_t block_number); // initialize the parameters static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) { @@ -58,7 +60,7 @@ static inline void ethash_params_init(ethash_params *params, const uint32_t bloc } typedef struct ethash_cache { - void *mem; + void *mem; } ethash_cache; void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]); @@ -66,6 +68,11 @@ void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cac void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); +static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { ethash_cache c; c.mem = cache; ethash_mkcache(&c, params, seed); } +static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_cache c; c.mem = (void*)cache; ethash_light(ret, &c, params, header_hash, nonce); } +static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_cache c; c.mem = (void*)cache; ethash_compute_full_data(full, params, &c); } +static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_full(ret, full, params, header_hash, nonce); } + static inline int ethash_check_difficulty( const uint8_t hash[32], const uint8_t difficulty[32]) { diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/fnv.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/fnv.h similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/fnv.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/fnv.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/internal.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c similarity index 98% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/internal.c rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c index cc48717d0..a2b82d375 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/internal.c +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.c @@ -31,18 +31,18 @@ #ifdef WITH_CRYPTOPP -#include "SHA3_cryptopp.h" +#include "sha3_cryptopp.h" #else #include "sha3.h" #endif // WITH_CRYPTOPP -size_t const ethash_get_datasize(const uint32_t block_number) { +size_t ethash_get_datasize(const uint32_t block_number) { assert(block_number / EPOCH_LENGTH < 500); return dag_sizes[block_number / EPOCH_LENGTH]; } -size_t const ethash_get_cachesize(const uint32_t block_number) { +size_t ethash_get_cachesize(const uint32_t block_number) { assert(block_number / EPOCH_LENGTH < 500); return cache_sizes[block_number / EPOCH_LENGTH]; } @@ -283,6 +283,7 @@ int ethash_quick_check_difficulty( const uint64_t nonce, const uint8_t mix_hash[32], const uint8_t difficulty[32]) { + uint8_t return_hash[32]; ethash_quick_hash(return_hash, header_hash, nonce, mix_hash); return ethash_check_difficulty(return_hash, difficulty); diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/internal.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/internal.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/internal.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/sha3.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.c similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/sha3.c rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.c diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/sha3.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.h similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/sha3.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/sha3_cryptopp.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.cpp similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/sha3_cryptopp.cpp rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.cpp diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/sha3_cryptopp.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.h similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/sha3_cryptopp.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/sha3_cryptopp.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/util.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.c similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/util.c rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.c diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/libethash/util.h b/Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.h similarity index 100% rename from Godeps/_workspace/src/github.com/ethereum/ethash/libethash/util.h rename to Godeps/_workspace/src/github.com/ethereum/ethash/src/libethash/util.h diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c b/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c new file mode 100644 index 000000000..f7d8be156 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/src/python/core.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include "../libethash/ethash.h" + +static PyObject* +get_cache_size(PyObject* self, PyObject* args) +{ + unsigned long block_number; + if (!PyArg_ParseTuple(args, "k", &block_number)) + return 0; + return Py_BuildValue("i", ethash_get_cachesize(block_number)); +} + +static PyObject* +get_full_size(PyObject* self, PyObject* args) +{ + unsigned long block_number; + if (!PyArg_ParseTuple(args, "k", &block_number)) + return 0; + return Py_BuildValue("i", ethash_get_datasize(block_number)); +} + + +static PyObject* +mkcache(PyObject* self, PyObject* args) +{ + char * seed; + unsigned long cache_size; + int seed_len; + + if (!PyArg_ParseTuple(args, "ks#", &cache_size, &seed, &seed_len)) + return 0; + + if (seed_len != 32) + { + PyErr_SetString(PyExc_ValueError, + "Seed must be 32 bytes long"); + return 0; + } + + printf("cache size: %lu\n", cache_size); + ethash_params params; + params.cache_size = (size_t) cache_size; + ethash_cache cache; + cache.mem = alloca(cache_size); + ethash_mkcache(&cache, ¶ms, (uint8_t *) seed); + return PyString_FromStringAndSize(cache.mem, cache_size); +} + + +static PyMethodDef CoreMethods[] = +{ + {"get_cache_size", get_cache_size, METH_VARARGS, "Get the cache size for a given block number"}, + {"get_full_size", get_full_size, METH_VARARGS, "Get the full size for a given block number"}, + {"mkcache", mkcache, METH_VARARGS, "Makes the cache for given parameters and seed hash"}, + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC +initcore(void) +{ + (void) Py_InitModule("core", CoreMethods); +} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/CMakeLists.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt similarity index 95% rename from Godeps/_workspace/src/github.com/ethereum/ethash/test/CMakeLists.txt rename to Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt index 431af6a99..02e2aab91 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/test/CMakeLists.txt +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/CMakeLists.txt @@ -4,7 +4,7 @@ ENDIF() IF( Boost_FOUND ) include_directories( ${Boost_INCLUDE_DIR} ) - include_directories(..) + include_directories(../../src) link_directories ( ${Boost_LIBRARY_DIRS} ) file(GLOB HEADERS "*.h") diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.cpp b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp similarity index 90% rename from Godeps/_workspace/src/github.com/ethereum/ethash/test/test.cpp rename to Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp index bec44e138..336713cb7 100644 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.cpp +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.cpp @@ -13,7 +13,6 @@ #define BOOST_TEST_MAIN #include -#include #include std::string bytesToHexString(const uint8_t *str, const size_t s) { @@ -90,24 +89,6 @@ BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) { << "actual: " << params.cache_size << "\n"); } -BOOST_AUTO_TEST_CASE(ethash_params_init_check) { - ethash_params params; - ethash_params_init(¶ms, 1971000); - const uint64_t nine_month_size = (uint64_t) 8*DAGSIZE_BYTES_INIT; - BOOST_REQUIRE_MESSAGE(params.full_size < nine_month_size, - "\nfull size: " << params.full_size << "\n" - << "should be less than or equal to: " << nine_month_size << "\n"); - BOOST_REQUIRE_MESSAGE(params.full_size + DAGSIZE_BYTES_INIT / 4 > nine_month_size, - "\nfull size + DAGSIZE_BYTES_INIT / 4: " << params.full_size + DAGSIZE_BYTES_INIT / 4 << "\n" - << "should be greater than or equal to: " << nine_month_size << "\n"); - BOOST_REQUIRE_MESSAGE(params.cache_size < nine_month_size / 1024, - "\nactual cache size: " << params.cache_size << "\n" - << "expected: " << nine_month_size / 1024 << "\n"); - BOOST_REQUIRE_MESSAGE(params.cache_size + DAGSIZE_BYTES_INIT / 4 / 1024 > nine_month_size / 1024 , - "\ncache size + DAGSIZE_BYTES_INIT / 4 / 1024: " << params.cache_size + DAGSIZE_BYTES_INIT / 4 / 1024 << "\n" - << "actual: " << nine_month_size / 32 << "\n"); -} - BOOST_AUTO_TEST_CASE(light_and_full_client_checks) { ethash_params params; uint8_t seed[32], hash[32]; diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh new file mode 100644 index 000000000..6d02d30f8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/c/test.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Strict mode +set -e + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" +done +TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +rm -rf $TEST_DIR/build +mkdir -p $TEST_DIR/build +cd $TEST_DIR/build ; +cmake ../../.. > /dev/null +make Test +./test/c/Test diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/go/ethash_test.go b/Godeps/_workspace/src/github.com/ethereum/ethash/test/go/ethash_test.go deleted file mode 100644 index d734954e1..000000000 --- a/Godeps/_workspace/src/github.com/ethereum/ethash/test/go/ethash_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package ethashTest - -import ( - "bytes" - "crypto/rand" - "log" - "math/big" - "testing" - - "github.com/ethereum/ethash" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/ethdb" -) - -func TestEthash(t *testing.T) { - seedHash := make([]byte, 32) - _, err := rand.Read(seedHash) - if err != nil { - panic(err) - } - - db, err := ethdb.NewMemDatabase() - if err != nil { - panic(err) - } - - blockProcessor, err := core.NewCanonical(5, db) - if err != nil { - panic(err) - } - - log.Println("Block Number: ", blockProcessor.ChainManager().CurrentBlock().Number()) - - e := ethash.New(blockProcessor.ChainManager()) - - miningHash := make([]byte, 32) - if _, err := rand.Read(miningHash); err != nil { - panic(err) - } - diff := big.NewInt(10000) - log.Println("difficulty", diff) - - nonce := uint64(0) - - ghash_full := e.FullHash(nonce, miningHash) - log.Printf("ethash full (on nonce): %x %x\n", ghash_full, nonce) - - ghash_light := e.LightHash(nonce, miningHash) - log.Printf("ethash light (on nonce): %x %x\n", ghash_light, nonce) - - if bytes.Compare(ghash_full, ghash_light) != 0 { - t.Errorf("full: %x, light: %x", ghash_full, ghash_light) - } -} diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore new file mode 100644 index 000000000..c304fd615 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/.gitignore @@ -0,0 +1 @@ +python-virtual-env/ diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt new file mode 100644 index 000000000..1f38dc3c7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/requirements.txt @@ -0,0 +1,2 @@ +pyethereum==0.7.522 +nose==1.3.4 diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh new file mode 100644 index 000000000..4a547d157 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Strict mode +set -e + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" +done +TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +[ -d $TEST_DIR/python-virtual-env ] || virtualenv --system-site-packages $TEST_DIR/python-virtual-env +source $TEST_DIR/python-virtual-env/bin/activate +pip install -r $TEST_DIR/requirements.txt > /dev/null +pip install -e $TEST_DIR/../.. > /dev/null +cd $TEST_DIR +nosetests --with-doctest -v diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py new file mode 100644 index 000000000..ca9321e92 --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/python/test_pyethash.py @@ -0,0 +1,45 @@ +import pyethash +from random import randint + +def test_get_cache_size_not_None(): + for _ in range(100): + block_num = randint(0,12456789) + out = pyethash.core.get_cache_size(block_num) + assert out != None + +def test_get_full_size_not_None(): + for _ in range(100): + block_num = randint(0,12456789) + out = pyethash.core.get_full_size(block_num) + assert out != None + +def test_get_cache_size_based_on_EPOCH(): + for _ in range(100): + block_num = randint(0,12456789) + out1 = pyethash.core.get_cache_size(block_num) + out2 = pyethash.core.get_cache_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH) + assert out1 == out2 + +def test_get_full_size_based_on_EPOCH(): + for _ in range(100): + block_num = randint(0,12456789) + out1 = pyethash.core.get_full_size(block_num) + out2 = pyethash.core.get_full_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH) + assert out1 == out2 + +#def test_get_params_based_on_EPOCH(): +# block_num = 123456 +# out1 = pyethash.core.get_params(block_num) +# out2 = pyethash.core.get_params((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH) +# assert out1["DAG Size"] == out2["DAG Size"] +# assert out1["Cache Size"] == out2["Cache Size"] +# +#def test_get_params_returns_different_values_based_on_different_block_input(): +# out1 = pyethash.core.get_params(123456) +# out2 = pyethash.core.get_params(12345) +# assert out1["DAG Size"] != out2["DAG Size"] +# assert out1["Cache Size"] != out2["Cache Size"] +# +#def test_get_cache_smoke_test(): +# params = pyethash.core.get_params(123456) +# assert pyethash.core.mkcache(params, "~~~~") != None diff --git a/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh b/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh new file mode 100644 index 000000000..eb38f6dfc --- /dev/null +++ b/Godeps/_workspace/src/github.com/ethereum/ethash/test/test.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Strict mode +set -e + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" +done +TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +echo -e "\n################# Testing JS ##################" +# TODO: Use mocha and real testing tools instead of rolling our own +cd $TEST_DIR/../js +node test.js + +echo -e "\n################# Testing C ##################" +$TEST_DIR/c/test.sh + +echo -e "\n################# Testing Python ##################" +$TEST_DIR/python/test.sh + +#echo "################# Testing Go ##################" +#$TEST_DIR/go/test.sh