def commit(self, chain, block, address_txn, ignore_save_wallet=False): # FIXME: This indexing approach is very inefficient blocks_left = helper.get_blocks_left(block.blockheader.blocknumber) staker = block.blockheader.stake_selector self.stake_validators_list.sv_list[staker].nonce += 1 for address in address_txn: self._save_address_state(address, address_txn[address]) for dup_tx in block.duplicate_transactions: if dup_tx.coinbase1.txto in self.stake_validators_list.sv_list: self.stake_validators_list.sv_list[dup_tx.coinbase1.txto].is_banned = True if blocks_left == 1: logger.info('EPOCH change: resetting stake_list, activating next_stake_list, updating PRF with ' 'seed+entropy updating wallet hashchains..') self.stake_validators_list.move_next_epoch() # TODO: To be fixed later #self.stake_list_put(self.stake_validators_list.to_json()) xmss = chain.wallet.address_bundle[0].xmss tmphc = hashchain(xmss.get_seed_private(), epoch=block.blockheader.epoch + 1) chain.hash_chain = tmphc.hashchain if not ignore_save_wallet: chain.wallet.save_wallet() self.state_set_blockheight(chain.height() + 1) logger.debug('%s %s tx passed verification.', bin2hstr(block.blockheader.headerhash), len(block.transactions)) return True
def state_add_block(self, chain, block, ignore_save_wallet=False): address_txn = dict() self.load_address_state(chain, block, address_txn) # FIXME: Bottleneck if block.blockheader.blocknumber == 1: if not self.state_update_genesis(chain, block, address_txn): return False self.commit(chain, block, address_txn, ignore_save_wallet=ignore_save_wallet) return True blocks_left = helper.get_blocks_left(block.blockheader.blocknumber) nonce = self.stake_validators_list.sv_list[block.transactions[0].txto].nonce logger.debug('BLOCK: %s epoch: %s blocks_left: %s nonce: %s stake_selector %s', block.blockheader.blocknumber, block.blockheader.epoch, blocks_left - 1, nonce, block.blockheader.stake_selector) if not self.state_update(block, self.stake_validators_list, address_txn): return self.commit(chain, block, address_txn, ignore_save_wallet=ignore_save_wallet) # FIXME: Bottleneck return True
def commit(self, block, stake_validators_list): blocknumber = block.blockheader.blocknumber blocks_left = get_blocks_left(blocknumber) stake_validators_list.sv_list[block.blockheader.stake_selector].nonce += 1 for dup_tx in block.duplicate_transactions: if dup_tx.coinbase1.txto in stake_validators_list.sv_list: stake_validators_list.sv_list[dup_tx.coinbase1.txto].is_banned = True if blocks_left == 1: stake_validators_list.move_next_epoch() self.update_hash_chain(blocknumber)
def state_update(self, block, stake_validators_list, address_txn): # reminder contents: (state address -> nonce, balance, [pubhash]) (stake -> address, hash_term, nonce) blocks_left = helper.get_blocks_left(block.blockheader.blocknumber) if block.blockheader.stake_selector not in stake_validators_list.sv_list: logger.warning('stake selector not in stake_list_get') return if stake_validators_list.sv_list[block.blockheader.stake_selector].is_banned: logger.warning('stake selector is in banned list') return # cycle through every tx in the new block to check state for tx in block.transactions: pubhash = tx.generate_pubhash(tx.PK, tx.ots_key) if tx.subtype == TX_SUBTYPE_COINBASE: expected_nonce = stake_validators_list.sv_list[tx.txfrom].nonce + 1 else: expected_nonce = address_txn[tx.txfrom][0] + 1 if tx.nonce != expected_nonce: logger.warning('nonce incorrect, invalid tx') logger.warning('subtype: %s', tx.subtype) logger.warning('%s actual: %s expected: %s', tx.txfrom, tx.nonce, expected_nonce) return False # TODO: To be fixed later if pubhash in address_txn[tx.txfrom][2]: logger.warning('pubkey reuse detected: invalid tx %s', tx.txhash) logger.warning('subtype: %s', tx.subtype) logger.info(pubhash) logger.info(address_txn[tx.txfrom][2]) return False if tx.subtype == TX_SUBTYPE_TX: if address_txn[tx.txfrom][1] - tx.amount < 0: logger.warning('%s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Transfer Amount %s', address_txn[tx.txfrom][1], tx.amount) return False elif tx.subtype == TX_SUBTYPE_STAKE: epoch_blocknum = config.dev.blocks_per_epoch - blocks_left if (not tx.first_hash) and epoch_blocknum >= config.dev.stake_before_x_blocks: logger.warning('Block rejected #%s due to ST without first_reveal beyond limit', block.blockheader.blocknumber) logger.warning('Stake_selector: %s', block.blockheader.stake_selector) logger.warning('epoch_blocknum: %s Threshold: %s', epoch_blocknum, config.dev.stake_before_x_blocks) return False address_txn[tx.txfrom][2].append(pubhash) next_sv_list = stake_validators_list.next_sv_list if tx.txfrom in next_sv_list: if not next_sv_list[tx.txfrom].first_hash and tx.first_hash: threshold_blocknum = stake_validators_list.get_threshold(tx.txfrom) if epoch_blocknum < threshold_blocknum - 1: logger.warning('Block rejected #%s due to ST before threshold', block.blockheader.blocknumber) logger.warning('Stake_selector: %s', block.blockheader.stake_selector) logger.warning('epoch_blocknum: %s Threshold: %s', epoch_blocknum, threshold_blocknum - 1) return False stake_validators_list.set_first_hash(tx.txfrom, tx.first_hash) else: stake_validators_list.add_next_sv(tx.txfrom, tx.slave_public_key, tx.hash, tx.first_hash, tx.balance) if tx.subtype != TX_SUBTYPE_COINBASE: address_txn[tx.txfrom][0] += 1 if tx.subtype == TX_SUBTYPE_TX: address_txn[tx.txfrom][1] -= tx.amount - tx.fee if tx.subtype in (TX_SUBTYPE_TX, TX_SUBTYPE_COINBASE): address_txn[tx.txto][1] += tx.amount address_txn[tx.txfrom][2].append(pubhash) return True