242 lines
13 KiB
Markdown
242 lines
13 KiB
Markdown
[](http://slack.bitshares.org/)
|
|
|
|
Intro for new developers
|
|
------------------------
|
|
|
|
This is a quick introduction to get new developers up to speed on BitShares.
|
|
|
|
Starting BitShares
|
|
-----------------
|
|
|
|
For Ubuntu 14.04 LTS users, see this link first:
|
|
https://github.com/cryptonomex/graphene/wiki/build-ubuntu
|
|
|
|
and then proceed with:
|
|
|
|
git clone https://github.com/bitshares/bitshares-2
|
|
cd bitshares-2
|
|
git submodule update --init --recursive
|
|
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .
|
|
make
|
|
./programs/witness_node/witness_node
|
|
|
|
This will launch the witness node. If you would like to launch the command-line wallet, you must first specify a port
|
|
for communication with the witness node. To do this, add text to `witness_node_data_dir/config.ini` as follows, then
|
|
restart the node:
|
|
|
|
rpc-endpoint = 127.0.0.1:8090
|
|
|
|
Then, in a separate terminal window, start the command-line wallet `cli_wallet`:
|
|
|
|
./programs/cli_wallet/cli_wallet
|
|
|
|
To set your iniital password to 'password' use:
|
|
|
|
>>> set_password password
|
|
>>> unlock password
|
|
|
|
To import your initial balance:
|
|
|
|
>>> import_balance nathan [5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3] true
|
|
|
|
If you send private keys over this connection, `rpc-endpoint` should be bound to localhost for security.
|
|
|
|
A list of CLI wallet commands is available
|
|
[here](https://github.com/bitshares/bitshares-2/blob/bitshares/libraries/wallet/include/graphene/wallet/wallet.hpp).
|
|
|
|
Code coverage testing
|
|
---------------------
|
|
|
|
Check how much code is covered by unit tests, using gcov/lcov (see http://ltp.sourceforge.net/coverage/lcov.php ).
|
|
|
|
cmake -D ENABLE_COVERAGE_TESTING=true -D CMAKE_BUILD_TYPE=Debug .
|
|
make
|
|
lcov --capture --initial --directory . --output-file base.info --no-external
|
|
libraries/fc/bloom_test
|
|
libraries/fc/task_cancel_test
|
|
libraries/fc/api
|
|
libraries/fc/blind
|
|
libraries/fc/ecc_test test
|
|
libraries/fc/real128_test
|
|
libraries/fc/lzma_test README.md
|
|
libraries/fc/ntp_test
|
|
tests/intense_test
|
|
tests/app_test
|
|
tests/chain_bench
|
|
tests/chain_test
|
|
tests/performance_test
|
|
lcov --capture --directory . --output-file test.info --no-external
|
|
lcov --add-tracefile base.info --add-tracefile test.info --output-file total.info
|
|
lcov -o interesting.info -r total.info libraries/fc/vendor/\* libraries/fc/tests/\* tests/\*
|
|
mkdir -p lcov
|
|
genhtml interesting.info --output-directory lcov --prefix `pwd`
|
|
|
|
Now open `lcov/index.html` in a browser.
|
|
|
|
Unit testing
|
|
------------
|
|
|
|
We use the Boost unit test framework for unit testing. Most unit
|
|
tests reside in the `chain_test` build target.
|
|
|
|
Witness node
|
|
------------
|
|
|
|
The role of the witness node is to broadcast transactions, download blocks, and optionally sign them.
|
|
|
|
```
|
|
./witness_node --rpc-endpoint 127.0.0.1:8090 --enable-stale-production -w '"1.6.0"' '"1.6.1"' '"1.6.2"' '"1.6.3"' '"1.6.4"' '"1.6.5"' '"1.6.6"' '"1.6.7"' '"1.6.8"' '"1.6.9"' '"1.6.10"' '"1.6.11"' '"1.6.12"' '"1.6.13"' '"1.6.14"' '"1.6.15"' '"1.6.16"' '"1.6.17"' '"1.6.18"' '"1.6.19"' '"1.6.20"' '"1.6.21"' '"1.6.22"' '"1.6.23"' '"1.6.24"' '"1.6.25"' '"1.6.26"' '"1.6.27"' '"1.6.28"' '"1.6.29"' '"1.6.30"' '"1.6.31"' '"1.6.32"' '"1.6.33"' '"1.6.34"' '"1.6.35"' '"1.6.36"' '"1.6.37"' '"1.6.38"' '"1.6.39"' '"1.6.40"' '"1.6.41"' '"1.6.42"' '"1.6.43"' '"1.6.44"' '"1.6.45"' '"1.6.46"' '"1.6.47"' '"1.6.48"' '"1.6.49"' '"1.6.50"' '"1.6.51"' '"1.6.52"' '"1.6.53"' '"1.6.54"' '"1.6.55"' '"1.6.56"' '"1.6.57"' '"1.6.58"' '"1.6.59"' '"1.6.60"' '"1.6.61"' '"1.6.62"' '"1.6.63"' '"1.6.64"' '"1.6.65"' '"1.6.66"' '"1.6.67"' '"1.6.68"' '"1.6.69"' '"1.6.70"' '"1.6.71"' '"1.6.72"' '"1.6.73"' '"1.6.74"' '"1.6.75"' '"1.6.76"' '"1.6.77"' '"1.6.78"' '"1.6.79"' '"1.6.80"' '"1.6.81"' '"1.6.82"' '"1.6.83"' '"1.6.84"' '"1.6.85"' '"1.6.86"' '"1.6.87"' '"1.6.88"' '"1.6.89"' '"1.6.90"' '"1.6.91"' '"1.6.92"' '"1.6.93"' '"1.6.94"' '"1.6.95"' '"1.6.96"' '"1.6.97"' '"1.6.98"' '"1.6.99"' '"1.6.100"'
|
|
```
|
|
|
|
Running specific tests
|
|
----------------------
|
|
|
|
- `tests/chain_tests -t block_tests/name_of_test`
|
|
|
|
Using the API
|
|
-------------
|
|
|
|
We provide several different API's. Each API has its own ID.
|
|
When running `witness_node`, initially two API's are available:
|
|
API 0 provides read-only access to the database, while API 1 is
|
|
used to login and gain access to additional, restricted API's.
|
|
|
|
Here is an example using `wscat` package from `npm` for websockets:
|
|
|
|
$ npm install -g wscat
|
|
$ wscat -c ws://127.0.0.1:8090
|
|
> {"id":1, "method":"call", "params":[0,"get_accounts",[["1.2.0"]]]}
|
|
< {"id":1,"result":[{"id":"1.2.0","annotations":[],"membership_expiration_date":"1969-12-31T23:59:59","registrar":"1.2.0","referrer":"1.2.0","lifetime_referrer":"1.2.0","network_fee_percentage":2000,"lifetime_referrer_fee_percentage":8000,"referrer_rewards_percentage":0,"name":"committee-account","owner":{"weight_threshold":1,"account_auths":[],"key_auths":[],"address_auths":[]},"active":{"weight_threshold":6,"account_auths":[["1.2.5",1],["1.2.6",1],["1.2.7",1],["1.2.8",1],["1.2.9",1],["1.2.10",1],["1.2.11",1],["1.2.12",1],["1.2.13",1],["1.2.14",1]],"key_auths":[],"address_auths":[]},"options":{"memo_key":"GPH1111111111111111111111111111111114T1Anm","voting_account":"1.2.0","num_witness":0,"num_committee":0,"votes":[],"extensions":[]},"statistics":"2.7.0","whitelisting_accounts":[],"blacklisting_accounts":[]}]}
|
|
|
|
We can do the same thing using an HTTP client such as `curl` for API's which do not require login or other session state:
|
|
|
|
$ curl --data '{"jsonrpc": "2.0", "method": "call", "params": [0, "get_accounts", [["1.2.0"]]], "id": 1}' http://127.0.0.1:8090/rpc
|
|
{"id":1,"result":[{"id":"1.2.0","annotations":[],"membership_expiration_date":"1969-12-31T23:59:59","registrar":"1.2.0","referrer":"1.2.0","lifetime_referrer":"1.2.0","network_fee_percentage":2000,"lifetime_referrer_fee_percentage":8000,"referrer_rewards_percentage":0,"name":"committee-account","owner":{"weight_threshold":1,"account_auths":[],"key_auths":[],"address_auths":[]},"active":{"weight_threshold":6,"account_auths":[["1.2.5",1],["1.2.6",1],["1.2.7",1],["1.2.8",1],["1.2.9",1],["1.2.10",1],["1.2.11",1],["1.2.12",1],["1.2.13",1],["1.2.14",1]],"key_auths":[],"address_auths":[]},"options":{"memo_key":"GPH1111111111111111111111111111111114T1Anm","voting_account":"1.2.0","num_witness":0,"num_committee":0,"votes":[],"extensions":[]},"statistics":"2.7.0","whitelisting_accounts":[],"blacklisting_accounts":[]}]}
|
|
|
|
API 0 is accessible using regular JSON-RPC:
|
|
|
|
$ curl --data '{"jsonrpc": "2.0", "method": "get_accounts", "params": [["1.2.0"]], "id": 1}' http://127.0.0.1:8090/rpc
|
|
|
|
Accessing restricted API's
|
|
--------------------------
|
|
|
|
You can restrict API's to particular users by specifying an `apiaccess` file in `config.ini`. Here is an example `apiaccess` file which allows
|
|
user `bytemaster` with password `supersecret` to access four different API's, while allowing any other user to access the three public API's
|
|
necessary to use the wallet:
|
|
|
|
{
|
|
"permission_map" :
|
|
[
|
|
[
|
|
"bytemaster",
|
|
{
|
|
"password_hash_b64" : "9e9GF7ooXVb9k4BoSfNIPTelXeGOZ5DrgOYMj94elaY=",
|
|
"password_salt_b64" : "INDdM6iCi/8=",
|
|
"allowed_apis" : ["database_api", "network_broadcast_api", "history_api", "network_node_api"]
|
|
}
|
|
],
|
|
[
|
|
"*",
|
|
{
|
|
"password_hash_b64" : "*",
|
|
"password_salt_b64" : "*",
|
|
"allowed_apis" : ["database_api", "network_broadcast_api", "history_api"]
|
|
}
|
|
]
|
|
]
|
|
}
|
|
|
|
Passwords are stored in `base64` as salted `sha256` hashes. A simple Python script, `saltpass.py` is avaliable to obtain hash and salt values from a password.
|
|
A single asterisk `"*"` may be specified as username or password hash to accept any value.
|
|
|
|
With the above configuration, here is an example of how to call `add_node` from the `network_node` API:
|
|
|
|
{"id":1, "method":"call", "params":[1,"login",["bytemaster", "supersecret"]]}
|
|
{"id":2, "method":"call", "params":[1,"network_node",[]]}
|
|
{"id":3, "method":"call", "params":[2,"add_node",["127.0.0.1:9090"]]}
|
|
|
|
Note, the call to `network_node` is necessary to obtain the correct API identifier for the network API. It is not guaranteed that the network API identifier will always be `2`.
|
|
|
|
Since the `network_node` API requires login, it is only accessible over the websocket RPC. Our `doxygen` documentation contains the most up-to-date information
|
|
about API's for the [witness node](https://bitshares.github.io/doxygen/namespacegraphene_1_1app.html) and the
|
|
[wallet](https://bitshares.github.io/doxygen/classgraphene_1_1wallet_1_1wallet__api.html).
|
|
If you want information which is not available from an API, it might be available
|
|
from the [database](https://bitshares.github.io/doxygen/classgraphene_1_1chain_1_1database.html);
|
|
it is fairly simple to write API methods to expose database methods.
|
|
|
|
Running private testnet
|
|
-----------------------
|
|
|
|
See the [documentation](https://github.com/cryptonomex/graphene/wiki/private-testnet) if you want to run a private testnet.
|
|
|
|
Questions
|
|
---------
|
|
|
|
- Is there a way to generate help with parameter names and method descriptions?
|
|
|
|
Yes. Documentation of the code base, including APIs, can be generated using Doxygen. Simply run `doxygen` in this directory.
|
|
|
|
If both Doxygen and perl are available in your build environment, the CLI wallet's `help` and `gethelp`
|
|
commands will display help generated from the doxygen documentation.
|
|
|
|
If your CLI wallet's `help` command displays descriptions without parameter names like
|
|
`signed_transaction transfer(string, string, string, string, string, bool)`
|
|
it means CMake was unable to find Doxygen or perl during configuration. If found, the
|
|
output should look like this:
|
|
`signed_transaction transfer(string from, string to, string amount, string asset_symbol, string memo, bool broadcast)`
|
|
|
|
- Is there a way to allow external program to drive `cli_wallet` via websocket, JSONRPC, or HTTP?
|
|
|
|
Yes. External programs may connect to the CLI wallet and make its calls over a websockets API. To do this, run the wallet in
|
|
server mode, i.e. `cli_wallet -s "127.0.0.1:9999"` and then have the external program connect to it over the specified port
|
|
(in this example, port 9999).
|
|
|
|
- Is there a way to access methods which require login over HTTP?
|
|
|
|
No. Login is inherently a stateful process (logging in changes what the server will do for certain requests, that's kind
|
|
of the point of having it). If you need to track state across HTTP RPC calls, you must maintain a session across multiple
|
|
connections. This is a famous source of security vulnerabilities for HTTP applications. Additionally, HTTP is not really
|
|
designed for "server push" notifications, and we would have to figure out a way to queue notifications for a polling client.
|
|
|
|
Websockets solves all these problems. If you need to access Graphene's stateful methods, you need to use Websockets.
|
|
|
|
- What is the meaning of `a.b.c` numbers?
|
|
|
|
The first number specifies the *space*. Space 1 is for protocol objects, 2 is for implementation objects.
|
|
Protocol space objects can appear on the wire, for example in the binary form of transactions.
|
|
Implementation space objects cannot appear on the wire and solely exist for implementation
|
|
purposes, such as optimization or internal bookkeeping.
|
|
|
|
The second number specifies the *type*. The type of the object determines what fields it has. For a
|
|
complete list of type ID's, see `enum object_type` and `enum impl_object_type` in
|
|
[types.hpp](https://github.com/bitshares/bitshares-2/blob/bitshares/libraries/chain/include/graphene/chain/protocol/types.hpp).
|
|
|
|
The third number specifies the *instance*. The instance of the object is different for each individual
|
|
object.
|
|
|
|
- The answer to the previous question was really confusing. Can you make it clearer?
|
|
|
|
All account ID's are of the form `1.2.x`. If you were the 9735th account to be registered,
|
|
your account's ID will be `1.2.9735`. Account `0` is special (it's the "committee account,"
|
|
which is controlled by the committee members and has a few abilities and restrictions other accounts
|
|
do not).
|
|
|
|
All asset ID's are of the form `1.3.x`. If you were the 29th asset to be registered,
|
|
your asset's ID will be `1.3.29`. Asset `0` is special (it's BTS, which is considered the "core asset").
|
|
|
|
The first and second number together identify the kind of thing you're talking about (`1.2` for accounts,
|
|
`1.3` for assets). The third number identifies the particular thing.
|
|
|
|
- How do I get the `network_add_nodes` command to work? Why is it so complicated?
|
|
|
|
You need to follow the instructions in the "Accessing restricted API's" section to
|
|
allow a username/password access to the `network_node` API. Then you need
|
|
to pass the username/password to the `cli_wallet` on the command line or in a config file.
|
|
|
|
It's set up this way so that the default configuration is secure even if the RPC port is
|
|
publicly accessible. It's fine if your `witness_node` allows the general public to query
|
|
the database or broadcast transactions (in fact, this is how the hosted web UI works). It's
|
|
less fine if your `witness_node` allows the general public to control which p2p nodes it's
|
|
connecting to. Therefore the API to add p2p connections needs to be set up with proper access
|
|
controls.
|
|
|