def PING(self, source, msg): #logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) #nodeState[self][MEMB_MSGS_RECEIVED] += 1 addEntryDB(self, source) sim.send(PONG, source, self, PONG_MSG)
def BLOCK(self, source, msg, block): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 if block.getHash() not in REPEATED_BLOCK_COUNT[self]: REPEATED_BLOCK_COUNT[self].update({block.getHash(): 1}) else: REPEATED_BLOCK_COUNT[self][block.getHash()] += 1 if block.getHash() not in nodeState[self][KNOWN_BLOCKS]: # Remove from missing/asked a = (ANN_BLOCK, block.getHash()) if a in nodeState[self][MISSING_ANN]: del nodeState[self][MISSING_ANN][a] if a in nodeState[self][ASKED_ANN]: del nodeState[self][ASKED_ANN][a] nodeState[self][KNOWN_BLOCKS][block.getHash()] = block nodeState[self][QUEUED_BLOCKS].append(block) eagerList = nodeState[self][BTREE][EAGER].copy() if source in eagerList: eagerList.remove(source) else: graftBTree(self, source) for n in eagerList: sim.send(BLOCK, n, self, BLOCK_MSG, block) nodeState[self][DISS_MSGS_SENT] += 1 nodeState[self][QUEUED_ANN].append((ANN_BLOCK, block.getHash())) else: pruneBTree(self, source) sim.send(PRUNE, source, self, PRUNE_MSG) nodeState[self][DISS_MSGS_SENT] += 1
def TXS(self, source, msg, tx): #logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 if tx.getHash() not in nodeState[self][KNOWN_TXS]: # Remove from missing/asked a = (ANN_TX, tx.getHash()) if a in nodeState[self][MISSING_ANN]: del nodeState[self][MISSING_ANN][a] if a in nodeState[self][ASKED_ANN]: del nodeState[self][ASKED_ANN][a] nodeState[self][KNOWN_TXS][tx.getHash()] = tx nodeState[self][QUEUED_TXS].append(tx) eagerList = nodeState[self][BTREE][EAGER].copy() if source in eagerList: eagerList.remove(source) else: graftBTree(self, source) for n in eagerList: sim.send(TXS, n, self, TXS_MSG, tx) nodeState[self][DISS_MSGS_SENT] += 1 nodeState[self][QUEUED_ANN].append((ANN_TX, tx.getHash())) elif tx.getNumber() % 100 == 0: pruneBTree(self, source) sim.send(PRUNE, source, self, PRUNE_MSG) nodeState[self][DISS_MSGS_SENT] += 1
def PING(self, source, msg): #logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) #nodeState[self][MEMB_MSGS_RECEIVED] += 1 addEntryDb(self, source) updateEntryPingDb(self, source, nodeState[self][CURRENT_TIME]) sim.send(PONG, source, self, PONG_MSG)
def NEWBLOCK(self, source, msg, block): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 if block.getHash() not in REPEATED_BLOCK_COUNT[self]: REPEATED_BLOCK_COUNT[self].update({block.getHash():1}) else: REPEATED_BLOCK_COUNT[self][block.getHash()] += 1 if block.getHash() in nodeState[self][KNOWN_BLOCKS]: propagate = False else: propagate = True nodeState[self][QUEUED_BLOCKS].append(block) nodeState[self][KNOWN_BLOCKS][block.getHash()] = block #propagation if propagate: neighbors = getNeighbors(self) if source in neighbors: neighbors.remove(source) rootSample = random.sample(neighbors, int(math.sqrt(len(neighbors)))) for n in neighbors: if n in rootSample: sim.send(NEWBLOCK, n, self, NEWBLOCK_MSG, block) else: sim.send(NEWBLOCKHASHES, n, self, NEWBLOCKHASHES_MSG, [block.getHash()]) nodeState[self][DISS_MSGS_SENT] += 1
def TRANSACTIONS(self, source, msg, txs): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 if verifyTxs(self, txs): for t in txs: nodeState[self][KNOWN_TXS][t.getHash()] = t if t not in nodeState[self][QUEUED_TXS]: nodeState[self][QUEUED_TXS].append(t) if not nodeState[self][ANN_TXS].get(t.getHash()): nodeState[self][ANN_TXS][t.getHash()] = [] if source not in nodeState[self][ANN_TXS][t.getHash()]: nodeState[self][ANN_TXS][t.getHash()].append(source) # Propagation for n in getNeighbors(self): tmp = [] for t in txs: if n not in nodeState[self][ANN_TXS][t.getHash()]: nodeState[self][ANN_TXS][t.getHash()].append(n) tmp.append(t) if tmp: sim.send(TRANSACTIONS, n, self, TRANSACTIONS_MSG, tmp) nodeState[self][DISS_MSGS_SENT] += 1
def GETDATA(self, source, msg, type, hashes, sync=False): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 if type == ANN_BLOCK: if sync: retrieve = [] b_index = nodeState[self][BLOCKCHAIN].index( nodeState[self][BLOCKCHAIN_HASHES].get(hashes[0])) for i in range(0, b_index): retrieve.append(nodeState[self][BLOCKCHAIN][b_index - i].getHeader()) else: retrieve = list(hashes) for h in retrieve: if h in nodeState[self][KNOWN_BLOCKS]: sim.send(BLOCK, source, self, BLOCK_MSG, nodeState[self][KNOWN_BLOCKS][h]) nodeState[self][DISS_MSGS_SENT] += 1 elif type == ANN_TX: for h in hashes: if h in nodeState[self][KNOWN_TXS]: sim.send(TXS, source, self, TXS_MSG, nodeState[self][KNOWN_TXS][h]) nodeState[self][DISS_MSGS_SENT] += 1
def GETADDR(self, source, msg): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][MEMB_MSGS_RECEIVED] += 1 if source not in nodeState[self][DB]: nodeState[self][DB].append(source) sim.send(ADDR, source, self, ADDR_MSG, createSample(self)) nodeState[self][MEMB_MSGS_SENT] += 1
def lookup(self, target): queries = 0 for n in lookupNeighbors(self, target): if queries >= alpha: break sim.send(FINDNODE, n, self, FINDNODE_MSG, target) nodeState[self][MEMB_MSGS_SENT] += 1 queries += 1
def PING(myself, source, nonce): global nodeState check_if_connected(myself, source) if should_log(myself): nodeState[myself][MSGS][PING_MSG] += 1 sim.send(PONG, source, myself, nonce)
def HEADERS(self, source, msg, headers): # The headers message sends block headers to a node which previously requested certain headers with a getheaders message. # A headers message can be empty. logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 if verifyHeaders(self, headers): sim.send(GETBLOCKS, source, self, GETBLOCKS_MSG, headers) nodeState[self][DISS_MSGS_SENT] += 1
def FINDNODE(self, source, msg): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][MEMB_MSGS_RECEIVED] += 1 addEntryDB(self, source) addEntryNeighbs(self, source) sim.send(NEIGHBORS, source, self, NEIGHBORS_MSG, lookupNeighbors(self)) nodeState[self][MEMB_MSGS_SENT] += 1
def NEWBLOCKHASHES(self, source, msg, hashes): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 tmp = [] for h in hashes: if h not in nodeState[self][KNOWN_BLOCKS].keys(): tmp.append(h) if tmp: sim.send(GETBLOCKBODIES, source, self, GETBLOCKBODIES_MSG, tmp) nodeState[self][DISS_MSGS_SENT] += 1
def VERSION(self, source, msg): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][MEMB_MSGS_RECEIVED] += 1 if self == source: return if source not in nodeState[self][DB]: nodeState[self][DB].append(source) sim.send(VERACK, source, self, VERACK_MSG) nodeState[self][MEMB_MSGS_SENT] += 1
def send_ping(myself, target, pto): global ping_nonce ping_send = False if pto[PING_STRC][PING_NONCE_SENT] == 0 and pto[PING_STRC][ PING_TIME_START] + PING_INTERVAL < nodeState[myself][CURRENT_TIME]: ping_send = True if ping_send: pto[PING_STRC][PING_TIME_START] = nodeState[myself][CURRENT_TIME] pto[PING_STRC][PING_NONCE_SENT] = ping_nonce ping_nonce += 1 sim.send(PING, target, myself, pto[PING_STRC][PING_NONCE_SENT])
def BLOCKHEADERS(self, source, msg, headers): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 hashes = [] if verifyHeaders(self, headers): for b in nodeState[self][BLOCKCHAIN]: if b.getHeader() in headers: hashes.append(b.getHash()) if hashes: sim.send(GETBLOCKBODIES, source, self, GETBLOCKBODIES_MSG, hashes) nodeState[self][DISS_MSGS_SENT] += 1
def send_addr(myself, target, pto): if pto[ADDR_STRC][NEXT_ADDR_SEND] < nodeState[myself][CURRENT_TIME]: pto[ADDR_STRC][NEXT_ADDR_SEND] = poisson_next_send( nodeState[myself][CURRENT_TIME], AVG_ADDRESS_BROADCAST_INTERVAL) addr_to_send = [] for addr in pto[ADDR_STRC][ADDR_TO_SEND]: if not has_addr(pto, addr): add_addr(pto, addr) addr_to_send.append(addr) if len(addr_to_send) >= MAX_ADDR_MSG_SIZE: sim.send(ADDR, target, myself, addr_to_send) pto[ADDR_STRC][ADDR_TO_SEND] = [] if addr_to_send: sim.send(ADDR, target, myself, addr_to_send)
def lookupBack(self, target, stopMatch): # recursive lookup # TODO move out of threads global neighborsQueue global nodeState asked = {} seen = [] result = [] pendingQueries = 0 result = lookupNeighbors(self, target) while True: for n in result: if pendingQueries >= alpha: break if n not in asked.keys(): asked[n] = time.time() pendingQueries += 1 addEntryDb(self, n) addEntryBucket(self, n) sim.send(FINDNODE, n, self, FINDNODE_MSG, target) nodeState[self][MEMB_MSGS_SENT] += 1 if pendingQueries == 0: break for queried in asked.keys(): if asked[queried] == 0 or queried not in neighborsQueue: continue response = neighborsQueue[queried] for n in response: if n not in seen: seen.append(n) result.append(n) if stopMatch and n == target: return result asked[queried] = 0 pendingQueries -= 1 for n in asked.keys(): if asked[n] == 0: continue t = (time.time() - asked[n]) * 1000 if t > lookupTimeout: pendingQueries = 0 return result
def GETBLOCKS(self, source, msg, headers): # The getblocks message requests an inv message that provides block header hashes starting from a particular point in the block chain. # It allows a peer which has been disconnected or started for the first time to get the data it needs to request the blocks it hasn’t seen. logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 tmp = [] for b in nodeState[self][BLOCKCHAIN]: if b.getHeader() in headers: tmp.append([MSG_BLOCK, b.getHash()]) if len(tmp) > 0: sim.send(INV, source, self, INV_MSG, tmp) nodeState[self][DISS_MSGS_SENT] += 1 del tmp
def ADDR(self, source, msg, addrs): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][MEMB_MSGS_RECEIVED] += 1 temp = [] for n in addrs: if n != self and n not in nodeState[self][CONNS]: temp.append(n) nodeState[self][RELAY_NODES].append(n) for n in temp: addConn(self, n) sim.send(VERSION, n, self, VERSION_MSG) nodeState[self][MEMB_MSGS_SENT] += 1 del temp
def GETBLOCKBODIES(self, source, msg, hashes): # Send full block logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 blocks = [] for h in hashes: if h in nodeState[self][KNOWN_BLOCKS].keys(): blocks.append(nodeState[self][KNOWN_BLOCKS].get(h)) elif h in nodeState[self][BLOCKCHAIN_HASHES].keys(): blocks.append(nodeState[self][BLOCKCHAIN_HASHES].get(h)) if blocks: sim.send(BLOCKBODIES, source, self, BLOCKBODIES_MSG, blocks) nodeState[self][DISS_MSGS_SENT] += 1
def join(self): if self not in NETWORK_NODES: NETWORK_NODES.append(self) if len(NETWORK_NODES) < 2: return destNodes = random.choices(NETWORK_NODES, k=min(len(NETWORK_NODES)-1, 5)) while self in destNodes: destNodes = random.choices(NETWORK_NODES, k=min(len(NETWORK_NODES)-1, 5)) for destNode in destNodes: addConn(self, destNode) sim.send(VERSION, destNode, self, VERSION_MSG) sim.send(GETADDR, destNode, self, GETADDR_MSG) nodeState[self][MEMB_MSGS_SENT] += 2
def STATUS(self, source, msg, bestHash, blockNum): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 if source not in nodeState[self][SENT_STATUS]: sim.send(STATUS, source, self, STATUS_MSG, nodeState[self][BLOCKCHAIN][-1].getHash(), nodeState[self][BLOCKCHAIN][-1].getNumber()) nodeState[self][DISS_MSGS_SENT] += 1 else: nodeState[self][SENT_STATUS].remove(source) # Request Headers if nodeState[self][BLOCKCHAIN][-1].getNumber() < blockNum: sim.send(GETDATA, source, self, ANN_BLOCK, GETDATA_MSG, [bestHash], True) nodeState[self][DISS_MSGS_SENT] += 1
def join(self): if self not in NETWORK_NODES: NETWORK_NODES.append(self) if len(NETWORK_NODES) < 2: return destNodes = random.choices(NETWORK_NODES, k=min(len(NETWORK_NODES)-1, 5)) while self in destNodes: destNodes = random.choices(NETWORK_NODES, k=min(len(NETWORK_NODES)-1, 5)) for destNode in destNodes: addEntryDb(self, destNode) addEntryBucket(self, destNode) sim.send(FINDNODE, destNode, self, FINDNODE_MSG, destNode) nodeState[self][SENT_STATUS].append(destNode) sim.send(STATUS, destNode, self, STATUS_MSG, nodeState[self][BLOCKCHAIN][-1].getHash(), nodeState[self][BLOCKCHAIN][-1].getNumber()) nodeState[self][DISS_MSGS_SENT] += 1 nodeState[self][MEMB_MSGS_SENT] += 1
def GETDATA(self, source, msg, inv): # The getdata message requests one or more data objects from another node. # The objects are requested by an inventory, which the requesting node typically received previously by way of an inv message. logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 for i in inv: if i[0] == MSG_TX: t = nodeState[self][KNOWN_TXS].get(i[1]) rmInvConn(self, source, MSG_TX, t.getHash()) sim.send(TX, source, self, TX_MSG, t) del t nodeState[self][DISS_MSGS_SENT] += 1 elif i[0] == MSG_BLOCK: b = nodeState[self][KNOWN_BLOCKS].get(i[1]) if b is None: continue rmInvConn(self, source, MSG_BLOCK, b.getHash()) sim.send(BLOCK, source, self, BLOCK_MSG, b) del b nodeState[self][DISS_MSGS_SENT] += 1
def INV(self, source, msg, inv): # The inv message (inventory message) transmits one or more inventories of objects known to the transmitting peer. # It can be sent unsolicited to announce new transactions or blocks, or it can be sent in reply to a getblocks message or mempool message. logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 if source not in nodeState[self][DB]: nodeState[self][DB].append(source) tmp = [] for i in inv: if i[0] == MSG_TX: if i[1] not in nodeState[self][KNOWN_TXS]: tmp.append(i) elif i[0] == MSG_BLOCK: if i[1] not in nodeState[self][KNOWN_BLOCKS]: tmp.append(i) if len(tmp) == 0: return sim.send(GETDATA, source, self, GETDATA_MSG, tmp) del tmp nodeState[self][DISS_MSGS_SENT] += 1
def VERSION(myself, source): global nodeState if should_log(myself): nodeState[myself][MSGS][VERSION_MSG] += 1 # Node connects to itself case, there's a condition in the Bitcoin code for this if myself == source: return if source not in nodeState[myself][NODE_NEIGHBOURHOOD]: add_new_addr(myself, source, source, 0) open_network_connection(myself, source, False) pto = nodeState[myself][NODE_NEIGHBOURHOOD][source] if pto[F_INBOUND]: sim.send(VERSION, source, myself) sim.send(VERACK, source, myself) if not pto[F_INBOUND]: addr = get_addr(myself) push_address(pto, addr) if len(nodeState[myself][RANDOM]) < 1000: sim.send(GETADDR, source, myself) pto[ADDR_STRC][F_GET_ADDR] = True mark_address_as_good(myself, source, True, nodeState[myself][CURRENT_TIME]) # TODO implement feeler return True
def GETBLOCKHEADERS(self, source, msg, hash, reverse): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 headers = [] b_index = nodeState[self][BLOCKCHAIN].index(nodeState[self][BLOCKCHAIN_HASHES].get(hash)) min_range = 0 if reverse == 0: min_range = len(nodeState[self][BLOCKCHAIN]) - b_index elif reverse == 1: min_range = b_index for i in range(0, min(maxBlockHeaders, min_range)): if reverse == 0: headers.append(nodeState[self][BLOCKCHAIN][b_index + i].getHeader()) elif reverse == 1: headers.append(nodeState[self][BLOCKCHAIN][b_index - i].getHeader()) if headers: sim.send(BLOCKHEADERS, source, self, BLOCKHEADERS_MSG, headers) nodeState[self][DISS_MSGS_SENT] += 1
def GETHEADERS(self, source, msg, start, end): # The getheaders message requests a headers message that provides block headers starting from a particular point in the block chain. # It allows a peer which has been disconnected or started for the first time to get the headers it hasn’t seen yet. logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 tmp = [] started = False for b in nodeState[self][BLOCKCHAIN]: if b.getHash() == end: tmp.append(b.getHeader()) break if started: tmp.append(b.getHeader()) elif not started and b.getHash() == start: started = True else: continue sim.send(HEADERS, source, self, HEADERS_MSG, tmp) del tmp nodeState[self][DISS_MSGS_SENT] += 1
def STATUS(self, source, msg, bestHash, blockNumber): logger.info("Node: {} Received: {} From: {}".format(self, msg, source)) nodeState[self][DISS_MSGS_RECEIVED] += 1 addEntryDb(self, source) if source not in nodeState[self][SENT_STATUS]: sim.send(STATUS, source, self, STATUS_MSG, nodeState[self][BLOCKCHAIN][-1].getHash(), nodeState[self][BLOCKCHAIN][-1].getNumber()) nodeState[self][DISS_MSGS_SENT] += 1 else: nodeState[self][SENT_STATUS].remove(source) # Send Transactions sim.send(TRANSACTIONS, source, self, TRANSACTIONS_MSG, nodeState[self][QUEUED_TXS]) nodeState[self][DISS_MSGS_SENT] += 1 # Request Headers if nodeState[self][BLOCKCHAIN][-1].getNumber() < blockNumber: sim.send(GETBLOCKHEADERS, source, self, GETBLOCKHEADERS_MSG, bestHash, 1) nodeState[self][DISS_MSGS_SENT] += 1