Skip to content

Commit c43c852

Browse files
committed
Merge pull request #57
8866983 Add support for encoding to compact (Ross Nicoll)
2 parents d721c36 + 8866983 commit c43c852

2 files changed

Lines changed: 50 additions & 1 deletion

File tree

bitcoin/core/serialize.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,30 @@ def uint256_from_compact(c):
311311
Used for the nBits compact encoding of the target in the block header.
312312
"""
313313
nbytes = (c >> 24) & 0xFF
314-
v = (c & 0xFFFFFF) << (8 * (nbytes - 3))
314+
if nbytes <= 3:
315+
v = (c & 0xFFFFFF) >> 8 * (3 - nbytes)
316+
else:
317+
v = (c & 0xFFFFFF) << (8 * (nbytes - 3))
315318
return v
316319

320+
def compact_from_uint256(v):
321+
"""Convert uint256 to compact encoding
322+
"""
323+
nbytes = (v.bit_length() + 7) >> 3
324+
compact = 0
325+
if nbytes <= 3:
326+
compact = (v & 0xFFFFFF) << 8 * (3 - nbytes)
327+
else:
328+
compact = v >> 8 * (nbytes - 3)
329+
compact = compact & 0xFFFFFF
330+
331+
# If the sign bit (0x00800000) is set, divide the mantissa by 256 and
332+
# increase the exponent to get an encoding without it set.
333+
if compact & 0x00800000:
334+
compact >>= 8
335+
nbytes += 1
336+
337+
return compact | nbytes << 24
317338

318339
def uint256_to_shortstr(u):
319340
s = "%064x" % (u,)
@@ -339,5 +360,6 @@ def uint256_to_shortstr(u):
339360
'VarStringSerializer',
340361
'uint256_from_str',
341362
'uint256_from_compact',
363+
'compact_from_uint256',
342364
'uint256_to_shortstr',
343365
)

bitcoin/tests/test_serialize.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,30 @@ def T(serialized, ex_cls=SerializationTruncationError):
107107
T(b'01')
108108
T(b'0200')
109109
T(b'ff00000000000000ff11223344', SerializationError) # > max_size
110+
111+
class Test_Compact(unittest.TestCase):
112+
def test_from_compact_zero(self):
113+
self.assertEqual(uint256_from_compact(0x00123456), 0)
114+
self.assertEqual(uint256_from_compact(0x01003456), 0)
115+
self.assertEqual(uint256_from_compact(0x02000056), 0)
116+
self.assertEqual(uint256_from_compact(0x03000000), 0)
117+
self.assertEqual(uint256_from_compact(0x04000000), 0)
118+
self.assertEqual(uint256_from_compact(0x00923456), 0)
119+
def test_from_compact_negative_zero(self):
120+
# Negative bit isn't supported yet
121+
# self.assertEqual(uint256_from_compact(0x01803456), 0)
122+
# self.assertEqual(uint256_from_compact(0x02800056), 0)
123+
# self.assertEqual(uint256_from_compact(0x03800000), 0)
124+
# self.assertEqual(uint256_from_compact(0x04800000), 0)
125+
return
126+
127+
def test_twelve(self):
128+
self.assertEqual(uint256_from_compact(0x01123456), 0x0012)
129+
self.assertEqual(compact_from_uint256(0x0012), 0x01120000)
130+
131+
def test_from_uint256(self):
132+
self.assertEqual(compact_from_uint256(0x1234), 0x02123400)
133+
self.assertEqual(compact_from_uint256(0x123456), 0x03123456)
134+
self.assertEqual(compact_from_uint256(0x12345600), 0x04123456)
135+
self.assertEqual(compact_from_uint256(0x92340000), 0x05009234)
136+
self.assertEqual(compact_from_uint256(0x1234560000000000000000000000000000000000000000000000000000000000), 0x20123456)

0 commit comments

Comments
 (0)