Conversation
554e4e2 to
b00d078
Compare
e19ea86 to
184291a
Compare
8a9d0ce to
6496fe8
Compare
b916d76 to
1f9d564
Compare
ImplOfAnImpl
left a comment
There was a problem hiding this comment.
CURRENT_STORAGE_VERSION wasn't updated - is this intended?
| &self, | ||
| tx_id: Id<Transaction>, | ||
| ) -> Result<Option<SignedTransaction>, Self::Error>; | ||
| async fn mempool_get_transactions(&self) -> Result<Vec<SignedTransaction>, Self::Error>; |
There was a problem hiding this comment.
Btw, the doc comment for MempoolRpc::get_all_transactions still says "This function is mostly used for testing purposes", which is no longer true.
There was a problem hiding this comment.
Removed that comment
| ) | ||
| .await; | ||
| } else { | ||
| increase_mempool_locked_address_balance( |
There was a problem hiding this comment.
I see that you increase locked balances in the mempool but never decrease them.
Mempool has some timelock tolerance defined by constants FUTURE_TIMELOCK_TOLERANCE/FUTURE_TIMELOCK_TOLERANCE_BLOCKS. So it should be possible to have e.g. a tx with LockThenTransfer output for 2 blocks and then a tx that consumes that output both in the mempool at the same time.
Probably you should decrease locked balances if a LockThenTransfer utxo is spent by a mempool tx.
There was a problem hiding this comment.
I added a test with a tx spending a locked UTXO with 1..FUTURE_TIMELOCK_TOLERANCE_BLOCKS.
71d7a6b to
1c9739a
Compare
6185680 to
f6d5c31
Compare
fa3a655 to
50cf265
Compare
50cf265 to
317964b
Compare
ImplOfAnImpl
left a comment
There was a problem hiding this comment.
-
The most complex changes are in the scanner-lib, but there are zero new tests in
api-server/scanner-lib/src/sync/tests. I don't think that the tests at the stack-test-suite level are enough: the current tests are limited and in general tests at that level are limited in what they can check compared to the ones in scanner-lib. Additionally, there is functionality that is not currently exposed via the API, so it's basically not tested.
Plz add tests at the scanner-lib level too. Plz make sure they're extensive enough. -
Regarding the pagination of the mempool transactions in the corresponding endpoint - obviously the current solution just wont work. I guess we should get rid of the pagination entirely in this case and return the entire contents in one call, as they do in bitcoin in
getrawmempool(by default, they only return tx ids, so the response is not that large even for a full mempool). Also, let's maybe introduce something similar to theirmempool_sequencecounter, which would be incremented every time the mempool contents change, so that the caller can use that to check that the mempool has changed.
| for (out_index, out) in tx.transaction().outputs().iter().enumerate() { | ||
| match out { | ||
| TxOutput::CreateOrder(order_data) => { | ||
| let order_id = make_order_id(inputs).expect("Valid TX from mempool"); |
There was a problem hiding this comment.
Plz don't expect. Create an error type specifically for dependency_graph and return it here.
P.S. also, this module is not mempool-specific, so mempool should not be mentioned here.
| assert_eq!(dependency_graph[1].dependencies, vec![txa_id]); | ||
| } | ||
|
|
||
| // test txs not dependednt on UTXO input/outputs but on token creation/command |
| let chain_config = create_regtest(); | ||
| let block_height = BlockHeight::new(0); | ||
|
|
||
| // A creates a new token, B uses a comand on it |
| .build(); | ||
| let txb_id = txb.transaction().get_id(); | ||
|
|
||
| let transactions = vec![txa, txb]; |
There was a problem hiding this comment.
Here and in other tests: shuffle the tx vector before building the graph?
|
|
||
| // Order transactions by dependency between each other. | ||
| // Returns a Vec of transactions starting from the top-most parent transaction | ||
| // which doesn't depend on any other transaction fallowing it, and ending with the leafs. |
| | OrderAccountCommand::FreezeOrder(order_id) | ||
| | OrderAccountCommand::ConcludeOrder(order_id) => { | ||
| let order = db_tx | ||
| .get_order(*order_id) |
There was a problem hiding this comment.
get_mempool_order_with_fallback?
Same above, where legacy orders are handled.
| } | ||
| } | ||
| } | ||
| _ => {} |
There was a problem hiding this comment.
Using wildcard in matches is dangerous - when the enum changes, you won't notice that the code needs updating.
But here you actually omitted orders v1 entirely.
Plz write a test in scanner-lib for this.
| } | ||
|
|
||
| // Save new UTXO as unspent in mempool | ||
| let utxo = Utxo::new(output.clone(), token_decimals_opt, None); |
There was a problem hiding this comment.
Btw, you call set_mempool_utxo/set_mempool_locked_utxo even for non-spendable outputs, which are not really utxos. As I can see, in update_tables_from_transaction_outputs only spendable outputs are recorded as utxos, so I guess here we should do the same?
| ## [1.3.0] - 2026-04-09 | ||
|
|
||
| ### Added | ||
| - New endpoint was added: `/v2/transaction/{id}/output/{idx}`. | ||
| - New endpoint was added: `/v2/transaction/{id}/output/{idx}`, including an optional `with_mempool` parameter that controls the display of mempool spent status. | ||
| - New endpoint was added: `/v2/token/{id}/transactions` will return all transactions related to a token.\ | ||
| Pagination works like the new absolute mode in `/v2/transaction`, using `offset` and `items`. | ||
| - New endpoints for addresses and transactions from the mempool: | ||
| - `/v2/mempool/transaction` | ||
| - `/v2/mempool/transaction/:id` | ||
| - `/v2/mempool/address/:address` | ||
| - `/v2/mempool/address/:address/all-utxos` |
There was a problem hiding this comment.
Wrong place. Add the changes to the [Unreleased] section instead.
| let (best_block_height, best_block_id, _) = local_state | ||
| .best_block() | ||
| .await | ||
| .map_err(|e| SyncError::BestBlockRetrievalError(e.to_string()))?; | ||
|
|
||
| if chain_info.best_block_id == best_block_id { | ||
| logging::log::info!("Fully synced! Scanning mempool..."); | ||
|
|
||
| // Fetch the current complete mempool | ||
| let all_mempool_txs = rpc_client | ||
| .mempool_get_transactions() | ||
| .await | ||
| .map_err(|e| SyncError::RemoteNode(e.to_string()))?; | ||
|
|
||
| let ordered_txs = | ||
| order_transactions_by_dependency(all_mempool_txs, chain_config, best_block_height) | ||
| .map_err(|e| SyncError::LocalNode(e.to_string()))?; | ||
|
|
||
| for tx in ordered_txs { | ||
| local_state | ||
| .add_mempool_tx(&tx) | ||
| .await | ||
| .map_err(|e| SyncError::LocalNode(e.to_string()))?; | ||
| } | ||
|
|
||
| return Ok(()); | ||
| } | ||
|
|
There was a problem hiding this comment.
-
As I can see, the caller function doesn't try to sleep between iterations. Previously most invocations of
sync_oncewere cheap - check the block id, see that it's the best one, exit. Now you pull the entire mempool, which in theory may be 300 Mb. Probably the caller function should sleep for some time between iterations, e.g. for 1 sec? -
Transactions can be evicted from mempool if it reaches the max size. Not a problem for now of course, but it's better to implement things properly from the beginning. So, scanner-lib should check for transactions that are in the mempool-related tables, but no longer in the current mempool, and update the db accordingly, marking the corresponding utxos as unspent etc.
API Server now scans the mempool after finishing syncing to the latest block.
New address and transaction endpoints for things from the mempool.
New transaction dependency sorter, first builds a graph of dependencies from the mempool transactions and then sorts them for inclusion.