def _calculate_nonce(self, signing_wallet_obj, transaction_id, starting_nonce=0): self._fail_expired_transactions() # First find the highest *continuous* nonce that isn't either pending, or consumed # (failed or succeeded on blockchain) likely_consumed_nonces = (session.query(BlockchainTransaction).filter( BlockchainTransaction.signing_wallet == signing_wallet_obj).filter( BlockchainTransaction.ignore == False).filter( BlockchainTransaction.first_block_hash == self.first_block_hash).filter( and_( or_(BlockchainTransaction.status == 'PENDING', BlockchainTransaction.nonce_consumed == True), BlockchainTransaction.nonce >= starting_nonce)).all()) # Use a set to find continous nonces because txns in db may be out of order nonce_set = set() for txn in likely_consumed_nonces: nonce_set.add(txn.nonce) next_nonce = starting_nonce while next_nonce in nonce_set: next_nonce += 1 return next_nonce
def create_blockchain_wallet_from_private_key( self, private_key, allow_existing=False, wei_target_balance=0, wei_topup_threshold=0, ): address = BlockchainWallet.address_from_private_key(private_key) existing_wallet = session.query(BlockchainWallet).filter_by( address=address).first() if existing_wallet: if allow_existing: return existing_wallet else: raise WalletExistsError( "Account for provided private key already exists") wallet = BlockchainWallet(private_key=private_key, wei_target_balance=wei_target_balance, wei_topup_threshold=wei_topup_threshold) session.add(wallet) session.commit() return wallet
def update_transaction_data(self, transaction_id, transaction_data): transaction = session.query(BlockchainTransaction).get(transaction_id) for attribute in transaction_data: setattr(transaction, attribute, transaction_data[attribute]) session.commit()
def _fail_expired_transactions(self): expire_time = datetime.datetime.utcnow() - datetime.timedelta( seconds=self.PENDING_TRANSACTION_EXPIRY_SECONDS) (session.query(BlockchainTransaction).filter( and_(BlockchainTransaction.status == 'PENDING', BlockchainTransaction.submitted_date < expire_time)).update( { BlockchainTransaction.status: 'FAILED', BlockchainTransaction.error: 'Timeout Error' }, synchronize_session=False))
def add_prior_tasks(self, task: BlockchainTask, prior_tasks: UUIDList): if prior_tasks is None: prior_tasks = [] if isinstance(prior_tasks, str): prior_tasks = [prior_tasks] for task_uuid in prior_tasks: # TODO: Make sure this can't be failed due to a race condition on tasks being added prior_task = session.query(BlockchainTask).filter_by( uuid=task_uuid).first() if prior_task: task.prior_tasks.append(prior_task)
def create_blockchain_transaction(self, task_uuid): task = session.query(BlockchainTask).filter_by(uuid=task_uuid).first() blockchain_transaction = BlockchainTransaction( signing_wallet=task.signing_wallet, first_block_hash=self.first_block_hash) session.add(blockchain_transaction) if task: blockchain_transaction.task = task session.commit() return blockchain_transaction
def claim_transaction_nonce(self, signing_wallet_obj, transaction_id): network_nonce = self.w3.eth.getTransactionCount( signing_wallet_obj.address, block_identifier='pending') blockchain_transaction = session.query(BlockchainTransaction).get( transaction_id) if blockchain_transaction.nonce is not None: return blockchain_transaction.nonce, blockchain_transaction.id calculated_nonce = self._calculate_nonce(signing_wallet_obj, transaction_id, network_nonce) blockchain_transaction.signing_wallet = signing_wallet_obj blockchain_transaction.nonce = calculated_nonce blockchain_transaction.status = 'PENDING' session.commit() return calculated_nonce, blockchain_transaction.id
def get_wallet_by_encrypted_private_key(self, encrypted_private_key): return session.query(BlockchainWallet).filter( BlockchainWallet.encrypted_private_key == encrypted_private_key).first()
def get_wallet_by_address(self, address): return session.query(BlockchainWallet).filter( BlockchainWallet.address == address).first()
def get_all_wallets(self): return session.query(BlockchainWallet).all()
def get_pending_tasks(self): return session.query(BlockchainTask).filter( BlockchainTask.status == 'PENDING').all()
def get_failed_tasks(self): return session.query(BlockchainTask).filter( BlockchainTask.status == 'FAILED').all()
def get_task_from_uuid(self, task_uuid): return session.query(BlockchainTask).filter_by(uuid=task_uuid).first()
def get_transaction_signing_wallet(self, transaction_id): transaction = session.query(BlockchainTransaction).get(transaction_id) return transaction.signing_wallet
def get_transaction(self, transaction_id): return session.query(BlockchainTransaction).get(transaction_id)