Neptune-Crypto / neptune-core

anonymous peer-to-peer cash
Apache License 2.0
23 stars 7 forks source link

Inconsistent balance numbers #93

Open Sword-Smith opened 6 months ago

Sword-Smith commented 6 months ago

On the dashboard's overview page, and with neptune-cli synced-balance I see a balance of 25.178. But in the History screen I see a balance of 6.478. To me, it looks like the overview/synced-balance number updates correctly whereas the History number only considers balance increases. I'm not sure, what's going on here. Maybe this involves a balance that has been restored from incoming_randomness somehow?

On another instance the behavior seems correct, the History and synced-balance numbers agree. So this problem might only arise when the client recovers UTXOs at startup in case the wallet database has been deleted.

dan-da commented 6 months ago

So this problem might only arise when the client recovers UTXOs at startup in case the wallet database has been deleted.

I believe this analysis is correct. I moved away my wallet DB (but kept wallet keys) and restarted neptune-core. Dashboard still showed my previous balance but the history was empty. I then restarted neptune-core with --unrestricted-mining and it quickly mined 3 blocks. History shows 3 tx, with "balance after" field == 300.

Do you have a suggestion how to fix this issue of history not matching balance? It seems at least this is an error condition that should be reported and maybe panic'ed at startup.

Also, as we are an archival node, it seems we should be able to walk the blockchain and find all "my" transactions. I would think this is something we might do during startup if a mis-match is detected. But a first step would be just to detect and panic/abort.

it looks like the overview/synced-balance number updates correctly whereas the History number only considers balance increases

in get_balance_history()

            if let Some((confirming_block, confirmation_timestamp, confirmation_height)) =
                monitored_utxo.confirmed_in_block
            {
                let amount = monitored_utxo.utxo.get_native_coin_amount();
                history.push((
                    confirming_block,
                    confirmation_timestamp,
                    confirmation_height,
                    amount,
                    Sign::NonNegative,
                ));
                if let Some((spending_block, spending_timestamp, spending_height)) =
                    monitored_utxo.spent_in_block
                {
                    history.push((
                        spending_block,
                        spending_timestamp,
                        spending_height,
                        amount,
                        Sign::Negative,
                    ));
                }
            }

in history_screen.rs

                    let bh = rpc_client.history(context::current()).await.unwrap();
                    let mut history_builder = Vec::with_capacity(bh.len());
                    let mut balance = Amount::zero();
                    for (_, block_height, timestamp, amount, sign) in bh.iter() {
                        match sign {
                            Sign::NonNegative => { balance = balance + *amount; }
                            Sign::Negative => {
                                    balance = match balance.checked_sub(amount) {
                                    Some(b) => b,
                                    None => Amount::zero(),
                                };
                            }
                        }
                        history_builder.push((*block_height, *timestamp, *amount, *sign, balance));
                    }

looks ok to me.