Skip to content

Commit

Permalink
do not throw when getting missing txs from wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
woodser committed Jul 24, 2023
1 parent 3df333b commit e70f2ef
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 93 deletions.
4 changes: 1 addition & 3 deletions src/main/cpp/monero_wasm_bridge.cpp
Expand Up @@ -625,8 +625,7 @@ void monero_wasm_bridge::get_txs(int handle, const string& tx_query_json, emscri
shared_ptr<monero_tx_query> tx_query = monero_tx_query::deserialize_from_block(tx_query_json);

// get txs
vector<string> missing_tx_hashes;
vector<shared_ptr<monero_tx_wallet>> txs = wallet->get_txs(*tx_query, missing_tx_hashes);
vector<shared_ptr<monero_tx_wallet>> txs = wallet->get_txs(*tx_query);

// collect unique blocks to preserve model relationships as trees
shared_ptr<monero_block> unconfirmed_block = nullptr; // placeholder to store unconfirmed txs in return json
Expand All @@ -649,7 +648,6 @@ void monero_wasm_bridge::get_txs(int handle, const string& tx_query_json, emscri
rapidjson::Document doc;
doc.SetObject();
doc.AddMember("blocks", monero_utils::to_rapidjson_val(doc.GetAllocator(), blocks), doc.GetAllocator());
if (!missing_tx_hashes.empty()) doc.AddMember("missingTxHashes", monero_utils::to_rapidjson_val(doc.GetAllocator(), missing_tx_hashes), doc.GetAllocator());
callback(monero_utils::serialize(doc));

// free memory
Expand Down
6 changes: 3 additions & 3 deletions src/main/js/common/MoneroWebWorker.js
Expand Up @@ -654,13 +654,13 @@ self.createSubaddress = async function(walletId, accountIdx, label) {
}

// TODO: easier or more efficient way than serializing from root blocks?
self.getTxs = async function(walletId, blockJsonQuery, missingTxHashes) {
self.getTxs = async function(walletId, blockJsonQuery) {

// deserialize query which is json string rooted at block
let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0];

// get txs
let txs = await self.WORKER_OBJECTS[walletId].getTxs(query, missingTxHashes);
let txs = await self.WORKER_OBJECTS[walletId].getTxs(query);

// collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs)
let seenBlocks = new Set();
Expand All @@ -680,7 +680,7 @@ self.getTxs = async function(walletId, blockJsonQuery, missingTxHashes) {

// serialize blocks to json
for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();
return {blocks: blocks, missingTxHashes: missingTxHashes};
return {blocks: blocks};
}

self.getTransfers = async function(walletId, blockJsonQuery) {
Expand Down
6 changes: 2 additions & 4 deletions src/main/js/wallet/MoneroWallet.js
Expand Up @@ -475,8 +475,7 @@ class MoneroWallet {
* Get a wallet transaction by hash.
*
* @param {string} txHash - hash of a transaction to get
* @return {MoneroTxWallet} the identified transactions
* @throws {MoneroError} if the transaction is not found
* @return {MoneroTxWallet} the identified transaction or undefined if not found
*/
async getTx(txHash) {
let txs = await this.getTxs([txHash]);
Expand Down Expand Up @@ -508,10 +507,9 @@ class MoneroWallet {
* @param {boolean} query.isIncoming - get txs with an incoming transfer or not (optional)
* @param {MoneroTransferQuery} query.transferQuery - get txs that have a transfer that meets this query (optional)
* @param {boolean} query.includeOutputs - specifies that tx outputs should be returned with tx results (optional)
* @param {string[]} missingTxHashes - populated with hashes of unfound or unmet transactions that were queried by hash (throws error if undefined and queried transaction hashes are unfound or unmet)
* @return {MoneroTxWallet[]} wallet transactions per the configuration
*/
async getTxs(query, missingTxHashes) {
async getTxs(query) {
throw new MoneroError("Not supported");
}

Expand Down
18 changes: 6 additions & 12 deletions src/main/js/wallet/MoneroWalletFull.js
Expand Up @@ -865,7 +865,7 @@ class MoneroWalletFull extends MoneroWalletKeys {
});
}

async getTxs(query, missingTxHashes) {
async getTxs(query) {
this._assertNotClosed();

// copy and normalize query up to block
Expand All @@ -888,7 +888,7 @@ class MoneroWalletFull extends MoneroWalletKeys {

// resolve with deserialized txs
try {
resolve(MoneroWalletFull._deserializeTxs(query, blocksJsonStr, missingTxHashes));
resolve(MoneroWalletFull._deserializeTxs(query, blocksJsonStr));
} catch (err) {
reject(err);
}
Expand Down Expand Up @@ -1831,18 +1831,14 @@ class MoneroWalletFull extends MoneroWalletKeys {
let blocksJson = JSON.parse(GenUtils.stringifyBIs(blocksJsonStr));
let deserializedBlocks = {};
deserializedBlocks.blocks = [];
deserializedBlocks.missingTxHashes = [];
if (blocksJson.blocks) for (let blockJson of blocksJson.blocks) deserializedBlocks.blocks.push(MoneroWalletFull._sanitizeBlock(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET)));
if (blocksJson.missingTxHashes) for (let missingTxHash of blocksJson.missingTxHashes) deserializedBlocks.missingTxHashes.push(missingTxHash);
return deserializedBlocks;
}

static _deserializeTxs(query, blocksJsonStr, missingTxHashes) {
static _deserializeTxs(query, blocksJsonStr) {

// deserialize blocks
let deserializedBlocks = MoneroWalletFull._deserializeBlocks(blocksJsonStr);
if (missingTxHashes === undefined && deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes);
for (let missingTxHash of deserializedBlocks.missingTxHashes) missingTxHashes.push(missingTxHash);
let blocks = deserializedBlocks.blocks;

// collect txs
Expand Down Expand Up @@ -1871,7 +1867,6 @@ class MoneroWalletFull extends MoneroWalletKeys {

// deserialize blocks
let deserializedBlocks = MoneroWalletFull._deserializeBlocks(blocksJsonStr);
if (deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes);
let blocks = deserializedBlocks.blocks;

// collect transfers
Expand All @@ -1893,7 +1888,6 @@ class MoneroWalletFull extends MoneroWalletKeys {

// deserialize blocks
let deserializedBlocks = MoneroWalletFull._deserializeBlocks(blocksJsonStr);
if (deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes);
let blocks = deserializedBlocks.blocks;

// collect outputs
Expand Down Expand Up @@ -2262,10 +2256,10 @@ class MoneroWalletFullProxy extends MoneroWallet {
return MoneroWalletFull._sanitizeSubaddress(new MoneroSubaddress(subaddressJson));
}

async getTxs(query, missingTxHashes) {
async getTxs(query) {
query = MoneroWallet._normalizeTxQuery(query);
let respJson = await this._invokeWorker("getTxs", [query.getBlock().toJson(), missingTxHashes]);
return MoneroWalletFull._deserializeTxs(query, JSON.stringify({blocks: respJson.blocks, missingTxHashes: respJson.missingTxHashes}), missingTxHashes); // initialize txs from blocks json string TODO: this stringifies then utility parses, avoid
let respJson = await this._invokeWorker("getTxs", [query.getBlock().toJson()]);
return MoneroWalletFull._deserializeTxs(query, JSON.stringify({blocks: respJson.blocks})); // initialize txs from blocks json string TODO: this stringifies then utility parses, avoid
}

async getTransfers(query) {
Expand Down
23 changes: 2 additions & 21 deletions src/main/js/wallet/MoneroWalletRpc.js
Expand Up @@ -783,7 +783,7 @@ class MoneroWalletRpc extends MoneroWallet {
await this.rpc.sendJsonRequest("label_address", {index: {major: accountIdx, minor: subaddressIdx}, label: label});
}

async getTxs(query, missingTxHashes) {
async getTxs(query) {

// copy query
query = MoneroWallet._normalizeTxQuery(query);
Expand Down Expand Up @@ -846,25 +846,6 @@ class MoneroWalletRpc extends MoneroWallet {
}
txs = txsQueried;

// collect unfound tx hashes
if (query.getHashes()) {
let unfoundTxHashes = [];
for (let txHash of query.getHashes()) {
let found = false;
for (let tx of txs) {
if (txHash === tx.getHash()) {
found = true;
break;
}
}
if (!found) unfoundTxHashes.push(txHash);
}

// if txs not found, collect missing hashes or throw error if no collection given
if (missingTxHashes) for (let unfoundTxHash of unfoundTxHashes) missingTxHashes.push(unfoundTxHash);
else if (unfoundTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + unfoundTxHashes);
}

// special case: re-fetch txs if inconsistency caused by needing to make multiple rpc calls
for (let tx of txs) {
if (tx.isConfirmed() && tx.getBlock() === undefined) {
Expand Down Expand Up @@ -2495,7 +2476,7 @@ class WalletPoller {
that._prevLockedTxs = lockedTxs;

// fetch txs which are no longer locked
let unlockedTxs = noLongerLockedHashes.length === 0 ? [] : await that._wallet.getTxs(new MoneroTxQuery().setIsLocked(false).setMinHeight(minHeight).setHashes(noLongerLockedHashes).setIncludeOutputs(true), []); // ignore missing tx hashes which could be removed due to re-org
let unlockedTxs = noLongerLockedHashes.length === 0 ? [] : await that._wallet.getTxs(new MoneroTxQuery().setIsLocked(false).setMinHeight(minHeight).setHashes(noLongerLockedHashes).setIncludeOutputs(true));

// announce new unconfirmed and confirmed outputs
for (let lockedTx of lockedTxs) {
Expand Down
69 changes: 19 additions & 50 deletions src/test/TestMoneroWalletCommon.js
Expand Up @@ -997,10 +997,7 @@ class TestMoneroWalletCommon {
// test fetching with missing tx hashes
let missingTxHash = "d01ede9cde813b2a693069b640c4b99c5adbdb49fbbd8da2c16c8087d0c3e320";
txHashes.push(missingTxHash);
let missingTxHashes = [];
fetchedTxs = await that.wallet.getTxs(txHashes, missingTxHashes);
assert.equal(1, missingTxHashes.length);
assert.equal(missingTxHash, missingTxHashes[0]);
fetchedTxs = await that.wallet.getTxs(txHashes);
assert.equal(txs.length, fetchedTxs.length);
for (let i = 0; i < txs.length; i++) {
assert.equal(txs[i].getHash(), fetchedTxs[i].getHash());
Expand Down Expand Up @@ -1285,67 +1282,39 @@ class TestMoneroWalletCommon {
let unknownHash2 = "ff397104dd875882f5e7c66e4f852ee134f8cf45e21f0c40777c9188bc92e943";

// fetch unknown tx hash
try {
await that.wallet.getTx(unknownHash1);
throw new Error("Should have thrown error getting tx hash unknown to wallet");
} catch (e) {
assert.equal(e.message, "Wallet missing requested tx hashes: " + [unknownHash1]);
}
assert.equal(await that.wallet.getTx(unknownHash1), undefined);

// fetch unknown tx hash using query
try {
await that.wallet.getTxs(new MoneroTxQuery().setHash(unknownHash1));
throw new Error("Should have thrown error getting tx hash unknown to wallet");
} catch (e) {
assert.equal(e.message, "Wallet missing requested tx hashes: " + [unknownHash1]);
}
let txs = await that.wallet.getTxs(new MoneroTxQuery().setHash(unknownHash1));
assert.equal(txs.length, 0);

// fetch unknown tx hash in collection
try {
await that.wallet.getTxs([txHash, unknownHash1]);
throw new Error("Should have thrown error getting tx hash unknown to wallet");
} catch (e) {
assert.equal(e.message, "Wallet missing requested tx hashes: " + [unknownHash1]);
}

txs = await that.wallet.getTxs([txHash, unknownHash1]);
assert.equal(txs.length, 1);
assert.equal(txs[0].getHash(), txHash);

// fetch unknown tx hashes in collection
try {
await that.wallet.getTxs([txHash, unknownHash1, unknownHash2]);
throw new Error("Should have thrown error getting tx hash unknown to wallet");
} catch (e) {
assert.equal(e.message, "Wallet missing requested tx hashes: " + [unknownHash1, unknownHash2]);
}
txs = await that.wallet.getTxs([txHash, unknownHash1, unknownHash2]);
assert.equal(txs.length, 1);
assert.equal(txs[0].getHash(), txHash);

// fetch invalid hash
try {
await that.wallet.getTx(invalidHash);
throw new Error("Should have thrown error getting tx hash unknown to wallet");
} catch (e) {
assert.equal(e.message, "Wallet missing requested tx hashes: " + [invalidHash]);
}
assert.equal(await wallet.getTx(invalidHash), undefined);

// fetch invalid hash collection
try {
await that.wallet.getTxs([txHash, invalidHash]);
throw new Error("Should have thrown error getting tx hash unknown to wallet");
} catch (e) {
assert.equal(e.message, "Wallet missing requested tx hashes: " + [invalidHash]);
}
txs = await that.wallet.getTxs([txHash, invalidHash]);
assert.equal(txs.length, 1);
assert.equal(txs[0].getHash(), txHash);

// fetch invalid hashes in collection
try {
await that.wallet.getTxs([txHash, invalidHash, "invalid_hash_2"]);
throw new Error("Should have thrown error getting tx hash unknown to wallet");
} catch (e) {
assert.equal(e.message, "Wallet missing requested tx hashes: " + [invalidHash, "invalid_hash_2"]);
}
txs = await that.wallet.getTxs([txHash, invalidHash, "invalid_hash_2"]);
assert.equal(txs.length, 1);
assert.equal(txs[0].getHash(), txHash);

// test collection of invalid hashes
let missingTxHashes = [];
let txs = await that.wallet.getTxs(new MoneroTxQuery().setHashes([txHash, invalidHash, "invalid_hash_2"]), missingTxHashes);
txs = await that.wallet.getTxs(new MoneroTxQuery().setHashes([txHash, invalidHash, "invalid_hash_2"]));
assert.equal(1, txs.length);
for (let tx of txs) await that._testTxWallet(tx);
assert.deepEqual([invalidHash, "invalid_hash_2"], missingTxHashes);
});

if (testConfig.testNonRelays)
Expand Down

0 comments on commit e70f2ef

Please sign in to comment.