def __init__(self, log, bsddb_env, runmode): self.log = log self.runmode = runmode self.indexdb = IndexDB(runmode, bsddb_env) self.blockstore = BlockStorage(runmode, bsddb_env.directory) self.version = 32200 self.genesishash = None self.genesisblock = None
class BSDDbBlockChainDatabase(BlockChainDatabase): def __init__(self, log, bsddb_env, runmode): self.log = log self.runmode = runmode self.indexdb = IndexDB(runmode, bsddb_env) self.blockstore = BlockStorage(runmode, bsddb_env.directory) self.version = 32200 self.genesishash = None self.genesisblock = None def open(self): self.indexdb.open() def exists(self): return (self.indexdb.exists()) def create(self, genesis_block): file, blockpos = self.blockstore.saveblock(genesis_block) self.blockstore.commit() genesis_index = DbBlockIndex(self.version, Uint256.zero(), file, blockpos, 0, genesis_block.blockheader) self.indexdb.create(hash_block(genesis_block), genesis_index) def open_or_create(self, genesisblock): self.genesisblock = genesisblock self.genesishash = hash_block(genesisblock) if self.exists(): self.open() else: self.create(genesisblock) def begin_updates(self): self.indexdb.begin_updates() def commit_updates(self): self.indexdb.commit_updates() def cancel_updates(self): self.indexdb.abort_updates() """ Transaction Operations """ def get_transaction_handle(self, hash): """Raises an exception if not found """ return DBTxHandle(self.log, self.indexdb, self.blockstore, hash) def contains_transaction(self, txhash): return self.indexdb.contains_transaction(txhash) """ Block Operations """ def contains_block(self, blockhash): return self.indexdb.contains_block(blockhash) def get_block_handle(self, blockhash): return DBBlockHandle(self.log, self.indexdb, self.blockstore, blockhash) def get_next_in_mainchain(self, blockhash): if not self.indexdb.contains_block(blockhash): raise BlockNotFound(str(blockhash)) blockindex = self.indexdb.get_blockindex(blockhash) if (blockindex.hash_next == Uint256.zero()): return None return blockindex.hash_next def append_block(self, blockhash, block): file, blockpos = self.blockstore.saveblock(block) prevblock = self.get_block_handle(block.blockheader.hash_prev) idx = DbBlockIndex(self.version, Uint256.zero(), file, blockpos, prevblock.get_height()+1, block.blockheader) self.indexdb.set_blockindex(blockhash, idx) if prevblock.hash == self.get_mainchain(): prevblock.blockindex.hash_next = blockhash self.indexdb.set_blockindex(prevblock.hash, prevblock.blockindex) self.indexdb.set_hashbestchain(blockhash) self._index_transactions(blockhash, block) return DBBlockHandle(self.log, self.indexdb, self.blockstore, blockhash, block=block) def pop_block(self): pass def set_besthash(self): pass """ Mainchain Operations """ def _find_fork(self, altchainhash): hash = altchainhash while hash != Uint256.zero(): handle = self.get_block_handle(hash) if handle.is_mainchain(): return hash hash = handle.get_blockheader().hash_prev return handle.hash # iterate backwards in [hashfirst-hashlast] and yield (hash, blkindex) def _iterate_branch(self, hashfirst, hashlast): hash = hashlast while (hash != hashfirst): blockindex = self.indexdb.get_blockindex(hash) yield (hash, blockindex) hash = blockindex.blockheader.hash_prev """ def reorganize(self, reorganize_update): old_afterfork_hash, old_afterfork_block = reorganize_update.old_mainchain[0] new_mainchain_besthash, new_mainchain_bestblock = reorganize_update.new_mainchain[-1] hashfork = old_afterfork_block.blockheader.hash_prev #Unindex transactions in old mainchain for hash, blk in reorganize_update.old_mainchain: blkindex = self.indexdb.get_blockindex(hash) self._unindex_transactions(hash) #Set hash_next to 0 in old mainchain for hash, blk in reorganize_update.old_mainchain: blkindex = self.indexdb.get_blockindex(hash) blkindex.hash_next = Uint256.zero() self.indexdb.set_blockindex(hash, blkindex) #Remove the blocks of the old mainchain for hash, blk in reorganize_update.old_mainchain: pass #self.append_block(hash, blk) #Add the blocks of the new mainchain for hash, blk in reorganize_update.new_mainchain: self.append_block(hash, blk) #Index transactions in new mainchain for hash, blk in reorganize_update.new_mainchain: self._index_transactions(hash) #Set hash_next to 'next' in new mainchain next = Uint256.zero() for hash, blkindex in reversed(reorganize_update.new_mainchain): blkindex = self.indexdb.get_blockindex(hash) blkindex.hash_next = next self.indexdb.set_blockindex(hash, blkindex) next = hash #set next of fork blkindex = self.indexdb.get_blockindex(hashfork) blkindex.hash_next = next self.indexdb.set_blockindex(hashfork, blkindex) #set hashbestchain self.indexdb.set_hashbestchain(new_mainchain_besthash) """ def get_mainchain(self): raise Exception("deprecated: use get_best_hash()") return self.indexdb.get_hashbestchain() def get_best_hash(self): return self.indexdb.get_hashbestchain() def get_genesis_hash(self): return self.genesishash def _index_transactions(self, blockhash, block=None): block_handle = self.get_block_handle(blockhash) #Add all transactions to the indexdb if not block: block = block_handle.get_block() size_blockheader = BlockheaderSerializer().get_size(block.blockheader) size_tx_size = VarintSerializer().get_size(len(block.transactions)) tx_serializer = TxSerializer() blockpos = block_handle.blockindex.blockpos txpos = block_handle.blockindex.blockpos + size_blockheader + size_tx_size for i, tx in enumerate(block.transactions): txindex = DbTxIndex(1, DiskTxPos(1, blockpos, txpos), [DiskTxPos() for _ in range(tx.output_count())]) self.indexdb.set_transactionindex(hash_tx(tx), txindex) #TODO: speed this up... if tx.rawdata: txpos += len(tx.rawdata) else: txpos += tx_serializer.get_size(tx) def _unindex_transactions(self, blockhash): block_handle = self.get_block_handle(blockhash) block = block_handle.get_block() for tx in block.transactions: self.indexdb.del_transactionindex(hash_tx(tx))