Ejemplo n.º 1
0
 def give_block_template(self):
     if not self.key_manager:
         raise Exception("Key manager is not set")
     transaction_fees = self.give_tx().relay_fee if self.give_tx() else 0
     value = next_reward(
         self.storage_space.blockchain.current_tip,
         self.storage_space.headers_storage) + transaction_fees
     coinbase = IOput()
     coinbase.fill(
         self.key_manager.new_address(),
         value,
         relay_fee=0,
         coinbase=True,
         lock_height=self.storage_space.blockchain.current_height + 1 +
         coinbase_maturity)
     coinbase.generate()
     self.storage_space.txos_storage.mempool[
         coinbase.serialized_index] = coinbase
     tx = Transaction(txos_storage=self.storage_space.txos_storage,
                      key_manager=self.key_manager)
     tx.add_coinbase(coinbase)
     tx.compose_block_transaction()
     block = generate_block_template(tx, self.storage_space)
     self.add_block_template(block)
     return block
Ejemplo n.º 2
0
    def non_context_verify(self):
        '''
      To verify block we need to
        0) check that header is known and valid
        1) verify transaction 
        2) check that transaction can be applied 
        3) #logic error, this is context validation# check that after tx applied to prev state, new state roots 
           and checksums coinside with block header
        4) check reward size (actually in can be checked on headers level)
    '''
        # stage 1
        assert self.header.hash in self.storage_space.headers_storage, "Block's header is unknown"
        #self.storage_space.headers_storage.context_validation(self.header.hash)
        assert not self.storage_space.headers_storage[
            self.header.
            hash].invalid, "Block's header is invalid. Reason: `%s`" % self.storage_space.headers_storage[
                self.header.hash].reason

        #currently during building we automatically check that tx can ba applied and tx is valid
        self.tx = build_tx_from_skeleton(
            self.transaction_skeleton,
            txos_storage=self.storage_space.txos_storage,
            block_height=self.header.height,
            non_context=True)
        # stage 3 => should be moved to blockchain
        #commitment_root, txos_root = self.storage_space.txos_storage.apply_tx_get_merkles_and_rollback(tx)
        #excesses_root = self.storage_space.excesses_storage.apply_tx_get_merkles_and_rollback(tx)
        #assert [commitment_root, txos_root, excesses_root]==self.header.merkles

        # This is context validation too??? TODO
        assert self.tx.coinbase.value == next_reward(
            self.header.prev,
            self.storage_space.headers_storage), "Wrong block subsidy"

        return True
Ejemplo n.º 3
0
    def context_validation(self, block, wtx):
        assert block.header.prev == self.current_tip(rtx=wtx)
        block.tx.verify(block_height=self.current_height(rtx=wtx),
                        block_version=block.header.version,
                        rtx=wtx,
                        skip_non_context=True)
        excesses_root = self.storage_space.excesses_storage.apply_block_tx_get_merkles_and_rollback(
            block.tx, wtx=wtx)
        commitment_root, txos_root = self.storage_space.txos_storage.apply_block_tx_get_merkles_and_rollback(
            block.tx, wtx=wtx)
        if not [commitment_root, txos_root, excesses_root
                ] == block.header.merkles:
            return False
        '''excesses = block.tx.additional_excesses + list(block.tx.updated_excesses.values())
    excesses_indexes = [e.index for e in excesses]
    for i in block.tx.inputs:
      if self.storage_space.txos_storage.confirmed.burden.has(i.serialized_index, rtx=wtx):
        required_commitment = txos.storage.confirmed.burden.get(i.serialized_index, rtx=wtx)
        required_index =
        if (not required_index in excesses_indexes) and (not self.storage_space.excesses_storage.has_index(required_index)):
          return False
    for excess in excesses:
      if  self.current_height(rtx=wtx)>0:
        prev_block_props = {'height': self.current_height(rtx=wtx), 
                         'timestamp': self.storage_space.headers_storage.get(self.current_tip(rtx=wtx), rtx=wtx).timestamp}
      else:
        prev_block_props = {'height':0, 'timestamp':0}
      burden_list = []
      excess_lookup_partial = partial(excess_lookup, rtx=wtx, tx=block.tx, excesses_storage = self.storage_space.excesses_storage)
      output_lookup_partial = partial(output_lookup, rtx=wtx, tx=block.tx, txos_storage = self.storage_space.txos_storage)
      result = execute(script = excess.message,
                       prev_block_props = prev_block_props,
                       excess_lookup = excess_lookup_partial,
                       output_lookup = output_lookup_partial,
                       burden = burden_list)
      if not result:
        return False
    '''
        if block.header.height > 0:
            cb_subsidy, dev_reward = next_reward(
                block.header.prev, self.storage_space.headers_storage, rtx=wtx)
            subsidy = cb_subsidy + dev_reward
            if not self.storage_space.headers_storage.get(block.header.prev, rtx=wtx).supply + \
                 subsidy - \
                 block.transaction_skeleton.calc_new_outputs_fee(is_block_transaction=True, dev_reward=bool(dev_reward)) == block.header.supply:
                return False
            if not block.tx.coinbase.value == cb_subsidy + block.tx.relay_fee:
                # Note we already check coinbase in non_context_check, but using tx_skeleton info
                # Since information in tx_skeleton may be forged, this check is not futile
                return False
            if dev_reward and (not block.tx.dev_reward.value == dev_reward):
                # Note we already check coinbase in non_context_check, but using tx_skeleton info
                # Since information in tx_skeleton may be forged, this check is not futile
                return False

        return True
Ejemplo n.º 4
0
 def context_validation(self, block):
   assert block.header.prev == self.current_tip
   block.tx.verify(block_height=self.current_height, skip_non_context=True)
   commitment_root, txos_root = self.storage_space.txos_storage.apply_tx_get_merkles_and_rollback(block.tx)
   excesses_root = self.storage_space.excesses_storage.apply_tx_get_merkles_and_rollback(block.tx)
   if not [commitment_root, txos_root, excesses_root]==block.header.merkles:
     return False
   if block.header.height>0:
     if not self.storage_space.headers_storage[block.header.prev].supply + \
          next_reward(block.header.prev, self.storage_space.headers_storage) - \
          block.transaction_skeleton.calc_new_outputs_fee(is_block_transaction=True) == block.header.supply:
       return False
   return True
Ejemplo n.º 5
0
 def mark_subchain_connected_to_genesis(self, _hash, wtx):
     to_be_marked = [_hash]
     # Recursion, while beatiful, can easily reach max depth here
     while len(to_be_marked):
         header_hash = to_be_marked.pop(0)
         header = self.storage_space.headers_storage.get(header_hash,
                                                         rtx=wtx)
         header.connected_to_genesis = True
         to_be_marked += list(header.descendants)
         if _hash == self.genesis.hash:
             header.coins_to_be_mint = header.supply
         else:
             try:
                 header.coins_to_be_mint = self.storage_space.headers_storage.get(header.prev,rtx=wtx).coins_to_be_mint + \
                                         sum(next_reward(header.prev, self.storage_space.headers_storage, rtx=wtx)) +\
                                         output_creation_fee
             except KeyError:
                 ''' If something is wrong with block.height, for instance it is set to 2000, while it is 20 in sequence
           next_reward will raise.
       '''
                 header.coins_to_be_mint = 0
             header.total_difficulty = self.storage_space.headers_storage.get(
                 header.prev, rtx=wtx).total_difficulty + header.difficulty
             # we should save here, since context_validation checks coins_to_be_mint too
             self.storage_space.headers_storage.put(header_hash,
                                                    header,
                                                    wtx=wtx)
             if self.storage_space.headers_storage.get(header.prev,
                                                       rtx=wtx).invalid:
                 header.invalid = True
                 header.reason = self.storage_space.headers_storage.get(
                     header.prev, rtx=wtx).reason
             else:
                 try:
                     self.context_validation(_hash, rtx=wtx)
                 except Exception as e:
                     header.invalid = True
                     header.reason = str(e)
         self.storage_space.headers_storage.put(header_hash,
                                                header,
                                                wtx=wtx)
         # NOTE if new header has the same height as current best tip, best_tip will not be changed
         # (header.height==self.best_tip[1] and header.hash > self.best_tip[0])
         if header.height > self.best_tip[1]:
             if not header.invalid:
                 self.best_tip = (header.hash, header.height)
Ejemplo n.º 6
0
    def non_context_verify(self, rtx):
        '''
      While this check is called 'non_context', it actually uses context since it needs:
        a) fully validated headers chain up to this block
        b) downloaded outputs
        c) blocks which create inputs spent in checked(self) block should be applied
      Currently if those conditions are not satisfied block is marked as not_downloaded and thus can not be validated.
      To verify block we need to
        0) check that header is known and valid
        1) verify transaction 
        2) check that transaction can be applied 
        3) check reward size (actually in can be checked on headers level)
    '''
        # stage 1
        assert self.storage_space.headers_storage.has(
            self.header.hash, rtx=rtx), "Block's header is unknown"
        #self.storage_space.headers_storage.context_validation(self.header.hash)
        assert not self.storage_space.headers_storage.get(
            self.header.hash, rtx=rtx
        ).invalid, "Block's header is invalid. Reason: `%s`" % self.storage_space.headers_storage.get(
            self.header.hash, rtx=rtx).reason

        #currently during building we automatically check that tx can ba applied and tx is valid
        self.tx = build_tx_from_skeleton(
            self.transaction_skeleton,
            txos_storage=self.storage_space.txos_storage,
            excesses_storage=self.storage_space.excesses_storage,
            block_height=self.header.height,
            block_version=self.header.version,
            rtx=rtx,
            non_context=True)
        # stage 3 => should be moved to blockchain
        #commitment_root, txos_root = self.storage_space.txos_storage.apply_block_tx_get_merkles_and_rollback(tx)
        #excesses_root = self.storage_space.excesses_storage.apply_block_tx_get_merkles_and_rollback(tx)
        #assert [commitment_root, txos_root, excesses_root]==self.header.merkles

        # This is context validation too??? TODO
        miner_subsidy, dev_reward = next_reward(
            self.header.prev, self.storage_space.headers_storage, rtx=rtx)
        assert self.tx.coinbase.value == (
            miner_subsidy +
            self.transaction_skeleton.relay_fee), "Wrong miner subsidy"
        if dev_reward:
            assert self.tx.dev_reward.value == dev_reward, "Wrong miner subsidy"

        return True
Ejemplo n.º 7
0
 def context_validation(self, block):
   assert block.header.prev == self.current_tip
   block.tx.verify(block_height=self.current_height, skip_non_context=True)
   commitment_root, txos_root = self.storage_space.txos_storage.apply_tx_get_merkles_and_rollback(block.tx)
   excesses_root = self.storage_space.excesses_storage.apply_tx_get_merkles_and_rollback(block.tx)
   if not [commitment_root, txos_root, excesses_root]==block.header.merkles:
     return False
   if block.header.height>0:
     subsidy = next_reward(block.header.prev, self.storage_space.headers_storage)
     if not self.storage_space.headers_storage[block.header.prev].supply + \
          subsidy - \
          block.transaction_skeleton.calc_new_outputs_fee(is_block_transaction=True) == block.header.supply:
       return False
     if not block.tx.coinbase.value == subsidy + block.tx.relay_fee: 
       # Note we already check coinbase in non_context_check, but using tx_skeleton info
       # However information in tx_skeleton may be forged, thus this check is not futile
       return False
     
   return True