3 # Original author: ArtForz
4 # Twisted integration: slush
13 from Crypto.Hash import SHA256
15 from twisted.internet.protocol import Protocol
21 class CAddress(object):
25 self.pchReserved = "\x00" * 10 + "\xff" * 2
28 def deserialize(self, f):
29 #self.nTime = struct.unpack("<I", f.read(4))[0]
30 self.nServices = struct.unpack("<Q", f.read(8))[0]
31 self.pchReserved = f.read(12)
32 self.ip = socket.inet_ntoa(f.read(4))
33 self.port = struct.unpack(">H", f.read(2))[0]
36 #r += struct.pack("<I", self.nTime)
37 r += struct.pack("<Q", self.nServices)
39 r += socket.inet_aton(self.ip)
40 r += struct.pack(">H", self.port)
43 return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices, self.ip, self.port)
53 def deserialize(self, f):
54 self.type = struct.unpack("<i", f.read(4))[0]
55 self.hash = deser_uint256(f)
58 r += struct.pack("<i", self.type)
59 r += ser_uint256(self.hash)
62 return "CInv(type=%s hash=%064x)" % (self.typemap[self.type], self.hash)
64 class CBlockLocator(object):
66 self.nVersion = MY_VERSION
68 def deserialize(self, f):
69 self.nVersion = struct.unpack("<i", f.read(4))[0]
70 self.vHave = deser_uint256_vector(f)
73 r += struct.pack("<i", self.nVersion)
74 r += ser_uint256_vector(self.vHave)
77 return "CBlockLocator(nVersion=%i vHave=%s)" % (self.nVersion, repr(self.vHave))
79 class COutPoint(object):
83 def deserialize(self, f):
84 self.hash = deser_uint256(f)
85 self.n = struct.unpack("<I", f.read(4))[0]
88 r += ser_uint256(self.hash)
89 r += struct.pack("<I", self.n)
92 return "COutPoint(hash=%064x n=%i)" % (self.hash, self.n)
96 self.prevout = COutPoint()
99 def deserialize(self, f):
100 self.prevout = COutPoint()
101 self.prevout.deserialize(f)
102 self.scriptSig = deser_string(f)
103 self.nSequence = struct.unpack("<I", f.read(4))[0]
106 r += self.prevout.serialize()
107 r += ser_string(self.scriptSig)
108 r += struct.pack("<I", self.nSequence)
111 return "CTxIn(prevout=%s scriptSig=%s nSequence=%i)" % (repr(self.prevout), binascii.hexlify(self.scriptSig), self.nSequence)
113 class CTxOut(object):
116 self.scriptPubKey = ""
117 def deserialize(self, f):
118 self.nValue = struct.unpack("<q", f.read(8))[0]
119 self.scriptPubKey = deser_string(f)
122 r += struct.pack("<q", self.nValue)
123 r += ser_string(self.scriptPubKey)
126 return "CTxOut(nValue=%i.%08i scriptPubKey=%s)" % (self.nValue // 100000000, self.nValue % 100000000, binascii.hexlify(self.scriptPubKey))
128 class CTransaction(object):
135 def deserialize(self, f):
136 self.nVersion = struct.unpack("<i", f.read(4))[0]
137 self.vin = deser_vector(f, CTxIn)
138 self.vout = deser_vector(f, CTxOut)
139 self.nLockTime = struct.unpack("<I", f.read(4))[0]
143 r += struct.pack("<i", self.nVersion)
144 r += ser_vector(self.vin)
145 r += ser_vector(self.vout)
146 r += struct.pack("<I", self.nLockTime)
149 def calc_sha256(self):
150 if self.sha256 is None:
151 self.sha256 = uint256_from_str(SHA256.new(SHA256.new(self.serialize()).digest()).digest())
156 for tout in self.vout:
157 if tout.nValue < 0 or tout.nValue > 21000000L * 100000000L:
161 return "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i)" % (self.nVersion, repr(self.vin), repr(self.vout), self.nLockTime)
163 class CBlock(object):
166 self.hashPrevBlock = 0
167 self.hashMerkleRoot = 0
173 def deserialize(self, f):
174 self.nVersion = struct.unpack("<i", f.read(4))[0]
175 self.hashPrevBlock = deser_uint256(f)
176 self.hashMerkleRoot = deser_uint256(f)
177 self.nTime = struct.unpack("<I", f.read(4))[0]
178 self.nBits = struct.unpack("<I", f.read(4))[0]
179 self.nNonce = struct.unpack("<I", f.read(4))[0]
180 self.vtx = deser_vector(f, CTransaction)
183 r.append(struct.pack("<i", self.nVersion))
184 r.append(ser_uint256(self.hashPrevBlock))
185 r.append(ser_uint256(self.hashMerkleRoot))
186 r.append(struct.pack("<I", self.nTime))
187 r.append(struct.pack("<I", self.nBits))
188 r.append(struct.pack("<I", self.nNonce))
189 r.append(ser_vector(self.vtx))
191 def calc_sha256(self):
192 if self.sha256 is None:
194 r.append(struct.pack("<i", self.nVersion))
195 r.append(ser_uint256(self.hashPrevBlock))
196 r.append(ser_uint256(self.hashMerkleRoot))
197 r.append(struct.pack("<I", self.nTime))
198 r.append(struct.pack("<I", self.nBits))
199 r.append(struct.pack("<I", self.nNonce))
200 self.sha256 = uint256_from_str(SHA256.new(SHA256.new(''.join(r)).digest()).digest())
205 target = uint256_from_compact(self.nBits)
206 if self.sha256 > target:
211 if not tx.is_valid():
214 hashes.append(ser_uint256(tx.sha256))
216 while len(hashes) > 1:
218 for i in xrange(0, len(hashes), 2):
219 i2 = min(i+1, len(hashes)-1)
220 newhashes.append(SHA256.new(SHA256.new(hashes[i] + hashes[i2]).digest()).digest())
223 if uint256_from_str(hashes[0]) != self.hashMerkleRoot:
227 return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx))
229 class msg_version(object):
232 self.nVersion = MY_VERSION
234 self.nTime = time.time()
235 self.addrTo = CAddress()
236 self.addrFrom = CAddress()
237 self.nNonce = random.getrandbits(64)
238 self.strSubVer = MY_SUBVERSION
239 self.nStartingHeight = 0
241 def deserialize(self, f):
242 self.nVersion = struct.unpack("<i", f.read(4))[0]
243 if self.nVersion == 10300:
245 self.nServices = struct.unpack("<Q", f.read(8))[0]
246 self.nTime = struct.unpack("<q", f.read(8))[0]
247 self.addrTo = CAddress()
248 self.addrTo.deserialize(f)
249 self.addrFrom = CAddress()
250 self.addrFrom.deserialize(f)
251 self.nNonce = struct.unpack("<Q", f.read(8))[0]
252 self.strSubVer = deser_string(f)
253 self.nStartingHeight = struct.unpack("<i", f.read(4))[0]
256 r.append(struct.pack("<i", self.nVersion))
257 r.append(struct.pack("<Q", self.nServices))
258 r.append(struct.pack("<q", self.nTime))
259 r.append(self.addrTo.serialize())
260 r.append(self.addrFrom.serialize())
261 r.append(struct.pack("<Q", self.nNonce))
262 r.append(ser_string(self.strSubVer))
263 r.append(struct.pack("<i", self.nStartingHeight))
266 return "msg_version(nVersion=%i nServices=%i nTime=%s addrTo=%s addrFrom=%s nNonce=0x%016X strSubVer=%s nStartingHeight=%i)" % (self.nVersion, self.nServices, time.ctime(self.nTime), repr(self.addrTo), repr(self.addrFrom), self.nNonce, self.strSubVer, self.nStartingHeight)
268 class msg_verack(object):
272 def deserialize(self, f):
277 return "msg_verack()"
279 class msg_addr(object):
283 def deserialize(self, f):
284 self.addrs = deser_vector(f, CAddress)
286 return ser_vector(self.addrs)
288 return "msg_addr(addrs=%s)" % (repr(self.addrs))
290 class msg_inv(object):
294 def deserialize(self, f):
295 self.inv = deser_vector(f, CInv)
297 return ser_vector(self.inv)
299 return "msg_inv(inv=%s)" % (repr(self.inv))
301 class msg_getdata(object):
305 def deserialize(self, f):
306 self.inv = deser_vector(f, CInv)
308 return ser_vector(self.inv)
310 return "msg_getdata(inv=%s)" % (repr(self.inv))
312 class msg_getblocks(object):
313 command = "getblocks"
315 self.locator = CBlockLocator()
317 def deserialize(self, f):
318 self.locator = CBlockLocator()
319 self.locator.deserialize(f)
320 self.hashstop = deser_uint256(f)
323 r.append(self.locator.serialize())
324 r.append(ser_uint256(self.hashstop))
327 return "msg_getblocks(locator=%s hashstop=%064x)" % (repr(self.locator), self.hashstop)
329 class msg_tx(object):
332 self.tx = CTransaction()
333 def deserialize(self, f):
334 self.tx.deserialize(f)
336 return self.tx.serialize()
338 return "msg_tx(tx=%s)" % (repr(self.tx))
340 class msg_block(object):
343 self.block = CBlock()
344 def deserialize(self, f):
345 self.block.deserialize(f)
347 return self.block.serialize()
349 return "msg_block(block=%s)" % (repr(self.block))
351 class msg_getaddr(object):
355 def deserialize(self, f):
360 return "msg_getaddr()"
362 class msg_ping(object):
366 def deserialize(self, f):
373 class msg_alert(object):
377 def deserialize(self, f):
384 class BitcoinP2PProtocol(Protocol):
386 "version": msg_version,
387 "verack": msg_verack,
390 "getdata": msg_getdata,
391 "getblocks": msg_getblocks,
394 "getaddr": msg_getaddr,
399 def connectionMade(self):
400 peer = self.transport.getPeer()
401 self.dstaddr = peer.host
402 self.dstport = peer.port
407 t.nStartingHeight = getattr(self, 'nStartingHeight', 0)
408 t.addrTo.ip = self.dstaddr
409 t.addrTo.port = self.dstport
410 t.addrTo.nTime = time.time()
411 t.addrFrom.ip = "0.0.0.0"
413 t.addrFrom.nTime = time.time()
416 def dataReceived(self, data):
422 if len(self.recvbuf) < 4:
424 if self.recvbuf[:4] != "\xf9\xbe\xb4\xd9":
425 raise ValueError("got garbage %s" % repr(self.recvbuf))
427 if len(self.recvbuf) < 4 + 12 + 4 + 4:
429 command = self.recvbuf[4:4+12].split("\x00", 1)[0]
430 msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
431 checksum = self.recvbuf[4+12+4:4+12+4+4]
432 if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen:
434 msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen]
435 th = SHA256.new(msg).digest()
436 h = SHA256.new(th).digest()
437 if checksum != h[:4]:
438 raise ValueError("got bad checksum %s" % repr(self.recvbuf))
439 self.recvbuf = self.recvbuf[4+12+4+4+msglen:]
441 if command in self.messagemap:
442 f = cStringIO.StringIO(msg)
443 t = self.messagemap[command]()
447 print "UNKNOWN COMMAND", command, repr(msg)
449 def prepare_message(self, message):
450 command = message.command
451 data = message.serialize()
452 tmsg = "\xf9\xbe\xb4\xd9"
454 tmsg += "\x00" * (12 - len(command))
455 tmsg += struct.pack("<I", len(data))
456 th = SHA256.new(data).digest()
457 h = SHA256.new(th).digest()
462 def send_serialized_message(self, tmsg):
463 if not self.connected:
466 self.transport.write(tmsg)
467 self.last_sent = time.time()
469 def send_message(self, message):
470 if not self.connected:
473 #print message.command
475 #print "send %s" % repr(message)
476 command = message.command
477 data = message.serialize()
478 tmsg = "\xf9\xbe\xb4\xd9"
480 tmsg += "\x00" * (12 - len(command))
481 tmsg += struct.pack("<I", len(data))
482 th = SHA256.new(data).digest()
483 h = SHA256.new(th).digest()
487 #print tmsg, len(tmsg)
488 self.transport.write(tmsg)
489 self.last_sent = time.time()
491 def got_message(self, message):
492 if self.last_sent + 30 * 60 < time.time():
493 self.send_message(msg_ping())
495 mname = 'do_' + message.command
497 if not hasattr(self, mname):
500 method = getattr(self, mname)
503 # if message.command == "tx":
504 # message.tx.calc_sha256()
505 # sha256 = message.tx.sha256
506 # pubkey = binascii.hexlify(message.tx.vout[0].scriptPubKey)
508 # tx.append([str(sha256), str(time.time()), str(self.dstaddr), pubkey])
511 def do_version(self, message):
513 self.send_message(msg_verack())
515 def do_inv(self, message):
517 for i in message.inv:
523 self.send_message(want)