Skip to content

Commit

Permalink
howto-exchanges
Browse files Browse the repository at this point in the history
  • Loading branch information
xeroc committed Sep 22, 2015
1 parent 0ae97a8 commit 3a58099
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 4 deletions.
204 changes: 204 additions & 0 deletions docs/howto-exchanges.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
Howto Interface your Exchange with Graphene
===========================================

It is recommended that the developer reads and understands the content of the
following articles:

.. toctree::
:maxdepth: 2

graphene-objects
graphene-api
graphene-ws
witness
wallet
rpc

Additionally, to get in touch with the implementation details an example script
is provided in :doc:`scripts-monitor`.

Delayed Witness Node
--------------------

Similar to other crypto currencies, it is recommended to wait for several
confirmations of a transcation. Even though the consensus scheme of Graphene is
alot more secure than regular proof-of-work or other proof-of-stake schemes, we
still support exchanges that require more confirmations for deposits.

We provide a so called *delayed* witness node which accepts two additional
parameters for the configuration besides those already available with the
standard daemon (read :doc:`witness`).

* `trusted-node` RPC endpoint of a trusted validating node (required)
* `delay-block-count` Number of blocks to delay before advancing chain state (required)

The trusted-node is a regular witness node directly connected to the P2P
network that works as a proxy. The `delay-block-count` gives the number of
blocks that the delayed witness node will be behind the real blockchain.

Network Setup for this Tutorial
-------------------------------

In the following, we will setup and use the following network.

P2P network <-> trusted witness node <-> delayed witness <-> API

Note that, for our monitoring script, we will only interface with the delayed witness.

For the trusted witness node, the default settings can be used, while for the
delaed witness node we will need to provide the IP address and port of the
p2p-endpoint from the trusted witness node. The delayed witness node will need
to open a RPC/Websocket port (to the local network!) so that we can interface
using RPC-JSON calls.

Interfacing via RPC and Websockets
----------------------------------

In order to access the websocket functionalities, we can extend the
`GrapheneWebsocketProtocol` class.

.. code-block:: python
import json
from grapheneapi import GrapheneWebsocket, GrapheneWebsocketProtocol
if __name__ == '__main__':
api = GrapheneWebsocket("localhost", 8090, "", "")
api.connect()
api.run_forever()
This example will not do anything.

Subscribing to Account Changes
------------------------------

Let's subscribe to modifications and have it printed out on screen

.. code-block:: python
api = GrapheneWebsocket("localhost", 8090, "", "")
api.setObjectCallbacks({ "2.6.69491" : print })
api.connect()
api.run_forever()
Hooking Up
----------

To have a more complex interaction with the wallet, we can either make use of
state-less RPC-calls to API-0 or use the websocket connection with callbacks to
access API-1:

* API-0: `api.info()`, `api.get_*()`, ...
* API-1: `api.ws_exec([call], callback)`

To do so, we extend the default websockets protocol with

.. code-block:: python
class GrapheneMonitor(GrapheneWebsocketProtocol) :
def __init__(self) :
super().__init__()
and ..

.. code-block:: python
protocol = GrapheneMonitor
api = GrapheneWebsocket(host, port, user, password, protocol)
As an example, we can have notifications for all incoming transactions for any account:

.. code-block:: python
from grapheneapi import GrapheneWebsocket, GrapheneWebsocketProtocol
class GrapheneMonitor(GrapheneWebsocketProtocol) :
last_op = "1.11.0"
account_id = "1"
def __init__(self) :
super().__init__()
def printJson(self,d) : print(json.dumps(d,indent=4))
def onAccountUpdate(self, data) :
# Get Operation ID that modifies our balance
opID = api.getObject(data["most_recent_op"])["operation_id"]
self.wsexec([self.api_ids["history"],
"get_account_history",
[self.account_id, self.last_op, 100, "1.11.0"]
], self.process_operations)
self.last_op = opID
def process_operations(self, operations) :
for operation in operations[::-1] :
opID = operation["id"]
block = operation["block_num"]
op = operation["op"][1]
# Get assets involved in Fee and Transfer
fee_asset = api.getObject(op["fee"]["asset_id"])
amount_asset = api.getObject(op["amount"]["asset_id"])
# Amounts for fee and transfer
fee_amount = op["fee"]["amount"] / float(10**int(fee_asset["precision"]))
amount_amount= op["amount"]["amount"] / float(10**int(amount_asset["precision"]))
# Get accounts involved
from_account = api.getObject(op["from"])
to_account = api.getObject(op["to"])
# Print out
print("last_op: %s | block:%s | from %s -> to: %s | fee: %f %s | amount: %f %s" % (
opID, block,
from_account["name"], to_account["name"],
fee_amount, fee_asset["symbol"],
amount_amount, amount_asset["symbol"]))
if __name__ == '__main__':
host = "localhost"
port = 8090
user = ""
password = ""
protocol = GrapheneMonitor
protocol.last_op = last_op ## last operation logged
protocol.account_id = "1.2.%s" % accountID.split(".")[2] ## account to monitor
api = GrapheneWebsocket(host, port, user, password, protocol)
api.setObjectCallbacks({accountID : protocol.onAccountUpdate})
api.connect()
api.run_forever()
Note, that in order to decode the memo associated with a given transaction, we
need the memo private key.

Decoding the Memo
-----------------

The memo public key can be obtained from the account settings or via command line:::

get_account myaccount

in the cli wallet. The corresponding private key can be obtain from:::

dump_private_keys

Note that the latter command exposes all private keys in clear-text wif.

The encrypted memo can be decoded with:

.. code-block:: python
from graphenebase import Memo, PrivateKey, PublicKey
memo_wif_key = "<wif-key>"
""" PubKey Prefix
Productive network: BTS
Testnetwork: GPH """
prefix = "GPH"
#prefix = "BTS"
privkey = PrivateKey(memo_wif_key)
pubkey = PublicKey(memo["from"], prefix=prefix)
memomsg = Memo.decode_memo(privkey, pubkey, memo["nonce"], memo["message"])
Complete Example
----------------

A full example is provided as `monnitor.py` in the `examples/` directory.
19 changes: 15 additions & 4 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@
Welcome to python-graphenelib's documentation!
===============================================

Contents:

General
-------
.. toctree::
:maxdepth: 2

General
-------
graphene
graphene-objects
graphene-api
Expand All @@ -28,6 +26,9 @@ General

Python Libraries
----------------
.. toctree::
:maxdepth: 2

installation
address
base58
Expand All @@ -36,8 +37,18 @@ Python Libraries

Examples
--------
.. toctree::
:maxdepth: 2

scripts-monitor

Howto
-----
.. toctree::
:maxdepth: 2

howto-exchanges

Indices and tables
==================

Expand Down

0 comments on commit 3a58099

Please sign in to comment.