PPCoin: Release alert and checkpoint master public keys
[novacoin.git] / bitcointools / deserialize.py
1 #
2 #
3 #
4
5 from BCDataStream import *
6 from enumeration import Enumeration
7 from base58 import public_key_to_bc_address, hash_160_to_bc_address
8 import socket
9 import time
10 from util import short_hex, long_hex
11
12 def parse_CAddress(vds):
13   d = {}
14   d['nVersion'] = vds.read_int32()
15   d['nTime'] = vds.read_uint32()
16   d['nServices'] = vds.read_uint64()
17   d['pchReserved'] = vds.read_bytes(12)
18   d['ip'] = socket.inet_ntoa(vds.read_bytes(4))
19   d['port'] = vds.read_uint16()
20   return d
21
22 def deserialize_CAddress(d):
23   return d['ip']+":"+str(d['port'])+" (lastseen: %s)"%(time.ctime(d['nTime']),)
24
25 def parse_setting(setting, vds):
26   if setting[0] == "f":  # flag (boolean) settings
27     return str(vds.read_boolean())
28   elif setting == "addrIncoming":
29     return "" # bitcoin 0.4 purposely breaks addrIncoming setting in encrypted wallets.
30   elif setting[0:4] == "addr": # CAddress
31     d = parse_CAddress(vds)
32     return deserialize_CAddress(d)
33   elif setting == "nTransactionFee":
34     return vds.read_int64()
35   elif setting == "nLimitProcessors":
36     return vds.read_int32()
37   return 'unknown setting'
38
39 def parse_TxIn(vds):
40   d = {}
41   d['prevout_hash'] = vds.read_bytes(32)
42   d['prevout_n'] = vds.read_uint32()
43   d['scriptSig'] = vds.read_bytes(vds.read_compact_size())
44   d['sequence'] = vds.read_uint32()
45   return d
46 def deserialize_TxIn(d, transaction_index=None, owner_keys=None):
47   if d['prevout_hash'] == "\x00"*32:
48     result = "TxIn: COIN GENERATED"
49     result += " coinbase:"+d['scriptSig'].encode('hex_codec')
50   elif transaction_index is not None and d['prevout_hash'] in transaction_index:
51     p = transaction_index[d['prevout_hash']]['txOut'][d['prevout_n']]
52     result = "TxIn: value: %f"%(p['value']/1.0e8,)
53     result += " prev("+long_hex(d['prevout_hash'][::-1])+":"+str(d['prevout_n'])+")"
54   else:
55     result = "TxIn: prev("+long_hex(d['prevout_hash'][::-1])+":"+str(d['prevout_n'])+")"
56     pk = extract_public_key(d['scriptSig'])
57     result += " pubkey: "+pk
58     result += " sig: "+decode_script(d['scriptSig'])
59   if d['sequence'] < 0xffffffff: result += " sequence: "+hex(d['sequence'])
60   return result
61
62 def parse_TxOut(vds):
63   d = {}
64   d['value'] = vds.read_int64()
65   d['scriptPubKey'] = vds.read_bytes(vds.read_compact_size())
66   return d
67
68 def deserialize_TxOut(d, owner_keys=None):
69   result =  "TxOut: value: %f"%(d['value']/1.0e8,)
70   pk = extract_public_key(d['scriptPubKey'])
71   result += " pubkey: "+pk
72   result += " Script: "+decode_script(d['scriptPubKey'])
73   if owner_keys is not None:
74     if pk in owner_keys: result += " Own: True"
75     else: result += " Own: False"
76   return result
77
78 def parse_Transaction(vds):
79   d = {}
80   d['version'] = vds.read_int32()
81   n_vin = vds.read_compact_size()
82   d['txIn'] = []
83   for i in xrange(n_vin):
84     d['txIn'].append(parse_TxIn(vds))
85   n_vout = vds.read_compact_size()
86   d['txOut'] = []
87   for i in xrange(n_vout):
88     d['txOut'].append(parse_TxOut(vds))
89   d['lockTime'] = vds.read_uint32()
90   return d
91 def deserialize_Transaction(d, transaction_index=None, owner_keys=None):
92   result = "%d tx in, %d out\n"%(len(d['txIn']), len(d['txOut']))
93   for txIn in d['txIn']:
94     result += deserialize_TxIn(txIn, transaction_index) + "\n"
95   for txOut in d['txOut']:
96     result += deserialize_TxOut(txOut, owner_keys) + "\n"
97   return result
98
99 def parse_MerkleTx(vds):
100   d = parse_Transaction(vds)
101   d['hashBlock'] = vds.read_bytes(32)
102   n_merkleBranch = vds.read_compact_size()
103   d['merkleBranch'] = vds.read_bytes(32*n_merkleBranch)
104   d['nIndex'] = vds.read_int32()
105   return d
106
107 def deserialize_MerkleTx(d, transaction_index=None, owner_keys=None):
108   tx = deserialize_Transaction(d, transaction_index, owner_keys)
109   result = "block: "+(d['hashBlock'][::-1]).encode('hex_codec')
110   result += " %d hashes in merkle branch\n"%(len(d['merkleBranch'])/32,)
111   return result+tx
112
113 def parse_WalletTx(vds):
114   d = parse_MerkleTx(vds)
115   n_vtxPrev = vds.read_compact_size()
116   d['vtxPrev'] = []
117   for i in xrange(n_vtxPrev):
118     d['vtxPrev'].append(parse_MerkleTx(vds))
119
120   d['mapValue'] = {}
121   n_mapValue = vds.read_compact_size()
122   for i in xrange(n_mapValue):
123     key = vds.read_string()
124     value = vds.read_string()
125     d['mapValue'][key] = value
126   n_orderForm = vds.read_compact_size()
127   d['orderForm'] = []
128   for i in xrange(n_orderForm):
129     first = vds.read_string()
130     second = vds.read_string()
131     d['orderForm'].append( (first, second) )
132   d['fTimeReceivedIsTxTime'] = vds.read_uint32()
133   d['timeReceived'] = vds.read_uint32()
134   d['fromMe'] = vds.read_boolean()
135   d['spent'] = vds.read_boolean()
136
137   return d
138
139 def deserialize_WalletTx(d, transaction_index=None, owner_keys=None):
140   result = deserialize_MerkleTx(d, transaction_index, owner_keys)
141   result += "%d vtxPrev txns\n"%(len(d['vtxPrev']),)
142   result += "mapValue:"+str(d['mapValue'])
143   if len(d['orderForm']) > 0:
144     result += "\n"+" orderForm:"+str(d['orderForm'])
145   result += "\n"+"timeReceived:"+time.ctime(d['timeReceived'])
146   result += " fromMe:"+str(d['fromMe'])+" spent:"+str(d['spent'])
147   return result
148
149 # The CAuxPow (auxiliary proof of work) structure supports merged mining.
150 # A flag in the block version field indicates the structure's presence.
151 # As of 8/2011, the Original Bitcoin Client does not use it.  CAuxPow
152 # originated in Namecoin; see
153 # https://github.com/vinced/namecoin/blob/mergedmine/doc/README_merged-mining.md.
154 def parse_AuxPow(vds):
155   d = parse_MerkleTx(vds)
156   n_chainMerkleBranch = vds.read_compact_size()
157   d['chainMerkleBranch'] = vds.read_bytes(32*n_chainMerkleBranch)
158   d['chainIndex'] = vds.read_int32()
159   d['parentBlock'] = parse_BlockHeader(vds)
160   return d
161
162 def parse_BlockHeader(vds):
163   d = {}
164   header_start = vds.read_cursor
165   d['version'] = vds.read_int32()
166   d['hashPrev'] = vds.read_bytes(32)
167   d['hashMerkleRoot'] = vds.read_bytes(32)
168   d['nTime'] = vds.read_uint32()
169   d['nBits'] = vds.read_uint32()
170   d['nNonce'] = vds.read_uint32()
171   header_end = vds.read_cursor
172   d['__header__'] = vds.input[header_start:header_end]
173   return d
174
175 def parse_Block(vds):
176   d = parse_BlockHeader(vds)
177   if d['version'] & (1 << 8):
178     d['auxpow'] = parse_AuxPow(vds)
179   d['transactions'] = []
180   nTransactions = vds.read_compact_size()
181   for i in xrange(nTransactions):
182     d['transactions'].append(parse_Transaction(vds))
183
184   return d
185   
186 def deserialize_Block(d):
187   result = "Time: "+time.ctime(d['nTime'])+" Nonce: "+str(d['nNonce'])
188   result += "\nnBits: 0x"+hex(d['nBits'])
189   result += "\nhashMerkleRoot: 0x"+d['hashMerkleRoot'][::-1].encode('hex_codec')
190   result += "\nPrevious block: "+d['hashPrev'][::-1].encode('hex_codec')
191   result += "\n%d transactions:\n"%len(d['transactions'])
192   for t in d['transactions']:
193     result += deserialize_Transaction(t)+"\n"
194   result += "\nRaw block header: "+d['__header__'].encode('hex_codec')
195   return result
196
197 def parse_BlockLocator(vds):
198   d = { 'hashes' : [] }
199   nHashes = vds.read_compact_size()
200   for i in xrange(nHashes):
201     d['hashes'].append(vds.read_bytes(32))
202   return d
203
204 def deserialize_BlockLocator(d):
205   result = "Block Locator top: "+d['hashes'][0][::-1].encode('hex_codec')
206   return result
207
208 opcodes = Enumeration("Opcodes", [
209     ("OP_0", 0), ("OP_PUSHDATA1",76), "OP_PUSHDATA2", "OP_PUSHDATA4", "OP_1NEGATE", "OP_RESERVED",
210     "OP_1", "OP_2", "OP_3", "OP_4", "OP_5", "OP_6", "OP_7",
211     "OP_8", "OP_9", "OP_10", "OP_11", "OP_12", "OP_13", "OP_14", "OP_15", "OP_16",
212     "OP_NOP", "OP_VER", "OP_IF", "OP_NOTIF", "OP_VERIF", "OP_VERNOTIF", "OP_ELSE", "OP_ENDIF", "OP_VERIFY",
213     "OP_RETURN", "OP_TOALTSTACK", "OP_FROMALTSTACK", "OP_2DROP", "OP_2DUP", "OP_3DUP", "OP_2OVER", "OP_2ROT", "OP_2SWAP",
214     "OP_IFDUP", "OP_DEPTH", "OP_DROP", "OP_DUP", "OP_NIP", "OP_OVER", "OP_PICK", "OP_ROLL", "OP_ROT",
215     "OP_SWAP", "OP_TUCK", "OP_CAT", "OP_SUBSTR", "OP_LEFT", "OP_RIGHT", "OP_SIZE", "OP_INVERT", "OP_AND",
216     "OP_OR", "OP_XOR", "OP_EQUAL", "OP_EQUALVERIFY", "OP_RESERVED1", "OP_RESERVED2", "OP_1ADD", "OP_1SUB", "OP_2MUL",
217     "OP_2DIV", "OP_NEGATE", "OP_ABS", "OP_NOT", "OP_0NOTEQUAL", "OP_ADD", "OP_SUB", "OP_MUL", "OP_DIV",
218     "OP_MOD", "OP_LSHIFT", "OP_RSHIFT", "OP_BOOLAND", "OP_BOOLOR",
219     "OP_NUMEQUAL", "OP_NUMEQUALVERIFY", "OP_NUMNOTEQUAL", "OP_LESSTHAN",
220     "OP_GREATERTHAN", "OP_LESSTHANOREQUAL", "OP_GREATERTHANOREQUAL", "OP_MIN", "OP_MAX",
221     "OP_WITHIN", "OP_RIPEMD160", "OP_SHA1", "OP_SHA256", "OP_HASH160",
222     "OP_HASH256", "OP_CODESEPARATOR", "OP_CHECKSIG", "OP_CHECKSIGVERIFY", "OP_CHECKMULTISIG",
223     "OP_CHECKMULTISIGVERIFY",
224     ("OP_SINGLEBYTE_END", 0xF0),
225     ("OP_DOUBLEBYTE_BEGIN", 0xF000),
226     "OP_PUBKEY", "OP_PUBKEYHASH",
227     ("OP_INVALIDOPCODE", 0xFFFF),
228 ])
229
230 def script_GetOp(bytes):
231   i = 0
232   while i < len(bytes):
233     vch = None
234     opcode = ord(bytes[i])
235     i += 1
236     if opcode >= opcodes.OP_SINGLEBYTE_END:
237       opcode <<= 8
238       opcode |= bytes[i]
239       i += 1
240
241     if opcode <= opcodes.OP_PUSHDATA4:
242       nSize = opcode
243       if opcode == opcodes.OP_PUSHDATA1:
244         nSize = ord(bytes[i])
245         i += 1
246       elif opcode == opcodes.OP_PUSHDATA2:
247         nSize = unpack_from('<H', bytes, i)
248         i += 2
249       elif opcode == opcodes.OP_PUSHDATA4:
250         nSize = unpack_from('<I', bytes, i)
251         i += 4
252       vch = bytes[i:i+nSize]
253       i += nSize
254
255     yield (opcode, vch)
256
257 def script_GetOpName(opcode):
258   return (opcodes.whatis(opcode)).replace("OP_", "")
259
260 def decode_script(bytes):
261   result = ''
262   for (opcode, vch) in script_GetOp(bytes):
263     if len(result) > 0: result += " "
264     if opcode <= opcodes.OP_PUSHDATA4:
265       result += "%d:"%(opcode,)
266       result += short_hex(vch)
267     else:
268       result += script_GetOpName(opcode)
269   return result
270
271 def match_decoded(decoded, to_match):
272   if len(decoded) != len(to_match):
273     return False;
274   for i in range(len(decoded)):
275     if to_match[i] == opcodes.OP_PUSHDATA4 and decoded[i][0] <= opcodes.OP_PUSHDATA4:
276       continue  # Opcodes below OP_PUSHDATA4 all just push data onto stack, and are equivalent.
277     if to_match[i] != decoded[i][0]:
278       return False
279   return True
280
281 def extract_public_key(bytes):
282   decoded = [ x for x in script_GetOp(bytes) ]
283
284   # non-generated TxIn transactions push a signature
285   # (seventy-something bytes) and then their public key
286   # (65 bytes) onto the stack:
287   match = [ opcodes.OP_PUSHDATA4, opcodes.OP_PUSHDATA4 ]
288   if match_decoded(decoded, match):
289     return public_key_to_bc_address(decoded[1][1])
290
291   # The Genesis Block, self-payments, and pay-by-IP-address payments look like:
292   # 65 BYTES:... CHECKSIG
293   match = [ opcodes.OP_PUSHDATA4, opcodes.OP_CHECKSIG ]
294   if match_decoded(decoded, match):
295     return public_key_to_bc_address(decoded[0][1])
296
297   # Pay-by-Bitcoin-address TxOuts look like:
298   # DUP HASH160 20 BYTES:... EQUALVERIFY CHECKSIG
299   match = [ opcodes.OP_DUP, opcodes.OP_HASH160, opcodes.OP_PUSHDATA4, opcodes.OP_EQUALVERIFY, opcodes.OP_CHECKSIG ]
300   if match_decoded(decoded, match):
301     return hash_160_to_bc_address(decoded[2][1])
302
303   return "(None)"