Browse Source

RPC maker/start returns 409 error if no coins

Fixes #1120. As per the discussion in that issue, while
we can only return 'processing started' by default, and
the client must monitor progress/state to see if the maker
service has connected successfully, nevertheless if the
maker startup is immediately invalidated by the fact that
the already-synced wallet does not contain confirmed coins,
we can and should return an error message instead of a 202.
This commit does that, adding to the spec a 409-No-Coins
response type which indicates to the API client that the
setup of the maker failed for this specific reason.
master
Adam Gibson 4 years ago
parent
commit
bd33b6d498
No known key found for this signature in database
GPG Key ID: 141001A1AF77F20B
  1. 2
      jmclient/jmclient/__init__.py
  2. 3
      jmclient/jmclient/wallet-rpc-api.md
  3. 10
      jmclient/jmclient/wallet-rpc-api.yaml
  4. 36
      jmclient/jmclient/wallet_rpc.py
  5. 10
      jmclient/jmclient/yieldgenerator.py

2
jmclient/jmclient/__init__.py

@ -61,7 +61,7 @@ from .wallet_utils import (
from .wallet_service import WalletService
from .maker import Maker
from .yieldgenerator import YieldGenerator, YieldGeneratorBasic, ygmain, \
YieldGeneratorService, YieldGeneratorServiceSetupFailed
YieldGeneratorService
from .snicker_receiver import SNICKERError, SNICKERReceiver, SNICKERReceiverService
from .payjoin import (parse_payjoin_setup, send_payjoin,
JMBIP78ReceiverManager)

3
jmclient/jmclient/wallet-rpc-api.md

@ -287,7 +287,7 @@ Start the yield generator service.
##### Description
Start the yield generator service with the configuration settings specified in the POST request. Note that if fidelity bonds are enabled in the wallet, and a timelock address has been generated, and then funded, the fidelity bond will automatically be advertised without any specific configuration in this request.
Start the yield generator service with the configuration settings specified in the POST request. Note that if fidelity bonds are enabled in the wallet, and a timelock address has been generated, and then funded, the fidelity bond will automatically be advertised without any specific configuration in this request. Note that if the wallet does not have confirmed coins, or another taker or maker coinjoin service is already running, the maker will not start.
##### Parameters
@ -303,6 +303,7 @@ Start the yield generator service with the configuration settings specified in t
| 400 | Bad request format. |
| 401 | Unable to authorise the credentials that were supplied. |
| 404 | Item not found. |
| 409 | Maker could not start without confirmed balance. |
| 503 | The server is not ready to process the request. |
##### Security

10
jmclient/jmclient/wallet-rpc-api.yaml

@ -234,7 +234,7 @@ paths:
- bearerAuth: []
summary: Start the yield generator service.
operationId: startmaker
description: Start the yield generator service with the configuration settings specified in the POST request. Note that if fidelity bonds are enabled in the wallet, and a timelock address has been generated, and then funded, the fidelity bond will automatically be advertised without any specific configuration in this request.
description: Start the yield generator service with the configuration settings specified in the POST request. Note that if fidelity bonds are enabled in the wallet, and a timelock address has been generated, and then funded, the fidelity bond will automatically be advertised without any specific configuration in this request. Note that if the wallet does not have confirmed coins, or another taker or maker coinjoin service is already running, the maker will not start.
parameters:
- name: walletname
in: path
@ -259,6 +259,8 @@ paths:
$ref: '#/components/responses/401-Unauthorized'
'404':
$ref: '#/components/responses/404-NotFound'
'409':
$ref: '#/components/responses/409-No-Coins'
'503':
$ref: '#/components/responses/503-ServiceUnavailable'
/wallet/{walletname}/maker/stop:
@ -859,6 +861,12 @@ components:
application/json:
schema:
$ref: '#/components/schemas/ErrorMessage'
409-No-Coins:
description: Maker could not start without confirmed balance.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorMessage'
404-NotFound:
description: Item not found.
content:

36
jmclient/jmclient/wallet_rpc.py

@ -21,8 +21,7 @@ from jmclient import Taker, jm_single, \
create_wallet, get_max_cj_fee_values, \
StorageError, StoragePasswordError, JmwalletdWebSocketServerFactory, \
JmwalletdWebSocketServerProtocol, RetryableStorageError, \
SegwitWalletFidelityBonds, wallet_gettimelockaddress, \
YieldGeneratorServiceSetupFailed
SegwitWalletFidelityBonds, wallet_gettimelockaddress
from jmbase.support import get_log
jlog = get_log()
@ -84,6 +83,11 @@ class ServiceNotStarted(Exception):
class TransactionFailed(Exception):
pass
# raised when we tried to start a Maker,
# but the wallet was empty/not enough.
class NotEnoughCoinsForMaker(Exception):
pass
def get_ssl_context(cert_directory):
"""Construct an SSL context factory from the user's privatekey/cert.
TODO:
@ -289,6 +293,12 @@ class JMWalletDaemon(Service):
request.setResponseCode(409)
return self.err(request, "Transaction failed.")
@app.handle_errors(NotEnoughCoinsForMaker)
def not_enough_coins(self, request, failure):
# as above, 409 may not be ideal
request.setResponseCode(409)
return self.err(request, "Maker could not start, no coins.")
def check_cookie(self, request):
#part after bearer is what we need
try:
@ -560,14 +570,26 @@ class JMWalletDaemon(Service):
self.activate_coinjoin_state(CJ_NOT_RUNNING)
def setup():
# note this returns False if we cannot update the state.
return self.activate_coinjoin_state(CJ_MAKER_RUNNING)
if not self.activate_coinjoin_state(CJ_MAKER_RUNNING):
raise ServiceAlreadyStarted()
# don't even start up the service if there aren't any coins
# to offer:
def setup_sanitycheck_balance():
# note: this will only be non-zero if coins are confirmed.
# note: a call to start_maker necessarily is after a successful
# sync has already happened (this is different from CLI yg).
# note: an edge case of dusty amounts is lost here; it will get
# picked up by Maker.try_to_create_my_orders().
if not len(self.wallet_service.get_balance_by_mixdepth(
verbose=False, minconfs=1)) > 0:
raise NotEnoughCoinsForMaker()
self.services["maker"].addCleanup(cleanup)
self.services["maker"].addSetup(setup)
self.services["maker"].addSetup(setup_sanitycheck_balance)
# Service startup now checks and updates coinjoin state:
try:
self.services["maker"].startService()
except YieldGeneratorServiceSetupFailed:
raise ServiceAlreadyStarted()
self.services["maker"].startService()
return make_jmwalletd_response(request, status=202)
@app.route('/wallet/<string:walletname>/maker/stop', methods=['GET'])

10
jmclient/jmclient/yieldgenerator.py

@ -268,9 +268,6 @@ class YieldGeneratorBasic(YieldGenerator):
cjoutmix = (input_mixdepth + 1) % (self.wallet_service.mixdepth + 1)
return self.wallet_service.get_internal_addr(cjoutmix)
class YieldGeneratorServiceSetupFailed(Exception):
pass
class YieldGeneratorService(Service):
def __init__(self, wallet_service, daemon_host, daemon_port, yg_config):
self.wallet_service = wallet_service
@ -292,8 +289,11 @@ class YieldGeneratorService(Service):
no need to check this here.
"""
for setup in self.setup_fns:
if not setup():
raise YieldGeneratorServiceSetupFailed
# we do not catch Exceptions in setup,
# deliberately; this must be caught and distinguished
# by whoever started the service.
setup()
# TODO genericise to any YG class:
self.yieldgen = YieldGeneratorBasic(self.wallet_service, self.yg_config)
self.clientfactory = JMClientProtocolFactory(self.yieldgen, proto_type="MAKER")

Loading…
Cancel
Save