def mine(self, cons): """ Create and send block in PUB socket based on consensus """ name = threading.current_thread().getName() while True and not self.k.is_set(): # move e flag inside generate? self.start.wait() self.f.wait() lastblock = self.bchain.getLastBlock() node = hashlib.sha256(self.ipaddr).hexdigest() self.stake = self.balance # find new block b = self.generateNewblock(lastblock, node, self.stake, cons) if b and not self.e.is_set(): logging.info("Mined block %s" % b.hash) sqldb.writeBlock(b) sqldb.writeChain(b) self.bchain.addBlocktoBlockchain(b) self.psocket.send_multipart( [consensus.MSG_BLOCK, self.ipaddr, pickle.dumps(b, 2)]) time.sleep(parameter.timeout) else: if (self.synced == True): self.e.clear()
def recursiveValidate(self, blockerror, address=None): index = blockerror.index - 1 pblock = sqldb.dbtoBlock(sqldb.blockQuery(['', index])) # previous block trials = 3 while index and trials: logging.debug('validating index %s' % index) chainnew = self.reqBlocks(index + 1, index + 1, address) new = chainnew[0] new = sqldb.dbtoBlock(new) print('NEW ID ON RECURSIVE', new.index) print('NEW ON RECURSIVE', new.hash) #print("NEW", new.index) if new and validations.validateBlockHeader(new): sqldb.writeBlock(new) if validations.validateBlock( new, pblock) and validations.validateChallenge( new, self.stake): logging.debug('returning') #print('FORK', new.index) return new else: index -= 1 pblock = sqldb.dbtoBlock(sqldb.blockQuery(['', index])) #print("PBLOCK", pblock.index) else: trials -= 1 return new
def validateChain(bc, l): lastBlock = bc.getLastBlock() print lastBlock.blockInfo() for b in l: b = sqldb.dbtoBlock(b) if not validateBlockHeader(b): # invalid return b, True if validateBlock(b, lastBlock): lastBlock = b bc.addBlocktoBlockchain(b) sqldb.writeBlock(b) sqldb.writeChain(b) else: # fork return b, False return None, False
def mine(self, cons): # target = 2 ** (20) - 1 name = threading.current_thread().getName() while True and not self.k.is_set(): # move e flag inside generate? self.start.wait() self.f.wait() lastblock = self.bchain.getLastBlock() b = cons.generateNewblock(lastblock, self.e) if b and not self.e.is_set(): logging.info("Mined block %s" % b.hash) sqldb.writeBlock(b) self.bchain.addBlocktoBlockchain(b) self.psocket.send_multipart([consensus.MSG_BLOCK, self.ipaddr, pickle.dumps(b, 2)]) else: self.e.clear()
def validateChain(bc, l): lastBlock = bc.getLastBlock() #print lastBlock.blockInfo() for b in l: #print b b = sqldb.dbtoBlock(b) # maybe avoid converting # validade block header ? #validateBlockHeader(b) if validateBlock(b, lastBlock): lastBlock = b bc.addBlocktoBlockchain(b) sqldb.writeBlock(b) else: # fork #sqldb.writeFork(b) return b return None
def listen(self): """ Listen to block messages in a SUB socket Message frames: [ 'block', ip, block data ] """ self.bind(self.psocket) while True and not self.k.is_set(): try: msg, ip, block_recv = self.subsocket.recv_multipart() self.f.clear() # serialize b = pickle.loads(block_recv) logging.info("Got block %s miner %s" % (b.hash, ip)) # Verify block if consensus.validateBlockHeader(b): logging.debug('valid block header') lb = self.bchain.getLastBlock() if (b.index - lb.index == 1) and consensus.validateBlock( b, lb): self.e.set() sqldb.writeBlock(b) sqldb.writeChain(b) self.bchain.addBlocktoBlockchain(b) # rebroadcast #logging.debug('rebroadcast') self.psocket.send_multipart( [consensus.MSG_BLOCK, ip, pickle.dumps(b, 2)]) elif b.index - lb.index > 1: self.synced = False self.sync(b, ip) elif b.index == lb.index: if b.hash == lb.hash: logging.debug('retransmission') else: logging.debug('fork') # double entry sqldb.writeBlock(b) else: # ignore old block logging.debug('old') # self.f.set() except (zmq.ContextTerminated): break
def recursiveValidate(self, blockerror): index = blockerror.index - 1 pblock = sqldb.dbtoBlock(sqldb.blockQuery(['', index])) # previous block tries = 3 while index and tries: logging.debug('validating index %s' % index) new = self.reqBlock(index) if new and consensus.validateBlockHeader(new): sqldb.writeBlock(new) if consensus.validateBlock(new, pblock): logging.debug('returning') return new else: index -= 1 pblock = sqldb.dbtoBlock(sqldb.blockQuery(['', index])) else: tries -= 1 return new
def listen(self): self.bind(self.psocket) while True and not self.k.is_set(): try: msg, ip, block_recv = self.subsocket.recv_multipart() self.f.clear() b = pickle.loads(block_recv) logging.info("Got block %s miner %s" % (b.hash, ip)) # Verify block if consensus.validateBlockHeader(b): logging.debug('valid block') lb = self.bchain.getLastBlock() if (b.index - lb.index == 1) and consensus.validateBlock( b, lb): self.e.set() sqldb.writeBlock(b) self.bchain.addBlocktoBlockchain(b) # rebroadcast #logging.debug('rebroadcast') self.psocket.send_multipart( [consensus.MSG_BLOCK, ip, pickle.dumps(b, 2)]) elif b.index - lb.index > 1: self.synced = False self.sync(b, ip) elif b.index == lb.index: if b.hash == lb.hash: logging.debug('retransmission') pass else: #fork logging.debug('strong fork') pass else: #fork logging.debug('weak fork') pass # self.f.set() except (zmq.ContextTerminated): break
def validateChain(bc, chain, stake): lastBlock = bc.getLastBlock() for b in chain: b = sqldb.dbtoBlock(b) if not validateBlockHeader(b): # invalid #print("HEADER NOT OK") return b, True #print("lastblock index",lastBlock.index) #print("current block index", b.index) if validateBlock(b, lastBlock): #print("BLOCK OK") if validateChallenge(b, stake) and validateRound( b, bc) and validateExpectedRound(b, lastBlock): print("BLOCO VALIDO SINCRONIZADO") lastBlock = b bc.addBlocktoBlockchain(b) sqldb.writeBlock(b) sqldb.writeChain(b) else: # fork return b, False return None, False
def sync(self, rBlock=None, address=None): # TODO change variables names and test again self.synced = True logging.debug('syncing...') # limit number of peers? if not rBlock: rBlock = self.bchain.getLastBlock() for i in range(0, min(len(self.peers), 3)): i += 1 logging.debug('request #%d' % i) b, ip = self.reqLastBlock() if b: logging.debug('Block index %s' % b.index) if (b and (b.index > rBlock.index)): rBlock = b address = ip logging.debug('Best index %s with ip %s' % (b.index, ip)) last = self.bchain.getLastBlock() # if (rBlock.index > last.index): self.e.set() if (rBlock.index - last.index == 1) and consensus.validateBlock( rBlock, last): logging.debug('valid block') sqldb.writeBlock(rBlock) self.bchain.addBlocktoBlockchain(rBlock) else: l = self.reqBlocks(address, last.index + 1, rBlock.index) if l: # validate here error = consensus.validateChain(self.bchain, l) if error: # maybe fork, request previous logging.debug('fork') # sync again? #sqldb.writeBlock(l) logging.debug('synced')
def sync(self, rBlock=None, address=None): """ Syncronize with peers and validate chain rBlock -- can be passed as argument to sync based on that block index instead of requesting address -- try to force requests to use this ip address """ self.synced = True logging.debug('syncing...') # Request before sync if not rBlock: rBlock = self.bchain.getLastBlock() # limit number of peers request for i in range(0, min(len(self.peers), 3)): i += 1 logging.debug('request #%d' % i) b, ip = self.reqLastBlock() if b: logging.debug('Block index %s' % b.index) if (b and (b.index > rBlock.index)): rBlock = b address = ip logging.debug('Best index %s with ip %s' % (b.index, ip)) last = self.bchain.getLastBlock() # Sync based on rBlock if (rBlock.index > last.index): self.e.set() if (rBlock.index - last.index == 1) and consensus.validateBlock( rBlock, last): logging.debug('valid block') sqldb.writeBlock(rBlock) sqldb.writeChain(rBlock) self.bchain.addBlocktoBlockchain(rBlock) else: l = self.reqBlocks(last.index + 1, rBlock.index, address) if l: # validate and write b_error, h_error = consensus.validateChain(self.bchain, l) if b_error: if not h_error and b_error.index == last.index + 1: logging.debug('fork') sqldb.writeBlock(b_error) # trying to solve and pick a fork n = self.recursiveValidate(b_error) if n: self.bchain.chain.clear( ) # TODO change this and refactor for i in xrange(n.index, last.index + 1): logging.debug('updating chain') if i == 1: sqldb.replaceChain(n) self.bchain.addBlocktoBlockchain(n) else: n = sqldb.forkUpdate(i) sqldb.replaceChain(n) self.bchain.addBlocktoBlockchain( sqldb.dbtoBlock(n)) consensus.validateChain(self.bchain, l) else: logging.debug('invalid') # request again new = self.reqBlock(b_error.index) self.sync(new) logging.debug('synced')
def rpcServer(self, ip='127.0.0.1', port=9999): """ RPC-like server to interact with rpcclient.py """ self.bind(self.rpcsocket, ip, port) time.sleep(1) while True: try: messages = self.rpcsocket.recv_multipart() except zmq.ContextTerminated: break time.sleep(1) cmd = messages[0].lower() if cmd == rpc.MSG_LASTBLOCK: b = self.bchain.getLastBlock() self.rpcsocket.send(b.blockInfo()) elif cmd == rpc.MSG_BLOCKCHAIN: b = self.bchain.Info() self.rpcsocket.send(b) elif cmd == rpc.MSG_BLOCK: b = sqldb.dbtoBlock(sqldb.blockQuery(messages)) self.rpcsocket.send(b.blockInfo() if b else 'error') elif cmd == rpc.MSG_BLOCKS: l = sqldb.blocksListQuery(messages) blocks = [] for b in l: blocks.append(sqldb.dbtoBlock(b).blockInfo()) self.rpcsocket.send_pyobj(blocks) elif cmd == rpc.MSG_ADD: m = self.addPeer(messages[1]) self.rpcsocket.send_string(m) elif cmd == rpc.MSG_REMOVE: m = self.removePeer(messages[1]) self.rpcsocket.send_string(m) elif cmd == rpc.MSG_PEERS: self.rpcsocket.send_pyobj(self.getPeers()) elif cmd == rpc.MSG_START: self.rpcsocket.send_string('Starting mining...') self.start.set() self.f.set() elif cmd == rpc.MSG_STOP: self.start.clear() self.f.clear() self.e.set() self.rpcsocket.send_string('Stopping mining...') elif cmd == rpc.MSG_EXIT: self.rpcsocket.send_string('Exiting...') raise StopException elif cmd == rpc.MSG_BALANCE: self.addBalance(int(messages[1])) self.rpcsocket.send_string('Node Balance is ' + str(self.balance)) elif cmd == rpc.MSG_ADDBLOCK: l = [] for i in messages[1:]: l.append(i) last_hash = sqldb.dbtoBlock( sqldb.blockQuery(['', str(int(l[0]) - 1)])).hash hash_node = hashlib.sha256(self.ipaddr).hexdigest() time_create = int( time.mktime(datetime.datetime.now().timetuple())) c_header = str(last_hash) + str(l[1]) + str(hash_node) hash = hashlib.sha256(c_header).hexdigest() b = block.Block(int(l[0]), last_hash, int(l[1]), hash_node, time_create, hash) sqldb.writeBlock(b) #sqldb.writeChain(b) self.bchain.addBlocktoBlockchain(b) self.rpcsocket.send_string('Block created ' + str(b.blockInfo())) self.psocket.send_multipart( [consensus.MSG_BLOCK, self.ipaddr, pickle.dumps(b, 2)]) else: self.rpcsocket.send_string('Command unknown') logging.warning('Command unknown')
def sync(self, rBlock=None, address=None): """ Syncronize with peers and validate chain rBlock -- can be passed as argument to sync based on that block index instead of requesting address -- try to force requests to use this ip address """ logging.debug('syncing...') # Request before sync if not rBlock: rBlock = self.bchain.getLastBlock() # limit number of peers request for i in xrange(0, min(len(self.peers), 3)): i += 1 logging.debug('request #%d' % i) b, ip = self.reqLastBlock() if b: logging.debug('Block index %s' % b.index) if (b and (b.index > rBlock.index)): rBlock = b address = ip logging.debug('Best index %s with ip %s' % (b.index, ip)) last = self.bchain.getLastBlock() #print('INDEX BLOCK', last.index) #print('LAST BLOCK ON SYNC FUNCTION', last.hash) #print('rBLOCK', rBlock.index) # Sync based on rBlock if (rBlock.index > last.index): #print("RBLOCK", rBlock.index) if (rBlock.index - last.index == 1): if (validations.validateBlockHeader(rBlock) and validations.validateChallenge(rBlock, self.stake) and validations.validateExpectedRound(rBlock, last)): if (validations.validateBlock(rBlock, last)): #print('SYNC-BLOCO CADEIA ATUAL') logging.debug('valid block') sqldb.writeBlock(rBlock) sqldb.writeChain(rBlock) self.bchain.addBlocktoBlockchain(rBlock) else: #print('SYNC-BLOCO OUTRA CADEIA') sqldb.writeBlock(rBlock) # trying to solve and pick a fork n = self.recursiveValidate(rBlock, address) #print('B_ERROR', b_error.index) #print("PONTO DO FORK:", n.index) if n: fork = n #print('BLOCO EM FORK', fork.index) #print('BLOCO EM FORK - HASH', fork.index) #self.bchain.chain.clear() # TODO change this and refactor #remove all blocks after fork point for i in xrange(n.index, last.index + 1): self.bchain.chain.popleft() teste = self.bchain.getLastBlock() #print('ULTIMO BLOCO DEPOIS DE REMOVER BLOCO DO FORK', teste.index) #print('ULTIMO BLOCO DEPOIS DE REMOVER BLOCO DO FORK - HASH', teste.hash) #insert new blocks starting on n block for i in xrange(last.index + 1, n.index - 1, -1): logging.debug('updating chain') if i == 1: sqldb.replaceChain(n) self.bchain.addBlocktoBlockchain(n) else: if (i == rBlock.index): #print('INSERIR rBLock', rBlock.index) sqldb.writeChain(rBlock) else: lastBlock = sqldb.dbtoBlock( sqldb.blockQuery(['', i + 1])) actualBlock = sqldb.dbtoBlock( sqldb.blockQuery(['', i])) #print('LAST BLOCK INDEX', lastBlock.index) #print('LAST BLOCK PREV_HASH', lastBlock.prev_hash) #print('ACTUAL BLOCK INDEX', actualBlock.index) #print('ACTUAL BLOCK CHAIN', actualBlock.hash) if (lastBlock.prev_hash != actualBlock.hash): search = sqldb.blockQueryFork( ['', i]) for j in search: value = sqldb.dbtoBlock(j) if (value.hash == lastBlock.prev_hash): sqldb.replaceChain(j) for i in xrange(n.index, last.index + 2): block = sqldb.dbtoBlock( sqldb.blockQuery(['', i])) self.bchain.addBlocktoBlockchain(block) #n = sqldb.forkUpdate(i) #if(i == rBlock.index-1): # fork = sqldb.dbtoBlock(sqldb.blockQuery(['',i])) # print('SUBSTITUINDO O FORK') # print('FORK HASH', fork.hash) # print('rBlock PREV HASH', rBlock.prev_hash) # if(fork.hash != rBlock.prev_hash): # print('SUBSTITUIR') # n = sqldb.blockQueryFork(['',i]) # for j in n: # value = sqldb.dbtoBlock(j) # if (value.hash == rBlock.prev_hash): # sqldb.replaceChain(j) # self.bchain.addBlocktoBlockchain(sqldb.dbtoBlock(j)) # else: # print('NAO SUBSTITUIR') # self.bchain.addBlocktoBlockchain(fork) #else: # sqldb.replaceChain(n) # self.bchain.addBlocktoBlockchain(sqldb.dbtoBlock(n)) teste = self.bchain.getLastBlock() #print('ULTIMO BLOCO DEPOIS DE INSERIR OS BLOCOS DA NOVA CADEIA', teste.index) self.synced = True else: if (validations.validateBlockHeader(rBlock) and validations.validateChallenge(rBlock, self.stake)): print('BLOCO RECEBIDO > 1 ON SYNC FUNCTION') chain = self.reqBlocks(last.index + 1, rBlock.index, address) if chain: # validate and write b_error, h_error = validations.validateChain( self.bchain, chain, self.stake) # update last block last = self.bchain.getLastBlock() print('LAST BLOCK ON LOCAL CHAIN', last.index) # if b_error is diffent to None if b_error: print('b_error', b_error.index) # TODO review from next line, because it is strange # if h_error is false and block index equal last block index plus one if not h_error and b_error.index == last.index + 1: print('FORK') sqldb.writeBlock(b_error) # trying to solve and pick a fork n = self.recursiveValidate(b_error, address) print('B_ERROR', b_error.index) print("PONTO DO FORK:", n.index) if n: #self.bchain.chain.clear() # TODO change this and refactor #remove all blocks after fork point teste = self.bchain.getLastBlock() print('BCHAIN BEFORE POPLEFT', teste.index) for i in xrange(n.index, last.index + 1): self.bchain.chain.popleft() teste = self.bchain.getLastBlock() print('BCHAIN AFTER POPLEFT', teste.index) #insert new blocks starting on n block for i in xrange(last.index + 1, n.index - 1, -1): logging.debug('updating chain') if i == 1: sqldb.replaceChain(n) self.bchain.addBlocktoBlockchain(n) else: if (i == b_error.index): print('INSERIR b_error', b_error.index) sqldb.writeChain(b_error) else: lastBlock = sqldb.dbtoBlock( sqldb.blockQuery( ['', i + 1])) actualBlock = sqldb.dbtoBlock( sqldb.blockQuery(['', i])) if (lastBlock.prev_hash != actualBlock.hash): search = sqldb.blockQueryFork( ['', i]) for j in search: value = sqldb.dbtoBlock( j) if (value.hash == lastBlock. prev_hash): sqldb.replaceChain( j) for i in xrange(n.index, last.index + 2): block = sqldb.dbtoBlock( sqldb.blockQuery(['', i])) self.bchain.addBlocktoBlockchain(block) #for i in xrange(n.index,last.index+1): # logging.debug('updating chain') # if i == 1: # sqldb.replaceChain(n) # self.bchain.addBlocktoBlockchain(n) # else: # n = sqldb.forkUpdate(i) # sqldb.replaceChain(n) # self.bchain.addBlocktoBlockchain(sqldb.dbtoBlock(n)) #validations.validateChain(self.bchain, chain, self.stake) self.synced = True else: logging.debug('invalid') # request again chainnew = self.reqBlocks( b_error.index, b_error.index, address) new = chainnew[0] new = sqldb.dbtoBlock(new) #print('NEW RETURN SYNC', new.index) self.sync(new) else: self.synced = True else: self.synced = True logging.debug('synced')
def listen(self): """ Listen to block messages in a SUB socket Message frames: [ 'block', ip, block data ] """ self.bind(self.psocket) while True and not self.k.is_set(): try: msg, ip, block_recv = self.subsocket.recv_multipart() self.f.clear() newChain = False # serialize b = pickle.loads(block_recv) logging.info("Got block %s miner %s" % (b.hash, ip)) b.arrive_time = int( time.mktime(datetime.datetime.now().timetuple())) # Verify block if validations.validateBlockHeader(b): logging.debug('valid block header') lb = self.bchain.getLastBlock() if (b.index - lb.index == 1): print('BLOCK', b.index) print('VALIDATEBLOCK', validations.validateBlock(b, lb)) print('VALIDATEROUND', validations.validateRound(b, self.bchain)) print('VALIDATECHALLENGE', validations.validateChallenge(b, self.stake)) self.e.set() if (validations.validateBlock(b, lb)): if (validations.validateRound(b, self.bchain) and validations.validateChallenge( b, self.stake) and validations.validateExpectedRound( b, lb)): #print('NOVO BLOCO RECEBIDO---ACEITO SEM PROBLEMAS') self.bchain.addBlocktoBlockchain(b) sqldb.writeBlock(b) sqldb.writeChain(b) else: if (validations.validateRound(b, self.bchain) and validations.validateChallenge( b, self.stake) and validations.validateExpectedRound( b, lb)): print('BLOCO RECEBIDO APOS O FORK-', b.index) self.synced = False self.sync(b, ip) # rebroadcast logging.debug('rebroadcast') self.psocket.send_multipart( [consensus.MSG_BLOCK, ip, pickle.dumps(b, 2)]) #self.e.clear() elif b.index - lb.index > 1: print('BLOCO RECEBIDO INDEX MAIOR QUE 1', b.index) self.e.set() self.synced = False self.sync(b, ip) self.e.clear() elif b.index == lb.index: if b.hash == lb.hash: logging.debug('retransmission') else: if (b.round == lb.round): logging.debug('possible fork') pre_block = sqldb.dbtoBlock( sqldb.blockQuery([ '', lb.index - 1 ])) #get the block that b and lb point. if (validations.validateBlock(b, pre_block) and validations.validateChallenge( b, self.stake) and validations.validateExpectedRound( b, pre_block)): # double entry sqldb.writeBlock(b) else: # ignore old block logging.debug('old') else: logging.debug('invalid block') # self.f.set() except (zmq.ContextTerminated): break