BitBotFactory / MikaLendingBot

Automated lending on Cryptocurrency exchanges Poloniex and Bitfinex
http://poloniexlendingbot.readthedocs.io/en/latest/index.html
MIT License
1.11k stars 344 forks source link

Nonce is too small (Bitfinex) #470

Closed cfatduck closed 7 years ago

cfatduck commented 7 years ago

Got "Nonce is too small" message frequently.

2017-08-18 16:47:08 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/balances Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/balances reading from exchange API, ignoring.

rnevet commented 7 years ago

You shouldn't reuse API keys.

cfatduck commented 7 years ago

Nope. Even I created a new one, I am still getting the message for some time. I am expecting 0 message like this for a brand new API key.

cfatduck commented 7 years ago

I am testing the nonce function with below. If this helps, I will submit a PR.

return str(int(round(time.time() * 10000)))

rnevet commented 7 years ago

Hmm.. I don't think it's an issue of the nonce function. It is working since a long time, nonce is a simple thing... every call should have a bigger nonce. If keys aren't being used, only other reason is that calls are prepared and handled in a different order or something, might be a Bitfinex issue.

cfatduck commented 7 years ago

For this str(time.time()), it returns

>>> str(time.time())
'1503050009.62'
>>> str(time.time())
'1503050010.15'
>>> str(time.time())
'1503050010.47'
>>> str(time.time())
'1503050010.65'
>>> str(time.time())
'1503050010.81'
>>> str(time.time())
'1503050010.94'
>>> str(time.time())
'1503050011.07'
>>> str(time.time())

If the decimals are ignored and the bot make multiple API requests in a short period of time. Chances are "Nonce is too small" response is generated from Bitfinex.

rnevet commented 7 years ago

You are correct, Poloniex nonce uses a multiplier. https://github.com/BitBotFactory/poloniexlendingbot/blob/master/modules/Poloniex.py#L109

ououmin commented 7 years ago

I have the same problem. Create new API key was not effective.

mark-995 commented 7 years ago

I am having the same issue, already tried to change api

rnevet commented 7 years ago

I one of you guys @ououmin @CyberBaby @mark-995 will confirm that multiplying the time by 1000 on this line: https://github.com/BitBotFactory/poloniexlendingbot/blob/master/modules/Bitfinex.py#L32 Solves the issue, I'll make the change.

return str(time.time()  * 1000)
ououmin commented 7 years ago

I think it works. No more 'nonce' message. Thanks.

rnevet commented 7 years ago

@ououmin can you check the following:

return  str(int(time.time()) * 1000)
ououmin commented 7 years ago

I used code of @CyberBaby . return str(int(round(time.time() * 1000))) And it works good.

rnevet commented 7 years ago

Pushed a fix to master.

ououmin commented 7 years ago

Not good. I saw "Nonce is too small." message again, just a moment ago. :( But I haven't seen it for a long time.

rnevet commented 7 years ago

@ououmin What env are you using?

ououmin commented 7 years ago

@rnevet Running bot at pythonanywhere.com

cfatduck commented 7 years ago

This is not a perm fix. Still looking for a solution.

cfatduck commented 7 years ago
https://api.bitfinex.com/v1/pubticker/btcusd
150328556863691
https://api.bitfinex.com/v1/offers
150328556930958
https://api.bitfinex.com/v1/balances
150328556984182
https://api.bitfinex.com/v1/credits
150328557022396
https://api.bitfinex.com/v1/credits
150328557036593
https://api.bitfinex.com/v1/balances
Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits

not sure why still getting Nonce is too small.

cfatduck commented 7 years ago

Limiting the supported currencies seems help. (If you don't have other currency to lend)


[BITFINEX]
#Full list of supported currencies
all_currencies = BTC
mahiso commented 7 years ago

The problem is the usage of time.time(). Documentation says: "Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls."

I observed same issue on Poloniex, same nonce method.

Concrete in our case two possible causes:

rnevet commented 7 years ago

I agree, it seems to be platform dependent... my test environment, and Digital Ocean do not present this issue. However I did find some suggestion on how to get a more precise time calculation.

JCBauza commented 7 years ago

I just had this issue as well, it started today pretty much. I was running without it for several hours but then it started: Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits

utdrmac commented 7 years ago

I've been running Bitfinex for over 2 weeks on my server at home (Debian 7) without any issue like this.

JCBauza commented 7 years ago

It happens seemingly at random times. Perhaps it has to do with the number of coins being lent? too many calls too close to each other or something? Mine is running on a VM with 24 virtual processors so not sure if there is multithreading or something causing this. I am just throwing darts in the dark here.

$ python2.7 lendingbot.py Welcome to Lending Bot on BITFINEX WARN: Incorrect coin entered for transferCurrencies: DSH WARN: Incorrect coin entered for transferCurrencies: OMG WARN: Incorrect coin entered for transferCurrencies: IOT WARN: Incorrect coin entered for transferCurrencies: BTC WARN: Incorrect coin entered for transferCurrencies: XRP Error in MarketAnalysis: API Error 429: { "error": "ERR_RATE_LIMIT"} Requesting https://api.bitfinex.com/v1/lendbook/ZEC?limit_asks=5&limit_bids=5 WARN: Incorrect coin entered for transferCurrencies: ZEC WARN: Incorrect coin entered for transferCurrencies: EOS WARN: Incorrect coin entered for transferCurrencies: LTC WARN: Incorrect coin entered for transferCurrencies: ETH 2017-08-24 14:23:55 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new reading from exchange API, ignoring. 2017-08-24 14:31:01 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new reading from exchange API, ignoring. Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits 2017-08-24 15:54:27 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new reading from exchange API, ignoring. 2017-08-24 15:56:21 Error HTTPSConnectionPool(host='api.bitfinex.com', port=443): Read timed out. (read timeout=30) Requesting https://api.bitfinex.com/v1/offer/new Timed out, will retry in 60.0sec Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits 2017-08-24 17:00:33 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new reading from exchange API, ignoring. 2017-08-24 17:59:22 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits reading from exchange API, ignoring. 2017-08-24 18:00:22 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits reading from exchange API, ignoring. 2017-08-24 18:03:25 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits reading from exchange API, ignoring. Error in MarketAnalysis: HTTPSConnectionPool(host='api.bitfinex.com', port=443): Read timed out. (read timeout=30) Requesting https://api.bitfinex.com/v1/lendbook/OMG?limit_asks=5&limit_bids=5 Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits 2017-08-24 19:13:26 Error API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new Caught API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/offer/new reading from exchange API, ignoring. Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits

utdrmac commented 7 years ago

Why don't you edit the code and have it print the nonce out to console on each API call? Then you can indeed see if it is repeating them.

JCBauza commented 7 years ago

Can you help me with the file/line and code if possible? I've only done .Net and I am not familiar with the code of the bot but willing to help debug this. Thank you!

utdrmac commented 7 years ago

modules/Bitfinex.py:32

Give it a try and if you can't get it to print, I've got code I just tested that works.

Here's the answer if you can't figure it out: https://ghostbin.com/paste/faz3c

cfatduck commented 7 years ago

I've tried to print the nonce, it was never repeated. But i am still getting the error. Running on a Pi3.

JCBauza commented 7 years ago

I'll post once the error happens again. Thus far nothing...

JCBauza commented 7 years ago

This isn't terribly helpful:

NONCE: 1503640740291 NONCE: 1503640740609 Error during new loans notification: API Error 400: {"message":"Nonce is too small."} Requesting https://api.bitfinex.com/v1/credits NONCE: 1503640740945

utdrmac commented 7 years ago

Hrm. You are 100% positive you are not using this API key anywhere else?

JCBauza commented 7 years ago

Yes. I created a new one just for this bot and have it only on one computer.

JCBauza commented 7 years ago

Just sent a support request to Bitfinex because I see no reason why the nonce is getting bounced. It is increasing as it should and it is consistent with all the other ones.

rnevet commented 7 years ago

@JCBauza any update?

JCBauza commented 7 years ago

haven't heard back from them yet :(

bwinckel commented 7 years ago

Hey @JCBauza, still no answer from bitfinex support? Thanks

JCBauza commented 7 years ago

Just heard back today: I may be wrong but I see this happening when you send two messages in rapid succession (NONCE: 1503681995631, 1503681995980 = 349ms, and NONCE: 1503682056864, 1503682056880 = 16ms).

It is possible that using REST services, a certain amount of network lag could interfere with message delivery order and trigger that "Nonce too small" error.

In order to verify my theory, please try again to see if this happens again waiting 500-800ms between requests.

bwinckel commented 7 years ago

Thanks for your answer.

I was already waiting 1 second between each API call, but still had the issue. I figured it out by increasing numbers of digits I send to the endpoint.

In PHP I now use this method to generate nonce, and this is working:

$nonce = (string) number_format(round(microtime(true) * 10000000), 0, '.', '');

Hope this can help.

laxdog commented 7 years ago

Been looking at this myself also. I've changed a few things and raised a PR:

1) The number was being rounded. I don't see why this is needed. I thought it was part of the issue initially, but I'm not sure now. If the second call to time returns a slightly lower value (see py doc below), close to .5 it would be rounded down and be lower than the first then. Though I think the same thing would happen with the 1.0 boundary. Anyway, it's redundant. 2) I've increase the multiplier from 1000 to 100000, which should decrease the chance of collisions. Note however, this is OS dependent. (see below)

time.time()

    Return the time in seconds since the epoch as a floating point number. Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls.

I've been running this in my on env (where I've seen nonce problems) with no issues for a while now. I'll let it run 24 hours.

https://github.com/BitBotFactory/poloniexlendingbot/pull/520

utdrmac commented 7 years ago

I've got this code running on another bot that, on start, determines what your starting nonce should be. And every so often it does a check to update it again. Maybe something similar could be implemented?

    def getNonceStart(self):
        post = "command=returnFeeInfo&nonce=1"
        headers = self.getPostHeaders(post)
        resp = False
        while not resp:
            resp = self.curlRequest("https://" + self.polo_ip + "/tradingApi", self.getPostHeaders(post), post)
            if not resp or "\"error\":\"Nonce" not in resp:
                print("Failed to retrieve nonce from poloniex, retrying in 30 seconds.")
                time.sleep(30)
        self.nonce = re.search("greater than (\d+)", resp)
        self.nonce = int(self.nonce.group(1)) + 1
        print("Got nonce " + str(self.nonce) + " from poloniex.")
rnevet commented 7 years ago

@utdrmac, that depends on a response containing the nonce from Poloniex "greater than...", is there one from Bitfinex? I also don't think this should be necessary as time should be a good enough nonce base.

JCBauza commented 7 years ago

I am not having the issue after the fix, thanks @laxdog !

walacemaia commented 6 years ago

I have resolved this problem in the follow way. In my case I have many threads interacting with Bitfinex, so I had to synchronize the getNonce method.

/**
 * nonce to exchange api requests.
 */
private static long nonce = System.currentTimeMillis();

private static void sleep(long millis) {
    try {
        Thread.sleep(millis);
    } catch (InterruptedException e) {
        Logger.log(e.getMessage());
        e.printStackTrace();
    }
}

/**
 * Generate nonce.
 * 
 * @return generated nonce.
 */
protected synchronized static long getNonce() {
    // Sleep 100 milliseconds to avoid too close exchange api requests.
    sleep(100);
    return nonce++;
}
rnevet commented 6 years ago

The POSt, GET methods are synced in current version.

walacemaia commented 6 years ago

But the question here is to guarantee that the threads get the nonce and then send the posts in the same order (the first to get is the first to call the post method). If two threads sleep at the same time this is not guaranteed.

rnevet commented 6 years ago

As the entire call is synced and nonce is only called from within then this should be guaranteed.