1 from __future__ import division
4 import cStringIO as StringIO
9 from p2pool.util import bases, expiring_dict, math
11 class EarlyEnd(Exception):
14 class LateEnd(Exception):
17 def read((data, pos), length):
18 data2 = data[pos:pos + length]
19 if len(data2) != length:
21 return data2, (data, pos + length)
24 # the same data can have only one unpacked representation, but multiple packed binary representations
27 # return hash(tuple(self.__dict__.items()))
29 #def __eq__(self, other):
30 # if not isinstance(other, Type):
31 # raise NotImplementedError()
32 # return self.__dict__ == other.__dict__
34 def _unpack(self, data):
35 f = StringIO.StringIO(data)
37 obj, (data2, pos) = self.read((data, 0))
41 raise LateEnd('underread ' + repr((self, data)))
45 def unpack(self, data):
46 obj = self._unpack(data)
49 data2 = self._pack(obj)
51 assert self._unpack(data2) == obj
56 f = StringIO.StringIO()
65 data = self._pack(obj)
66 assert self._unpack(data) == obj
71 def pack_base58(self, obj):
72 return base58.base58_encode(self.pack(obj))
74 def unpack_base58(self, base58_data):
75 return self.unpack(base58.base58_decode(base58_data))
78 def hash160(self, obj):
79 return ShortHashType().unpack(hashlib.new('ripemd160', hashlib.sha256(self.pack(obj)).digest()).digest())
81 def hash256(self, obj):
82 return HashType().unpack(hashlib.sha256(hashlib.sha256(self.pack(obj)).digest()).digest())
84 class VarIntType(Type):
85 # redundancy doesn't matter here because bitcoin and p2pool both reencode before hashing
87 data, file = read(file, 1)
92 desc, length = '<H', 2
94 desc, length = '<I', 4
96 desc, length = '<Q', 8
98 raise AssertionError()
99 data, file = read(file, length)
100 return struct.unpack(desc, data)[0], file
102 def write(self, file, item):
104 file.write(struct.pack('<B', item))
106 file.write(struct.pack('<BH', 0xfd, item))
107 elif item <= 0xffffffff:
108 file.write(struct.pack('<BI', 0xfe, item))
109 elif item <= 0xffffffffffffffff:
110 file.write(struct.pack('<BQ', 0xff, item))
112 raise ValueError('int too large for varint')
114 class VarStrType(Type):
115 _inner_size = VarIntType()
117 def read(self, file):
118 length, file = self._inner_size.read(file)
119 return read(file, length)
121 def write(self, file, item):
122 self._inner_size.write(file, len(item))
125 class FixedStrType(Type):
126 def __init__(self, length):
129 def read(self, file):
130 return read(file, self.length)
132 def write(self, file, item):
133 if len(item) != self.length:
134 raise ValueError('incorrect length!')
137 class EnumType(Type):
138 def __init__(self, inner, values):
143 for k, v in values.iteritems():
145 raise ValueError('duplicate value in values')
148 def read(self, file):
149 data, file = self.inner.read(file)
150 return self.keys[data], file
152 def write(self, file, item):
153 self.inner.write(file, self.values[item])
155 class HashType(Type):
156 def read(self, file):
157 data, file = read(file, 256//8)
158 return int(data[::-1].encode('hex'), 16), file
160 def write(self, file, item):
161 if not 0 <= item < 2**256:
162 raise ValueError("invalid hash value")
163 if item != 0 and item < 2**160:
164 warnings.warn("very low hash value - maybe you meant to use ShortHashType? %x" % (item,))
165 file.write(('%064x' % (item,)).decode('hex')[::-1])
167 class ShortHashType(Type):
168 def read(self, file):
169 data, file = read(file, 160//8)
170 return int(data[::-1].encode('hex'), 16), file
172 def write(self, file, item):
174 raise ValueError("invalid hash value")
175 file.write(('%040x' % (item,)).decode('hex')[::-1])
177 class ListType(Type):
178 _inner_size = VarIntType()
180 def __init__(self, type):
183 def read(self, file):
184 length, file = self._inner_size.read(file)
186 for i in xrange(length):
187 item, file = self.type.read(file)
191 def write(self, file, item):
192 self._inner_size.write(file, len(item))
194 self.type.write(file, subitem)
196 class FastLittleEndianUnsignedInteger(Type):
197 def read(self, file):
198 data, file = read(file, 4)
199 data = map(ord, data)
200 return data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24), file
202 def write(self, file, item):
203 StructType("<I").write(file, item)
205 class StructType(Type):
206 def __init__(self, desc):
208 self.length = struct.calcsize(self.desc)
210 def read(self, file):
211 data, file = read(file, self.length)
212 res, = struct.unpack(self.desc, data)
215 def write(self, file, item):
216 data = struct.pack(self.desc, item)
217 if struct.unpack(self.desc, data)[0] != item:
218 # special test because struct doesn't error on some overflows
219 raise ValueError("item didn't survive pack cycle (%r)" % (item,))
222 class IPV6AddressType(Type):
223 def read(self, file):
224 data, file = read(file, 16)
225 if data[:12] != '00000000000000000000ffff'.decode('hex'):
226 raise ValueError("ipv6 addresses not supported yet")
227 return '.'.join(str(ord(x)) for x in data[12:]), file
229 def write(self, file, item):
230 bits = map(int, item.split('.'))
232 raise ValueError("invalid address: %r" % (bits,))
233 data = '00000000000000000000ffff'.decode('hex') + ''.join(chr(x) for x in bits)
234 assert len(data) == 16, len(data)
237 class ComposedType(Type):
238 def __init__(self, fields):
241 def read(self, file):
243 for key, type_ in self.fields:
244 item[key], file = type_.read(file)
247 def write(self, file, item):
248 for key, type_ in self.fields:
249 type_.write(file, item[key])
251 class ChecksummedType(Type):
252 def __init__(self, inner):
255 def read(self, file):
256 obj, file = self.inner.read(file)
257 data = self.inner.pack(obj)
259 if file.read(4) != hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4]:
260 raise ValueError("invalid checksum")
264 def write(self, file, item):
265 data = self.inner.pack(item)
267 file.write(hashlib.sha256(hashlib.sha256(data).digest()).digest()[:4])
269 class FloatingIntegerType(Type):
270 # redundancy doesn't matter here because bitcoin checks binary bits against its own computed bits
271 # so it will always be encoded 'normally' in blocks (they way bitcoin does it)
272 _inner = StructType("<I")
273 _inner = FastLittleEndianUnsignedInteger()
275 def read(self, file):
276 bits, file = self._inner.read(file)
277 target = self._bits_to_target(bits)
279 if self._target_to_bits(target) != bits:
280 raise ValueError("bits in non-canonical form")
283 def write(self, file, item):
284 self._inner.write(file, self._target_to_bits(item))
286 def truncate_to(self, x):
287 return self._bits_to_target(self._target_to_bits(x, _check=False))
289 def _bits_to_target(self, bits2):
290 target = math.shift_left(bits2 & 0x00ffffff, 8 * ((bits2 >> 24) - 3))
291 assert target == self._bits_to_target1(struct.pack("<I", bits2))
292 assert self._target_to_bits(target, _check=False) == bits2
295 def _bits_to_target1(self, bits):
297 length = ord(bits[0])
298 return bases.string_to_natural((bits[1:] + "\0"*length)[:length])
300 def _target_to_bits(self, target, _check=True):
301 n = bases.natural_to_string(target)
302 if n and ord(n[0]) >= 128:
304 bits2 = (chr(len(n)) + (n + 3*chr(0))[:3])[::-1]
305 bits = struct.unpack("<I", bits2)[0]
307 if self._bits_to_target(bits) != target:
308 raise ValueError(repr((target, self._bits_to_target(bits, _check=False))))
311 class PossiblyNone(Type):
312 def __init__(self, none_value, inner):
313 self.none_value = none_value
316 def read(self, file):
317 value, file = self.inner.read(file)
318 return None if value == self.none_value else value, file
320 def write(self, file, item):
321 if item == self.none_value:
322 raise ValueError("none_value used")
323 self.inner.write(file, self.none_value if item is None else item)
325 address_type = ComposedType([
326 ('services', StructType('<Q')),
327 ('address', IPV6AddressType()),
328 ('port', StructType('>H')),
331 tx_type = ComposedType([
332 ('version', StructType('<I')),
333 ('tx_ins', ListType(ComposedType([
334 ('previous_output', PossiblyNone(dict(hash=0, index=2**32 - 1), ComposedType([
335 ('hash', HashType()),
336 ('index', StructType('<I')),
338 ('script', VarStrType()),
339 ('sequence', PossiblyNone(2**32 - 1, StructType('<I'))),
341 ('tx_outs', ListType(ComposedType([
342 ('value', StructType('<Q')),
343 ('script', VarStrType()),
345 ('lock_time', StructType('<I')),
348 block_header_type = ComposedType([
349 ('version', StructType('<I')),
350 ('previous_block', PossiblyNone(0, HashType())),
351 ('merkle_root', HashType()),
352 ('timestamp', StructType('<I')),
353 ('target', FloatingIntegerType()),
354 ('nonce', StructType('<I')),
357 block_type = ComposedType([
358 ('header', block_header_type),
359 ('txs', ListType(tx_type)),
363 merkle_record_type = ComposedType([
364 ('left', HashType()),
365 ('right', HashType()),
368 def merkle_hash(tx_list):
371 hash_list = map(tx_type.hash256, tx_list)
372 while len(hash_list) > 1:
373 hash_list = [merkle_record_type.hash256(dict(left=left, right=left if right is None else right))
374 for left, right in zip(hash_list[::2], hash_list[1::2] + [None])]
377 def target_to_average_attempts(target):
378 return 2**256//(target + 1)
382 human_address_type = ChecksummedType(ComposedType([
383 ('version', StructType("<B")),
384 ('pubkey_hash', ShortHashType()),
387 pubkey_type = FixedStrType(65)
389 def pubkey_hash_to_address(pubkey_hash, net):
390 return human_address_type.pack_base58(dict(version=net.BITCOIN_ADDRESS_VERSION, pubkey_hash=pubkey_hash))
392 def pubkey_to_address(pubkey, net):
393 return pubkey_hash_to_address(pubkey_type.hash160(pubkey), net)
395 def address_to_pubkey_hash(address, net):
396 x = human_address_type.unpack_base58(address)
397 if x['version'] != net.BITCOIN_ADDRESS_VERSION:
398 raise ValueError('address not for this net!')
399 return x['pubkey_hash']
401 # network definitions
403 class Mainnet(object):
404 BITCOIN_P2P_PREFIX = 'f9beb4d9'.decode('hex')
405 BITCOIN_P2P_PORT = 8333
406 BITCOIN_ADDRESS_VERSION = 0
408 class Testnet(object):
409 BITCOIN_P2P_PREFIX = 'fabfb5da'.decode('hex')
410 BITCOIN_P2P_PORT = 18333
411 BITCOIN_ADDRESS_VERSION = 111