Esempio n. 1
0
    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")
Esempio n. 2
0
    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")