freicoin / freicoin-old

Bitcoin integration/staging tree
http://www.bitcoin.org
MIT License
26 stars 8 forks source link

Distributive Property failure #5

Closed mhredmond21 closed 12 years ago

mhredmond21 commented 12 years ago

Test output:

test/transaction_tests.cpp(88): error in "test_Get": 0 back - inputs = 93000000 outputs = 93000000 test/transaction_tests.cpp(89): error in "test_Get": 20 back - inputs = 92998225 outputs = 92998226

For some reason t1.vout with nValue = 94 is evaluating differently than 3 input transactions grabbing outputs with values 51, 21, and 22.

I had to make some additional changes to the code to get this to work which I cannot commit because they would break the program.

I will continue to investigate.

https://github.com/mhredmond21/freicoin/commit/b5d11bd7af050d3b167583475887d9acd6cef029

maaku commented 12 years ago

I have a hypothosis about this. Demurrage is actually calculated via 128-bit software floating point with explicit precision and truncation (that's what the MPFR library is for). It's possible then that the combined inputs of 51 + 21 + 22 would differ from an input of 94 by a couple of satoshis.

I'll test this theory to make sure, but it might take a little time.

maaku commented 12 years ago

To clarify, if that explanation is correct, this is expected behavior and the test just needs to be modified.

mhredmond21 commented 12 years ago

I think the problem is a failure of the distributive property, meaning A * (x1 + x2 + x3) does not equal A* x1 + A * x2 + A * x3 . Where A, in this case, is the interest rate multiplication factor. This will always be the case unless we use mpfr to represent values all of the time. I think this shouldn't affect the calculations because it seems that you're always sending extra to cover 12 blocks worth of demurrage. I would hope that 12 blocks would be more than any rounding errors.

maaku commented 12 years ago

More to the point you will always be using SelectCoins() from the wallet api to build transactions in the first place, and SelectCoins() as it is currently written correctly handles this issue (it calls GetValueIn() where the rounding occurs, and if resulting value is less than the output, more coins are added). If my theory is correct, this unit test's hand-crafted transaction was done incorrectly and simply doesn't match a real use scenario.

It remains to be seen, however. Hopefully I'll have time to look at this tomorrow.

maaku commented 12 years ago

In this particular case, that doesn't seem to be the issue. The following test program:

#include <stdint.h>
#include <inttypes.h>
#include <mpfr.h>
#include <stdio.h>
typedef long int64;
int64 GetPresentValue(int64 nInitialValue, int nRelativeDepth)
{
    int64 nResult;
    if ( !nRelativeDepth )
        nResult = nInitialValue;
    else {
        mpfr_t rate, mp, init;
        mpfr_inits2(128, rate, mp, init, (mpfr_ptr) 0);
        mpfr_set_ui(mp,       1048575,        MPFR_RNDN);
        mpfr_div_ui(rate, mp, 1048576,        MPFR_RNDN);
        mpfr_pow_si(mp, rate, nRelativeDepth, MPFR_RNDN);
        mpfr_set_sj(init,     nInitialValue,  MPFR_RNDN);
        mpfr_mul   (mp,   mp, init,           MPFR_RNDN);
        nResult = mpfr_get_sj(mp,             MPFR_RNDN);
        mpfr_clears(rate, mp, init, (mpfr_ptr) 0);
    }
    return nResult;
}
int main(int argc, char **argv) {
  printf("94           = %ld\n", GetPresentValue(9400000000, 20));
  printf("51           = %ld\n", GetPresentValue(5100000000, 20));
  printf("21           = %ld\n", GetPresentValue(2100000000, 20));
  printf("22           = %ld\n", GetPresentValue(2200000000, 20));
  printf("51 + 21 + 22 = %ld\n", GetPresentValue(5100000000, 20) + GetPresentValue(2100000000, 20) + GetPresentValue(2200000000, 20));
}

Produced this output:

94           = 9399820711
51           = 5099902726
21           = 2099959946
22           = 2199958039
51 + 21 + 22 = 9399820711

I wonder if this was an artifact of overflow problem we fixed. Can you reproduce it now?

mhredmond21 commented 12 years ago

My bitcoin_test compiles 64 bit. Only the qt version compiles with 32 bits, so this problem still exists for me.

Try using 50 instead of 51 in your test program. That's what I failed (but its only by one integer value).

Obviously, this wasn't the source of our problem. I think we can close this but still be aware of it.

maaku commented 12 years ago

Closing as invalid: this is expected, albeit non-intuitive behavior.