示例#1
0
 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
示例#2
0
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))