As for the rest, soon I will put up my draft for fixing remaining security issue - small PoS blocks. In part it will resonate with what you write here.
Hello Senj,
The "code"
nSubsidy = 100 / (diff ^ 1/6)
is seen in YAC 0.4.4 source, in
main.cpp =>
GetProofOfWorkReward()
And it is Pseudo-code in a comment! Nevertheless, it brings up points that I have made over and over again, for more than 30 years!
Whenever a MAGIC NUMBER (out of the blue, undocumented) appears in code, it brings understanding to a crashing halt.
Is it a REQUIRED value? Is it ARBITRARY? Is it DEPENDENT upon some other value elsewhere in the program?? Is it a WILD ASS GUESS?
You get the idea. Well, we have two (or three) in this pseudo code snippet!
Upon looking at the code (with the help of MSVC++ in Visual Studio) I found that the 100
actually was a constant!
There are literally hundreds of "naked" numbers in the YACoin (and Bitcoin and all the others) sources.
Until every one is replaced by a MEANINGFUL name that truly represents what it is, no real understanding and improvement can come to this or any "open source" project, since the "open source" is so obfuscated by lack of clarity it is impossible to understand how the code is interrelated, etc. etc.
And it's worse. Method/function names are so bad they may as well be numbers! Ditto for properties/variables.
There has been no excuse for cryptic, short, vowel challenged, abbreviated names for classes, structures, methods, properties, etc. etc. since the 1980s, when memory and disk storage was expensive, and we had 32 character or less restrictions on names in C (back then).
Now students and adults today have studied from books and authors who came from that past and have perpetuated this ugliness of language in their books, and so it continues for another generation.
You shouldn't have to translate literally every word you see in a line of code, in your head, in order to understand it! But the myth continues that that is how it must be. I don't buy it, never have, never will. In a commercial professional environment, one was required to write much clearer code. And document it too! Seems today, it is get it done fast, no documents, no nothing.
If you want to bring fresh eyes to a problem, the code must be clear, more clear, beyond clear. No tricks, no assumptions...
The C++ compiler will optimize out everything anyway, so there is no point in trying to be "cute".
Here is the original:
int64 GetProofOfWorkReward(unsigned int nBits)
{
CBigNum bnSubsidyLimit = MAX_MINT_PROOF_OF_WORK;
CBigNum bnTarget;
bnTarget.SetCompact(nBits);
CBigNum bnTargetLimit = bnProofOfWorkLimit;
bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
// ppcoin: subsidy is cut in half every 64x multiply of difficulty
// A reasonably continuous curve is used to avoid shock to market
// (nSubsidyLimit / nSubsidy) ** 6 == bnProofOfWorkLimit / bnTarget
//
// Human readable form:
//
// nSubsidy = 100 / (diff ^ 1/6)
CBigNum bnLowerBound = CENT;
CBigNum bnUpperBound = bnSubsidyLimit;
while (bnLowerBound + CENT <= bnUpperBound)
{
CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfWorkReward() : lower=%"PRI64d" upper=%"PRI64d" mid=%"PRI64d"\n", bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64());
if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnTarget)
bnUpperBound = bnMidValue;
else
bnLowerBound = bnMidValue;
}
int64 nSubsidy = bnUpperBound.getuint64();
nSubsidy = (nSubsidy / CENT) * CENT;
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfWorkReward() : create=%s nBits=0x%08x nSubsidy=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nBits, nSubsidy);
return min(nSubsidy, MAX_MINT_PROOF_OF_WORK);
}
Study that for a while and notice that it raises more questions than it answers. Long lines are stupid too, for many reasons.
Here is what I wrote for myself, in my MSVC++ project, and it is only a first pass:
int64 GetProofOfWorkReward(unsigned int nBits)
{
CBigNum
bnSubsidyLimit = MAX_MINT_PROOF_OF_WORK;
CBigNum
bnTarget;
bnTarget.SetCompact(nBits);
CBigNum
bnTargetLimit = bnProofOfWorkLimit;
bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
// ppcoin: subsidy is cut in half every 64x multiply of difficulty
// 64 = 2 to the 6th power
// A reasonably continuous curve is used to avoid shock to market
// (nSubsidyLimit / nSubsidy) ** 6 == bnProofOfWorkLimit / bnTarget
// what are these terms and how do they relate to the discussion, exactly??????
//
// Human readable form:
//
// nSubsidy = 100 / (diff ^ 1/6)
// again, but worse!!! Undefined magic numbers. I think that 100 is the
// maximum subsidy in COINs ???????????
// diff is ??????????????
// 1/6 is 0 if we are talking integer divide, so obviously we are not?????????????
// So what are we talking???????????????????
// is ^ from GWBASIC??????????????
// Do we mean power?????????????????
// even so, after all of that, what does this code below actually do?????????
CBigNum
bnLowerBound = CENT; // this is 0.01 * COIN
CBigNum
bnUpperBound = bnSubsidyLimit; // seems that this is just 100* COIN
while (bnLowerBound + CENT <= bnUpperBound)
{
CBigNum
bnMidValue = (bnLowerBound + bnUpperBound) / 2;
if (fDebug && GetBoolArg("-printcreation"))
printf(
"GetProofOfWorkReward() : lower=%"PRI64d" upper=%"PRI64d" mid=%"PRI64d"\n",
bnLowerBound.getuint64(),
bnUpperBound.getuint64(),
bnMidValue.getuint64()
);
if (
bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue *
bnTargetLimit >
bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit *
bnTarget
)
bnUpperBound = bnMidValue;
else
bnLowerBound = bnMidValue;
}
int64
nSubsidy = bnUpperBound.getuint64();
nSubsidy = (nSubsidy / CENT) * CENT;
if (fDebug && GetBoolArg("-printcreation"))
printf(
"GetProofOfWorkReward() : create=%s nBits=0x%08x nSubsidy=%"PRI64d"\n",
FormatMoney(nSubsidy).c_str(),
nBits,
nSubsidy
);
return min(nSubsidy, MAX_MINT_PROOF_OF_WORK);
}
I just formatted it so I could read it!! Can you swear that that
while loop, with a test in an
if statement is doing what the comment says? I can't! I think it is doing more but I haven't analyzed it, yet.
I have said this, in many Bitcoin forums, and more, but my words do not resonate with people who don't care about communicating their coding ideas clearly. They most probably never took any writing or English courses, and have never read Joel Spolsky
Dismounting from high horse now...
Ron