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):
136 def deserialize(self, f):
137 self.nVersion = struct.unpack("<i", f.read(4))[0]
138 self.nTime = struct.unpack("<i", f.read(4))[0]
139 self.vin = deser_vector(f, CTxIn)
140 self.vout = deser_vector(f, CTxOut)
141 self.nLockTime = struct.unpack("<I", f.read(4))[0]
145 r += struct.pack("<i", self.nVersion)
146 r += struct.pack("<i", self.nTime)
147 r += ser_vector(self.vin)
148 r += ser_vector(self.vout)
149 r += struct.pack("<I", self.nLockTime)
152 def calc_sha256(self):
153 if self.sha256 is None:
154 self.sha256 = uint256_from_str(SHA256.new(SHA256.new(self.serialize()).digest()).digest())
159 for tout in self.vout:
160 if tout.nValue < 0 or tout.nValue > 21000000L * 100000000L:
164 return "CTransaction(nVersion=%i vin=%s vout=%s nLockTime=%i)" % (self.nVersion, repr(self.vin), repr(self.vout), self.nLockTime)
166 class CBlock(object):
169 self.hashPrevBlock = 0
170 self.hashMerkleRoot = 0
177 def deserialize(self, f):
178 self.nVersion = struct.unpack("<i", f.read(4))[0]
179 self.hashPrevBlock = deser_uint256(f)
180 self.hashMerkleRoot = deser_uint256(f)
181 self.nTime = struct.unpack("<I", f.read(4))[0]
182 self.nBits = struct.unpack("<I", f.read(4))[0]
183 self.nNonce = struct.unpack("<I", f.read(4))[0]
184 self.vtx = deser_vector(f, CTransaction)
185 self.signature = deser_string(f)
188 r.append(struct.pack("<i", self.nVersion))
189 r.append(ser_uint256(self.hashPrevBlock))
190 r.append(ser_uint256(self.hashMerkleRoot))
191 r.append(struct.pack("<I", self.nTime))
192 r.append(struct.pack("<I", self.nBits))
193 r.append(struct.pack("<I", self.nNonce))
194 r.append(ser_vector(self.vtx))
195 r.append(ser_string(self.signature))
197 def calc_sha256(self):
198 if self.sha256 is None:
200 r.append(struct.pack("<i", self.nVersion))
201 r.append(ser_uint256(self.hashPrevBlock))
202 r.append(ser_uint256(self.hashMerkleRoot))
203 r.append(struct.pack("<I", self.nTime))
204 r.append(struct.pack("<I", self.nBits))
205 r.append(struct.pack("<I", self.nNonce))
206 self.sha256 = uint256_from_str(scrypt(''.join(r)))
211 target = uint256_from_compact(self.nBits)
212 if self.sha256 > target:
217 if not tx.is_valid():
220 hashes.append(ser_uint256(tx.sha256))
222 while len(hashes) > 1:
224 for i in xrange(0, len(hashes), 2):
225 i2 = min(i+1, len(hashes)-1)
226 newhashes.append(SHA256.new(SHA256.new(hashes[i] + hashes[i2]).digest()).digest())
229 if uint256_from_str(hashes[0]) != self.hashMerkleRoot:
233 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))
235 class msg_version(object):
238 self.nVersion = MY_VERSION
240 self.nTime = time.time()
241 self.addrTo = CAddress()
242 self.addrFrom = CAddress()
243 self.nNonce = random.getrandbits(64)
244 self.strSubVer = MY_SUBVERSION
245 self.nStartingHeight = 0
247 def deserialize(self, f):
248 self.nVersion = struct.unpack("<i", f.read(4))[0]
249 if self.nVersion == 10300:
251 self.nServices = struct.unpack("<Q", f.read(8))[0]
252 self.nTime = struct.unpack("<q", f.read(8))[0]
253 self.addrTo = CAddress()
254 self.addrTo.deserialize(f)
255 self.addrFrom = CAddress()
256 self.addrFrom.deserialize(f)
257 self.nNonce = struct.unpack("<Q", f.read(8))[0]
258 self.strSubVer = deser_string(f)
259 self.nStartingHeight = struct.unpack("<i", f.read(4))[0]
262 r.append(struct.pack("<i", self.nVersion))
263 r.append(struct.pack("<Q", self.nServices))
264 r.append(struct.pack("<q", self.nTime))
265 r.append(self.addrTo.serialize())
266 r.append(self.addrFrom.serialize())
267 r.append(struct.pack("<Q", self.nNonce))
268 r.append(ser_string(self.strSubVer))
269 r.append(struct.pack("<i", self.nStartingHeight))
272 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)
274 class msg_verack(object):
278 def deserialize(self, f):
283 return "msg_verack()"
285 class msg_addr(object):
289 def deserialize(self, f):
290 self.addrs = deser_vector(f, CAddress)
292 return ser_vector(self.addrs)
294 return "msg_addr(addrs=%s)" % (repr(self.addrs))
296 class msg_inv(object):
300 def deserialize(self, f):
301 self.inv = deser_vector(f, CInv)
303 return ser_vector(self.inv)
305 return "msg_inv(inv=%s)" % (repr(self.inv))
307 class msg_getdata(object):
311 def deserialize(self, f):
312 self.inv = deser_vector(f, CInv)
314 return ser_vector(self.inv)
316 return "msg_getdata(inv=%s)" % (repr(self.inv))
318 class msg_getblocks(object):
319 command = "getblocks"
321 self.locator = CBlockLocator()
323 def deserialize(self, f):
324 self.locator = CBlockLocator()
325 self.locator.deserialize(f)
326 self.hashstop = deser_uint256(f)
329 r.append(self.locator.serialize())
330 r.append(ser_uint256(self.hashstop))
333 return "msg_getblocks(locator=%s hashstop=%064x)" % (repr(self.locator), self.hashstop)
335 class msg_tx(object):
338 self.tx = CTransaction()
339 def deserialize(self, f):
340 self.tx.deserialize(f)
342 return self.tx.serialize()
344 return "msg_tx(tx=%s)" % (repr(self.tx))
346 class msg_block(object):
349 self.block = CBlock()
350 def deserialize(self, f):
351 self.block.deserialize(f)
353 return self.block.serialize()
355 return "msg_block(block=%s)" % (repr(self.block))
357 class msg_getaddr(object):
361 def deserialize(self, f):
366 return "msg_getaddr()"
368 class msg_ping(object):
372 def deserialize(self, f):
379 class msg_alert(object):
383 def deserialize(self, f):
390 class BitcoinP2PProtocol(Protocol):
392 "version": msg_version,
393 "verack": msg_verack,
396 "getdata": msg_getdata,
397 "getblocks": msg_getblocks,
400 "getaddr": msg_getaddr,
405 def connectionMade(self):
406 peer = self.transport.getPeer()
407 self.dstaddr = peer.host
408 self.dstport = peer.port
413 t.nStartingHeight = getattr(self, 'nStartingHeight', 0)
414 t.addrTo.ip = self.dstaddr
415 t.addrTo.port = self.dstport
416 t.addrTo.nTime = time.time()
417 t.addrFrom.ip = "0.0.0.0"
419 t.addrFrom.nTime = time.time()
422 def dataReceived(self, data):
428 if len(self.recvbuf) < 4:
430 if self.recvbuf[:4] != "\xf9\xbe\xb4\xd9":
431 raise ValueError("got garbage %s" % repr(self.recvbuf))
433 if len(self.recvbuf) < 4 + 12 + 4 + 4:
435 command = self.recvbuf[4:4+12].split("\x00", 1)[0]
436 msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
437 checksum = self.recvbuf[4+12+4:4+12+4+4]
438 if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen:
440 msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen]
441 th = SHA256.new(msg).digest()
442 h = SHA256.new(th).digest()
443 if checksum != h[:4]:
444 raise ValueError("got bad checksum %s" % repr(self.recvbuf))
445 self.recvbuf = self.recvbuf[4+12+4+4+msglen:]
447 if command in self.messagemap:
448 f = cStringIO.StringIO(msg)
449 t = self.messagemap[command]()
453 print "UNKNOWN COMMAND", command, repr(msg)
455 def prepare_message(self, message):
456 command = message.command
457 data = message.serialize()
458 tmsg = "\xf9\xbe\xb4\xd9"
460 tmsg += "\x00" * (12 - len(command))
461 tmsg += struct.pack("<I", len(data))
462 th = SHA256.new(data).digest()
463 h = SHA256.new(th).digest()
468 def send_serialized_message(self, tmsg):
469 if not self.connected:
472 self.transport.write(tmsg)
473 self.last_sent = time.time()
475 def send_message(self, message):
476 if not self.connected:
479 #print message.command
481 #print "send %s" % repr(message)
482 command = message.command
483 data = message.serialize()
484 tmsg = "\xf9\xbe\xb4\xd9"
486 tmsg += "\x00" * (12 - len(command))
487 tmsg += struct.pack("<I", len(data))
488 th = SHA256.new(data).digest()
489 h = SHA256.new(th).digest()
493 #print tmsg, len(tmsg)
494 self.transport.write(tmsg)
495 self.last_sent = time.time()
497 def got_message(self, message):
498 if self.last_sent + 30 * 60 < time.time():
499 self.send_message(msg_ping())
501 mname = 'do_' + message.command
503 if not hasattr(self, mname):
506 method = getattr(self, mname)
509 # if message.command == "tx":
510 # message.tx.calc_sha256()
511 # sha256 = message.tx.sha256
512 # pubkey = binascii.hexlify(message.tx.vout[0].scriptPubKey)
514 # tx.append([str(sha256), str(time.time()), str(self.dstaddr), pubkey])
517 def do_version(self, message):
519 self.send_message(msg_verack())
521 def do_inv(self, message):
523 for i in message.inv:
529 self.send_message(want)