public function executeWithLockedSend(Send $send, callable $func, $timeout = 60) { return DB::transaction(function () use($send, $func, $timeout) { return RecordLock::acquireAndExecute('xchain.send' . $send['id'], function () use($send, $func) { $locked_send = Send::where('id', $send['id'])->first(); $out = $func($locked_send); // update $send in memory from any changes made to $locked_send $send->setRawAttributes($locked_send->getAttributes()); return $out; }, $timeout); }); }
public function close(PaymentAddress $payment_address, $from, $to, APICall $api_call) { RecordLock::acquireAndExecute($payment_address['uuid'], function () use($payment_address, $from, $to, $api_call) { return DB::transaction(function () use($payment_address, $from, $to, $api_call) { // from account $from_account = $this->account_repository->findByName($from, $payment_address['id']); if (!$from_account) { throw new AccountException('ERR_FROM_ACCOUNT_NOT_FOUND', 404, "unable to find `from` account"); } // check for unconfirmed or sending funds $all_balances_by_asset = $this->ledger_entry_repository->accountBalancesByAsset($from_account, null); if (isset($all_balances_by_asset['unconfirmed'])) { foreach ($all_balances_by_asset['unconfirmed'] as $asset => $quantity) { if ($quantity > 0) { throw new AccountException('ERR_ACCOUNT_HAS_UNCONFIRMED_FUNDS', 400, "Cannot close an account with unconfirmed funds"); } } } if (isset($all_balances_by_asset['sending'])) { foreach ($all_balances_by_asset['sending'] as $asset => $quantity) { if ($quantity > 0) { throw new AccountException('ERR_ACCOUNT_HAS_SENDING_FUNDS', 400, "Cannot close an account with sending funds"); } } } // to account $to_account = $this->account_repository->findByName($to, $payment_address['id']); if (!$to_account) { // create one $to_account = $this->account_repository->create(['name' => $to, 'payment_address_id' => $payment_address['id'], 'user_id' => $payment_address['user_id']]); } // move all balances // accountBalancesByAsset foreach ($all_balances_by_asset as $type_string => $balances) { $type = LedgerEntry::typeStringToInteger($type_string); $txid = null; foreach ($balances as $asset => $quantity) { if ($quantity < 0) { throw new Exception("Attempt to transfer negative quantity for account {$from_account['name']} ({$from_account['uuid']})", 1); } if ($quantity > 0) { $this->ledger_entry_repository->transfer($quantity, $asset, $from_account, $to_account, $type, $txid, $api_call); } } } // close the account $this->account_repository->update($from_account, ['active' => false]); // done return; }); }, self::SEND_LOCK_TIMEOUT); }