Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(nft): add token_id field to the tx history primary key, fix balance #2209

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from

Conversation

laruh
Copy link
Member

@laruh laruh commented Sep 3, 2024

fixes #2208

also in this commit 2bdee4f fixes withdarw_erc1155 decimal issue. ERC1155 "balanceOf" method started returning exact Nft amount owned by wallet without any scaling, so we dont need to use self.decimals shift when we convert U256 type to BigDecimal

@laruh laruh requested a review from smk762 September 3, 2024 02:57
@laruh laruh added under review in progress Changes will be made from the author and removed under review labels Sep 3, 2024
@laruh laruh added under review and removed in progress Changes will be made from the author labels Sep 3, 2024
…t amount of token without any decimals or scaling factors
@laruh laruh changed the title fix(nft_db): add token_id field to the tx history primary key fix(nft): add token_id field to the tx history primary key, fix balanceOf Sep 3, 2024
@laruh laruh changed the title fix(nft): add token_id field to the tx history primary key, fix balanceOf fix(nft): add token_id field to the tx history primary key, fix balance Sep 3, 2024
smk762
smk762 previously approved these changes Sep 5, 2024
Copy link

@smk762 smk762 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, NFT history and 1155 withdraws confirmed working.

Note: Withdraws of a spammy NFT were throwing gas errrors, but a good NFT was fine. I assume the spammy one was trying to scalp gas.

Copy link
Collaborator

@shamardy shamardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix! First review iteration!

mm2src/coins/eth.rs Show resolved Hide resolved
@@ -103,7 +103,7 @@ fn create_transfer_history_table_sql(chain: &Chain) -> Result<String, SqlError>
image_domain TEXT,
token_name TEXT,
details_json TEXT,
PRIMARY KEY (transaction_hash, log_index)
PRIMARY KEY (transaction_hash, log_index, token_id)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about already created tables? Shouldn't we do a migration for these tables?

Copy link
Member Author

@laruh laruh Sep 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm yeah, need to do it

I think it’s worth considering the use of sql client (eg SQLx) or ORM (eg Diesel) in the future, if we decide to fully refactor KDF. These sql tools natively support migrations.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it’s worth considering the use of sql client (eg SQLx) or ORM (eg Diesel) in the future, if we decide to fully refactor KDF. These sql tools natively support migrations.

Do we have an issue open for this? If not, please open one.

@laruh laruh added in progress Changes will be made from the author and removed under review labels Sep 8, 2024
@laruh laruh force-pushed the fix-nft-tx-history-primkey branch 2 times, most recently from 44ca4a5 to a5c612c Compare September 15, 2024 10:57
@shamardy
Copy link
Collaborator

@borngraced can you please review the wasm / indexeddb changes?

@laruh
Copy link
Member Author

laruh commented Sep 23, 2024

@borngraced can you please review the wasm / indexeddb changes?

ps right now it doesnt work as expected.

Screenshot 2024-09-23 at 16 42 34
Screenshot 2024-09-23 at 16 43 15

We use web-sys to access Web APIs available in the browser. Despite the fact that web-sys functions are sync, the actuall process in browser can be async (that what happens with IndexedDB). I suppose thats why I got A mutation operation was attempted on a database that did not allow mutations. error.
In another branch Im working on async versions of on_upgrade_needed and with_table function to see will it work.

UPD: I also suggest to check for wasm db clients which support migrations.

@borngraced
Copy link
Member

borngraced commented Sep 23, 2024

@borngraced can you please review the wasm / indexeddb changes?

ps right now it doesnt work as expected.

Screenshot 2024-09-23 at 16 42 34 Screenshot 2024-09-23 at 16 43 15

We use web-sys to access Web APIs available in the browser. Despite the fact that web-sys functions are sync, the actuall process in browser can be async (that what happens with IndexedDB). I suppose thats why I got A mutation operation was attempted on a database that did not allow mutations. error. In another branch Im working on async versions of on_upgrade_needed and with_table function to see will it work.

UPD: I also suggest to check for wasm db clients which support migrations.

Have checked the cursor implementation example on how async and channels are used?

@laruh
Copy link
Member Author

laruh commented Sep 23, 2024

@borngraced can you please review the wasm / indexeddb changes?

ps right now it doesnt work as expected.
Screenshot 2024-09-23 at 16 42 34 Screenshot 2024-09-23 at 16 43 15
We use web-sys to access Web APIs available in the browser. Despite the fact that web-sys functions are sync, the actuall process in browser can be async (that what happens with IndexedDB). I suppose thats why I got A mutation operation was attempted on a database that did not allow mutations. error. In another branch Im working on async versions of on_upgrade_needed and with_table function to see will it work.
UPD: I also suggest to check for wasm db clients which support migrations.

Have checked the cursor implementation example on how async and channels are used?

yes, in the end cursor usage requires to call "await" somewhere to wait for the end of the process.
When we init table only build function is async

    async fn init(db_id: DbIdentifier) -> InitDbResult<Self> {
        let inner = IndexedDbBuilder::new(db_id)
            .with_version(...)
            .with_table::<...>()
            .build()
            .await?;

        Ok(Self { inner })
    }

The other idea is that, the current migration fails, bcz it started earlier than upgrade permission was granted in build function

let onupgradeneeded_closure = construct_event_closure(DbOpenEvent::UpgradeNeeded, tx.clone());
db_request.set_onerror(Some(onerror_closure.as_ref().unchecked_ref()));
db_request.set_onsuccess(Some(onsuccess_closure.as_ref().unchecked_ref()));
db_request.set_onupgradeneeded(Some(onupgradeneeded_closure.as_ref().unchecked_ref()));

UPD: may be it worth trying to reuse our cursor driver implementation withour making with_table async

@borngraced
Copy link
Member

@borngraced can you please review the wasm / indexeddb changes?

ps right now it doesnt work as expected.
Screenshot 2024-09-23 at 16 42 34 Screenshot 2024-09-23 at 16 43 15
We use web-sys to access Web APIs available in the browser. Despite the fact that web-sys functions are sync, the actuall process in browser can be async (that what happens with IndexedDB). I suppose thats why I got A mutation operation was attempted on a database that did not allow mutations. error. In another branch Im working on async versions of on_upgrade_needed and with_table function to see will it work.
UPD: I also suggest to check for wasm db clients which support migrations.

Have checked the cursor implementation example on how async and channels are used?

yes, in the end cursor usage requires to call "await" somewhere to wait for the end of the process. When we init table only build function is async

    async fn init(db_id: DbIdentifier) -> InitDbResult<Self> {
        let inner = IndexedDbBuilder::new(db_id)
            .with_version(...)
            .with_table::<...>()
            .build()
            .await?;

        Ok(Self { inner })
    }

The other idea is that, the current migration fails, bcz it started earlier than upgrade permission was granted in build function

let onupgradeneeded_closure = construct_event_closure(DbOpenEvent::UpgradeNeeded, tx.clone());
db_request.set_onerror(Some(onerror_closure.as_ref().unchecked_ref()));
db_request.set_onsuccess(Some(onsuccess_closure.as_ref().unchecked_ref()));

UPD: may be it worth trying to reuse our cursor driver implementation withour making with_table async

I will dedicate some time to this later today/tomorrow morning and get back to you for sure!

@borngraced
Copy link
Member

@borngraced can you please review the wasm / indexeddb changes?

ps right now it doesnt work as expected.
Screenshot 2024-09-23 at 16 42 34 Screenshot 2024-09-23 at 16 43 15
We use web-sys to access Web APIs available in the browser. Despite the fact that web-sys functions are sync, the actuall process in browser can be async (that what happens with IndexedDB). I suppose thats why I got A mutation operation was attempted on a database that did not allow mutations. error. In another branch Im working on async versions of on_upgrade_needed and with_table function to see will it work.
UPD: I also suggest to check for wasm db clients which support migrations.

Have checked the cursor implementation example on how async and channels are used?

yes, in the end cursor usage requires to call "await" somewhere to wait for the end of the process. When we init table only build function is async

    async fn init(db_id: DbIdentifier) -> InitDbResult<Self> {
        let inner = IndexedDbBuilder::new(db_id)
            .with_version(...)
            .with_table::<...>()
            .build()
            .await?;

        Ok(Self { inner })
    }

The other idea is that, the current migration fails, bcz it started earlier than upgrade permission was granted in build function

let onupgradeneeded_closure = construct_event_closure(DbOpenEvent::UpgradeNeeded, tx.clone());
db_request.set_onerror(Some(onerror_closure.as_ref().unchecked_ref()));
db_request.set_onsuccess(Some(onsuccess_closure.as_ref().unchecked_ref()));

UPD: may be it worth trying to reuse our cursor driver implementation withour making with_table async

I will dedicate some time to this later today/tomorrow morning and get back to you for sure!

@laruh have you seen this yet?

pub(super) async fn get_current_migration(
migration_table: &DbTable<'_, SwapsMigrationTable>,
) -> MmResult<u32, SavedSwapError> {
let migrations = migration_table
.cursor_builder()
.bound("migration", 0, u32::MAX)
.reverse()
.open_cursor("migration")
.await?
// TODO refactor when "closure invoked recursively or after being dropped" is fixed
.collect()
.await?;
Ok(migrations.first().map(|(_, m)| m.migration).unwrap_or_default())
}
pub async fn migrate_swaps_data(ctx: &MmArc) -> MmResult<(), SavedSwapError> {
let swaps_ctx = SwapsContext::from_ctx(ctx).map_to_mm(SavedSwapError::InternalError)?;
let db = swaps_ctx.swap_db().await?;
let transaction = db.transaction().await?;
let migration_table = transaction.table::<SwapsMigrationTable>().await?;
let mut migration = get_current_migration(&migration_table).await?;
info!("Current swaps data migration {}", migration);
loop {
match migration {
0 => {
let filters_table = transaction.table::<MySwapsFiltersTable>().await?;
let swaps_table = transaction.table::<SavedSwapTable>().await?;
let swaps = swaps_table.get_all_items().await?;
let swaps = swaps
.into_iter()
.map(|(_item_id, SavedSwapTable { saved_swap, .. })| saved_swap)
.map(json::from_value)
.map(|res: Result<SavedSwap, _>| {
res.map_to_mm(|e| SavedSwapError::ErrorDeserializing(e.to_string()))
})
.collect::<Result<Vec<SavedSwap>, _>>()?;
for swap in swaps {
let (filter_id, mut filter_record) =
match filters_table.get_item_by_unique_index("uuid", swap.uuid()).await? {
Some(f) => f,
None => {
warn!("No MySwapsFiltersTable for {}", swap.uuid());
continue;
},
};
filter_record.swap_type = LEGACY_SWAP_TYPE;
filter_record.is_finished = swap.is_finished().into();
filters_table.replace_item(filter_id, &filter_record).await?;
}
},
1 => break,
unsupported => {
return MmError::err(SavedSwapError::InternalError(format!(
"Unsupported migration {}",
unsupported
)))
},
}
migration += 1;
migration_table.add_item(&SwapsMigrationTable { migration }).await?;
}
info!("Swaps data migration is completed, new version {}", migration);
Ok(())
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in progress Changes will be made from the author
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants