diff --git a/docs/source/daemon.rst b/docs/source/daemon.rst index 22b6f05..4ffc698 100644 --- a/docs/source/daemon.rst +++ b/docs/source/daemon.rst @@ -1,5 +1,141 @@ Interacting with daemon ======================= +The module offers an interface to interact with Monero daemon. For the time being, like with +wallet, the only available backend is JSON RPC. + +.. code-block:: python + + In [1]: from monero.daemon import Daemon + + In [2]: from monero.backends.jsonrpc import JSONRPCDaemon + + In [3]: daemon = Daemon(JSONRPCDaemon(port=28081)) + + In [4]: daemon.height() + Out[4]: 1099108 + +Also, the ``info()`` method will return a dictionary with details about the current daemon status. + +Sending prepared transactions +----------------------------- + +The daemon connection may be used for two-step sending of transactions. For example, you may want +to check the fee before broadcasting the transaction to the network. + +To prepare a transaction, use ``transfer()`` or ``transfer_multiple()`` method of the wallet or +account, as described in :ref:`the section about sending payments `. +The only difference is that now you want to add the ``relay=False`` argument. + +.. code-block:: python + + In [5]: from monero.wallet import Wallet + + In [6]: from monero.backends.jsonrpc import JSONRPCWallet + + In [7]: wallet = Wallet(JSONRPCWallet(port=28088)) + + In [8]: wallet.balance() + Out[8]: Decimal('17.642325205670') + + In [9]: txs = wallet.transfer('Bg1nUjsEx6UUByxr68o6gXcQRF58BpQyKauoZSo2HwubGErEnz9x6AS9o5ybmk3QmgeUpX3Msgm74QkwZKx2CeVWFrrZZqt', 10, relay=False) + +Now the return value is a list of resulting transactions (usually just one) which may be inspected +and validated. + +.. code-block:: python + + In [10]: txs + Out[10]: [38964a0c8c3be041051464b413996ad8d696223dc34925d98156848ed76a3ae3] + + In [11]: txs[0].fee + Out[11]: Decimal('0.003766080000') + +If anything is not OK, just discard the transaction and create a new one. There's no need to clean +up anything in the wallet. + +Once you have the transaction accepted, it's time to post it to the daemon: + +.. code-block:: python + + In [12]: result = daemon.send_transaction(txs[0]) + + In [13]: result + Out[13]: + {'double_spend': False, + 'fee_too_low': False, + 'invalid_input': False, + 'invalid_output': False, + 'low_mixin': False, + 'not_rct': False, + 'not_relayed': False, + 'overspend': False, + 'reason': '', + 'status': 'OK', + 'too_big': False} + +No batching due to double spends +-------------------------------- + +.. warning:: The workflow described above should not be used for preparing a batch of transactions + to be sent later. The wallet doesn't remember which inputs have been spent and will very likely + use the same in the next transaction, resulting in a double spend and broadcast failure. + +The following example shows such behavior: + +.. code-block:: python + + In [14]: txs1 = wallet.transfer('BYSXsmmK44xdjNVMGprUW5Yau9tsc9SAMJrQsANjGgpk2RB83cvVhWjZAgYNwLgmhdPawATh5q1CTEoLGKZSeZqtThefV7D', 1, relay=False) + + In [15]: txs2 = wallet.transfer('Bd5m5wTjWdYSaLBKe4i2avJjuFLYMEUKpiiE86F83NFiDXKE7QseSRvS7efTtJu5xHiHm5XmxgB2mfLu7NFrG7e3UTYRzEf', 2, relay=False) + + In [16]: txs1, txs2 + Out[16]: + ([315901f250a1018e89e1fc2b3953bd5acfdfa759f843cf5a38306a2255de6d54], + [2bd978172226b486badc8a9dcbafb04acb4760c3f2a5794c694fee8575739c6e]) + + In [17]: daemon.send_transaction(txs1[0]) + Out[17]: + {'double_spend': False, + 'fee_too_low': False, + 'invalid_input': False, + 'invalid_output': False, + 'low_mixin': False, + 'not_rct': False, + 'not_relayed': False, + 'overspend': False, + 'reason': '', + 'status': 'OK', + 'too_big': False} + + In [18]: daemon.send_transaction(txs2[0]) + --------------------------------------------------------------------------- + TransactionBroadcastError Traceback (most recent call last) + in () + ----> 1 daemon.send_transaction(txs2[0]) + + ~/devel/monero-python/monero/daemon.py in send_transaction(self, tx, relay) + 10 + 11 def send_transaction(self, tx, relay=True): + ---> 12 return self._backend.send_transaction(tx.blob, relay=relay) + 13 + 14 def mempool(self): + + ~/devel/monero-python/monero/backends/jsonrpc.py in send_transaction(self, blob, relay) + 36 raise exceptions.TransactionBroadcastError( + 37 "{status}: {reason}".format(**res), + ---> 38 details=res) + 39 + 40 def mempool(self): + + TransactionBroadcastError: Failed: double spend + +The second transaction failed because it used the same inputs as the previous one. The daemon +checks all incoming transactions for possible double-spends and rejects them if such conflict +is discovered. + +API reference +------------- + .. automodule:: monero.daemon :members: diff --git a/docs/source/transactions.rst b/docs/source/transactions.rst index 47e3c4e..b40b286 100644 --- a/docs/source/transactions.rst +++ b/docs/source/transactions.rst @@ -177,6 +177,8 @@ and ``unconfirmed`` query parameters that accept boolean values: You may as well query for both confirmed and unconfirmed transactions using ``wallet.incoming(unconfirmed=True)`` (the default value for ``confirmed`` is ``True``). +.. _sending-payments: + Sending payments ----------------