-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Replace uint256/uint160 by opaque blobs where possible #5478
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Eases step-by-step migration to blob.
Replace x=0 with .SetNull(), x==0 with IsNull(), x!=0 with !IsNull(). Replace uses of uint256(0) with uint256().
Convert between blobs and uints, mostly for proof of work checks.
SignatureHash and its test function SignatureHashOld return uint256(1) as a special error signaling value. Return a local static constant with the same value instead.
Clients outside the class have no business poking at the internals.
Avoid dangerous cases where 0 is interpreted as std::string(0). Keyword `explicit` does not help here.
6777175
to
e129c6a
Compare
This appears to be unused now:
|
@paveljanik Thanks, I'll remove it. All *S variables in |
No uint160 arithmetic is used at all. Also remove the tests.
Re: people complaining about rebasing their pulls, if the large diff in 'A: pure renames' is problematic, we could cheat by changing uint256 and uint160 to be blob types and introduce a new type for actual 256 bit integer arithmetic. But as clear type names are important I don't really like this. |
e129c6a
to
8f1563a
Compare
|
||
friend inline bool operator==(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) == 0; } | ||
friend inline bool operator!=(const base_blob& a, const base_blob& b) { return memcmp(a.data, b.data, sizeof(a.data)) != 0; } | ||
friend inline bool operator<(const base_blob& a, const base_blob& b) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it break anything if we defined the ordering of blob256 as platform-dependent? That would allow using memcmp for this operator too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, I think that would allow implementing blob* as wrappers around byte arrays, and leave all integer conversion to uint*.
EDIT: Sorry, they already are byte-arrays; I should read more before commenting.
EDIT2: In fact, I think the implementation below is already identical to just "memcmp(a.data, b.data, sizeof(a.data)) < 0".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's identical to memcmp, good catch. Will use that.
I would actually like the PR as a whole to just introduce arith_uint256 or something (for the version with arithmetic semantics) and leave uint256/uint160 in place (for the version without). That will result in a much smaller patchset, and require much less rebasings while this is being reviewed. Perhaps later there can be mass rename that is trivial to review and merge. |
Ok, reluctantly agreed... As I say above already I hate the idea of using uint160/uint256 for what are not actually integers and introduce a yes_this_is_really_an_int256 for real uint256 arithmetic, but yes the diff will be much smaller. |
Closing, will reopen after reorganization. Continued in #5490 |
This pull replaces almost all uses of
uint256
and all uses ofuint160
to use opaque byte blobsblob256
andblob160
with only the following operations:IsNull()
compare to special all-zeros valueSetNull()
clear to special all-zeros value: Bitcoin needsIsNull()
/SetNull()
because we often use the all-zeroes value as a marker for errors and empty values.<
for sorting in maps.!=
==
test for (in)equalityGetHex
/SetHex
/ToString
because they're just so usefulbegin()
/end()
raw access to the datasize()
returns a fixed sizeGetSerializeSize()
Serialize
Unserialize
serialization just reads and writes the bytesGetCheapHash()
this is similar toGetLow64()
and returns part of the value as uint64_t, for cheap hashing when the contents are assumed distributed uniformy random.uint256
(used for proof-of-work mainly), on the other hand, loses all functionality like raw bytes access and serialization. Its memory should not be accessed directly. This is necessary for #888 (big endian support).uint160
is completely removed as Bitcoin Core does no 160-bit integer arithmetic.Overall steps (see commits)
Even though the diff is huge, I've tried to follow a logical and easy to review process:
Introduce
base_uint::SetNull
andbase_uint::IsNull()
as well as other methods that will later be onbase_blob
, to prepare for migrationReplace x=0 with .SetNull(), x==0 with IsNull(), x!=0 with !IsNull(). Replace uses of uint256(0) with uint256().
Introduce blob256 and blob160 as well as conversion functions (only needed for blob256, we don't ever compute with uint160).
Replace
GetLow64()
withGetCheapHash()
Rename uint256 and uint160 to blob256 and blob160 except where big integers are really necessary. For reviewing convenience I separated this out into
A) pure renames uintXXX to blobXXX, can easily be verified (in reverse) with
find -name *.h -print0 | xargs -0 sed -i 's/blob256/uint256/g'
find -name *.cpp -print0 | xargs -0 sed -i 's/blob256/uint256/g'
find -name *.h -print0 | xargs -0 sed -i 's/blob160/uint160/g'
find -name *.cpp -print0 | xargs -0 sed -i 's/blob160/uint160/g'
B) string conversions uint256("string") to blob256S("string")
C) Added #includes and predeclared classes
D) Necessary conversions between uint256 and blob256 Focus reviewing here
Remove now-unused methods from base_uint and blob160/blob256, eg GetHash, also remove unused uint160.