def __next__(self): tx = self.transaction_pool_obj.get_pending_transaction() if not tx: raise StopIteration if not tx.validate(): return False addr_from_state = self.state.get_address(address=tx.addr_from) addr_from_pk_state = addr_from_state addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = self.state.get_address(address=addr_from_pk) is_valid_state = tx.validate_extended(addr_from_state=addr_from_state, addr_from_pk_state=addr_from_pk_state) is_valid_pool_state = tx.validate_transaction_pool(self.transaction_pool_obj.transaction_pool) if not (is_valid_state and is_valid_pool_state): logger.info('>>>TX %s failed state_validate', tx.txhash) return False logger.info('A TXN has been Processed %s', bin2hstr(tx.txhash)) self.transaction_pool_obj.add_tx_to_pool(tx) self.transaction_pool_obj.append_addr_ots_hash(tx) self.broadcast_tx(tx) return True
def __next__(self): if not self.transaction_pool_obj.pending_tx_pool: raise StopIteration if len(self.transaction_pool_obj.transaction_pool) >= config.dev.transaction_pool_size: raise StopIteration tx = self.transaction_pool_obj.pending_tx_pool.pop(0) tx = tx[0] if not tx.validate(): return False addr_from_state = self.state.get_address(address=tx.txfrom) addr_from_pk_state = addr_from_state addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = self.state.get_address(address=addr_from_pk) is_valid_state = tx.validate_extended(addr_from_state=addr_from_state, addr_from_pk_state=addr_from_pk_state, transaction_pool=self.transaction_pool_obj.transaction_pool) is_valid_pool_state = tx.validate_transaction_pool(self.transaction_pool_obj.transaction_pool) if not (is_valid_state and is_valid_pool_state): logger.info('>>>TX %s failed state_validate', tx.txhash) return False logger.info('A TXN has been Processed %s', bin2hstr(tx.txhash)) self.transaction_pool_obj.add_tx_to_pool(tx) self.broadcast_tx(tx) return True
def validate_block(self, block, address_txn) -> bool: len_transactions = len(block.transactions) if len_transactions < 1: return False coinbase_tx = Transaction.from_pbdata(block.transactions[0]) if not isinstance(coinbase_tx, CoinBase): return False if not coinbase_tx.validate_extended(): return False if not PoWValidator().validate_mining_nonce(self.state, block.blockheader): return False coinbase_tx.apply_on_state(address_txn) # TODO: check block reward must be equal to coinbase amount for tx_idx in range(1, len_transactions): tx = Transaction.from_pbdata(block.transactions[tx_idx]) if isinstance(tx, CoinBase): return False if not tx.validate( ): # TODO: Move this validation, before adding txn to pool return False addr_from_pk_state = address_txn[tx.addr_from] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = address_txn[addr_from_pk] if not tx.validate_extended(address_txn[tx.addr_from], addr_from_pk_state): return False expected_nonce = addr_from_pk_state.nonce + 1 if tx.nonce != expected_nonce: logger.warning('nonce incorrect, invalid tx') logger.warning('subtype: %s', tx.type) logger.warning('%s actual: %s expected: %s', tx.addr_from, tx.nonce, expected_nonce) return False if addr_from_pk_state.ots_key_reuse(tx.ots_key): logger.warning('pubkey reuse detected: invalid tx %s', tx.txhash) logger.warning('subtype: %s', tx.type) return False tx.apply_on_state(address_txn) return True
def create_block(self, last_block, mining_nonce, tx_pool: TransactionPool, miner_address) -> Optional[Block]: # TODO: Persistence will move to rocksdb # FIXME: Difference between this and create block????????????? dummy_block = Block.create(block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=[], miner_address=miner_address) dummy_block.set_nonces(mining_nonce, 0) t_pool2 = tx_pool.transactions addresses_set = set() for tx_set in t_pool2: tx = tx_set[1] tx.set_effected_address(addresses_set) addresses_state = dict() for address in addresses_set: addresses_state[address] = self.state.get_address(address) block_size = dummy_block.size block_size_limit = self.state.get_block_size_limit(last_block) transactions = [] for tx_set in t_pool2: tx = tx_set[1] # Skip Transactions for later, which doesn't fit into block if block_size + tx.size + config.dev.tx_extra_overhead > block_size_limit: continue addr_from_pk_state = addresses_state[tx.addr_from] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = addresses_state[addr_from_pk] if not tx.validate_extended(addresses_state[tx.addr_from], addr_from_pk_state): logger.warning('Txn validation failed for tx in tx_pool') tx_pool.remove_tx_from_pool(tx) continue tx.apply_on_state(addresses_state) tx._data.nonce = addr_from_pk_state.nonce block_size += tx.size + config.dev.tx_extra_overhead transactions.append(tx) block = Block.create(block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=transactions, miner_address=miner_address) return block
def apply_state_changes(self, address_txn) -> bool: coinbase_tx = Transaction.from_pbdata(self.transactions[0]) if not coinbase_tx.validate_extended(): logger.warning('Coinbase transaction failed') return False coinbase_tx.apply_state_changes(address_txn) len_transactions = len(self.transactions) for tx_idx in range(1, len_transactions): tx = Transaction.from_pbdata(self.transactions[tx_idx]) if isinstance(tx, CoinBase): logger.warning('Found another coinbase transaction') return False if not tx.validate(): return False addr_from_pk_state = address_txn[tx.addr_from] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = address_txn[addr_from_pk] if not tx.validate_extended(address_txn[tx.addr_from], addr_from_pk_state): return False expected_nonce = addr_from_pk_state.nonce + 1 if tx.nonce != expected_nonce: logger.warning('nonce incorrect, invalid tx') logger.warning('subtype: %s', tx.type) logger.warning('%s actual: %s expected: %s', tx.addr_from, tx.nonce, expected_nonce) return False if addr_from_pk_state.ots_key_reuse(tx.ots_key): logger.warning('pubkey reuse detected: invalid tx %s', bin2hstr(tx.txhash)) logger.warning('subtype: %s', tx.type) return False tx.apply_state_changes(address_txn) return True
def __next__(self): if not self.transaction_pool_obj.pending_tx_pool: raise StopIteration if len(self.transaction_pool_obj.transaction_pool ) >= config.dev.transaction_pool_size: raise StopIteration tx = self.transaction_pool_obj.pending_tx_pool.pop(0) tx = tx[0] if not tx.validate(): return False addr_from_state = self.state.get_address(address=tx.addr_from) addr_from_pk_state = addr_from_state addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = self.state.get_address(address=addr_from_pk) is_valid_state = tx.validate_extended( addr_from_state=addr_from_state, addr_from_pk_state=addr_from_pk_state) is_valid_pool_state = tx.validate_transaction_pool( self.transaction_pool_obj.transaction_pool) if not (is_valid_state and is_valid_pool_state): logger.info('>>>TX %s failed state_validate', tx.txhash) return False for old_tx in self.transaction_pool_obj.transaction_pool: if old_tx.txhash == tx.txhash: return True logger.info('A TXN has been Processed %s', bin2hstr(tx.txhash)) self.transaction_pool_obj.add_tx_to_pool(tx) self.broadcast_tx(tx) return True
def validate_block(self, block, address_txn) -> bool: len_transactions = len(block.transactions) if len_transactions < 1: return False coinbase_tx = Transaction.from_pbdata(block.transactions[0]) coinbase_tx.validate() if not self.validate_mining_nonce(block): return False if coinbase_tx.subtype != qrl_pb2.Transaction.COINBASE: return False if not coinbase_tx.validate(): return False coinbase_tx.apply_on_state(address_txn) addr_from_pk_state = address_txn[coinbase_tx.txto] addr_from_pk = Transaction.get_slave(coinbase_tx) if addr_from_pk: addr_from_pk_state = address_txn[addr_from_pk] if not coinbase_tx.validate_extended(address_txn[coinbase_tx.txto], addr_from_pk_state, []): return False # TODO: check block reward must be equal to coinbase amount for tx_idx in range(1, len_transactions): tx = Transaction.from_pbdata(block.transactions[tx_idx]) if tx.subtype == qrl_pb2.Transaction.COINBASE: return False if not tx.validate(): # TODO: Move this validation, before adding txn to pool return False addr_from_pk_state = address_txn[tx.txfrom] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = address_txn[addr_from_pk] if not tx.validate_extended(address_txn[tx.txfrom], addr_from_pk_state, []): return False expected_nonce = address_txn[tx.txfrom].nonce + 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 if tx.ots_key_reuse(address_txn[tx.txfrom], tx.ots_key): logger.warning('pubkey reuse detected: invalid tx %s', tx.txhash) logger.warning('subtype: %s', tx.subtype) return False tx.apply_on_state(address_txn) return True
def create_block(self, last_block, mining_nonce, tx_pool, signing_xmss, master_address) -> Optional[Block]: # TODO: Persistence will move to rocksdb # FIXME: Difference between this and create block????????????? # FIXME: Break encapsulation if not self._dummy_xmss: self._dummy_xmss = XMSS.from_height(signing_xmss.height) dummy_block = Block.create(block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=[], signing_xmss=self._dummy_xmss, master_address=master_address, nonce=0) dummy_block.set_mining_nonce(mining_nonce) t_pool2 = copy.deepcopy(tx_pool.transaction_pool) del tx_pool.transaction_pool[:] ###### # recreate the transaction pool as in the tx_hash_list, ordered by txhash.. total_txn = len(t_pool2) txnum = 0 addresses_set = set() while txnum < total_txn: tx = t_pool2[txnum] tx.set_effected_address(addresses_set) txnum += 1 addresses_state = dict() for address in addresses_set: addresses_state[address] = self.state.get_address(address) block_size = dummy_block.size block_size_limit = self.state.get_block_size_limit(last_block) txnum = 0 while txnum < total_txn: tx = t_pool2[txnum] # Skip Transactions for later, which doesn't fit into block if block_size + tx.size + config.dev.tx_extra_overhead > block_size_limit: txnum += 1 continue addr_from_pk_state = addresses_state[tx.addr_from] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = addresses_state[addr_from_pk] if addr_from_pk_state.ots_key_reuse(tx.ots_key): del t_pool2[txnum] total_txn -= 1 continue if isinstance(tx, TransferTransaction): if addresses_state[ tx.addr_from].balance < tx.total_amount + tx.fee: logger.warning('%s %s exceeds balance, invalid tx', tx, tx.addr_from) logger.warning('type: %s', tx.type) logger.warning( 'Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.addr_from].balance, tx.total_amount) del t_pool2[txnum] total_txn -= 1 continue if isinstance(tx, MessageTransaction): if addresses_state[tx.addr_from].balance < tx.fee: logger.warning('%s %s exceeds balance, invalid message tx', tx, tx.addr_from) logger.warning('type: %s', tx.type) logger.warning('Buffer State Balance: %s Free %s', addresses_state[tx.addr_from].balance, tx.fee) total_txn -= 1 continue if isinstance(tx, TokenTransaction): if addresses_state[tx.addr_from].balance < tx.fee: logger.warning('%s %s exceeds balance, invalid tx', tx, tx.addr_from) logger.warning('type: %s', tx.type) logger.warning('Buffer State Balance: %s Fee %s', addresses_state[tx.addr_from].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if isinstance(tx, TransferTokenTransaction): if addresses_state[tx.addr_from].balance < tx.fee: logger.warning('%s %s exceeds balance, invalid tx', tx, tx.addr_from) logger.warning('type: %s', tx.type) logger.warning( 'Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.addr_from].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if bin2hstr(tx.token_txhash).encode() not in addresses_state[ tx.addr_from].tokens: logger.warning( '%s doesnt own any token with token_txnhash %s', tx.addr_from, bin2hstr(tx.token_txhash).encode()) del t_pool2[txnum] total_txn -= 1 continue if addresses_state[tx.addr_from].tokens[bin2hstr( tx.token_txhash).encode()] < tx.total_amount: logger.warning( 'Token Transfer amount exceeds available token') logger.warning('Token Txhash %s', bin2hstr(tx.token_txhash).encode()) logger.warning( 'Available Token Amount %s', addresses_state[tx.addr_from].tokens[bin2hstr( tx.token_txhash).encode()]) logger.warning('Transaction Amount %s', tx.total_amount) del t_pool2[txnum] total_txn -= 1 continue if isinstance(tx, LatticePublicKey): if addresses_state[tx.addr_from].balance < tx.fee: logger.warning( 'Lattice TXN %s %s exceeds balance, invalid tx', tx, tx.addr_from) logger.warning('type: %s', tx.type) logger.warning( 'Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.addr_from].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if isinstance(tx, SlaveTransaction): if addresses_state[tx.addr_from].balance < tx.fee: logger.warning( 'Slave TXN %s %s exceeds balance, invalid tx', tx, tx.addr_from) logger.warning('type: %s', tx.type) logger.warning( 'Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.addr_from].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue tx.apply_on_state(addresses_state) tx_pool.add_tx_to_pool(tx) tx._data.nonce = addresses_state[tx.addr_from].nonce txnum += 1 block_size += tx.size + config.dev.tx_extra_overhead coinbase_nonce = self.state.get_address(signing_xmss.address).nonce if signing_xmss.address in addresses_state: coinbase_nonce = addresses_state[signing_xmss.address].nonce + 1 block = Block.create(block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=t_pool2, signing_xmss=signing_xmss, master_address=master_address, nonce=coinbase_nonce) return block
def create_block(self, last_block, mining_nonce, tx_pool, signing_xmss, master_address) -> Optional[Block]: # TODO: Persistence will move to rocksdb # FIXME: Difference between this and create block????????????? # FIXME: Break encapsulation dummy_block = Block.create(mining_nonce=mining_nonce, block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=[], signing_xmss=signing_xmss, master_address=master_address, nonce=0) dummy_block.set_mining_nonce(mining_nonce) signing_xmss.set_index(signing_xmss.get_index() - 1) t_pool2 = copy.deepcopy(tx_pool.transaction_pool) del tx_pool.transaction_pool[:] ###### # recreate the transaction pool as in the tx_hash_list, ordered by txhash.. total_txn = len(t_pool2) txnum = 0 addresses_set = set() while txnum < total_txn: tx = t_pool2[txnum] tx.set_effected_address(addresses_set) txnum += 1 addresses_state = dict() for address in addresses_set: addresses_state[address] = self.state.get_address(address) block_size = dummy_block.size block_size_limit = self.state.get_block_size_limit(last_block) txnum = 0 while txnum < total_txn: tx = t_pool2[txnum] # Skip Transactions for later, which doesn't fit into block if block_size + tx.size + config.dev.tx_extra_overhead > block_size_limit: txnum += 1 continue addr_from_pk_state = addresses_state[tx.txfrom] addr_from_pk = Transaction.get_slave(tx) if addr_from_pk: addr_from_pk_state = addresses_state[addr_from_pk] if tx.ots_key_reuse(addr_from_pk_state, tx.ots_key): del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.TRANSFER: if addresses_state[tx.txfrom].balance < tx.amount + tx.fee: 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', addresses_state[tx.txfrom].balance, tx.amount) del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.MESSAGE: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('%s %s exceeds balance, invalid message tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Free %s', addresses_state[tx.txfrom].balance, tx.fee) total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.TOKEN: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('%s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Fee %s', addresses_state[tx.txfrom].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.TRANSFERTOKEN: if addresses_state[tx.txfrom].balance < tx.fee: 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', addresses_state[tx.txfrom].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if bin2hstr(tx.token_txhash).encode() not in addresses_state[tx.txfrom].tokens: logger.warning('%s doesnt own any token with token_txnhash %s', tx.txfrom, bin2hstr(tx.token_txhash).encode()) del t_pool2[txnum] total_txn -= 1 continue if addresses_state[tx.txfrom].tokens[bin2hstr(tx.token_txhash).encode()] < tx.amount: logger.warning('Token Transfer amount exceeds available token') logger.warning('Token Txhash %s', bin2hstr(tx.token_txhash).encode()) logger.warning('Available Token Amount %s', addresses_state[tx.txfrom].tokens[bin2hstr(tx.token_txhash).encode()]) logger.warning('Transaction Amount %s', tx.amount) del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.LATTICE: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('Lattice TXN %s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.txfrom].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue if tx.subtype == qrl_pb2.Transaction.SLAVE: if addresses_state[tx.txfrom].balance < tx.fee: logger.warning('Slave TXN %s %s exceeds balance, invalid tx', tx, tx.txfrom) logger.warning('subtype: %s', tx.subtype) logger.warning('Buffer State Balance: %s Transfer Amount %s', addresses_state[tx.txfrom].balance, tx.fee) del t_pool2[txnum] total_txn -= 1 continue tx.apply_on_state(addresses_state) tx_pool.add_tx_to_pool(tx) tx._data.nonce = addresses_state[tx.txfrom].nonce txnum += 1 block_size += tx.size + config.dev.tx_extra_overhead coinbase_nonce = self.state.get_address(signing_xmss.get_address()).nonce if signing_xmss.get_address() in addresses_state: coinbase_nonce = addresses_state[signing_xmss.get_address()].nonce + 1 block = Block.create(mining_nonce=mining_nonce, block_number=last_block.block_number + 1, prevblock_headerhash=last_block.headerhash, transactions=t_pool2, signing_xmss=signing_xmss, master_address=master_address, nonce=coinbase_nonce) return block