diff --git a/Cargo.lock b/Cargo.lock
index ebb6a80bb..dd914f9ab 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2383,7 +2383,7 @@ dependencies = [
[[package]]
name = "mc-full-service"
-version = "1.6.0"
+version = "1.7.0"
dependencies = [
"anyhow",
"base64 0.13.0",
diff --git a/cli/mobilecoin/cli.py b/cli/mobilecoin/cli.py
index 40a72a6ac..4fb6ef887 100644
--- a/cli/mobilecoin/cli.py
+++ b/cli/mobilecoin/cli.py
@@ -391,7 +391,7 @@ def history(self, account_id):
account = self._load_account_prefix(account_id)
account_id = account['account_id']
- transactions = self.client.get_all_transaction_logs_for_account(account_id)
+ transactions = self.client.get_transaction_logs_for_account(account_id, limit=1000)
def block_key(t):
submitted = t['submitted_block_index']
@@ -585,7 +585,7 @@ def address(self, action, **args):
def address_list(self, account_id):
account = self._load_account_prefix(account_id)
- addresses = self.client.get_addresses_for_account(account['account_id'])
+ addresses = self.client.get_addresses_for_account(account['account_id'], limit=1000)
print()
print(_format_account_header(account))
diff --git a/cli/mobilecoin/client.py b/cli/mobilecoin/client.py
index 25c4b5f86..2146c1d74 100755
--- a/cli/mobilecoin/client.py
+++ b/cli/mobilecoin/client.py
@@ -45,13 +45,17 @@ def _req(self, request_data):
except ConnectionError:
raise ConnectionError(f'Could not connect to wallet server at {self.url}.')
+ raw_response = None
try:
- response_data = json.load(r)
+ raw_response = r.read()
+ response_data = json.loads(raw_response)
except ValueError:
- raise ValueError('API returned invalid JSON:', r.text)
+ raise ValueError('API returned invalid JSON:', raw_response)
if self.verbose:
print(r.status, http.client.responses[r.status])
+ print(repr(raw_response))
+ print(len(raw_response), 'bytes')
print(json.dumps(response_data, indent=2))
print()
@@ -147,10 +151,14 @@ def export_account_secrets(self, account_id):
})
return r['account_secrets']
- def get_all_txos_for_account(self, account_id):
+ def get_txos_for_account(self, account_id, offset=0, limit=100):
r = self._req({
- "method": "get_all_txos_for_account",
- "params": {"account_id": account_id}
+ "method": "get_txos_for_account",
+ "params": {
+ "account_id": account_id,
+ "offset": offset,
+ "limit": limit,
+ }
})
return r['txo_map']
@@ -200,7 +208,7 @@ def assign_address_for_account(self, account_id, metadata=None):
})
return r['address']
- def get_addresses_for_account(self, account_id, offset=0, limit=1000):
+ def get_addresses_for_account(self, account_id, offset=0, limit=100):
r = self._req({
"method": "get_addresses_for_account",
"params": {
@@ -259,11 +267,13 @@ def submit_transaction(self, tx_proposal, account_id=None):
})
return r['transaction_log']
- def get_all_transaction_logs_for_account(self, account_id):
+ def get_transaction_logs_for_account(self, account_id, offset=0, limit=100):
r = self._req({
- "method": "get_all_transaction_logs_for_account",
+ "method": "get_transaction_logs_for_account",
"params": {
"account_id": account_id,
+ "offset": str(int(offset)),
+ "limit": str(int(limit)),
},
})
return r['transaction_log_map']
diff --git a/cli/test/client_tests.py b/cli/test/client_tests.py
index c2c4d8328..72052766f 100644
--- a/cli/test/client_tests.py
+++ b/cli/test/client_tests.py
@@ -113,7 +113,7 @@ def tests_with_wallet(c, source_wallet):
# Check its balance and make sure it has txos.
balance = c.poll_balance(source_account_id, seconds=60)
assert pmob2mob(balance['unspent_pmob']) >= 1
- txos = c.get_all_txos_for_account(source_account_id)
+ txos = c.get_txos_for_account(source_account_id)
assert len(txos) > 0
try:
@@ -149,7 +149,7 @@ def test_transaction(c, source_account_id):
assert pmob2mob(balance['unspent_pmob']) == Decimal('0.0')
# Check transaction logs.
- transaction_log_map = c.get_all_transaction_logs_for_account(dest_account_id)
+ transaction_log_map = c.get_transaction_logs_for_account(dest_account_id)
amounts = [ pmob2mob(t['value_pmob']) for t in transaction_log_map.values() ]
assert sorted( float(a) for a in amounts ) == [0.0996, 0.1], str(amounts)
assert all( t['status'] == 'tx_status_succeeded' for t in transaction_log_map.values() )
diff --git a/cli/test/stress.py b/cli/test/stress.py
new file mode 100644
index 000000000..c4e80b29b
--- /dev/null
+++ b/cli/test/stress.py
@@ -0,0 +1,126 @@
+import aiohttp
+import asyncio
+from time import perf_counter
+
+
+async def main():
+ c = StressClient()
+ await test_account_create(c)
+ await test_subaddresses(c)
+
+
+async def test_account_create(c, n=10):
+ accounts = await c.get_all_accounts()
+ num_accounts_before = len(accounts)
+
+ account_ids = []
+ async def create_one(i):
+ account = await c.create_account(str(i))
+ account_ids.append(account['account_id'])
+
+ with Timer() as timer:
+ await asyncio.gather(*[
+ create_one(i)
+ for i in range(1, n+1)
+ ])
+
+ accounts = await c.get_all_accounts()
+ assert len(accounts) == num_accounts_before + n
+
+ await asyncio.gather(*[
+ c.remove_account(account_id)
+ for account_id in account_ids
+ ])
+
+ print('Created {} accounts in {:.3f}s'.format(n, timer.elapsed))
+
+
+async def test_subaddresses(c, n=10):
+ account = await c.create_account()
+ account_id = account['account_id']
+
+ addresses = await c.get_addresses_for_account(account_id)
+ assert len(addresses) == 2
+
+ with Timer() as timer:
+ await asyncio.gather(*[
+ c.assign_address(account_id, str(i))
+ for i in range(1, n+1)
+ ])
+
+ addresses = await c.get_addresses_for_account(account_id)
+ assert len(addresses) == 2 + n
+
+ await c.remove_account(account_id)
+
+ print('Created {} addresses in {:.3f}s'.format(n, timer.elapsed))
+
+
+class StressClient:
+
+ async def _req(self, request_data):
+ default_params = {
+ "jsonrpc": "2.0",
+ "api_version": "2",
+ "id": 1,
+ }
+ request_data = {**request_data, **default_params}
+ async with aiohttp.ClientSession() as session:
+ async with session.post('http://localhost:9090/wallet', json=request_data) as response:
+ r = await response.json()
+ try:
+ return r['result']
+ except KeyError:
+ print(r)
+ raise
+
+ async def get_all_accounts(self):
+ r = await self._req({"method": "get_all_accounts"})
+ return r['account_map']
+
+ async def create_account(self, name=''):
+ r = await self._req({
+ "method": "create_account",
+ "params": {"name": name}
+ })
+ return r['account']
+
+ async def remove_account(self, account_id):
+ return await self._req({
+ "method": "remove_account",
+ "params": {"account_id": account_id}
+ })
+
+ async def assign_address(self, account_id, name=''):
+ return await self._req({
+ "method": "assign_address_for_account",
+ "params": {
+ "account_id": account_id,
+ "metadata": name,
+ },
+ })
+
+ async def get_addresses_for_account(self, account_id):
+ r = await self._req({
+ "method": "get_addresses_for_account",
+ "params": {
+ "account_id": account_id,
+ "offset": "0",
+ "limit": "1000",
+ },
+ })
+ return r['address_map']
+
+
+class Timer:
+ def __enter__(self):
+ self._start_time = perf_counter()
+ return self
+
+ def __exit__(self, *_):
+ end_time = perf_counter()
+ self.elapsed = end_time - self._start_time
+
+
+if __name__ == '__main__':
+ asyncio.run(main())
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index 1bbb44a61..176fcc93e 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -23,7 +23,6 @@
* [Export View Only Account Secrets](accounts/account-secrets/export_view_only_account_secrets.md)
* [Address](accounts/address/README.md)
* [Assign Address For Account](accounts/address/assign_address_for_account.md)
- * [Get All Addresses For Account](accounts/address/get_all_addresses_for_account.md)
* [Get Addresses For Account](accounts/address/get_addresses_for_account.md)
* [Verify Address](accounts/address/verify_address.md)
* [Balance](accounts/balance/README.md)
@@ -42,7 +41,6 @@
* [Get TXO](transactions/txo/get_txo.md)
* [Get MobileCoin Protocol TXO](transactions/txo/get_mc_protocol_txo.md)
* [Get TXOs For Account](transactions/txo/get_txos_for_account.md)
- * [Get All TXOs For Account](transactions/txo/get_all_txos_for_account.md)
* [Get TXOs For Account](transactions/txo/get_txos_for_account.md)
* [Get TXOs For View Only Account](transactions/txo/get_txos_for_view_only_account.md)
* [Get All TXOs For Address](transactions/txo/get_txo_object.md)
@@ -55,7 +53,6 @@
* [Transaction Log](transactions/transaction-log/README.md)
* [Get Transaction Object](transactions/transaction-log/get_transaction_object.md)
* [Get Transaction Log](transactions/transaction-log/get_transaction_log.md)
- * [Get All Transaction Logs For Account](transactions/transaction-log/get_all_transaction_logs_for_account.md)
* [Get Transaction Logs For Account](transactions/transaction-log/get_transaction_logs_for_account.md)
* [Get All Transaction Logs For Block](transactions/transaction-log/get_all_transaction_logs_for_block.md)
* [Get All Transaction Logs Ordered By Block](transactions/transaction-log/get_all_transaction_logs_ordered_by_block.md)
diff --git a/docs/accounts/address/README.md b/docs/accounts/address/README.md
index 74f657cd9..392faf762 100644
--- a/docs/accounts/address/README.md
+++ b/docs/accounts/address/README.md
@@ -22,8 +22,6 @@ Important: If you receive funds at a subaddress that has not yet been assigned,
| `account_id` | string | A unique identifier for the assigned associated account. |
| `metadata` | string | An arbitrary string attached to the object. |
| `subaddress_index` | string \(uint64\) | The assigned subaddress index on the associated account. |
-| `offset` | integer | The value to offset pagination requests. Requests will exclude all list items up to and including this object. |
-| `limit` | integer | The limit of returned results. |
## Example
diff --git a/docs/accounts/address/get_addresses_for_account.md b/docs/accounts/address/get_addresses_for_account.md
index effa784ef..0048f9d01 100644
--- a/docs/accounts/address/get_addresses_for_account.md
+++ b/docs/accounts/address/get_addresses_for_account.md
@@ -9,8 +9,8 @@ description: Get assigned addresses for an account.
| Required Param | Purpose | Requirements |
| :--- | :--- | :--- |
| `account_id` | The account on which to perform this action. | The account must exist in the wallet. |
-| `offset` | integer | The value to offset pagination requests. Requests will exclude all list items up to and including this object. |
-| `limit` | integer | The limit of returned results. This has a max value of 1000, and will return an error if exceeded. |
+| `offset` | The pagination offset. Results start at the offset index. Optional, defaults to 0. | |
+| `limit` | Limit for the number of results. Optional, defaults to 100 | |
## Example
diff --git a/docs/accounts/address/get_all_addresses_for_account.md b/docs/accounts/address/get_all_addresses_for_account.md
deleted file mode 100644
index b5f4cdf21..000000000
--- a/docs/accounts/address/get_all_addresses_for_account.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-description: Get all assigned addresses for a given account.
----
-
-# Get All Addresses For Account
-
-## Parameters
-
-| Required Param | Purpose | Requirements |
-| :--- | :--- | :--- |
-| `account_id` | The account on which to perform this action. | The account must exist in the wallet. |
-
-## Example
-
-{% tabs %}
-{% tab title="Request Body" %}
-```text
-{
- "method": "get_all_addresses_for_account",
- "params": {
- "account_id": "a8c9c7acb96cf4ad9154eec9384c09f2c75a340b441924847fe5f60a41805bde"
- },
- "jsonrpc": "2.0",
- "id": 1
-}
-```
-{% endtab %}
-
-{% tab title="Response" %}
-```text
-{
- "method": "get_all_addresses_for_account",
- "result": {
- "public_addresses": [
- "4bgkVAH1hs55dwLTGVpZER8ZayhqXbYqfuyisoRrmQPXoWcYQ3SQRTjsAytCiAgk21CRrVNysVw5qwzweURzDK9HL3rGXFmAAahb364kYe3",
- "6prEWE8yEmHAznkZ3QUtHRmVf7q8DS6XpkjzecYCGMj7hVh8fivmCcujamLtugsvvmWE9P2WgTb2o7xGHw8FhiBr1hSrku1u9KKfRJFMenG",
- "3P4GtGkp5UVBXUzBqirgj7QFetWn4PsFPsHBXbC6A8AXw1a9CMej969jneiN1qKcwdn6e1VtD64EruGVSFQ8wHk5xuBHndpV9WUGQ78vV7Z"
- ],
- "address_map": {
- "4bgkVAH1hs55dwLTGVpZER8ZayhqXbYqfuyisoRrmQPXoWcYQ3SQRTjsAytCiAgk21CRrVNysVw5qwzweURzDK9HL3rGXFmAAahb364kYe3": {
- "object": "address",
- "public_address": "4bgkVAH1hs55dwLTGVpZER8ZayhqXbYqfuyisoRrmQPXoWcYQ3SQRTjsAytCiAgk21CRrVNysVw5qwzweURzDK9HL3rGXFmAAahb364kYe3",
- "account_id": "3407fbbc250799f5ce9089658380c5fe152403643a525f581f359917d8d59d52",
- "metadata": "Main",
- "subaddress_index": "0"
- },
- "6prEWE8yEmHAznkZ3QUtHRmVf7q8DS6XpkjzecYCGMj7hVh8fivmCcujamLtugsvvmWE9P2WgTb2o7xGHw8FhiBr1hSrku1u9KKfRJFMenG": {
- "object": "address",
- "public_address": "6prEWE8yEmHAznkZ3QUtHRmVf7q8DS6XpkjzecYCGMj7hVh8fivmCcujamLtugsvvmWE9P2WgTb2o7xGHw8FhiBr1hSrku1u9KKfRJFMenG",
- "account_id": "3407fbbc250799f5ce9089658380c5fe152403643a525f581f359917d8d59d52",
- "metadata": "Change",
- "subaddress_index": "1"
- },
- "3P4GtGkp5UVBXUzBqirgj7QFetWn4PsFPsHBXbC6A8AXw1a9CMej969jneiN1qKcwdn6e1VtD64EruGVSFQ8wHk5xuBHndpV9WUGQ78vV7Z": {
- "object": "address",
- "public_address": "3P4GtGkp5UVBXUzBqirgj7QFetWn4PsFPsHBXbC6A8AXw1a9CMej969jneiN1qKcwdn6e1VtD64EruGVSFQ8wHk5xuBHndpV9WUGQ78vV7Z",
- "account_id": "3407fbbc250799f5ce9089658380c5fe152403643a525f581f359917d8d59d52",
- "metadata": "",
- "subaddress_index": "2"
- }
- }
- },
- "error": null,
- "jsonrpc": "2.0",
- "id": 1,
-}
-verify_a
-```
-{% endtab %}
-{% endtabs %}
-
diff --git a/docs/gift-codes/gift-code/build_gift_code.md b/docs/gift-codes/gift-code/build_gift_code.md
index 98b4fb2d0..b25cf2bff 100644
--- a/docs/gift-codes/gift-code/build_gift_code.md
+++ b/docs/gift-codes/gift-code/build_gift_code.md
@@ -13,7 +13,7 @@ description: Build a gift code in a tx_proposal that you can fund and submit to
| Optional Param | Purpose | Requirements |
| :--- | :--- | :--- |
-| `input_txo_ids` | The specific TXOs to use as inputs to this transaction. | TXO IDs \(obtain from `get_all_txos_for_account`\) |
+| `input_txo_ids` | The specific TXOs to use as inputs to this transaction. | TXO IDs \(obtain from `get_txos_for_account`\) |
| `fee` | The fee amount to submit with this transaction. | If not provided, uses `MINIMUM_FEE` = .01 MOB. |
| `tombstone_block` | The block after which this transaction expires. | If not provided, uses `cur_height` + 10. |
| `max_spendable_value` | The maximum amount for an input TXO selected for this transaction. | |
diff --git a/docs/transactions/transaction-log/README.md b/docs/transactions/transaction-log/README.md
index cbdeb5df1..372c1ccdc 100644
--- a/docs/transactions/transaction-log/README.md
+++ b/docs/transactions/transaction-log/README.md
@@ -32,7 +32,6 @@ Due to the privacy properties of the MobileCoin ledger, transactions are ephemer
| `comment` | string | An arbitrary string attached to the object. |
| `failure_code` | integer | Code representing the cause of "failed" status. |
| `failure_message` | string | Human parsable explanation of "failed" status. |
-| `offset` | integer | The value to offset pagination requests for `transaction_log` list. Requests will exclude all list items up to and including this object. |
## Example
diff --git a/docs/transactions/transaction-log/get_all_transaction_logs_for_account.md b/docs/transactions/transaction-log/get_all_transaction_logs_for_account.md
deleted file mode 100644
index 910d797d9..000000000
--- a/docs/transactions/transaction-log/get_all_transaction_logs_for_account.md
+++ /dev/null
@@ -1,99 +0,0 @@
----
-description: Get all transaction logs for a given account.
----
-
-# Get All Transaction Logs For Account
-
-## Parameters
-
-| Required Param | Purpose | Requirements |
-| :--- | :--- | :--- |
-| `account_id` | The account on which to perform this action. | Account must exist in the wallet. |
-
-## Example
-
-{% tabs %}
-{% tab title="Request Body" %}
-```text
-{
- "method": "get_all_transaction_logs_for_account",
- "params": {
- "account_id": "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10"
- },
- "jsonrpc": "2.0",
- "id": 1
-}
-```
-{% endtab %}
-
-{% tab title="Response" %}
-```text
-{
- "method": "get_all_transaction_logs_for_account",
- "result": {
- "transaction_log_ids": [
- "49da8168e26331fc9bc109d1e59f7ed572b453f232591de4196f9cefb381c3f4",
- "ff1c85e7a488c2821110597ba75db30d913bb1595de549f83c6e8c56b06d70d1"
- ],
- "transaction_log_map": {
- "49da8168e26331fc9bc109d1e59f7ed572b453f232591de4196f9cefb381c3f4": {
- "object": "transaction_log",
- "transaction_log_id": "49da8168e26331fc9bc109d1e59f7ed572b453f232591de4196f9cefb381c3f4",
- "direction": "tx_direction_received",
- "is_sent_recovered": null,
- "account_id": "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10",
- "recipient_address_id": null,
- "assigned_address_id": "7JvajhkAZYGmrpCY7ZpEiXRK5yW1ooTV7EWfDNu3Eyt572mH1wNb37BWiU6JqRUvgopPqSVZRexhXXpjF3wqLQR7HaJrcdbHmULujgFmzav",
- "value_pmob": "8199980000000000",
- "fee_pmob": null,
- "submitted_block_index": null,
- "finalized_block_index": "130689",
- "status": "tx_status_succeeded",
- "input_txo_ids": [],
- "output_txo_ids": [
- "49da8168e26331fc9bc109d1e59f7ed572b453f232591de4196f9cefb381c3f4"
- ],
- "change_txo_ids": [],
- "sent_time": null,
- "comment": "",
- "failure_code": null,
- "failure_message": null
- },
- "ff1c85e7a488c2821110597ba75db30d913bb1595de549f83c6e8c56b06d70d1": {
- "object": "transaction_log",
- "transaction_log_id": "ff1c85e7a488c2821110597ba75db30d913bb1595de549f83c6e8c56b06d70d1",
- "direction": "tx_direction_sent",
- "is_sent_recovered": null,
- "account_id": "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10",
- "recipient_address_id": "7JvajhkAZYGmrpCY7ZpEiXRK5yW1ooTV7EWfDNu3Eyt572mH1wNb37BWiU6JqRUvgopPqSVZRexhXXpjF3wqLQR7HaJrcdbHmULujgFmzav",
- "assigned_address_id": null,
- "value_pmob": "8000000000008",
- "fee_pmob": "10000000000",
- "submitted_block_index": "152951",
- "finalized_block_index": "152951",
- "status": "tx_status_succeeded",
- "input_txo_ids": [
- "135c3861be4034fccb8d0b329f86124cb6e2404cd4debf52a3c3a10cb4a7bdfb",
- "c91b5f27e28460ef6c4f33229e70c4cfe6dc4bc1517a22122a86df9fb8e40815"
- ],
- "output_txo_ids": [
- "243494a0030bcbac40e87670b9288834047ef0727bcc6630a2fe2799439879ab"
- ],
- "change_txo_ids": [
- "58729797de0929eed37acb45225d3631235933b709c00015f46bfc002d5754fc"
- ],
- "sent_time": "2021-02-28 03:05:11 UTC",
- "comment": "",
- "failure_code": null,
- "failure_message": null
- }
- }
- },
- "error": null,
- "jsonrpc": "2.0",
- "id": 1,
-}
-```
-{% endtab %}
-{% endtabs %}
-
diff --git a/docs/transactions/transaction-log/get_transaction_logs_for_account.md b/docs/transactions/transaction-log/get_transaction_logs_for_account.md
index 05432f912..df9da680c 100644
--- a/docs/transactions/transaction-log/get_transaction_logs_for_account.md
+++ b/docs/transactions/transaction-log/get_transaction_logs_for_account.md
@@ -5,8 +5,8 @@
| Required Param | Purpose | Requirement |
| :--- | :--- | :--- |
| `transaction_log_id` | The transaction log ID to get. | Transaction log must exist in the wallet. |
-| `offset` | integer | The value to offset pagination requests. Requests will exclude all list items up to and including this object. |
-| `limit` | integer | The limit of returned results. This has a max value of 1000, and will return an error if exceeded. |
+| `offset` | The pagination offset. Results start at the offset index. Optional, defaults to 0. | |
+| `limit` | Limit for the number of results. Optional, defaults to 100 | |
## Example
@@ -118,4 +118,4 @@
}
```
{% endtab %}
-{% endtabs %}
\ No newline at end of file
+{% endtabs %}
diff --git a/docs/transactions/transaction/build_and_submit_transaction.md b/docs/transactions/transaction/build_and_submit_transaction.md
index ed2542161..1a6a6697d 100644
--- a/docs/transactions/transaction/build_and_submit_transaction.md
+++ b/docs/transactions/transaction/build_and_submit_transaction.md
@@ -17,7 +17,7 @@ description: >-
| `recipient_public_address` | The recipient for this transaction | b58-encoded public address bytes |
| `value_pmob` | The amount of MOB to send in this transaction | |
| `addresses_and_values` | An array of public addresses and value tuples | addresses are b58-encoded public addresses, value is in pmob |
-| `input_txo_ids` | Specific TXOs to use as inputs to this transaction | TXO IDs \(obtain from `get_all_txos_for_account`\) |
+| `input_txo_ids` | Specific TXOs to use as inputs to this transaction | TXO IDs \(obtain from `get_txos_for_account`\) |
| `fee` | The fee amount to submit with this transaction | If not provided, uses `MINIMUM_FEE` = .01 MOB |
| `tombstone_block` | The block after which this transaction expires | If not provided, uses `cur_height` + 10 |
| `max_spendable_value` | The maximum amount for an input TXO selected for this transaction | |
diff --git a/docs/transactions/transaction/build_transaction.md b/docs/transactions/transaction/build_transaction.md
index 002762a95..9f4e8e9d3 100644
--- a/docs/transactions/transaction/build_transaction.md
+++ b/docs/transactions/transaction/build_transaction.md
@@ -17,7 +17,7 @@ description: >-
| `recipient_public_address` | The recipient for this transaction | b58-encoded public address bytes |
| `value_pmob` | The amount of MOB to send in this transaction | |
| `addresses_and_values` | An array of public addresses and value tuples | addresses are b58-encoded public addresses, value is in pmob |
-| `input_txo_ids` | Specific TXOs to use as inputs to this transaction | TXO IDs (obtain from `get_all_txos_for_account`) |
+| `input_txo_ids` | Specific TXOs to use as inputs to this transaction | TXO IDs (obtain from `get_txos_for_account`) |
| `fee` | The fee amount to submit with this transaction | If not provided, uses `MINIMUM_FEE` = .01 MOB |
| `tombstone_block` | The block after which this transaction expires | If not provided, uses `cur_height` + 10 |
| `max_spendable_value` | The maximum amount for an input TXO selected for this transaction | |
diff --git a/docs/transactions/txo/README.md b/docs/transactions/txo/README.md
index 17d8880fe..f81417221 100644
--- a/docs/transactions/txo/README.md
+++ b/docs/transactions/txo/README.md
@@ -29,8 +29,6 @@ In order to construct a transaction, the wallet will select "Unspent Transaction
| `assigned_address` | string \(uint64\) | The address corresponding to the subaddress index which was assigned as an intended sender for this TXO. |
| `key_image` \(only on pending/spent\) | string \(hex\) | A fingerprint of the TXO derived from your private spend key materials, required to spend a TXO |
| `confirmation` | string \(hex\) | A confirmation that the sender of the TXO can provide to validate that they participated in the construction of this TXO. |
-| `offset` | integer | The value to offset pagination requests. Requests will exclude all list items up to and including this object. |
-| `limit` | integer | The limit of returned results. |
## Example
@@ -109,4 +107,4 @@ a minimal txo entity useful for view-only-accounts
| `spent` | string | Whether or not this txo has been manually marked as spent. |
| `txo_id_hex` | string | A synthetic ID created from properties of the TXO. This will be the same for a given TXO across systems. |
-## Example
\ No newline at end of file
+## Example
diff --git a/docs/transactions/txo/get_all_txos_for_account.md b/docs/transactions/txo/get_all_txos_for_account.md
deleted file mode 100644
index b39eb248b..000000000
--- a/docs/transactions/txo/get_all_txos_for_account.md
+++ /dev/null
@@ -1,158 +0,0 @@
----
-description: Get all TXOs for a given account.
----
-
-# Get All TXOs For Account
-
-## Parameters
-
-| Parameter | Purpose | Requirements |
-| :--- | :--- | :--- |
-| `account_id` | The account on which to perform this action. | Account must exist in the wallet. |
-
-## Example
-
-{% tabs %}
-{% tab title="Request Body" %}
-```text
-{
- "method": "get_all_txos_for_account",
- "params": {
- "account_id": "a8c9c7acb96cf4ad9154eec9384c09f2c75a340b441924847fe5f60a41805bde"
- },
- "jsonrpc": "2.0",
- "id": 1
-}
-```
-{% endtab %}
-
-{% tab title="Response" %}
-```text
-{
- "method": "get_all_txos_for_account",
- "result": {
- "txo_ids": [
- "001cdcc1f0a22dc0ddcdaac6020cc03d919cbc3c36923f157b4a6bf0dc980167",
- "00408833347550b046f0996afe92313745f76e307904686e93de5bab3590e9da",
- "005b41a40be1401426f9a00965cc334e4703e4089adb8fa00616e7b25b92c6e5",
- ...
- ],
- "txo_map": {
- "001cdcc1f0a22dc0ddcdaac6020cc03d919cbc3c36923f157b4a6bf0dc980167": {
- "account_status_map": {
- "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10": {
- "txo_status": "spent",
- "txo_type": "received"
- }
- },
- "assigned_subaddress": "7BeDc5jpZu72AuNavumc8qo8CRJijtQ7QJXyPo9dpnqULaPhe6GdaDNF7cjxkTrDfTcfMgWVgDzKzbvTTwp32KQ78qpx7bUnPYxAgy92caJ",
- "e_fog_hint": "0a54bf0a5f37989b379b9db3e8937387c5033428b399d44ee524c02b53ce8b7fa7ffc7181a854255cefc68704f69eedd43a891d2ed65c9f6e4c0fc645c2bc156278395221100a4fc3a1d617d04f6eca8851e846a0100",
- "is_spent_recovered": false,
- "key_image": "0a20f041e3da520a6e3328d43a920b90bf87826a1602c9249cf6591dd32328a4544e",
- "minted_account_id": null,
- "object": "txo",
- "confirmation": null,
- "public_key": "0a201a592874a596aeb14cbeb1c7d3449cbd20dc8078ad7fff657e131d619145ef0a",
- "received_account_id": "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10",
- "received_block_index": "128567",
- "spent_block_index": "128569",
- "subaddress_index": "0",
- "target_key": "0a209e1067117870549a77a47de04bd810da052abfc23d60a0c433367bfc689b7428",
- "txo_id": "001cdcc1f0a22dc0ddcdaac6020cc03d919cbc3c36923f157b4a6bf0dc980167",
- "value_pmob": "990000000000"
- },
- "84f30233774d728bb7844bed59d471fe55ee3680ab70ddc312840db0f978f3ba": {
- "account_status_map": {
- "36fdf8fbdaa35ad8e661209b8a7c7057f29bf16a1e399a34aa92c3873dfb853c": {
- "txo_status": "unspent",
- "txo_type": "received"
- },
- "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10": {
- "txo_status": "secreted",
- "txo_type": "minted"
- }
- },
- "assigned_subaddress": null,
- "e_fog_hint": "0a5472b079a520696518cc7d7c3036e855cbbcf1a3e247db32ab2e62e835183077b862ef86ec4963a584650cc028eb645569f9de1392b88f8fd7fa07aa28c4e035fd5f4866f3db3d403a05d2adb5e4f2992c010b0100",
- "is_spent_recovered": false,
- "key_image": null,
- "minted_account_id": "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10",
- "object": "txo",
- "confirmation": "0a204488e153cce1e4bcdd4419eecb778f3d2d2b024b39aaa29532d2e47e238b2e31",
- "public_key": "0a20e6736474f73e440686736bfd045d838c2b3bc056ffc647ad6b1c990f5a46b123",
- "received_account_id": "36fdf8fbdaa35ad8e661209b8a7c7057f29bf16a1e399a34aa92c3873dfb853c",
- "received_block_index": null,
- "spent_block_index": null,
- "subaddress_index": null,
- "target_key": "0a20762d8a723aae2aa70cc11c62c91af715f957a7455b695641fe8c94210812cf1b",
- "txo_id": "84f30233774d728bb7844bed59d471fe55ee3680ab70ddc312840db0f978f3ba",
- "value_pmob": "200"
- },
- "58c2c3780792ccf9c51014c7688a71f03732b633f8c5dfa49040fa7f51328280": {
- "account_status_map": {
- "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10": {
- "txo_status": "unspent",
- "txo_type": "received"
- }
- },
- "assigned_subaddress": "7BeDc5jpZu72AuNavumc8qo8CRJijtQ7QJXyPo9dpnqULaPhe6GdaDNF7cjxkTrDfTcfMgWVgDzKzbvTTwp32KQ78qpx7bUnPYxAgy92caJ",
- "e_fog_hint": "0a546f862ccf5e96a89b3ede770a70aa26ce8be704a7e5a73fff02d16ee1f694297b6c17d2e668d6181df047ae68730dfc7913b28aca66450ee1de0ca3b0bedb07664918899848f217bcbbe48be2ef40074ae5dd0100",
- "is_spent_recovered": false,
- "key_image": "0a20784ab38c4541ce23abbec6744431d6ae14101c49c6535b3e9bf3fd728db13848",
- "minted_account_id": null,
- "object": "txo",
- "confirmation": null,
- "public_key": "0a20d803a979c9ec0531f106363a885dde29101fcd70209f9ed686905512dfd14d5f",
- "received_account_id": "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10",
- "received_block_index": "79",
- "spent_block_index": null,
- "subaddress_index": "0",
- "target_key": "0a209abadbfcec6c81b3d184dc104e51cac4c4faa8bab4da21a3714901519810c20d",
- "txo_id": "58c2c3780792ccf9c51014c7688a71f03732b633f8c5dfa49040fa7f51328280",
- "value_pmob": "4000000000000"
- },
- "b496f4f3ec3159bf48517aa7d9cda193ef8bfcac343f81eaed0e0a55849e4726": {
- "account_status_map": {
- "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10": {
- "txo_status": "secreted",
- "txo_type": "minted"
- }
- },
- "assigned_subaddress": null,
- "e_fog_hint": "0a54338fcf8609cf80dfe017bee2339b22b626af2957ef579ae8829f3d8e7fab6c20365b6a99727fcd5e3de7784fca7e1cbb77ec35e7f2c39ea47ef6121716119ba5a67f8a6026a6a6274e7262ea8ea8280782440100",
- "is_spent_recovered": false,
- "key_image": null,
- "minted_account_id": "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10",
- "object": "txo",
- "confirmation": null,
- "public_key": "0a209432c589bb4e5101c26e935b70930dfe45c78417527fb994872ebd65fcb9c116",
- "received_account_id": null,
- "received_block_index": null,
- "spent_block_index": null,
- "subaddress_index": null,
- "target_key": "0a208c75723e9b9a4af0c833bfe190c43900c3b41834cf37024f5fecfbe9919dff23",
- "txo_id": "b496f4f3ec3159bf48517aa7d9cda193ef8bfcac343f81eaed0e0a55849e4726",
- "value_pmob": "980000000000"
- }
- ]
- }
-}
-```
-{% endtab %}
-{% endtabs %}
-
-{% hint style="info" %}
-Note, you may wish to filter TXOs using a tool like jq. For example, to get all unspent TXOs, you can use:
-
-```text
-{
- "method": "get_all_txos_for_account",
- "params": {
- "account_id": "a4db032dcedc14e39608fe6f26deadf57e306e8c03823b52065724fb4d274c10"
- },
- "jsonrpc": "2.0",
- "id": 1,
-}
-```
-{% endhint %}
-
diff --git a/docs/transactions/txo/get_txos_for_account.md b/docs/transactions/txo/get_txos_for_account.md
index b7b4d24c6..4ebe30ee0 100644
--- a/docs/transactions/txo/get_txos_for_account.md
+++ b/docs/transactions/txo/get_txos_for_account.md
@@ -9,8 +9,8 @@ description: Get TXOs for a given account with offset and limit parameters
| Parameter | Purpose | Requirements |
| :--- | :--- | :--- |
| `account_id` | The account on which to perform this action. | Account must exist in the wallet. |
-| `offset` | The value to offset pagination requests. Requests will exclude all list items up to and including this object. | |
-| `limit` | The limit of returned results. | This has a max value of 1000, and will return an error if exceeded. |
+| `offset` | The pagination offset. Results start at the offset index. Optional, defaults to 0. | |
+| `limit` | Limit for the number of results. Optional, defaults to 100 | |
## Example
@@ -144,4 +144,4 @@ description: Get TXOs for a given account with offset and limit parameters
}
```
{% endtab %}
-{% endtabs %}
\ No newline at end of file
+{% endtabs %}
diff --git a/docs/transactions/txo/get_txos_for_view_only_account.md b/docs/transactions/txo/get_txos_for_view_only_account.md
index 2bc50c0ca..7f1357ec0 100644
--- a/docs/transactions/txo/get_txos_for_view_only_account.md
+++ b/docs/transactions/txo/get_txos_for_view_only_account.md
@@ -9,8 +9,8 @@ description: Get view only TXOs for a given view only account with offset and li
| Parameter | Purpose | Requirements |
| :--- | :--- | :--- |
| `account_id` | The account on which to perform this action. | Account must exist in the wallet. |
-| `offset` | The value to offset pagination requests. Requests will exclude all list items up to and including this object. | |
-| `limit` | The limit of returned results. | This has a max value of 1000, and will return an error if exceeded. |
+| `offset` | The pagination offset. Results start at the offset index. Optional, defaults to 0. | |
+| `limit` | Limit for the number of results. Optional, defaults to 100 | |
## Example
@@ -71,4 +71,4 @@ description: Get view only TXOs for a given view only account with offset and li
}
```
{% endtab %}
-{% endtabs %}
\ No newline at end of file
+{% endtabs %}
diff --git a/full-service/Cargo.toml b/full-service/Cargo.toml
index 8730e9871..8b02a0ddc 100644
--- a/full-service/Cargo.toml
+++ b/full-service/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "mc-full-service"
-version = "1.6.0"
+version = "1.7.0"
authors = ["MobileCoin"]
edition = "2018"
build = "build.rs"
diff --git a/full-service/src/bin/main.rs b/full-service/src/bin/main.rs
index d599708e0..264d77c73 100644
--- a/full-service/src/bin/main.rs
+++ b/full-service/src/bin/main.rs
@@ -3,8 +3,7 @@
//! MobileCoin wallet service
#![feature(proc_macro_hygiene, decl_macro)]
-use diesel::{connection::SimpleConnection, prelude::*, SqliteConnection};
-use diesel_migrations::embed_migrations;
+use diesel::{prelude::*, SqliteConnection};
use dotenv::dotenv;
use mc_attest_verifier::{MrSignerVerifier, Verifier, DEBUG_ENCLAVE};
use mc_common::logger::{create_app_logger, log, o, Logger};
@@ -31,8 +30,6 @@ use structopt::StructOpt;
#[macro_use]
extern crate diesel_migrations;
-embed_migrations!("migrations/");
-
// Exit codes.
const EXIT_NO_DATABASE_CONNECTION: i32 = 2;
const EXIT_WRONG_PASSWORD: i32 = 3;
@@ -76,24 +73,7 @@ fn main() {
eprintln!("Incorrect password for database {:?}.", config.wallet_db);
exit(EXIT_WRONG_PASSWORD);
};
-
- // Our migrations sometimes violate foreign keys, so disable foreign key checks
- // while we apply them.
- // Unfortunately this has to happen outside the scope of a transaction. Quoting
- // https://www.sqlite.org/pragma.html,
- // "This pragma is a no-op within a transaction; foreign key constraint
- // enforcement may only be enabled or disabled when there is no pending
- // BEGIN or SAVEPOINT."
- // Check foreign key constraints after the migration. If they fail,
- // we will abort until the user resolves it.
- conn.batch_execute("PRAGMA foreign_keys = OFF;")
- .expect("failed disabling foreign keys");
- embedded_migrations::run_with_output(&conn, &mut std::io::stdout())
- .expect("failed running migrations");
- WalletDb::validate_foreign_keys(&conn);
- conn.batch_execute("PRAGMA foreign_keys = ON;")
- .expect("failed enabling foreign keys");
-
+ WalletDb::run_migrations(&conn);
log::info!(logger, "Connected to database.");
let wallet_db = WalletDb::new_from_url(
diff --git a/full-service/src/db/account.rs b/full-service/src/db/account.rs
index 8775e458b..1b435cc91 100644
--- a/full-service/src/db/account.rs
+++ b/full-service/src/db/account.rs
@@ -8,7 +8,7 @@ use crate::{
models::{Account, AssignedSubaddress, NewAccount, TransactionLog, Txo},
transaction_log::TransactionLogModel,
txo::TxoModel,
- WalletDbError,
+ Conn, WalletDbError,
},
util::constants::{
DEFAULT_CHANGE_SUBADDRESS_INDEX, DEFAULT_FIRST_BLOCK_INDEX, DEFAULT_NEXT_SUBADDRESS_INDEX,
@@ -18,11 +18,7 @@ use crate::{
};
use bip39::Mnemonic;
-use diesel::{
- prelude::*,
- r2d2::{ConnectionManager, PooledConnection},
- RunQueryDsl,
-};
+use diesel::prelude::*;
use mc_account_keys::{AccountKey, RootEntropy, RootIdentity};
use mc_account_keys_slip10::Slip10Key;
use mc_crypto_digestible::{Digestible, MerlinTranscript};
@@ -60,7 +56,7 @@ pub trait AccountModel {
fog_report_url: String,
fog_report_id: String,
fog_authority_spki: String,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(AccountID, String), WalletDbError>;
/// Create an account.
@@ -77,7 +73,7 @@ pub trait AccountModel {
fog_report_url: String,
fog_report_id: String,
fog_authority_spki: String,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(AccountID, String), WalletDbError>;
/// Create an account.
@@ -94,7 +90,7 @@ pub trait AccountModel {
next_subaddress_index: Option,
name: &str,
fog_enabled: bool,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(AccountID, String), WalletDbError>;
/// Import account.
@@ -108,7 +104,7 @@ pub trait AccountModel {
fog_report_url: String,
fog_report_id: String,
fog_authority_spki: String,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
/// Import account.
@@ -122,53 +118,38 @@ pub trait AccountModel {
fog_report_url: String,
fog_report_id: String,
fog_authority_spki: String,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
/// List all accounts.
///
/// Returns:
/// * Vector of all Accounts in the DB
- fn list_all(
- conn: &PooledConnection>,
- ) -> Result, WalletDbError>;
+ fn list_all(conn: &Conn) -> Result, WalletDbError>;
/// Get a specific account.
///
/// Returns:
/// * Account
- fn get(
- account_id: &AccountID,
- conn: &PooledConnection>,
- ) -> Result;
+ fn get(account_id: &AccountID, conn: &Conn) -> Result;
/// Get the accounts associated with the given Txo.
- fn get_by_txo_id(
- txo_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError>;
+ fn get_by_txo_id(txo_id_hex: &str, conn: &Conn) -> Result, WalletDbError>;
/// Update an account.
/// The only updatable field is the name. Any other desired update requires
/// adding a new account, and deleting the existing if desired.
- fn update_name(
- &self,
- new_name: String,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError>;
+ fn update_name(&self, new_name: String, conn: &Conn) -> Result<(), WalletDbError>;
/// Update the next block index this account will need to sync.
fn update_next_block_index(
&self,
next_block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
/// Delete an account.
- fn delete(
- self,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError>;
+ fn delete(self, conn: &Conn) -> Result<(), WalletDbError>;
}
impl AccountModel for Account {
@@ -181,7 +162,7 @@ impl AccountModel for Account {
fog_report_url: String,
fog_report_id: String,
fog_authority_spki: String,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(AccountID, String), WalletDbError> {
let fog_enabled = !fog_report_url.is_empty();
@@ -213,7 +194,7 @@ impl AccountModel for Account {
fog_report_url: String,
fog_report_id: String,
fog_authority_spki: String,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(AccountID, String), WalletDbError> {
let fog_enabled = !fog_report_url.is_empty();
@@ -247,7 +228,7 @@ impl AccountModel for Account {
next_subaddress_index: Option,
name: &str,
fog_enabled: bool,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(AccountID, String), WalletDbError> {
use crate::db::schema::accounts;
@@ -323,7 +304,7 @@ impl AccountModel for Account {
fog_report_url: String,
fog_report_id: String,
fog_authority_spki: String,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result {
let (account_id, _public_address_b58) = Account::create_from_mnemonic(
mnemonic,
@@ -348,7 +329,7 @@ impl AccountModel for Account {
fog_report_url: String,
fog_report_id: String,
fog_authority_spki: String,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result {
let (account_id, _public_address_b58) = Account::create_from_root_entropy(
root_entropy,
@@ -364,9 +345,7 @@ impl AccountModel for Account {
Account::get(&account_id, conn)
}
- fn list_all(
- conn: &PooledConnection>,
- ) -> Result, WalletDbError> {
+ fn list_all(conn: &Conn) -> Result, WalletDbError> {
use crate::db::schema::accounts;
Ok(accounts::table
@@ -374,10 +353,7 @@ impl AccountModel for Account {
.load::(conn)?)
}
- fn get(
- account_id: &AccountID,
- conn: &PooledConnection>,
- ) -> Result {
+ fn get(account_id: &AccountID, conn: &Conn) -> Result {
use crate::db::schema::accounts::dsl::{account_id_hex as dsl_account_id_hex, accounts};
match accounts
@@ -393,10 +369,7 @@ impl AccountModel for Account {
}
}
- fn get_by_txo_id(
- txo_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError> {
+ fn get_by_txo_id(txo_id_hex: &str, conn: &Conn) -> Result, WalletDbError> {
let txo = Txo::get(txo_id_hex, conn)?;
let mut accounts: Vec = Vec::::new();
@@ -414,11 +387,7 @@ impl AccountModel for Account {
Ok(accounts)
}
- fn update_name(
- &self,
- new_name: String,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError> {
+ fn update_name(&self, new_name: String, conn: &Conn) -> Result<(), WalletDbError> {
use crate::db::schema::accounts::dsl::{account_id_hex, accounts};
diesel::update(accounts.filter(account_id_hex.eq(&self.account_id_hex)))
@@ -430,7 +399,7 @@ impl AccountModel for Account {
fn update_next_block_index(
&self,
next_block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::accounts::dsl::{account_id_hex, accounts};
diesel::update(accounts.filter(account_id_hex.eq(&self.account_id_hex)))
@@ -439,10 +408,7 @@ impl AccountModel for Account {
Ok(())
}
- fn delete(
- self,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError> {
+ fn delete(self, conn: &Conn) -> Result<(), WalletDbError> {
use crate::db::schema::accounts::dsl::{account_id_hex, accounts};
// Delete transaction logs associated with this account
diff --git a/full-service/src/db/assigned_subaddress.rs b/full-service/src/db/assigned_subaddress.rs
index c3cebbcf7..312ec26b0 100644
--- a/full-service/src/db/assigned_subaddress.rs
+++ b/full-service/src/db/assigned_subaddress.rs
@@ -20,11 +20,8 @@ use mc_account_keys::AccountKey;
use mc_crypto_keys::{CompressedRistrettoPublic, RistrettoPublic};
use mc_ledger_db::{Ledger, LedgerDB};
-use crate::db::WalletDbError;
-use diesel::{
- prelude::*,
- r2d2::{ConnectionManager, PooledConnection},
-};
+use crate::db::{Conn, WalletDbError};
+use diesel::prelude::*;
pub trait AssignedSubaddressModel {
/// Assign a subaddress to a contact.
@@ -45,7 +42,7 @@ pub trait AssignedSubaddressModel {
address_book_entry: Option,
subaddress_index: u64,
comment: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
/// Create the next subaddress for a given account.
@@ -56,21 +53,18 @@ pub trait AssignedSubaddressModel {
account_id_hex: &str,
comment: &str,
ledger_db: &LedgerDB,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(String, i64), WalletDbError>;
/// Get the AssignedSubaddress for a given assigned_subaddress_b58
- fn get(
- public_address_b58: &str,
- conn: &PooledConnection>,
- ) -> Result;
+ fn get(public_address_b58: &str, conn: &Conn) -> Result;
/// Get the Assigned Subaddress for a given index in an account, if it
/// exists
fn get_for_account_by_index(
account_id_hex: &str,
index: i64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
/// Find an AssignedSubaddress by the subaddress spend public key
@@ -79,22 +73,19 @@ pub trait AssignedSubaddressModel {
/// * (subaddress_index, assigned_subaddress_b58)
fn find_by_subaddress_spend_public_key(
subaddress_spend_public_key: &RistrettoPublic,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(i64, String), WalletDbError>;
/// List all AssignedSubaddresses for a given account.
fn list_all(
account_id_hex: &str,
- offset: Option,
- limit: Option,
- conn: &PooledConnection>,
+ offset: Option,
+ limit: Option,
+ conn: &Conn,
) -> Result, WalletDbError>;
/// Delete all AssignedSubaddresses for a given account.
- fn delete_all(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError>;
+ fn delete_all(account_id_hex: &str, conn: &Conn) -> Result<(), WalletDbError>;
}
impl AssignedSubaddressModel for AssignedSubaddress {
@@ -103,7 +94,7 @@ impl AssignedSubaddressModel for AssignedSubaddress {
address_book_entry: Option,
subaddress_index: u64,
comment: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result {
use crate::db::schema::assigned_subaddresses;
@@ -132,7 +123,7 @@ impl AssignedSubaddressModel for AssignedSubaddress {
account_id_hex: &str,
comment: &str,
ledger_db: &LedgerDB,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(String, i64), WalletDbError> {
use crate::db::schema::{
accounts::dsl::{account_id_hex as dsl_account_id_hex, accounts},
@@ -236,10 +227,7 @@ impl AssignedSubaddressModel for AssignedSubaddress {
Ok((subaddress_b58, subaddress_index))
}
- fn get(
- public_address_b58: &str,
- conn: &PooledConnection>,
- ) -> Result {
+ fn get(public_address_b58: &str, conn: &Conn) -> Result {
use crate::db::schema::assigned_subaddresses::dsl::{
assigned_subaddress_b58, assigned_subaddresses,
};
@@ -265,7 +253,7 @@ impl AssignedSubaddressModel for AssignedSubaddress {
fn get_for_account_by_index(
account_id_hex: &str,
index: i64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result {
let account = Account::get(&AccountID(account_id_hex.to_string()), conn)?;
@@ -278,7 +266,7 @@ impl AssignedSubaddressModel for AssignedSubaddress {
fn find_by_subaddress_spend_public_key(
subaddress_spend_public_key: &RistrettoPublic,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(i64, String), WalletDbError> {
use crate::db::schema::assigned_subaddresses::{
account_id_hex, dsl::assigned_subaddresses, subaddress_index, subaddress_spend_key,
@@ -306,9 +294,9 @@ impl AssignedSubaddressModel for AssignedSubaddress {
fn list_all(
account_id_hex: &str,
- offset: Option,
- limit: Option,
- conn: &PooledConnection>,
+ offset: Option,
+ limit: Option,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::assigned_subaddresses::{
account_id_hex as schema_account_id_hex, all_columns, dsl::assigned_subaddresses,
@@ -319,7 +307,10 @@ impl AssignedSubaddressModel for AssignedSubaddress {
.filter(schema_account_id_hex.eq(account_id_hex));
let addresses: Vec = if let (Some(o), Some(l)) = (offset, limit) {
- addresses_query.offset(o).limit(l).load(conn)?
+ addresses_query
+ .offset(o as i64)
+ .limit(l as i64)
+ .load(conn)?
} else {
addresses_query.load(conn)?
};
@@ -327,10 +318,7 @@ impl AssignedSubaddressModel for AssignedSubaddress {
Ok(addresses)
}
- fn delete_all(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError> {
+ fn delete_all(account_id_hex: &str, conn: &Conn) -> Result<(), WalletDbError> {
use crate::db::schema::assigned_subaddresses::dsl::{
account_id_hex as schema_account_id_hex, assigned_subaddresses,
};
diff --git a/full-service/src/db/gift_code.rs b/full-service/src/db/gift_code.rs
index da8d799e1..09ed8a4e2 100644
--- a/full-service/src/db/gift_code.rs
+++ b/full-service/src/db/gift_code.rs
@@ -5,15 +5,11 @@
use crate::{
db::{
models::{GiftCode, NewGiftCode},
- WalletDbError,
+ Conn, WalletDbError,
},
service::gift_code::EncodedGiftCode,
};
-use diesel::{
- prelude::*,
- r2d2::{ConnectionManager, PooledConnection},
- RunQueryDsl,
-};
+use diesel::prelude::*;
use displaydoc::Display;
#[derive(Display, Debug)]
@@ -41,32 +37,24 @@ pub trait GiftCodeModel {
fn create(
gift_code_b58: &EncodedGiftCode,
value: i64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
/// Get the details of a specific Gift Code.
- fn get(
- gift_code_b58: &EncodedGiftCode,
- conn: &PooledConnection>,
- ) -> Result;
+ fn get(gift_code_b58: &EncodedGiftCode, conn: &Conn) -> Result;
/// Get all Gift Codes in this wallet.
- fn list_all(
- conn: &PooledConnection>,
- ) -> Result, WalletDbError>;
+ fn list_all(conn: &Conn) -> Result, WalletDbError>;
/// Delete a gift code.
- fn delete(
- self,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError>;
+ fn delete(self, conn: &Conn) -> Result<(), WalletDbError>;
}
impl GiftCodeModel for GiftCode {
fn create(
gift_code_b58: &EncodedGiftCode,
value: i64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result {
use crate::db::schema::gift_codes;
@@ -83,10 +71,7 @@ impl GiftCodeModel for GiftCode {
Ok(gift_code)
}
- fn get(
- gift_code_b58: &EncodedGiftCode,
- conn: &PooledConnection>,
- ) -> Result {
+ fn get(gift_code_b58: &EncodedGiftCode, conn: &Conn) -> Result {
use crate::db::schema::gift_codes::dsl::{gift_code_b58 as dsl_gift_code_b58, gift_codes};
match gift_codes
@@ -102,9 +87,7 @@ impl GiftCodeModel for GiftCode {
}
}
- fn list_all(
- conn: &PooledConnection>,
- ) -> Result, WalletDbError> {
+ fn list_all(conn: &Conn) -> Result, WalletDbError> {
use crate::db::schema::gift_codes;
Ok(gift_codes::table
@@ -112,10 +95,7 @@ impl GiftCodeModel for GiftCode {
.load::(conn)?)
}
- fn delete(
- self,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError> {
+ fn delete(self, conn: &Conn) -> Result<(), WalletDbError> {
use crate::db::schema::gift_codes::dsl::{gift_code_b58, gift_codes};
diesel::delete(gift_codes.filter(gift_code_b58.eq(&self.gift_code_b58))).execute(conn)?;
diff --git a/full-service/src/db/migration_testing/migration_testing.rs b/full-service/src/db/migration_testing/migration_testing.rs
new file mode 100644
index 000000000..a61d7641c
--- /dev/null
+++ b/full-service/src/db/migration_testing/migration_testing.rs
@@ -0,0 +1,62 @@
+#[cfg(test)]
+mod migration_testing {
+ use crate::{
+ db::{
+ account::AccountID,
+ migration_testing::{
+ seed_accounts::{seed_accounts, test_accounts},
+ seed_gift_codes::{seed_gift_codes, test_gift_codes},
+ seed_txos::{seed_txos, test_txos},
+ },
+ },
+ test_utils::{get_test_ledger, setup_wallet_service, WalletDbTestContext},
+ };
+ use diesel_migrations::{revert_latest_migration, run_pending_migrations};
+ use mc_account_keys::PublicAddress;
+ use mc_common::logger::{test_with_logger, Logger};
+ use rand::{rngs::StdRng, SeedableRng};
+
+ #[test_with_logger]
+ fn test_latest_migration(logger: Logger) {
+ // set up wallet and service. this will run all migrations
+ let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]);
+ let known_recipients: Vec = Vec::new();
+ let mut ledger_db = get_test_ledger(5, &known_recipients, 12, &mut rng);
+ let _db_test_context = WalletDbTestContext::default();
+ let service = setup_wallet_service(ledger_db.clone(), logger.clone());
+ let wallet_db = &service.wallet_db;
+ let conn = wallet_db.get_conn().unwrap();
+
+ // revert the last migration
+ revert_latest_migration(&conn).unwrap();
+
+ // seed the entities
+ let (txo_account, gift_code_account, gift_code_receiver_account) = seed_accounts(&service);
+ seed_txos(&conn, &mut ledger_db, &wallet_db, &logger, &txo_account);
+ let gift_codes = seed_gift_codes(
+ &conn,
+ &mut ledger_db,
+ &wallet_db,
+ &service,
+ &logger,
+ &gift_code_account,
+ &gift_code_receiver_account,
+ );
+
+ let txo_account_id =
+ AccountID::from(&mc_util_serial::decode(&txo_account.account_key).unwrap());
+
+ // validate expected state of entities in DB
+ test_accounts(&service);
+ test_txos(txo_account_id.clone(), &conn);
+ test_gift_codes(&gift_codes, &service);
+
+ // run the last migration
+ run_pending_migrations(&conn).unwrap();
+
+ // validate expected state of entities in DB again, post-migration
+ test_accounts(&service);
+ test_txos(txo_account_id, &conn);
+ test_gift_codes(&gift_codes, &service);
+ }
+}
diff --git a/full-service/src/db/migration_testing/mod.rs b/full-service/src/db/migration_testing/mod.rs
new file mode 100644
index 000000000..228ddb510
--- /dev/null
+++ b/full-service/src/db/migration_testing/mod.rs
@@ -0,0 +1,5 @@
+#[cfg(any(test))]
+pub mod migration_testing;
+pub mod seed_accounts;
+pub mod seed_gift_codes;
+pub mod seed_txos;
diff --git a/full-service/src/db/migration_testing/seed_accounts.rs b/full-service/src/db/migration_testing/seed_accounts.rs
new file mode 100644
index 000000000..f9c51a1e2
--- /dev/null
+++ b/full-service/src/db/migration_testing/seed_accounts.rs
@@ -0,0 +1,48 @@
+use crate::{
+ db::models::Account,
+ service::{account::AccountService, WalletService},
+};
+use mc_connection_test_utils::MockBlockchainConnection;
+use mc_fog_report_validation::MockFogPubkeyResolver;
+use mc_ledger_db::LedgerDB;
+
+pub fn seed_accounts(
+ service: &WalletService, MockFogPubkeyResolver>,
+) -> (Account, Account, Account) {
+ let txo_account = service
+ .create_account(
+ Some("txo_account".to_string()),
+ "".to_string(),
+ "".to_string(),
+ "".to_string(),
+ )
+ .unwrap();
+
+ let gift_code_account = service
+ .create_account(
+ Some("gift_code_account".to_string()),
+ "".to_string(),
+ "".to_string(),
+ "".to_string(),
+ )
+ .unwrap();
+
+ let gift_code_receiver_account = service
+ .create_account(
+ Some("gift_code_receiver_account".to_string()),
+ "".to_string(),
+ "".to_string(),
+ "".to_string(),
+ )
+ .unwrap();
+
+ (txo_account, gift_code_account, gift_code_receiver_account)
+}
+
+pub fn test_accounts(
+ service: &WalletService, MockFogPubkeyResolver>,
+) {
+ let accounts = service.list_accounts().unwrap();
+
+ assert_eq!(accounts.len(), 3);
+}
diff --git a/full-service/src/db/migration_testing/seed_gift_codes.rs b/full-service/src/db/migration_testing/seed_gift_codes.rs
new file mode 100644
index 000000000..d78c3a6f2
--- /dev/null
+++ b/full-service/src/db/migration_testing/seed_gift_codes.rs
@@ -0,0 +1,165 @@
+use crate::{
+ db::{account::AccountID, models::Account, WalletDb},
+ service::{
+ gift_code::{EncodedGiftCode, GiftCodeService, GiftCodeStatus},
+ WalletService,
+ },
+ test_utils::{
+ add_block_to_ledger_db, add_block_with_tx, add_block_with_tx_proposal,
+ manually_sync_account, MOB,
+ },
+};
+use diesel::{
+ r2d2::{ConnectionManager, PooledConnection},
+ SqliteConnection,
+};
+use mc_account_keys::AccountKey;
+use mc_common::logger::Logger;
+use mc_connection_test_utils::MockBlockchainConnection;
+use mc_crypto_rand::RngCore;
+use mc_fog_report_validation::MockFogPubkeyResolver;
+use mc_ledger_db::LedgerDB;
+use mc_transaction_core::ring_signature::KeyImage;
+use rand::{rngs::StdRng, SeedableRng};
+
+pub struct SeedGiftCodesResult {
+ unsubmitted: EncodedGiftCode,
+ submitted: EncodedGiftCode,
+ claimed: EncodedGiftCode,
+}
+pub fn seed_gift_codes(
+ _conn: &PooledConnection>,
+ ledger_db: &mut LedgerDB,
+ wallet_db: &WalletDb,
+ service: &WalletService, MockFogPubkeyResolver>,
+ logger: &Logger,
+ account: &Account,
+ receiver_account: &Account,
+) -> SeedGiftCodesResult {
+ let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]);
+
+ // Add a block with a transaction for the gifter account
+ let gifter_account_key: AccountKey = mc_util_serial::decode(&account.account_key).unwrap();
+ let gifter_public_address =
+ &gifter_account_key.subaddress(account.main_subaddress_index as u64);
+ let gifter_account_id = AccountID(account.account_id_hex.to_string());
+
+ add_block_to_ledger_db(
+ ledger_db,
+ &vec![gifter_public_address.clone()],
+ 100 * MOB as u64,
+ &vec![KeyImage::from(rng.next_u64())],
+ &mut rng,
+ );
+ manually_sync_account(ledger_db, wallet_db, &gifter_account_id, logger);
+
+ // Create 3 gift codes
+ let (tx_proposal, gift_code_b58) = service
+ .build_gift_code(
+ &gifter_account_id,
+ 2 * MOB as u64,
+ Some("Gift code".to_string()),
+ None,
+ None,
+ None,
+ None,
+ )
+ .unwrap();
+
+ // going to submit but not claim this code
+ let gift_code_1_submitted = service
+ .submit_gift_code(
+ &gifter_account_id,
+ &gift_code_b58.clone(),
+ &tx_proposal.clone(),
+ )
+ .unwrap();
+
+ add_block_with_tx_proposal(ledger_db, tx_proposal);
+ manually_sync_account(&ledger_db, &service.wallet_db, &gifter_account_id, &logger);
+
+ let (tx_proposal, gift_code_b58) = service
+ .build_gift_code(
+ &gifter_account_id,
+ 2 * MOB as u64,
+ Some("Gift code".to_string()),
+ None,
+ None,
+ None,
+ None,
+ )
+ .unwrap();
+
+ // going to submit and claim this one
+ let gift_code_2_claimed = service
+ .submit_gift_code(
+ &gifter_account_id,
+ &gift_code_b58.clone(),
+ &tx_proposal.clone(),
+ )
+ .unwrap();
+
+ add_block_with_tx_proposal(ledger_db, tx_proposal);
+ manually_sync_account(&ledger_db, &service.wallet_db, &gifter_account_id, &logger);
+
+ // leave this code as pending
+ let (_tx_proposal, gift_code_b58_pending) = service
+ .build_gift_code(
+ &gifter_account_id,
+ 2 * MOB as u64,
+ Some("Gift code".to_string()),
+ None,
+ None,
+ None,
+ None,
+ )
+ .unwrap();
+
+ // Claim the gift code to another account
+ manually_sync_account(
+ &ledger_db,
+ &service.wallet_db,
+ &AccountID(receiver_account.account_id_hex.clone()),
+ &logger,
+ );
+
+ let tx = service
+ .claim_gift_code(
+ &EncodedGiftCode(gift_code_2_claimed.gift_code_b58.clone()),
+ &AccountID(receiver_account.account_id_hex.clone()),
+ None,
+ )
+ .unwrap();
+ add_block_with_tx(ledger_db, tx);
+ manually_sync_account(
+ &ledger_db,
+ &service.wallet_db,
+ &AccountID(receiver_account.account_id_hex.clone()),
+ &logger,
+ );
+
+ SeedGiftCodesResult {
+ unsubmitted: gift_code_b58_pending,
+ submitted: EncodedGiftCode(gift_code_1_submitted.gift_code_b58),
+ claimed: EncodedGiftCode(gift_code_2_claimed.gift_code_b58),
+ }
+}
+
+pub fn test_gift_codes(
+ gift_codes: &SeedGiftCodesResult,
+ service: &WalletService, MockFogPubkeyResolver>,
+) {
+ let (status, _gift_code_value_opt, _memo) = service
+ .check_gift_code_status(&gift_codes.unsubmitted)
+ .unwrap();
+ assert_eq!(status, GiftCodeStatus::GiftCodeSubmittedPending);
+
+ let (status, _gift_code_value_opt, _memo) = service
+ .check_gift_code_status(&gift_codes.submitted)
+ .unwrap();
+ assert_eq!(status, GiftCodeStatus::GiftCodeAvailable);
+
+ let (status, _gift_code_value_opt, _memo) =
+ service.check_gift_code_status(&gift_codes.claimed).unwrap();
+ assert_eq!(status, GiftCodeStatus::GiftCodeClaimed);
+}
diff --git a/full-service/src/db/migration_testing/seed_txos.rs b/full-service/src/db/migration_testing/seed_txos.rs
new file mode 100644
index 000000000..465de08cc
--- /dev/null
+++ b/full-service/src/db/migration_testing/seed_txos.rs
@@ -0,0 +1,120 @@
+use crate::{
+ db::{
+ account::AccountID,
+ models::{Account, TransactionLog, Txo},
+ transaction_log::TransactionLogModel,
+ txo::TxoModel,
+ WalletDb,
+ },
+ test_utils::{
+ add_block_with_db_txos, add_block_with_tx_outs, create_test_minted_and_change_txos,
+ create_test_txo_for_recipient, manually_sync_account, MOB,
+ },
+};
+use diesel::{
+ r2d2::{ConnectionManager, PooledConnection},
+ SqliteConnection,
+};
+use mc_common::logger::Logger;
+use mc_crypto_rand::RngCore;
+use mc_ledger_db::LedgerDB;
+use mc_transaction_core::ring_signature::KeyImage;
+use rand::{rngs::StdRng, SeedableRng};
+
+// create 1 spent, 1 change (minted), and 1 orphaned txo
+pub fn seed_txos(
+ _conn: &PooledConnection>,
+ ledger_db: &mut LedgerDB,
+ wallet_db: &WalletDb,
+ logger: &Logger,
+ account: &Account,
+) {
+ let mut rng: StdRng = SeedableRng::from_seed([20u8; 32]);
+ // Create received txo for account
+ let account_key = mc_util_serial::decode(&account.account_key).unwrap();
+ let (for_account_txo, for_account_key_image) =
+ create_test_txo_for_recipient(&account_key, 0, 1000 * MOB, &mut rng);
+
+ // add this txo to the ledger
+ add_block_with_tx_outs(
+ ledger_db,
+ &[for_account_txo.clone()],
+ &[KeyImage::from(rng.next_u64())],
+ );
+
+ manually_sync_account(
+ &ledger_db,
+ &wallet_db,
+ &AccountID::from(&account_key),
+ &logger,
+ );
+
+ // "spend" the TXO by sending it to same account, but at a subaddress we
+ // have not yet assigned. At the DB layer, we accomplish this by
+ // constructing the output txos, then logging sent and received for this
+ // account.
+ let ((output_txo_id, _output_value), (change_txo_id, _change_value)) =
+ create_test_minted_and_change_txos(
+ account_key.clone(),
+ account_key.subaddress(4),
+ 33 * MOB,
+ wallet_db.clone(),
+ ledger_db.clone(),
+ logger.clone(),
+ );
+
+ add_block_with_db_txos(
+ ledger_db,
+ &wallet_db,
+ &[output_txo_id, change_txo_id],
+ &[KeyImage::from(for_account_key_image)],
+ );
+
+ manually_sync_account(
+ &ledger_db,
+ &wallet_db,
+ &AccountID::from(&account_key),
+ &logger,
+ );
+}
+
+pub fn test_txos(
+ account_id: AccountID,
+ conn: &PooledConnection>,
+) {
+ // validate expected txo states
+ let txos = Txo::list_for_account(&account_id.to_string(), None, None, &conn).unwrap();
+ assert_eq!(txos.len(), 3);
+
+ // Check that we have 2 spendable (1 is orphaned)
+ let spendable: Vec<&Txo> = txos.iter().filter(|f| f.key_image.is_some()).collect();
+ assert_eq!(spendable.len(), 2);
+
+ // Check that we have one spent - went from [Received, Unspent] -> [Received,
+ // Spent]
+ let spent = Txo::list_spent(&account_id.to_string(), None, &conn).unwrap();
+ assert_eq!(spent.len(), 1);
+ assert_eq!(spent[0].spent_block_index.clone().unwrap(), 13);
+ assert_eq!(spent[0].minted_account_id_hex, None);
+
+ // Check that we have one orphaned - went from [Minted, Secreted] -> [Minted,
+ // Orphaned]
+ let orphaned = Txo::list_orphaned(&account_id.to_string(), &conn).unwrap();
+ assert_eq!(orphaned.len(), 1);
+ assert!(orphaned[0].key_image.is_none());
+ assert_eq!(orphaned[0].received_block_index.clone().unwrap(), 13);
+ assert!(orphaned[0].minted_account_id_hex.is_some());
+ assert!(orphaned[0].received_account_id_hex.is_some());
+
+ // Check that we have one unspent (change) - went from [Minted, Secreted] ->
+ // [Minted, Unspent]
+ let unspent = Txo::list_unspent(&account_id.to_string(), None, &conn).unwrap();
+ assert_eq!(unspent.len(), 1);
+ assert_eq!(unspent[0].received_block_index.clone().unwrap(), 13);
+
+ // Check that a transaction log entry was created for each received TxOut (note:
+ // we are not creating submit logs in this test)
+ let transaction_logs =
+ TransactionLog::list_all(&account_id.to_string(), None, None, &conn).unwrap();
+ assert_eq!(transaction_logs.len(), 3);
+}
diff --git a/full-service/src/db/mod.rs b/full-service/src/db/mod.rs
index 3db28d5a7..d8b61419e 100644
--- a/full-service/src/db/mod.rs
+++ b/full-service/src/db/mod.rs
@@ -16,5 +16,8 @@ pub mod view_only_txo;
mod wallet_db;
mod wallet_db_error;
-pub use wallet_db::WalletDb;
+pub use wallet_db::{transaction, Conn, WalletDb};
pub use wallet_db_error::WalletDbError;
+
+#[cfg(any(test))]
+pub mod migration_testing;
diff --git a/full-service/src/db/transaction_log.rs b/full-service/src/db/transaction_log.rs
index 3a8c6a2e2..eacdeeeb9 100644
--- a/full-service/src/db/transaction_log.rs
+++ b/full-service/src/db/transaction_log.rs
@@ -3,11 +3,7 @@
//! DB impl for the Transaction model.
use chrono::Utc;
-use diesel::{
- prelude::*,
- r2d2::{ConnectionManager, PooledConnection},
- RunQueryDsl,
-};
+use diesel::prelude::*;
use mc_common::HashMap;
use mc_crypto_digestible::{Digestible, MerlinTranscript};
use mc_mobilecoind::payments::TxProposal;
@@ -23,7 +19,7 @@ use crate::db::{
TX_STATUS_SUCCEEDED,
},
txo::{TxoID, TxoModel},
- WalletDbError,
+ Conn, WalletDbError,
};
#[derive(Debug)]
@@ -59,37 +55,26 @@ pub struct AssociatedTxos {
pub trait TransactionLogModel {
/// Get a transaction log from the TransactionId.
- fn get(
- transaction_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result;
+ fn get(transaction_id_hex: &str, conn: &Conn) -> Result;
/// Get all transaction logs for the given block index.
fn get_all_for_block_index(
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
/// Get all transaction logs ordered by finalized_block_index.
- fn get_all_ordered_by_block_index(
- conn: &PooledConnection>,
- ) -> Result, WalletDbError>;
+ fn get_all_ordered_by_block_index(conn: &Conn) -> Result, WalletDbError>;
/// Get the Txos associated with a given TransactionId, grouped according to
/// their type.
///
/// Returns:
/// * AssoiatedTxos(inputs, outputs, change)
- fn get_associated_txos(
- &self,
- conn: &PooledConnection>,
- ) -> Result;
+ fn get_associated_txos(&self, conn: &Conn) -> Result;
/// Select the TransactionLogs associated with a given TxoId.
- fn select_for_txo(
- txo_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError>;
+ fn select_for_txo(txo_id_hex: &str, conn: &Conn) -> Result, WalletDbError>;
/// List all TransactionLogs and their associated Txos for a given account.
///
@@ -97,9 +82,9 @@ pub trait TransactionLogModel {
/// * Vec(TransactionLog, AssociatedTxos(inputs, outputs, change))
fn list_all(
account_id_hex: &str,
- offset: Option,
- limit: Option,
- conn: &PooledConnection>,
+ offset: Option,
+ limit: Option,
+ conn: &Conn,
) -> Result, WalletDbError>;
/// Log a received transaction.
@@ -109,7 +94,7 @@ pub trait TransactionLogModel {
txo_id_hex: &str,
amount: u64,
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
/// Log a submitted transaction.
@@ -127,32 +112,26 @@ pub trait TransactionLogModel {
block_index: u64,
comment: String,
account_id_hex: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
/// Remove all logs for an account
- fn delete_all_for_account(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError>;
+ fn delete_all_for_account(account_id_hex: &str, conn: &Conn) -> Result<(), WalletDbError>;
fn update_tx_logs_associated_with_txo_to_succeeded(
txo_id_hex: &str,
finalized_block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
fn update_tx_logs_associated_with_txos_to_failed(
txos: &[Txo],
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
}
impl TransactionLogModel for TransactionLog {
- fn get(
- transaction_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result {
+ fn get(transaction_id_hex: &str, conn: &Conn) -> Result {
use crate::db::schema::transaction_logs::dsl::{
transaction_id_hex as dsl_transaction_id_hex, transaction_logs,
};
@@ -172,7 +151,7 @@ impl TransactionLogModel for TransactionLog {
fn get_all_for_block_index(
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::transaction_logs::{
all_columns, dsl::transaction_logs, finalized_block_index,
@@ -186,9 +165,7 @@ impl TransactionLogModel for TransactionLog {
Ok(matches)
}
- fn get_all_ordered_by_block_index(
- conn: &PooledConnection>,
- ) -> Result, WalletDbError> {
+ fn get_all_ordered_by_block_index(conn: &Conn) -> Result, WalletDbError> {
use crate::db::schema::transaction_logs::{
all_columns, dsl::transaction_logs, finalized_block_index,
};
@@ -201,10 +178,7 @@ impl TransactionLogModel for TransactionLog {
Ok(matches)
}
- fn get_associated_txos(
- &self,
- conn: &PooledConnection>,
- ) -> Result {
+ fn get_associated_txos(&self, conn: &Conn) -> Result {
use crate::db::schema::{transaction_txo_types, txos};
// FIXME: WS-29 - use group_by rather than the processing below:
@@ -239,10 +213,7 @@ impl TransactionLogModel for TransactionLog {
})
}
- fn select_for_txo(
- txo_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError> {
+ fn select_for_txo(txo_id_hex: &str, conn: &Conn) -> Result, WalletDbError> {
use crate::db::schema::{transaction_logs, transaction_txo_types};
Ok(transaction_logs::table
@@ -256,9 +227,9 @@ impl TransactionLogModel for TransactionLog {
fn list_all(
account_id_hex: &str,
- offset: Option,
- limit: Option,
- conn: &PooledConnection>,
+ offset: Option,
+ limit: Option,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::{transaction_logs, transaction_txo_types, txos};
@@ -281,7 +252,10 @@ impl TransactionLogModel for TransactionLog {
let transactions: Vec<(TransactionLog, TransactionTxoType, Txo)> =
if let (Some(o), Some(l)) = (offset, limit) {
- transactions_query.offset(o).limit(l).load(conn)?
+ transactions_query
+ .offset(o as i64)
+ .limit(l as i64)
+ .load(conn)?
} else {
transactions_query.load(conn)?
};
@@ -350,7 +324,7 @@ impl TransactionLogModel for TransactionLog {
txo_id_hex: &str,
amount: u64,
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::transaction_txo_types;
@@ -392,7 +366,7 @@ impl TransactionLogModel for TransactionLog {
block_index: u64,
comment: String,
account_id_hex: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result {
// Verify that the account exists.
Account::get(&AccountID(account_id_hex.to_string()), conn)?;
@@ -472,10 +446,7 @@ impl TransactionLogModel for TransactionLog {
TransactionLog::get(&transaction_id.to_string(), conn)
}
- fn delete_all_for_account(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError> {
+ fn delete_all_for_account(account_id_hex: &str, conn: &Conn) -> Result<(), WalletDbError> {
use crate::db::schema::{
transaction_logs as cols, transaction_logs::dsl::transaction_logs,
transaction_txo_types as types_cols, transaction_txo_types::dsl::transaction_txo_types,
@@ -502,7 +473,7 @@ impl TransactionLogModel for TransactionLog {
fn update_tx_logs_associated_with_txo_to_succeeded(
txo_id_hex: &str,
finalized_block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::{transaction_logs, transaction_txo_types};
@@ -533,7 +504,7 @@ impl TransactionLogModel for TransactionLog {
fn update_tx_logs_associated_with_txos_to_failed(
txos: &[Txo],
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::{transaction_logs, transaction_txo_types};
@@ -691,12 +662,13 @@ mod tests {
);
// Build a transaction
+ let conn = wallet_db.get_conn().unwrap();
let (recipient, mut builder) =
- builder_for_random_recipient(&account_key, &wallet_db, &ledger_db, &mut rng, &logger);
+ builder_for_random_recipient(&account_key, &ledger_db, &mut rng, &logger);
builder.add_recipient(recipient.clone(), 50 * MOB).unwrap();
builder.set_tombstone(0).unwrap();
- builder.select_txos(None, false).unwrap();
- let tx_proposal = builder.build().unwrap();
+ builder.select_txos(&conn, None, false).unwrap();
+ let tx_proposal = builder.build(&conn).unwrap();
// Log submitted transaction from tx_proposal
let tx_log = TransactionLog::log_submitted(
@@ -704,7 +676,7 @@ mod tests {
ledger_db.num_blocks().unwrap(),
"".to_string(),
&AccountID::from(&account_key).to_string(),
- &wallet_db.get_conn().unwrap(),
+ &conn,
)
.unwrap();
@@ -843,22 +815,23 @@ mod tests {
);
// Build a transaction
+ let conn = wallet_db.get_conn().unwrap();
let (recipient, mut builder) =
- builder_for_random_recipient(&account_key, &wallet_db, &ledger_db, &mut rng, &logger);
+ builder_for_random_recipient(&account_key, &ledger_db, &mut rng, &logger);
// Add outlays all to the same recipient, so that we exceed u64::MAX in this tx
let value = 100 * MOB - Mob::MINIMUM_FEE;
builder.add_recipient(recipient.clone(), value).unwrap();
builder.set_tombstone(0).unwrap();
- builder.select_txos(None, false).unwrap();
- let tx_proposal = builder.build().unwrap();
+ builder.select_txos(&conn, None, false).unwrap();
+ let tx_proposal = builder.build(&conn).unwrap();
let tx_log = TransactionLog::log_submitted(
tx_proposal.clone(),
ledger_db.num_blocks().unwrap(),
"".to_string(),
&AccountID::from(&account_key).to_string(),
- &wallet_db.get_conn().unwrap(),
+ &conn,
)
.unwrap();
@@ -1022,14 +995,15 @@ mod tests {
);
// Build a transaction for > i64::Max
+ let conn = wallet_db.get_conn().unwrap();
let (recipient, mut builder) =
- builder_for_random_recipient(&account_key, &wallet_db, &ledger_db, &mut rng, &logger);
+ builder_for_random_recipient(&account_key, &ledger_db, &mut rng, &logger);
builder
.add_recipient(recipient.clone(), 10_000_000 * MOB)
.unwrap();
builder.set_tombstone(0).unwrap();
- builder.select_txos(None, false).unwrap();
- let tx_proposal = builder.build().unwrap();
+ builder.select_txos(&conn, None, false).unwrap();
+ let tx_proposal = builder.build(&conn).unwrap();
assert_eq!(tx_proposal.outlays[0].value, 10_000_000_000_000_000_000);
@@ -1039,7 +1013,7 @@ mod tests {
ledger_db.num_blocks().unwrap(),
"".to_string(),
&AccountID::from(&account_key).to_string(),
- &wallet_db.get_conn().unwrap(),
+ &conn,
)
.unwrap();
@@ -1079,9 +1053,9 @@ mod tests {
&logger,
);
+ let conn = wallet_db.get_conn().unwrap();
let mut builder = WalletTransactionBuilder::new(
AccountID::from(&account_key).to_string(),
- wallet_db.clone(),
ledger_db.clone(),
get_resolver_factory(&mut rng).unwrap(),
logger.clone(),
@@ -1091,8 +1065,8 @@ mod tests {
.add_recipient(account_key.subaddress(0), 12 * MOB)
.unwrap();
builder.set_tombstone(0).unwrap();
- builder.select_txos(None, false).unwrap();
- let tx_proposal = builder.build().unwrap();
+ builder.select_txos(&conn, None, false).unwrap();
+ let tx_proposal = builder.build(&conn).unwrap();
// Log submitted transaction from tx_proposal
let tx_log = TransactionLog::log_submitted(
@@ -1100,7 +1074,7 @@ mod tests {
ledger_db.num_blocks().unwrap(),
"".to_string(),
&AccountID::from(&account_key).to_string(),
- &wallet_db.get_conn().unwrap(),
+ &conn,
)
.unwrap();
diff --git a/full-service/src/db/txo.rs b/full-service/src/db/txo.rs
index 66fb877a0..f2f550687 100644
--- a/full-service/src/db/txo.rs
+++ b/full-service/src/db/txo.rs
@@ -2,11 +2,7 @@
//! DB impl for the Txo model.
-use diesel::{
- prelude::*,
- r2d2::{ConnectionManager, PooledConnection},
- RunQueryDsl,
-};
+use diesel::prelude::*;
use mc_account_keys::{AccountKey, PublicAddress};
use mc_common::HashMap;
use mc_crypto_digestible::{Digestible, MerlinTranscript};
@@ -26,7 +22,7 @@ use crate::{
models::{
Account, AssignedSubaddress, NewTxo, Txo, TXO_USED_AS_CHANGE, TXO_USED_AS_OUTPUT,
},
- WalletDbError,
+ Conn, WalletDbError,
},
util::{b58::b58_encode_public_address, constants::DEFAULT_CHANGE_SUBADDRESS_INDEX},
};
@@ -82,7 +78,7 @@ pub trait TxoModel {
value: u64,
received_block_index: u64,
account_id_hex: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
/// Processes a TxProposal to create a new minted Txo and a change Txo.
@@ -94,7 +90,7 @@ pub trait TxoModel {
txo: &TxOut,
tx_proposal: &TxProposal,
outlay_index: usize,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
/// Update an existing Txo to spendable by including its subaddress_index
@@ -105,35 +101,35 @@ pub trait TxoModel {
received_subaddress_index: Option,
received_key_image: Option,
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
/// Update a Txo's received block count.
fn update_received_block_index(
&self,
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
/// Update a Txo's status to pending
fn update_to_pending(
&self,
pending_tombstone_block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
/// Update a Txo's status to spent
fn update_to_spent(
txo_id_hex: &str,
spent_block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
/// Update all Txo's that are pending with a pending_tombstone_block_index
/// less than the target block index to unspent
fn update_txos_exceeding_pending_tombstone_block_index_to_unspent(
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError>;
/// Get all Txos associated with a given account.
@@ -141,67 +137,55 @@ pub trait TxoModel {
account_id_hex: &str,
offset: Option,
limit: Option,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
fn list_for_address(
assigned_subaddress_b58: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
fn list_unspent(
account_id_hex: &str,
assigned_subaddress_b58: Option<&str>,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
/// Get a map from key images to unspent txos for this account.
fn list_unspent_or_pending_key_images(
account_id_hex: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
fn list_spent(
account_id_hex: &str,
assigned_subaddress_b58: Option<&str>,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
- fn list_secreted(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError>;
+ fn list_secreted(account_id_hex: &str, conn: &Conn) -> Result, WalletDbError>;
- fn list_orphaned(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError>;
+ fn list_orphaned(account_id_hex: &str, conn: &Conn) -> Result, WalletDbError>;
fn list_pending(
account_id_hex: &str,
assigned_subaddress_b58: Option<&str>,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
- fn list_minted(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError>;
+ fn list_minted(account_id_hex: &str, conn: &Conn) -> Result, WalletDbError>;
fn list_pending_exceeding_block_index(
account_id_hex: &str,
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
/// Get the details for a specific Txo.
///
/// Returns:
/// * Txo
- fn get(
- txo_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result;
+ fn get(txo_id_hex: &str, conn: &Conn) -> Result;
/// Get several Txos by Txo public_keys
///
@@ -209,7 +193,7 @@ pub trait TxoModel {
/// * Vec
fn select_by_public_key(
public_keys: &[&CompressedRistrettoPublic],
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
/// Select several Txos by their TxoIds
@@ -219,7 +203,7 @@ pub trait TxoModel {
fn select_by_id(
txo_ids: &[String],
pending_tombstone_block_index: Option,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
/// Select a set of unspent Txos to reach a given value.
@@ -231,7 +215,7 @@ pub trait TxoModel {
target_value: u64,
max_spendable_value: Option,
pending_tombstone_block_index: Option,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError>;
/// Validate a confirmation number for a Txo
@@ -242,18 +226,13 @@ pub trait TxoModel {
account_id: &AccountID,
txo_id_hex: &str,
confirmation: &TxOutConfirmationNumber,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result;
- fn scrub_account(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError>;
+ fn scrub_account(account_id_hex: &str, conn: &Conn) -> Result<(), WalletDbError>;
/// Delete txos which are not referenced by any account or transaction.
- fn delete_unreferenced(
- conn: &PooledConnection>,
- ) -> Result<(), WalletDbError>;
+ fn delete_unreferenced(conn: &Conn) -> Result<(), WalletDbError>;
fn is_change(&self) -> bool;
@@ -278,7 +257,7 @@ impl TxoModel for Txo {
value: u64,
received_block_index: u64,
account_id_hex: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result {
// Verify that the account exists.
Account::get(&AccountID(account_id_hex.to_string()), conn)?;
@@ -334,7 +313,7 @@ impl TxoModel for Txo {
output: &TxOut,
tx_proposal: &TxProposal,
output_index: usize,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result {
use crate::db::schema::txos;
@@ -420,7 +399,7 @@ impl TxoModel for Txo {
received_subaddress_index: Option,
received_key_image: Option,
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::txos;
@@ -441,7 +420,7 @@ impl TxoModel for Txo {
fn update_received_block_index(
&self,
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::txos::received_block_index;
@@ -454,7 +433,7 @@ impl TxoModel for Txo {
fn update_to_pending(
&self,
pending_tombstone_block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::txos;
@@ -467,7 +446,7 @@ impl TxoModel for Txo {
fn update_to_spent(
txo_id_hex: &str,
spent_block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::txos;
@@ -482,7 +461,7 @@ impl TxoModel for Txo {
fn update_txos_exceeding_pending_tombstone_block_index_to_unspent(
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result<(), WalletDbError> {
use crate::db::schema::txos;
@@ -501,7 +480,7 @@ impl TxoModel for Txo {
account_id_hex: &str,
offset: Option,
limit: Option,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::txos;
@@ -520,7 +499,7 @@ impl TxoModel for Txo {
fn list_for_address(
assigned_subaddress_b58: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::txos;
let subaddress = AssignedSubaddress::get(assigned_subaddress_b58, conn)?;
@@ -534,7 +513,7 @@ impl TxoModel for Txo {
fn list_unspent(
account_id_hex: &str,
assigned_subaddress_b58: Option<&str>,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::txos;
@@ -558,7 +537,7 @@ impl TxoModel for Txo {
fn list_unspent_or_pending_key_images(
account_id_hex: &str,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::txos;
@@ -585,7 +564,7 @@ impl TxoModel for Txo {
fn list_spent(
account_id_hex: &str,
assigned_subaddress_b58: Option<&str>,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::txos;
@@ -605,10 +584,7 @@ impl TxoModel for Txo {
Ok(txos)
}
- fn list_secreted(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError> {
+ fn list_secreted(account_id_hex: &str, conn: &Conn) -> Result, WalletDbError> {
use crate::db::schema::txos;
// Secreted txos were minted by this account, but not received by this account,
@@ -625,10 +601,7 @@ impl TxoModel for Txo {
Ok(txos)
}
- fn list_orphaned(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError> {
+ fn list_orphaned(account_id_hex: &str, conn: &Conn) -> Result, WalletDbError> {
use crate::db::schema::txos;
let txos: Vec = txos::table
@@ -642,7 +615,7 @@ impl TxoModel for Txo {
fn list_pending(
account_id_hex: &str,
assigned_subaddress_b58: Option<&str>,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::txos;
@@ -667,7 +640,7 @@ impl TxoModel for Txo {
fn list_pending_exceeding_block_index(
account_id_hex: &str,
block_index: u64,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::txos;
@@ -682,10 +655,7 @@ impl TxoModel for Txo {
Ok(txos)
}
- fn list_minted(
- account_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result, WalletDbError> {
+ fn list_minted(account_id_hex: &str, conn: &Conn) -> Result, WalletDbError> {
use crate::db::schema::txos;
let results = txos::table
@@ -695,10 +665,7 @@ impl TxoModel for Txo {
Ok(results)
}
- fn get(
- txo_id_hex: &str,
- conn: &PooledConnection>,
- ) -> Result {
+ fn get(txo_id_hex: &str, conn: &Conn) -> Result {
use crate::db::schema::txos;
let txo = match txos::table
@@ -719,7 +686,7 @@ impl TxoModel for Txo {
fn select_by_public_key(
public_keys: &[&CompressedRistrettoPublic],
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result, WalletDbError> {
use crate::db::schema::txos;
@@ -736,23 +703,21 @@ impl TxoModel for Txo {
fn select_by_id(
txo_ids: &[String],
pending_tombstone_block_index: Option,
- conn: &PooledConnection>,
+ conn: &Conn,
) -> Result