1 # this code comes from ABE. it can probably be simplified
13 class SerializationError(Exception):
14 """Thrown when there's a problem deserializing or serializing."""
17 class BCDataStream(object):
18 """Workalike python implementation of Bitcoin's CDataStream class."""
27 def write(self, bytes): # Initialize with string of bytes
28 if self.input is None:
33 def map_file(self, file, start): # Initialize with bytes from file
34 self.input = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ)
35 self.read_cursor = start
37 def seek_file(self, position):
38 self.read_cursor = position
43 def read_string(self):
44 # Strings are encoded depending on length:
45 # 0 to 252 : 1-byte-length followed by bytes (if any)
46 # 253 to 65,535 : byte'253' 2-byte-length followed by bytes
47 # 65,536 to 4,294,967,295 : byte '254' 4-byte-length followed by bytes
48 # ... and the Bitcoin client is coded to understand:
49 # greater than 4,294,967,295 : byte '255' 8-byte-length followed by bytes of string
50 # ... but I don't think it actually handles any strings that big.
51 if self.input is None:
52 raise SerializationError("call write(bytes) before trying to deserialize")
55 length = self.read_compact_size()
57 raise SerializationError("attempt to read past end of buffer")
59 return self.read_bytes(length)
61 def write_string(self, string):
62 # Length-encoded as with read-string
63 self.write_compact_size(len(string))
66 def read_bytes(self, length):
68 result = self.input[self.read_cursor:self.read_cursor+length]
69 self.read_cursor += length
72 raise SerializationError("attempt to read past end of buffer")
76 def read_boolean(self):
77 return self.read_bytes(1)[0] != chr(0)
80 return self._read_num('<h')
82 def read_uint16(self):
83 return self._read_num('<H')
86 return self._read_num('<i')
88 def read_uint32(self):
89 return self._read_num('<I')
92 return self._read_num('<q')
94 def read_uint64(self):
95 return self._read_num('<Q')
97 def write_boolean(self, val):
98 return self.write(chr(1) if val else chr(0))
100 def write_int16(self, val):
101 return self._write_num('<h', val)
103 def write_uint16(self, val):
104 return self._write_num('<H', val)
106 def write_int32(self, val):
107 return self._write_num('<i', val)
109 def write_uint32(self, val):
110 return self._write_num('<I', val)
112 def write_int64(self, val):
113 return self._write_num('<q', val)
115 def write_uint64(self, val):
116 return self._write_num('<Q', val)
118 def read_compact_size(self):
119 size = ord(self.input[self.read_cursor])
120 self.read_cursor += 1
122 size = self._read_num('<H')
124 size = self._read_num('<I')
126 size = self._read_num('<Q')
129 def write_compact_size(self, size):
131 raise SerializationError("attempt to write size < 0")
133 self.write(chr(size))
136 self._write_num('<H', size)
139 self._write_num('<I', size)
142 self._write_num('<Q', size)
144 def _read_num(self, format):
145 (i,) = struct.unpack_from(format, self.input, self.read_cursor)
146 self.read_cursor += struct.calcsize(format)
149 def _write_num(self, format, num):
150 s = struct.pack(format, num)
154 class EnumException(Exception):
161 From the Python Cookbook, downloaded from http://code.activestate.com/recipes/67107/
164 def __init__(self, name, enumList):
172 if isinstance(x, types.TupleType):
174 if not isinstance(x, types.StringType):
175 raise EnumException("enum name is not a string: %r" % x)
176 if not isinstance(i, types.IntType):
177 raise EnumException("enum value is not an integer: %r" % i)
179 raise EnumException("enum name is not unique: %r" % x)
180 if i in uniqueValues:
181 raise EnumException("enum value is not unique for %r" % x)
182 uniqueNames.append(x)
183 uniqueValues.append(i)
188 self.reverseLookup = reverseLookup
190 def __getattr__(self, attr):
191 if attr not in self.lookup:
193 return self.lookup[attr]
195 def whatis(self, value):
196 return self.reverseLookup[value]
199 # This function comes from bitcointools, bct-LICENSE.txt.
201 return bytes.encode('hex_codec')
204 # This function comes from bitcointools, bct-LICENSE.txt.
205 def short_hex(bytes):
206 t = bytes.encode('hex_codec')
209 return t[0:4]+"..."+t[-4:]
214 d['prevout_hash'] = hash_encode(vds.read_bytes(32))
215 d['prevout_n'] = vds.read_uint32()
216 scriptSig = vds.read_bytes(vds.read_compact_size())
217 d['sequence'] = vds.read_uint32()
218 # actually I don't need that at all
219 # if not is_coinbase: d['address'] = extract_public_key(scriptSig)
220 # d['script'] = decode_script(scriptSig)
224 def parse_TxOut(vds, i):
226 d['value'] = vds.read_int64()
227 scriptPubKey = vds.read_bytes(vds.read_compact_size())
228 d['address'] = get_address_from_output_script(scriptPubKey)
229 d['raw_output_script'] = scriptPubKey.encode('hex')
234 def parse_Transaction(vds, is_coinbase):
236 start = vds.read_cursor
237 d['version'] = vds.read_int32()
238 n_vin = vds.read_compact_size()
240 for i in xrange(n_vin):
243 d['inputs'].append(o)
244 n_vout = vds.read_compact_size()
246 for i in xrange(n_vout):
247 o = parse_TxOut(vds, i)
249 #if o['address'] == "None" and o['value']==0:
250 # print("skipping strange tx output with zero value")
252 # if o['address'] != "None":
253 d['outputs'].append(o)
255 d['lockTime'] = vds.read_uint32()
259 opcodes = Enumeration("Opcodes", [
260 ("OP_0", 0), ("OP_PUSHDATA1", 76), "OP_PUSHDATA2", "OP_PUSHDATA4", "OP_1NEGATE", "OP_RESERVED",
261 "OP_1", "OP_2", "OP_3", "OP_4", "OP_5", "OP_6", "OP_7",
262 "OP_8", "OP_9", "OP_10", "OP_11", "OP_12", "OP_13", "OP_14", "OP_15", "OP_16",
263 "OP_NOP", "OP_VER", "OP_IF", "OP_NOTIF", "OP_VERIF", "OP_VERNOTIF", "OP_ELSE", "OP_ENDIF", "OP_VERIFY",
264 "OP_RETURN", "OP_TOALTSTACK", "OP_FROMALTSTACK", "OP_2DROP", "OP_2DUP", "OP_3DUP", "OP_2OVER", "OP_2ROT", "OP_2SWAP",
265 "OP_IFDUP", "OP_DEPTH", "OP_DROP", "OP_DUP", "OP_NIP", "OP_OVER", "OP_PICK", "OP_ROLL", "OP_ROT",
266 "OP_SWAP", "OP_TUCK", "OP_CAT", "OP_SUBSTR", "OP_LEFT", "OP_RIGHT", "OP_SIZE", "OP_INVERT", "OP_AND",
267 "OP_OR", "OP_XOR", "OP_EQUAL", "OP_EQUALVERIFY", "OP_RESERVED1", "OP_RESERVED2", "OP_1ADD", "OP_1SUB", "OP_2MUL",
268 "OP_2DIV", "OP_NEGATE", "OP_ABS", "OP_NOT", "OP_0NOTEQUAL", "OP_ADD", "OP_SUB", "OP_MUL", "OP_DIV",
269 "OP_MOD", "OP_LSHIFT", "OP_RSHIFT", "OP_BOOLAND", "OP_BOOLOR",
270 "OP_NUMEQUAL", "OP_NUMEQUALVERIFY", "OP_NUMNOTEQUAL", "OP_LESSTHAN",
271 "OP_GREATERTHAN", "OP_LESSTHANOREQUAL", "OP_GREATERTHANOREQUAL", "OP_MIN", "OP_MAX",
272 "OP_WITHIN", "OP_RIPEMD160", "OP_SHA1", "OP_SHA256", "OP_HASH160",
273 "OP_HASH256", "OP_CODESEPARATOR", "OP_CHECKSIG", "OP_CHECKSIGVERIFY", "OP_CHECKMULTISIG",
274 "OP_CHECKMULTISIGVERIFY",
275 ("OP_SINGLEBYTE_END", 0xF0),
276 ("OP_DOUBLEBYTE_BEGIN", 0xF000),
277 "OP_PUBKEY", "OP_PUBKEYHASH",
278 ("OP_INVALIDOPCODE", 0xFFFF),
282 def script_GetOp(bytes):
284 while i < len(bytes):
286 opcode = ord(bytes[i])
288 if opcode >= opcodes.OP_SINGLEBYTE_END:
290 opcode |= ord(bytes[i])
293 if opcode <= opcodes.OP_PUSHDATA4:
295 if opcode == opcodes.OP_PUSHDATA1:
296 nSize = ord(bytes[i])
298 elif opcode == opcodes.OP_PUSHDATA2:
299 (nSize,) = struct.unpack_from('<H', bytes, i)
301 elif opcode == opcodes.OP_PUSHDATA4:
302 (nSize,) = struct.unpack_from('<I', bytes, i)
304 vch = bytes[i:i+nSize]
307 yield (opcode, vch, i)
310 def script_GetOpName(opcode):
311 return (opcodes.whatis(opcode)).replace("OP_", "")
314 def decode_script(bytes):
316 for (opcode, vch, i) in script_GetOp(bytes):
319 if opcode <= opcodes.OP_PUSHDATA4:
320 result += "%d:" % (opcode,)
321 result += short_hex(vch)
323 result += script_GetOpName(opcode)
327 def match_decoded(decoded, to_match):
328 if len(decoded) != len(to_match):
330 for i in range(len(decoded)):
331 if to_match[i] == opcodes.OP_PUSHDATA4 and decoded[i][0] <= opcodes.OP_PUSHDATA4:
332 continue # Opcodes below OP_PUSHDATA4 all just push data onto stack, and are equivalent.
333 if to_match[i] != decoded[i][0]:
340 def get_address_from_output_script(bytes):
341 decoded = [ x for x in script_GetOp(bytes) ]
343 # The Genesis Block, self-payments, and pay-by-IP-address payments look like:
344 # 65 BYTES:... CHECKSIG
345 match = [opcodes.OP_PUSHDATA4, opcodes.OP_CHECKSIG]
346 if match_decoded(decoded, match):
347 return public_key_to_bc_address(decoded[0][1])
349 # coins sent to black hole
350 # DUP HASH160 20 BYTES:... EQUALVERIFY CHECKSIG
351 match = [opcodes.OP_DUP, opcodes.OP_HASH160, opcodes.OP_0, opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG]
352 if match_decoded(decoded, match):
355 # Pay-by-Bitcoin-address TxOuts look like:
356 # DUP HASH160 20 BYTES:... EQUALVERIFY CHECKSIG
357 match = [opcodes.OP_DUP, opcodes.OP_HASH160, opcodes.OP_PUSHDATA4, opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG]
358 if match_decoded(decoded, match):
359 return hash_160_to_bc_address(decoded[2][1])
362 match = [opcodes.OP_DUP, opcodes.OP_HASH160, opcodes.OP_PUSHDATA4, opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG, opcodes.OP_NOP]
363 if match_decoded(decoded, match):
364 return hash_160_to_bc_address(decoded[2][1])
367 match = [ opcodes.OP_HASH160, opcodes.OP_PUSHDATA4, opcodes.OP_EQUAL ]
368 if match_decoded(decoded, match):
369 addr = hash_160_to_bc_address(decoded[1][1],5)
373 #raise BaseException("address not found in script") see ce35795fb64c268a52324b884793b3165233b1e6d678ccaadf760628ec34d76b