def __init__(self, path, skip_version_check=False, skip_header_check=False): super(LevelDBBlockchain, self).__init__() self._path = path self._header_index = [] self._header_index.append( Blockchain.GenesisBlock().Header.Hash.ToBytes()) self.TXProcessed = 0 try: self._db = plyvel.DB(self._path, create_if_missing=True) logger.info("Created Blockchain DB at %s " % self._path) except Exception as e: logger.info( "leveldb unavailable, you may already be running this process: %s " % e) raise Exception('Leveldb Unavailable') version = self._db.get(DBPrefix.SYS_Version) if skip_version_check: self._db.put(DBPrefix.SYS_Version, self._sysversion) version = self._sysversion if version == self._sysversion: # or in the future, if version doesn't equal the current version... ba = bytearray(self._db.get(DBPrefix.SYS_CurrentBlock, 0)) self._current_block_height = int.from_bytes(ba[-4:], 'little') if not skip_header_check: ba = bytearray(self._db.get(DBPrefix.SYS_CurrentHeader, 0)) current_header_height = int.from_bytes(ba[-4:], 'little') current_header_hash = bytes(ba[:64].decode('utf-8'), encoding='utf-8') hashes = [] try: for key, value in self._db.iterator( prefix=DBPrefix.IX_HeaderHashList): ms = StreamManager.GetStream(value) reader = BinaryReader(ms) hlist = reader.Read2000256List() key = int.from_bytes(key[-4:], 'little') hashes.append({'k': key, 'v': hlist}) StreamManager.ReleaseStream(ms) except Exception as e: logger.info("Could not get stored header hash list: %s " % e) if len(hashes): hashes.sort(key=lambda x: x['k']) genstr = Blockchain.GenesisBlock().Hash.ToBytes() for hlist in hashes: for hash in hlist['v']: if hash != genstr: self._header_index.append(hash) self._stored_header_count += 1 if self._stored_header_count == 0: logger.info( "Current stored headers empty, re-creating from stored blocks..." ) headers = [] for key, value in self._db.iterator( prefix=DBPrefix.DATA_Block): dbhash = bytearray(value)[8:] headers.append( Header.FromTrimmedData(binascii.unhexlify(dbhash), 0)) headers.sort(key=lambda h: h.Index) for h in headers: if h.Index > 0: self._header_index.append(h.Hash.ToBytes()) # this will trigger the write of stored headers if len(headers): self.OnAddHeader(headers[-1]) elif current_header_height > self._stored_header_count: try: hash = current_header_hash targethash = self._header_index[-1] newhashes = [] while hash != targethash: header = self.GetHeader(hash) newhashes.insert(0, header) hash = header.PrevHash.ToBytes() self.AddHeaders(newhashes) except Exception as e: pass elif version is None: self.Persist(Blockchain.GenesisBlock()) self._db.put(DBPrefix.SYS_Version, self._sysversion) else: logger.error("\n\n") logger.warning("Database schema has changed from %s to %s.\n" % (version, self._sysversion)) logger.warning( "You must either resync from scratch, or use the np-bootstrap command to bootstrap the chain." ) try: res = prompt( "Type 'continue' to erase your current database and sync from new. Otherwise this program will exit:\n> " ) except KeyboardInterrupt: res = False if res == 'continue': with self._db.write_batch() as wb: for key, value in self._db.iterator(): wb.delete(key) self.Persist(Blockchain.GenesisBlock()) self._db.put(DBPrefix.SYS_Version, self._sysversion) else: raise Exception("Database schema changed")
def __init__(self, db, skip_version_check=False, skip_header_check=False): self._db = db self._header_index = [] self._header_index.append( Blockchain.GenesisBlock().Header.Hash.ToBytes()) self.TXProcessed = 0 version = self._db.get(DBPrefix.SYS_Version) if skip_version_check: self._db.write(DBPrefix.SYS_Version, self._sysversion) version = self._sysversion if version == self._sysversion: # or in the future, if version doesn't equal the current version... ba = bytearray(self._db.get(DBPrefix.SYS_CurrentBlock, 0)) self._current_block_height = int.from_bytes(ba[-4:], 'little') if not skip_header_check: ba = bytearray(self._db.get(DBPrefix.SYS_CurrentHeader, 0)) current_header_height = int.from_bytes(ba[-4:], 'little') current_header_hash = bytes(ba[:64].decode('utf-8'), encoding='utf-8') hashes = [] try: with self._db.openIter( DBProperties(DBPrefix.IX_HeaderHashList)) as it: for key, value in it: ms = StreamManager.GetStream(value) reader = BinaryReader(ms) hlist = reader.Read2000256List() key = int.from_bytes(key[-4:], 'little') hashes.append({'k': key, 'v': hlist}) StreamManager.ReleaseStream(ms) except Exception as e: logger.info("Could not get stored header hash list: %s " % e) if len(hashes): hashes.sort(key=lambda x: x['k']) genstr = Blockchain.GenesisBlock().Hash.ToBytes() for hlist in hashes: for hash in hlist['v']: if hash != genstr: self._header_index.append(hash) self._stored_header_count += 1 if self._stored_header_count == 0: logger.info( "Current stored headers empty, re-creating from stored blocks..." ) headers = [] logger.info('Recreate headers') with self._db.openIter(DBProperties( DBPrefix.DATA_Block)) as it: for key, value in it: dbhash = bytearray(value)[8:] headers.append( Header.FromTrimmedData( binascii.unhexlify(dbhash), 0)) headers.sort(key=lambda h: h.Index) for h in headers: if h.Index > 0: self._header_index.append(h.Hash.ToBytes()) if len(headers): self.OnAddHeader(headers[-1]) elif current_header_height > self._stored_header_count: try: hash = current_header_hash targethash = self._header_index[-1] newhashes = [] while hash != targethash: header = self.GetHeader(hash) newhashes.insert(0, header) hash = header.PrevHash.ToBytes() self.AddHeaders(newhashes) except Exception as e: pass elif version is None: wait_for(self.Persist(Blockchain.GenesisBlock())) self._db.write(DBPrefix.SYS_Version, self._sysversion) else: logger.error("\n\n") logger.warning("Database schema has changed from %s to %s.\n" % (version, self._sysversion)) logger.warning( "You must either resync from scratch, or use the np-bootstrap command to bootstrap the chain." ) res = prompt( "Type 'continue' to erase your current database and sync from new. Otherwise this program will exit:\n> " ) if res == 'continue': with self._db.getBatch() as wb: with self._db.openIter( DBProperties(include_value=False)) as it: for key in it: wb.delete(key) wait_for(self.Persist(Blockchain.GenesisBlock())) self._db.write(DBPrefix.SYS_Version, self._sysversion) else: raise Exception("Database schema changed")