ERROR: AcceptBlockHeader: Consensus::CheckBlockHeader: ..., high-hash, proof of work failed #121
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Core-Wallets/monacoin#121
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
When compiling monacoin, the chain fails to sync with the following error:
Googling this error brings up a report, with some responses mentioning bdb compatibility, however since bdb is used for the wallet only and not for on-chain data, it should have no impact whatsoever.
References found online:
This block seems to be at the heart of the issue:
At block 450000 mona has switched from scrypt to Lyra2REv2_DGW proof of work algorithm, my guess is that the compile environment might have had an effect on the algorithm and is causing the issue. I was hoping running tests would allow finding more information however the tests didn't compile at first and do not seem to want to run.
When checking, the block target is
00000fffff000000000000000000000000000000000000000000000000000000The hash value obtained is
cba2241c7eace873b8b79ff413b682bb02e790fd81a57a8c0f00db6531e80223which is obviously wrong.Some debugging data
The raw block header:
030000002539610f9c6b910c354032b3f70045edfbdc75a5da9ed6c53fcdca78851eb9be8078d8cefa1b499ae86da3758df5d48a187236e29c450acd930ee98e0f7a08df4cd00756ffff0f1ec5320000lyra2re2 hash states at various points:
Final bmw256 value is indeed used after bytes reversal.
Test with a working implementation:
The issue appears at the end on bmw256
Each time I run monacoin the value for bmw256 changes, which makes me think this function is using some piece of uninitialized memory.
run 1:
run 2:
Modifying
bmw32_init()to do amemseton the context causes the value to not vary anymore, but it is still not correct, meaning there is other parts of uninitialized memory somewhere.Compiling monacoin with
-ftrivial-auto-var-init=zeroinCFLAGSfully "solves" the issue.This confirms the implementation of bmw256 is using uninitialized variables. It is likely the official build has something to the effect of
-ftrivial-auto-var-init=zeroincluded, however for people like me who want to build their binaries it might be an issue.The issue happens somewhere near the end of
bmw32_close, probably incompress_smallbutcompress_smallis made of so many macros in macros it's quite difficult to track the issue, and adding some debug tends to make the issue disappear.I'll give up for now, at the very least this makes things a bit better (the result becomes wrong in a fixed way instead of being random):
Confirmed adding a call to
zeroStack()as defined below at the beginning ofcompress_smallmakes the issue go away, confirming use of uninitialized memory in that function.@MagicalTux
Thanks!
……Are you planning on making a pull request?
@wakiyamap
I'm hoping to make one once I'm able to do a proper fix, and not just hide the issue by clearing the stack.
To test the final part of the issue, I've extracted the problematic code & testing it in a separate environment.
Just setting
-O0causes the right value to be returned, which is puzzling. I tried various detection tools like-fsanitize=addressbut when specifying those options the issue disappears.-fno-strict-aliasingalso causes the issue to disappear.It turns out that when
compress_smallis included multiple times in the same function (by inlining), gcc may reorder the content of the functions as part of the optimization, and if things aren't written correctly this can cause data to be read incorrectly.This issue comes from gcc's aggressive optimization and assumption code isn't doing weird typecasting. Unfortunately, sph is doing some weird typecasting (a
char*becomes avoid*to later become asph_uint32*) and because of the strict aliasing rules gcc assumes the pointers to be different, and orders reads according to that assumption, resulting in garbage.This can be easily fixed by using
memcpyinstead of just casting a void tosph_uint32*which will be optimized nicely anyway since memcpy is a builtin function in all recent compilers.