From 37bbdbe52a5411d42d30a87bab8586fa687a1a86 Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Tue, 25 Dec 2018 10:25:48 +0300 Subject: [PATCH] fix: iguana autosplit / acsplit issue this was a most hard to find and hard to debug issue, bcz sometimes iguana did splitfunds correctly and sometimes not. nobody tried to help me to catch the "wrong state" in which it fails, despite all provided instructions. i spent all night along to catch the state of utxos in which splitfunds guarantee fails. so, i have only wallet.dat state and just every acsplit try fails on it. this was a half of victory. second stage was debugging iguana and komodod sources, adding printouts for preimage calculation, printouts for hashes, printouts for everything, launching gdb under VSCode and other things. and after spent ~24 hours of continuous work i found root of the issue. it was in spendamount (!) ... i found that dpow_gettxout returns 34.26707593 in "value" field. but after conversion to uint_64 it becomes 34.26707592 . for non-sapling enabled chains seems nothing hurts, but since sapling activated in KMD and assetchains it's significantly. bcz according to zip-243 https://github.com/zcash/zips/blob/master/zip-0243.rst amount field is a part of preimage calculation. and as we have wrong spendamount we have a wrong sighash when calc crypto_generichash_blake2b_salt_personal with sig_hash_personal = ZCASH_SIG_HASH_SAPLING_PERSONALIZATION . Look at the "Test vector 3" in ZIP-243 and amount field in preimage and you will understand the bug. Sometimes double -> uint64_t was fine and splitfunds is success, but sometimes (depends on double representation of value) it was wrong and splitfunds fails. That's why it was so hard to catch and fix. But now, seems the issue is fixed! --- iguana/iguana_sign.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index 9b3a2f510..cb1dc4c35 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -33,6 +33,24 @@ const unsigned char ZCASH_SIG_HASH_SAPLING_PERSONALIZATION[16] = const unsigned char ZCASH_SIG_HASH_OVERWINTER_PERSONALIZATION[16] = { 'Z','c','a','s','h','S','i','g','H','a','s','h', '\x19', '\x1B', '\xA8', '\x5B' }; +uint64_t amountfromvalue(double value) { + +// http://c-faq.com/fp/round.html + +/* double frac = value - (uint64_t)value; + double whole = value - frac; + char frac_str[64], whole_str[64], *stopstring; + snprintf(frac_str, sizeof(frac_str), "%.8f", frac); + snprintf(whole_str, sizeof(whole_str), "%.8f", whole); + frac = strtod(frac_str, &stopstring); + whole = strtod(whole_str, &stopstring); + frac = frac * SATOSHIDEN; + whole = whole * SATOSHIDEN; + return (uint64_t)whole + (uint64_t)frac; +*/ + +return (uint64_t)(value * SATOSHIDEN + 0.5); +} int32_t iguana_rwjoinsplit(int32_t rwflag,uint8_t *serialized,struct iguana_msgjoinsplit *msg, uint32_t proof_size); // defined in iguana_msg.c @@ -1033,7 +1051,8 @@ int32_t iguana_rwmsgtx(struct iguana_info *coin,int32_t height,int32_t rwflag,cJ struct supernet_info *myinfo = SuperNET_MYINFO(0); cJSON *jtxout = 0; jtxout = dpow_gettxout(0, coin, msg->vins[i].prev_hash, msg->vins[i].prev_vout); - spendamount = jdouble(jtxout, "value") * SATOSHIDEN; + //spendamount = jdouble(jtxout, "value") * SATOSHIDEN; + spendamount = amountfromvalue(jdouble(jtxout, "value")); //printf("JSON (txout): %s\n", cJSON_Print(jtxout)); //printf("spendamount = %.8f\n", dstr(spendamount)); free(jtxout); @@ -1355,7 +1374,8 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,int32_t height,bits256 *sign struct supernet_info *myinfo = SuperNET_MYINFO(0); cJSON *jtxout = 0; jtxout = dpow_gettxout(0, coin, msgtx->vins[vini].prev_hash, msgtx->vins[vini].prev_vout); - spendamount = jdouble(jtxout, "value") * SATOSHIDEN; + //spendamount = jdouble(jtxout, "value") * SATOSHIDEN; + spendamount = amountfromvalue(jdouble(jtxout, "value")); //printf("JSON (txout): %s\n", cJSON_Print(jtxout)); //printf("spendamount = %.8f\n", dstr(spendamount)); free(jtxout);