diff --git a/README.md b/README.md index 75e169f04..90a5f8df2 100644 --- a/README.md +++ b/README.md @@ -1 +1,184 @@ -# Server for thelonious-tendermint +# Eris-DB (Alpha) + +`eris-db` is Eris' blockchain-client. It consists of a [Tendermint](http://tendermint.com/) node wrapped by a simple server. Tendermint is a blockchain-client with a PoS consensus system for agreeing on blocks. This makes it perfect for Eris chains. + +The server allows requests to be made over HTTP - either using JSON-RPC 2.0 or a RESTlike web-api - and websocket (JSON-RPC 2.0). The documentation can be found [here](TODO). We also have javascript bindings for the RPC methods in [erisdb-js](https://github.com/eris-ltd/erisdb-js). + +### Installation + +There are no binary downloads, and probably won't be before `1.0`. + +#### Ubuntu/OSX + +Make sure you have the proper [Go](https://golang.org/) distribution for your OS and architecture. The recommended version is `1.4.2`. + +Start by installing [godep](https://github.com/tools/godep). + +Get the code: + +`godep go get github.com/eris-ltd/erisdb/cmd/erisdb` + +Note that it uses `godep` before the regular go command. + +This will download and install the program. From there on you can run the same command with the `-u` flag when you want to update. + +If you want to re-install code that you already have, use: + +`godep go install github.com/eris-ltd/erisdb/cmd/erisdb` + +Installing will build the `erisdb` executable and put it in `$GOPATH/bin`, which should be on your PATH. If not, then add it. + +To run `erisdb`, just type `$ erisdb /path/to/working/folder` + +This will start the node using the provided folder as working dir. If the path is omitted, it will default to `~/.erisdb` + +##### Summary + +* Install Go and Godep. +* `$ godep go get github.com/eris-ltd/erisdb/cmd/erisdb` + +#### Others + +There is no docker container for this library yet, but it will be soon. + +##### Windows + +The server itself run on Windows, and it is possible to tweak Tendermint so that it works on Windows too (did so myself, mostly just some network and file stuff), but we do not recommend that. Eris programs are supposed to run on Linux; preferably through docker. One reason for this is security. The new `eris` command-line tool (formerly `epm`) will make the management of these containers easy. + +Tendermint officially supports only 64 bit Ubuntu. + +### Usage + +The simplest way to get started is by simply running `$ erisdb`. That will start a fresh node with `~/.erisdb` as the working directory, and the default settings. You will be asked to type in a hostname, which could be anything. `anonymous` is a commonly used one. + +Once the server has started, it will begin syncing up with the network. At that point you may begin using it. The preferred way is through our [javascript api](https://github.com/eris-ltd/erisdb-js), but it is possible to connect directly via HTTP or websocket. The JSON-RPC and web-api reference can be found [here](https://github.com/eris-ltd/erisdb/blob/master/api.md). + +### Configuration + +There will be more info on how to set up a private net when this is added to Tendermint. That would include information about the various different fields in `config.toml`, `genesis.json`, and `priv_validator.json`. + +#### server_conf.toml + +The server configuration file looks like this: + +``` +[bind] + address= + port= +[TLS] + tls= + cert_path= + key_path= +[CORS] + enable + allow_origins <[]string> + allow_credentials + allow_methods <[]string> + allow_headers <[]string> + expose_headers <[]string> + max_age +[HTTP] + json_rpc_endpoint= +[web_socket] + websocket_endpoint= + max_websocket_sessions= +[logging] + console_log_level= + file_log_level= + log_file= +``` + +**NOTE**: **CORS** and **TLS** are not yet fully implemented, and cannot be used. It is unlikely that it will be supported before `1.0`. CORS will be implemented through [gin middleware](https://github.com/tommy351/gin-cors), and TLS through the standard Go http package via the [graceful library](https://github.com/tylerb/graceful). + +##### Bind + +- `address` is the address. +- `port` is the port number + +##### TLS + +- `tls` is used to enable/disable TLS +- `cert_path` is the absolute path to the certificate file. +- `key_path` is the absolute path to the key file. + +##### CORS + +- `enable` is whether or not the CORS middleware should be added at all. + +Details about the other fields and how this is implemented can be found [here](https://github.com/tommy351/gin-cors). + +##### HTTP + +- `json_rpc_endpoint` is the name of the endpoint used for JSON-RPC (2.0) over HTTP. + +##### web_socket + +- `websocket_endpoint` is the name of the endpoint that is used to establish a websocket connection. +- `max_websocket_connections` is the maximum number of websocket connections that is allowed at the same time. + +##### logging + +- `console_log_level` is the logging level used for the console. +- `file_log_level` is the logging level used for the log file. +- `log_file` is the path to the log file. Leaving this empty means file logging will not be used. + +The possible log levels are these: `crit`, `error`, `warn`, `info`, `debug`. + +The server log level will override the log level set in the Tendermint `config.toml`. + +##### example server_conf.toml file + +``` +[bind] +address="0.0.0.0" +port=1337 +[TLS] +tls=false +cert_path="" +key_path="" +[CORS] +enable=false +allow_origins=[] +allow_credentials=false +allow_methods=[] +allow_headers=[] +expose_headers=[] +max_age=0 +[HTTP] +json_rpc_endpoint="/rpc" +[web_socket] +websocket_endpoint="/socketrpc" +max_websocket_sessions=50 +[logging] +console_log_level="debug" +file_log_level="warn" +log_file="" +``` + +### Server-server + +The library includes a "server-server". This server accepts POST requests with some chain data (such as priv_validator.json and genesis.json), and will use that to create a new working directory in the temp folder, write the data, deploy a new node in that folder, generate a port, use it to serve that node and then pass the url back in the response. It will also manage all the servers and shut them down as they become inactive. + +NOTE: This is not safe in production, as it requires private keys to be passed over a network, but it is very useful when doing tests. If the same chain data is used, then each node is guaranteed to give the same output (for the same input) when calling the methods. + +To start one up, just run `godep go install` in the `erisdb/cmd/erisdbss` directory, then run `erisdbss`. It takes no parameters. There are many examples on how to call it in the javascript library, and if people find it useful there will be a tutorial. + +### Testing + +Run using `go test` as usual. There are 3 tiers of tests: + +* Tier 1 is unit tests of components, such as the http/websocket servers, query parser and event cache. +* Tier 2 is a full client-server test of `erisdb` using a mock implementation of the [Pipe](https://github.com/eris-ltd/erisdb/blob/master/erisdb/pipe/pipe.go). +* Tier 3 is a full client-server test of `erisdb` using a live node. + +There will be a pipe-only test as well. + +#### JSON test-data + +The tests uses test data in JSON form. This means the same data can be used to do integration tests with clients; whether it's our own javascript client (it uses the server-server btw) or if we or someone else decides to create clients in other languages. + +As of `0.9.0`, the test-data needs to be cleaned up a bit, and there really should be some tools available for generating new sets. It will probably take a few minor versions before it is convenient to work with. + +### Benchmarking + +As of `0.9.0`, there are no benchmarks. We aim to have a framework built before `1.0`. \ No newline at end of file diff --git a/erisdb.md b/api.md similarity index 77% rename from erisdb.md rename to api.md index fa3221ac0..4563ef75d 100644 --- a/erisdb.md +++ b/api.md @@ -1,12 +1,20 @@ # Eris DB -Eris DB allows remote access to its functionality over http and websockets. It currently supports JSON-RPC (over both http and websockets), and REST-like http. There is also javascript bindings available in the [erisdb-js](TODO) library. +Eris DB allows remote access to its functionality over http and websocket. It currently supports JSON-RPC, and REST-like http. There is also javascript bindings available in the [erisdb-js](TODO) library. + +## TOC + +- [JSON-RPC 2.0](#json-rpc) +- [REST-like HTTP](#rest-like) +- [Common objects and formatting](#formatting-conventions) +- [Event-system](#event-system) +- [Methods](#methods) +- [Filters](#filters) ## JSON RPC 2.0 -The default endpoints for JSON-RPC (2.0) is `/rpc` for http based, and `/socketrpc` for websockets. The namespace for the JSON-RPC service is `erisdb`. - +The default endpoints for JSON-RPC (2.0) is `/rpc` for http based, and `/socketrpc` for websocket. The namespace for the JSON-RPC service is `erisdb`. ### Objects @@ -21,6 +29,7 @@ INTERNAL_ERROR = -32603 ``` #####Request + ``` { jsonrpc: @@ -31,6 +40,7 @@ INTERNAL_ERROR = -32603 ``` #####Response + ``` { jsonrpc: @@ -41,17 +51,20 @@ INTERNAL_ERROR = -32603 ``` #####Error + ``` { code: message: } ``` + Id can be any string value. Parameters are named, and wrapped in objects. Also, params, result and error params may be `null`. #####Example -Request: +Request: + ``` { jsonrpc: "2.0", @@ -62,6 +75,7 @@ Request: ``` Response: + ``` { address: "37236DF251AB70022B1DA351F08A20FB52443E37", @@ -74,15 +88,15 @@ Response: ``` -## REST-like api +## REST-like HTTP -The REST-like web-api provides the typical endpoint structure i.e. endpoints are resources, GET params in path, and queries used only for filtering. It is not fully compatible with normal REST and probably won't be. This is partly because some GET requests can contain sizable input so POST is used instead. There are also some modeling issues but those will most likely be resolved before 1.0. +The REST-like API provides the typical endpoint structure i.e. endpoints are resources, parameters can be put in the path, and queries are used only for filtering. It is not fully compatible with REST; partly because some GET requests can contain sizable input so POST is used instead. There are also some modeling issues but those will most likely be resolved before version 1.0. ##Common objects and formatting -This section contains some common objects and explanations of how they behave. +This section contains some common objects and explanations of how they work. ###Numbers and strings @@ -102,11 +116,9 @@ Hex strings are never prefixed. Public and Private keys in JSON data are either null, or on the form: `[type, hex]`, where `type` is the [public](https://github.com/tendermint/tendermint/blob/master/account/pub_key.go), or [private](https://github.com/tendermint/tendermint/blob/master/account/pub_key.go) key type, and `hex` is the hex-string representation of the key bytes. -* A `public address` is a 20 byte hex string. - -* A `public key` is a 32 byte hex string. - -* A `private key` is a 64 byte hex string. +- A `public address` is a 20 byte hex string. +- A `public key` is a 32 byte hex string. +- A `private key` is a 64 byte hex string. #####WARNING @@ -127,6 +139,7 @@ The corresponding Ed25519 private key: `[1, "6B72D45EB65F619F11CE580C8CAED9E0BAD These are the types of transactions: ####SendTx + ``` { inputs: [] @@ -135,6 +148,7 @@ These are the types of transactions: ``` ####CallTx + ``` { input: @@ -146,6 +160,7 @@ These are the types of transactions: ``` ####NameTx + ``` { input: @@ -156,6 +171,7 @@ These are the types of transactions: ``` ####BondTx + ``` { pub_key: @@ -166,6 +182,7 @@ These are the types of transactions: ``` ####UnbondTx + ``` { address: @@ -175,6 +192,7 @@ These are the types of transactions: ``` ####RebondTx + ``` { address: @@ -184,6 +202,7 @@ These are the types of transactions: ``` ####DupeoutTx + ``` { address: @@ -195,6 +214,7 @@ These are the types of transactions: These are the support types that are referenced in the transactions: ####TxInput + ``` { address: @@ -206,6 +226,7 @@ These are the support types that are referenced in the transactions: ``` ####TxOutput + ``` { address: @@ -231,10 +252,153 @@ These are the support types that are referenced in the transactions: ##Event system +Tendermint events can be subscribed to regardless of what connection type is used. There are three methods for this: + +- [EventSubscribe](#event-subscribe) is used to subscribe to a given event, using an event-id string as argument. The response will contain a `subscription ID`, which can be used to close down the subscription later, or poll for new events if using HTTP. More on event-ids below. +- [EventUnsubscribe](#event-unsubscribe) is used to unsubscribe to an event. It requires you to pass the `subscription ID` as an argument. +- [EventPoll](#event-poll) is used to get all the events that has accumulated since the last time the subscription was polled. It takes the `subscription ID` as a parameter. NOTE: This only works over HTTP. Websocket connections will automatically receive events as they happen. They are sent as regular JSON-RPC 2.0 responses with the `subscriber ID` as response id. + +There is another slight difference between polling and websocket, and that is the data you receive. If using sockets, it will always be one event at a time, whereas polling will give you an array of events. + +### Event types + +These are the type of events you can subscribe to. + +The "Account" events are triggered when someone transacts with the given account, and can be used to keep track of account activity. + +NewBlock and Fork happens when a new block is committed or a fork happens, respectively. + +The other events are directly related to consensus. You can find out more about the Tendermint consensus system in the Tendermint [white paper](http://tendermint.com/docs/tendermint.pdf). There is also information in the consensus [sources](https://github.com/tendermint/tendermint/blob/master/consensus/state.go), although a normal user would not be concerned with the consensus mechanisms, but would mostly just listen to account- and perhaps block-events. + +#### Account Input + +This notifies you when an account is receiving input. + +Event ID: `Acc/
/Input` + +Example: `Acc/B4F9DA82738D37A1D83AD2CDD0C0D3CBA76EA4E7/Input` will subscribe to input events from the account with address: B4F9DA82738D37A1D83AD2CDD0C0D3CBA76EA4E7. + +Event object: + +``` +{ + tx: + return: + exception: +} +``` + +#### Account Output + +This notifies you when an account is yielding output. + +Event ID: `Acc/
/Output` + +Example: `Acc/B4F9DA82738D37A1D83AD2CDD0C0D3CBA76EA4E7/Output` will subscribe to output events from the account with address: B4F9DA82738D37A1D83AD2CDD0C0D3CBA76EA4E7. + +Event object: + +``` + +``` + +#### Account Receive + +This notifies you when an account is the target of a call, like when calling an accessor function. + +Event ID: `Acc/
/Receive` + +Example: `Acc/B4F9DA82738D37A1D83AD2CDD0C0D3CBA76EA4E7/Input` will subscribe to call receive events from the account with address: B4F9DA82738D37A1D83AD2CDD0C0D3CBA76EA4E7. + -####Contract code +``` +{ + call_data: { + caller: + callee: + data: + value: + gas: + } + origin: + tx_id: + return: + exception: +} +``` + +#### New Block + +This notifies you when a new block is committed. + +Event ID: `NewBlock` + +Event object: + +``` + +``` + +#### Fork + +This notifies you when a fork event happens. + +Event ID: `Fork` + +Event object: TODO +``` + +``` + +#### Bond + +This notifies you when a bond event happens. + +Event ID: `Bond` + +Event object: + +``` + +``` + +#### Unbond + +This notifies you when an unbond event happens. + +Event ID: `Unbond` + +Event object: + +``` + +``` + +#### Rebond + +This notifies you when a rebond event happens. + +Event ID: `Rebond` + +Event object: + +``` + +``` + +#### Dupeout + +This notifies you when a dupeout event happens. + +Event ID: `Dupeout` + +Event object: + +``` + +``` ##Methods @@ -275,6 +439,7 @@ TODO | Name | RPC method name | REST method | REST endpoint | | :--- | :-------------- | :---------: | :------------ | | [GetNetworkInfo](#get-network-info) | erisdb.getNetworkInfo | GET | `/network` | +| [GetClientVersion](#get-client-version) | erisdb.getClientVersion | GET | `/network/client_version` | | [GetMoniker](#get-moniker) | erisdb.getMoniker | GET | `/network/moniker` | | [GetChainId](#get-chain-id) | erisdb.getChainId | GET | `/network/chain_id` | | [IsListening](#is-listening) | erisdb.isListening | GET | `/network/listening` | @@ -315,7 +480,7 @@ Here are the catagories. In the case of **JSON-RPC**, the parameters are wrapped in a request object, and the return value is wrapped in a response object. -In the case of **REST**, the params (and query) is provided in the url of the request. If it's a POST, PATCH or PUT request, the parameter object should be written to the body of the request in JSON form. It is normally the same object as would be the params in the corresponding JSON-RPC request. +In the case of **REST-like HTTP** GET requests, the params (and query) is provided in the url. If it's a POST, PATCH or PUT request, the parameter object should be written to the body of the request as JSON. It is normally the same params object as in JSON-RPC. **Unsafe** is methods that require a private key to be sent either to or from the client, and should therefore be used only during development/testing, or with extreme care. They may be phased out entirely. @@ -331,14 +496,10 @@ Get accounts will return a list of accounts. If no filtering is used, it will re #####HTTP -Method: GET +Method: GET Endpoint: `/accounts` -Search terms: - -` - #####JSON-RPC Method: `erisdb.getAccounts` @@ -351,9 +512,16 @@ Parameter: } ``` +##### Filters + +| Field | Underlying type | Ops | Example Queries | +| :---- | :-------------- | :-- | :-------------- | +| `balance` | uint64 | `<`, `>`, `<=`, `>=`, `==` | `q=balance:<=11` | +| `code` | byte[] | `==`, `!=` | `q=code:1FA872` | #####Return value -``` + +``` { accounts: [] } @@ -394,7 +562,8 @@ Parameter: ``` #####Return value -``` + +``` { address: pub_key: @@ -445,7 +614,8 @@ Parameter: ``` #####Return value -``` + +``` { storage_root: storage_items: [] @@ -486,7 +656,8 @@ Parameter: ``` #####Return value -``` + +``` { key: value: @@ -520,7 +691,8 @@ Method: `erisdb.getBlockchainInfo` Parameter: - #####Return value -``` + +``` { chain_id: genesis_hash: @@ -560,12 +732,12 @@ Method: `erisdb.getChainId` Parameter: - #####Return value -``` + +``` { chain_id: } ``` - *** @@ -586,7 +758,8 @@ Method: `erisdb.getGenesisHash` Parameter: - #####Return value -``` + +``` { genesis_hash: } @@ -612,7 +785,8 @@ Method: `erisdb.getLatestBlockHeight` Parameter: - #####Return value -``` + +``` { latest_block_height: } @@ -638,7 +812,8 @@ Method: `erisdb.getLatestBlock` Parameter: - #####Return value -``` + +``` { latest_block: } @@ -673,9 +848,17 @@ Parameter: } ``` +##### Filters + +| Field | Underlying type | Ops | Example Queries | +| :---- | :-------------- | :-- | :-------------- | +| `height` | uint | `<`, `>`, `<=`, `>=`, `==` | `q=height:>4`, `q=height:10..*` | + + + #####Return value -``` +``` { min_height: max_height: @@ -737,14 +920,15 @@ Method: `erisdb.getBlock` Parameter: -``` +``` { height: } ``` #####Return value -``` + +``` { header: { @@ -813,7 +997,7 @@ Parameter: - #####Return value -``` +``` { height: round: @@ -864,7 +1048,7 @@ Parameter: - #####Return value -``` +``` { block_height: bonded_validators: [] @@ -916,7 +1100,7 @@ Method: `erisdb.eventSubscribe` Parameter: -``` +``` { event_id: } @@ -924,7 +1108,7 @@ Parameter: #####Return value -``` +``` { sub_id: } @@ -955,7 +1139,7 @@ Parameter: - #####Return value -``` +``` { result: } @@ -984,7 +1168,7 @@ Method: `erisdb.eventPoll` #####Return value -``` +``` { events: [] } @@ -1020,8 +1204,9 @@ Parameters: - #####Return value -``` +``` { + client_version: moniker: listening: listeners: [] @@ -1031,6 +1216,7 @@ Parameters: - #####Additional info +`client_version` is the version of the running client, or node. `moniker` is a moniker for the node. `listening` is a check if the node is listening for connections. `listeners` is a list of active listeners. @@ -1040,6 +1226,33 @@ See [GetPeer](#get-peer) for info on the `Peer` object. *** + +####GetClientVersion + +Get the version of the running client (node). + +#####HTTP + +Method: GET + +Endpoint: `/network/client_version` + +#####JSON-RPC + +Method: `erisdb.getClientVersion` + +Parameters: - + +#####Return value + +``` +{ + client_version: +} +``` + +*** + ####GetMoniker @@ -1059,7 +1272,7 @@ Parameters: - #####Return value -``` +``` { moniker: } @@ -1086,7 +1299,7 @@ Parameters: - #####Return value -``` +``` { listening: } @@ -1113,7 +1326,7 @@ Parameters: - #####Return value -``` +``` { listeners: [] } @@ -1140,7 +1353,7 @@ Parameters: - #####Return value -``` +``` { peers: [] } @@ -1167,7 +1380,7 @@ Method: `erisdb.getPeer` Parameters: -``` +``` { address: } @@ -1177,7 +1390,7 @@ Parameters: This is the peer object. -``` +``` { is_outbound: moniker: @@ -1214,7 +1427,7 @@ Endpoint: `/txpool` Body: -``` +``` ``` @@ -1224,13 +1437,13 @@ Method: `erisdb.BroadcastTx` Parameters: -``` +``` ``` #####Return value -``` +``` { tx_hash: creates_contract: @@ -1269,7 +1482,7 @@ Parameters: - #####Return value -``` +``` { txs: [] } @@ -1306,7 +1519,7 @@ Method: `erisdb.call` Parameters: -``` +``` { address: data: @@ -1315,7 +1528,7 @@ Parameters: #####Return value -``` +``` { return: gas_used: @@ -1347,7 +1560,7 @@ Method: `erisdb.callCode` Parameters: -``` +``` { code: data: @@ -1356,7 +1569,7 @@ Parameters: #####Return value -``` +``` { return: gas_used: @@ -1390,7 +1603,7 @@ Endpoint: `/unsafe/tx_signer` Body: -``` +``` ``` @@ -1400,7 +1613,7 @@ Method: `erisdb.SignTx` Parameters: -``` +``` ``` @@ -1438,7 +1651,7 @@ Method: `erisdb.SignTx` Parameters: -``` +``` { priv_key: data: @@ -1452,7 +1665,7 @@ Parameters: The same as with BroadcastTx: -``` +``` { tx_hash: creates_contract: @@ -1484,7 +1697,7 @@ Parameters: - #####Return value -``` +``` { address: pub_key: @@ -1503,13 +1716,14 @@ Again - This is unsafe. Be warned. ##Filters -Filters are used in searches. The filter query structure is similar to that of the [Github api (v3)](https://developer.github.com/v3/search/). +Filters are used in searches. The structure is similar to that of the [Github api (v3)](https://developer.github.com/v3/search/). ###JSON-RPC Filters are added as objects in the request parameter. Methods that supports filtering includes an array of filters somewhere in their params object. Filter: + ``` { field: @@ -1571,75 +1785,32 @@ If we wanted only non-contract accounts then we would have used the same object The structure of a normal query is: `q=field:statement+field2:statement2+ ... `. -*`q` means it's a query. -*`field` is the field name. -*`:` is a separator. -* `statement` is normally on the form `[op]value` where `op` is a relational operator, and `value` a value, e.g. `balance:>=5` or `language:==golang`. There is also support for [range queries](https://help.github.com/articles/search-syntax/): `*..*`, where `*` is a number. If on the left of `..` it means minimum value, and if it's on the right it means maximum value. `height:*..55`. There is only the non-quoted version as of now. +- `q` means it's a query. +- `+` is the filter separator (expands to a space when parsed) +- `field` is the field name. +- `:` is the field-statement separator. +- `statement` is normally on the form `[op]value` where `op` is a relational operator, and `value` a string-value, e.g. `balance:>=5` or `language:==golang`. There is also support for [range queries](https://help.github.com/articles/search-syntax/): `A..B`, where `A` and `B` are numbers. You may use the wildcard `*` instead of a number. The wildcard is context-sensitive. If it is put on the left-hand side it means the minimum value, and if it's on the right-hand side it means the maximum value. Let's say `height` is an unsigned byte with no additional restrictions. `height:*..55` would then be the same as `height:0..55`, and `height:*..*` would be the same as `height:0..255`. NOTE: URL encoding applies as usual. Omitting it here for clarity. -If you leave `op` out it will default to equals (`==`). +`op` will default to (`==`) if left out, meaning `balance:5` is the same as `balance:==5` -`value` may be left empty if the underlying type for that field is a string. This means if `code` is a supported string type, `/accounts?q=code:%3D%3D` would check if the code field is empty. We could also use inferred `==` here, meaning this query would be equivalent: `/accounts?q=code:`. +`value` may be left out if the field accepts the empty string as input. This means if `code` is a supported string type, `code:==` would check if the code field is empty. We could also use the inferred `==` meaning this would be equivalent: `code:`. The system may be extended so that the empty string is automatically converted to the null-type of the underlying field, no matter what that type is. If balance is a number then `balance:` would be the same as `balance:==0` (and `balance:0`). #####Example We want to use the same filter as in the JSON version; one that finds all contract accounts. -`http://localhost:1337/accounts?q=code:%21%3D` (code != "") +`q=code:!=` One that finds those with balance less then 1000: -`http://localhost:1337/accounts?q=balance:%3C1000` (balance < 1000) - -One that finds those with balance more then 0, but less then 1000. - -`http://localhost:1337/accounts?q=balance:0..1000` - -One that finds contract accounts with a balance less then 1000: - -`http://localhost:1337/accounts?q=code:%21%3D+balance:0..1000` - -###Supported types - -Right now you can only filter searches when getting blocks and accounts. The system will expand to handle a lot more before version 1.0. - -#### Accounts - -#####Code - -Field name: `code` - -Ops: `==`, `!=` - -Field type: hex-string - -Underlying type: byte-array - -`http://localhost:1337/accounts?q=code:%3D%3Dabababab` (code == "abababab") - -#####Balance - -Field name: `balance` - -Ops: All - -Field type: integer-string. - -Underlying type: uint64 - -`http://localhost:1337/accounts?q=balance:0..1000` - -#### Blocks - -#####Height - -Field name: `height` +`q=balance:<1000` -Ops: `<`, `>`, `<=`, `>=`, `==` (`!=` is not supported because disjoint result sets are not allowed) +One that finds those where 0 <= balance <= 1000. -Field type: integer string +`q=balance:0..1000` -Underlying type: uint +One that finds non-contract accounts with 0 <= balance <= 1000: -`http://localhost:1337/blockchain/blocks?q=height:0..10` \ No newline at end of file +`q=balance:0..1000+code:` \ No newline at end of file diff --git a/client/ws_client.go b/client/ws_client.go index db0c32bbe..41ef214c7 100644 --- a/client/ws_client.go +++ b/client/ws_client.go @@ -1,4 +1,4 @@ -// Websocket client implementation. +// Websocket client implementation. This will be used in tests. package client import ( @@ -29,22 +29,23 @@ func (this *WSClient) Dial() (*http.Response, error) { return r, err } this.conn = conn + return r, nil } // returns a channel from which messages can be pulled // from a go routine that reads the socket. // if the ws returns an error (eg. closes), we return -func (this *WSClient) Read() chan []byte { +func (this *WSClient) StartRead() <- chan []byte { ch := make(chan []byte) go func() { for { _, msg, err := this.conn.ReadMessage() - if err != nil { if !this.closed { - // TODO For now. If it's not a graceful shutdown, log. + // TODO For now. fmt.Println("Error: " + err.Error()) + close(ch) } return } diff --git a/erisdb/erisdbss/http.go b/erisdb/erisdbss/http.go index 9d79ee100..8774897d6 100644 --- a/erisdb/erisdbss/http.go +++ b/erisdb/erisdbss/http.go @@ -1,4 +1,3 @@ -// Library code for the server-server. package erisdbss import ( diff --git a/erisdb/json_service.go b/erisdb/json_service.go index 5237301a8..ef3176697 100644 --- a/erisdb/json_service.go +++ b/erisdb/json_service.go @@ -23,7 +23,7 @@ func NewJsonRpcServer(service server.HttpService) *JsonRpcServer { // Start adds the rpc path to the router. func (this *JsonRpcServer) Start(config *server.ServerConfig, router *gin.Engine) { - router.POST(config.HTTP.JsonRpcPath, this.handleFunc) + router.POST(config.HTTP.JsonRpcEndpoint, this.handleFunc) this.running = true } diff --git a/erisdb/pipe/pipe.go b/erisdb/pipe/pipe.go index 156607199..d5569211b 100644 --- a/erisdb/pipe/pipe.go +++ b/erisdb/pipe/pipe.go @@ -1,4 +1,4 @@ -// This +// The pipe is used to call methods on the Tendermint node. package pipe import ( diff --git a/erisdb/serve.go b/erisdb/serve.go index 855c6a08f..1a173e657 100644 --- a/erisdb/serve.go +++ b/erisdb/serve.go @@ -1,3 +1,5 @@ +// The erisdb package contains tendermint-specific services that goes with the +// server. package erisdb import ( @@ -12,7 +14,8 @@ import ( "path" ) -const VERSION = "0.9.0" +const ERISDB_VERSION = "0.9.1" +const TENDERMINT_VERSION = "0.3.0" var log = log15.New("module", "eris/erisdb_server") var tmConfig cfg.Config @@ -33,8 +36,13 @@ func ServeErisDB(workDir string) (*server.ServeProcess, error) { sConfPath := path.Join(workDir, "server_conf.toml") if !FileExists(sConfPath) { + log.Info("No server configuration, using default.") + log.Info("Writing to: " + sConfPath) sConf = server.DefaultServerConfig() - server.WriteServerConfig(sConfPath, sConf) + errW := server.WriteServerConfig(sConfPath, sConf) + if errW != nil { + panic(errW) + } } else { var errRSC error sConf, errRSC = server.ReadServerConfig(sConfPath) @@ -45,7 +53,7 @@ func ServeErisDB(workDir string) (*server.ServeProcess, error) { // Get tendermint configuration tmConfig = tmcfg.GetConfig(workDir) - tmConfig.Set("version", VERSION) + tmConfig.Set("version", TENDERMINT_VERSION) cfg.ApplyConfig(tmConfig) // Notify modules of new config // Set the node up. diff --git a/server/config.go b/server/config.go index fdc88232c..acb67361a 100644 --- a/server/config.go +++ b/server/config.go @@ -8,9 +8,9 @@ import ( // Standard configuration file for the server. type ( ServerConfig struct { - Bind Bind `toml:"bind"` - TLS TLS `toml:"TLS"` - //CORS *CORS `toml:"CORS"` + Bind Bind `toml:"bind"` + TLS TLS `toml:"TLS"` + CORS CORS `toml:"CORS"` HTTP HTTP `toml:"HTTP"` WebSocket WebSocket `toml:"web_socket"` Logging Logging `toml:"logging"` @@ -29,6 +29,7 @@ type ( // Options stores configurations CORS struct { + Enable bool `toml:"enable"` AllowOrigins []string `toml:"allow_origins"` AllowCredentials bool `toml:"allow_credentials"` AllowMethods []string `toml:"allow_methods"` @@ -38,18 +39,18 @@ type ( } HTTP struct { - JsonRpcPath string `toml:"json_rpc_path"` + JsonRpcEndpoint string `toml:"json_rpc_endpoint"` } WebSocket struct { - WebSocketPath string `toml:"websocket_path"` + WebSocketEndpoint string `toml:"websocket_endpoint"` MaxWebSocketSessions uint `toml:"max_websocket_sessions"` } Logging struct { ConsoleLogLevel string `toml:"console_log_level"` FileLogLevel string `toml:"file_log_level"` - LogFile string `toml:"log_level"` + LogFile string `toml:"log_file"` } ) @@ -65,17 +66,15 @@ func DefaultServerConfig() *ServerConfig { CertPath: cp, KeyPath: kp, }, - /* - CORS: CORS{ - },*/ - HTTP: HTTP{JsonRpcPath: "/rpc"}, + CORS: CORS{}, + HTTP: HTTP{JsonRpcEndpoint: "/rpc"}, WebSocket: WebSocket{ - WebSocketPath: "/socketrpc", + WebSocketEndpoint: "/socketrpc", MaxWebSocketSessions: 50, }, Logging: Logging{ - ConsoleLogLevel: "error", - FileLogLevel: "error", + ConsoleLogLevel: "info", + FileLogLevel: "warn", LogFile: "", }, } diff --git a/server/logging.go b/server/logging.go index b77a15191..a5a70031a 100644 --- a/server/logging.go +++ b/server/logging.go @@ -10,7 +10,7 @@ var rootHandler log15.Handler // This is basically the same code as in tendermint. Initialize root // and maybe later also track the loggers here. -func Init(config *ServerConfig) { +func InitLogger(config *ServerConfig) { consoleLogLevel := config.Logging.ConsoleLogLevel diff --git a/server/server.go b/server/server.go index 93a552bd9..95ad77904 100644 --- a/server/server.go +++ b/server/server.go @@ -4,7 +4,7 @@ import ( "crypto/tls" "fmt" "github.com/gin-gonic/gin" - // cors "github.com/tommy351/gin-cors" + cors "github.com/tommy351/gin-cors" "gopkg.in/tylerb/graceful.v1" "net" "net/http" @@ -51,10 +51,15 @@ func (this *ServeProcess) Start() error { router := gin.New() config := this.config + + InitLogger(config) - // ch := NewCORSMiddleware(config.CORS) - // router.Use(gin.Recovery(), logHandler, ch) - router.Use(gin.Recovery(), logHandler) + if config.CORS.Enable { + ch := NewCORSMiddleware(config.CORS) + router.Use(gin.Recovery(), logHandler, ch) + } else { + router.Use(gin.Recovery(), logHandler) + } address := config.Bind.Address port := config.Bind.Port @@ -218,7 +223,6 @@ func logHandler(c *gin.Context) { } -/* func NewCORSMiddleware(options CORS) gin.HandlerFunc { o := cors.Options{ AllowCredentials: options.AllowCredentials, @@ -230,4 +234,4 @@ func NewCORSMiddleware(options CORS) gin.HandlerFunc { } return cors.Middleware(o) } -*/ + diff --git a/server/websocket.go b/server/websocket.go index 5b6546be9..732b45aaa 100644 --- a/server/websocket.go +++ b/server/websocket.go @@ -72,7 +72,7 @@ func (this *WebSocketServer) Start(config *ServerConfig, router *gin.Engine) { } this.upgrader.CheckOrigin = nil - router.GET(config.WebSocket.WebSocketPath, this.handleFunc) + router.GET(config.WebSocket.WebSocketEndpoint, this.handleFunc) this.running = true } diff --git a/test/server/scumbag.go b/test/server/scumbag.go index d895b6a4f..6ba0dfcd8 100644 --- a/test/server/scumbag.go +++ b/test/server/scumbag.go @@ -63,7 +63,7 @@ func NewServeScumbag() *server.ServeProcess { func NewServeScumSocket(wsServer *server.WebSocketServer) *server.ServeProcess { cfg := server.DefaultServerConfig() - cfg.WebSocket.WebSocketPath = "/scumsocket" + cfg.WebSocket.WebSocketEndpoint = "/scumsocket" cfg.Bind.Port = uint16(31337) return server.NewServeProcess(cfg, wsServer) } diff --git a/test/server/ws_burst_test.go b/test/server/ws_burst_test.go index c677b8cfa..451c580ee 100644 --- a/test/server/ws_burst_test.go +++ b/test/server/ws_burst_test.go @@ -95,7 +95,7 @@ func wsClient(doneChan chan bool, errChan chan error) { errChan <- err return } - readChan := client.Read() + readChan := client.StartRead() i := 0 for i < MESSAGES { client.WriteMsg([]byte("test")) diff --git a/test/testdata/testdata/testdata.go b/test/testdata/testdata/testdata.go index 69d32d982..78e3613a5 100644 --- a/test/testdata/testdata/testdata.go +++ b/test/testdata/testdata/testdata.go @@ -121,14 +121,14 @@ var testDataJson = `{ "unbonding_validators": [] }, "network_info": { - "client_version": "0.9.0", + "client_version": "0.3.0", "moniker": "anothertester", "listening": false, "listeners": [], "peers": [] }, "client_version": { - "client_version": "0.9.0" + "client_version": "0.3.0" }, "moniker": { "moniker": "anothertester"