-
Notifications
You must be signed in to change notification settings - Fork 573
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2599 from iron-fish/staging
STAGING -> MASTER v53
- Loading branch information
Showing
29 changed files
with
1,186 additions
and
433 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"name": "ironfish", | ||
"version": "0.1.52", | ||
"version": "0.1.53", | ||
"description": "CLI for running and interacting with an Iron Fish node", | ||
"author": "Iron Fish <[email protected]> (https://ironfish.network)", | ||
"main": "build/src/index.js", | ||
|
@@ -56,7 +56,7 @@ | |
"dependencies": { | ||
"@aws-sdk/client-s3": "3.127.0", | ||
"@ironfish/rust-nodejs": "0.1.17", | ||
"@ironfish/sdk": "0.0.29", | ||
"@ironfish/sdk": "0.0.30", | ||
"@oclif/core": "1.16.1", | ||
"@oclif/plugin-help": "5.1.12", | ||
"@oclif/plugin-not-found": "2.3.1", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ | ||
import { | ||
Account, | ||
Assert, | ||
Blockchain, | ||
CurrencyUtils, | ||
NodeUtils, | ||
Wallet, | ||
WalletDB, | ||
} from '@ironfish/sdk' | ||
import { IronfishCommand } from '../../command' | ||
import { LocalFlags } from '../../flags' | ||
|
||
const RESCAN_MESSAGE = 'Account must be rescanned using `accounts:rescan --reset`.' | ||
export default class Repair extends IronfishCommand { | ||
static hidden = false | ||
|
||
static description = `Repairs wallet database stores` | ||
|
||
static flags = { | ||
...LocalFlags, | ||
} | ||
|
||
static args = [ | ||
{ | ||
name: 'account', | ||
parse: (input: string): Promise<string> => Promise.resolve(input.trim()), | ||
required: false, | ||
description: 'Name of the account to repair the database for', | ||
}, | ||
] | ||
|
||
async start(): Promise<void> { | ||
const { args } = await this.parse(Repair) | ||
|
||
const node = await this.sdk.node() | ||
await NodeUtils.waitForOpen(node) | ||
|
||
const account = this.loadAccount(node.wallet, args.account) | ||
|
||
this.log(`Repairing wallet for account ${account.name}`) | ||
|
||
this.log('Repairing balance') | ||
await this.repairBalance(account, node.wallet.walletDb, node.chain) | ||
|
||
this.log('Repairing nullifierToNote') | ||
await this.repairNullifierToNoteHash(account, node.wallet.walletDb) | ||
|
||
this.log('Repairing sequenceToNoteHash') | ||
await this.repairSequenceToNoteHash(account, node.wallet.walletDb) | ||
} | ||
|
||
private loadAccount(wallet: Wallet, accountName: string | undefined): Account { | ||
if (accountName) { | ||
const account = wallet.getAccountByName(accountName) | ||
if (account) { | ||
return account | ||
} | ||
throw new Error(`No account with name ${accountName}`) | ||
} | ||
|
||
const defaultAccount = wallet.getDefaultAccount() | ||
if (defaultAccount) { | ||
return defaultAccount | ||
} | ||
|
||
throw new Error('Could not find an account to repair.') | ||
} | ||
|
||
private async repairBalance( | ||
account: Account, | ||
walletDb: WalletDB, | ||
chain: Blockchain, | ||
): Promise<void> { | ||
let unconfirmedBalance = 0n | ||
|
||
let noteUnspentMismatches = 0 | ||
|
||
for await (const decryptedNoteValue of account.getNotes()) { | ||
const transactionValue = await account.getTransaction(decryptedNoteValue.transactionHash) | ||
|
||
Assert.isNotUndefined( | ||
transactionValue, | ||
`Account has a note but is missing the transaction that it received the note from. ${RESCAN_MESSAGE}`, | ||
) | ||
|
||
if (!decryptedNoteValue.nullifier) { | ||
if (transactionValue.sequence) { | ||
throw new Error( | ||
`Transaction marked as on chain, but note missing nullifier. ${RESCAN_MESSAGE}`, | ||
) | ||
} | ||
|
||
continue | ||
} | ||
|
||
const spent = await chain.nullifiers.contains(decryptedNoteValue.nullifier) | ||
|
||
if (spent && !decryptedNoteValue.spent) { | ||
noteUnspentMismatches++ | ||
|
||
await walletDb.saveDecryptedNote(account, decryptedNoteValue.hash, { | ||
...decryptedNoteValue, | ||
spent: true, | ||
}) | ||
} else if ( | ||
!spent && | ||
!chain.verifier.isExpiredSequence( | ||
transactionValue.transaction.expirationSequence(), | ||
chain.head.sequence, | ||
) | ||
) { | ||
if (decryptedNoteValue.spent) { | ||
await walletDb.saveDecryptedNote(account, decryptedNoteValue.hash, { | ||
...decryptedNoteValue, | ||
spent: false, | ||
}) | ||
} | ||
|
||
unconfirmedBalance += decryptedNoteValue.note.value() | ||
} | ||
} | ||
|
||
this.log( | ||
`\tSaving new unconfirmed balance: ${CurrencyUtils.renderIron(unconfirmedBalance, true)}`, | ||
) | ||
await walletDb.saveUnconfirmedBalance(account, unconfirmedBalance) | ||
|
||
this.log( | ||
`\tRepaired ${noteUnspentMismatches} decrypted notes incorrectly marked as unspent`, | ||
) | ||
} | ||
|
||
private async repairNullifierToNoteHash(account: Account, walletDb: WalletDB): Promise<void> { | ||
let missingNotes = 0 | ||
|
||
for await (const [[, nullifier], noteHash] of walletDb.nullifierToNoteHash.getAllIter( | ||
undefined, | ||
account.prefixRange, | ||
)) { | ||
const decryptedNoteValue = await account.getDecryptedNote(noteHash) | ||
|
||
if (!decryptedNoteValue || !decryptedNoteValue.nullifier) { | ||
missingNotes++ | ||
|
||
await walletDb.deleteNullifier(account, nullifier) | ||
} | ||
} | ||
|
||
this.log( | ||
`\tRepaired ${missingNotes} nullifiers that map to notes that are not in the wallet`, | ||
) | ||
} | ||
|
||
private async repairSequenceToNoteHash(account: Account, walletDb: WalletDB): Promise<void> { | ||
let incorrectSequences = 0 | ||
|
||
for await (const [, [sequence, noteHash]] of walletDb.sequenceToNoteHash.getAllKeysIter( | ||
undefined, | ||
account.prefixRange, | ||
)) { | ||
const decryptedNoteValue = await account.getDecryptedNote(noteHash) | ||
|
||
if (!decryptedNoteValue) { | ||
incorrectSequences++ | ||
|
||
await walletDb.sequenceToNoteHash.del([account.prefix, [sequence, noteHash]]) | ||
|
||
continue | ||
} | ||
|
||
const transactionValue = await account.getTransaction(decryptedNoteValue.transactionHash) | ||
|
||
Assert.isNotUndefined( | ||
transactionValue, | ||
`Account has a note but is missing the transaction that it received the note from. ${RESCAN_MESSAGE}`, | ||
) | ||
|
||
if (transactionValue.sequence !== sequence) { | ||
incorrectSequences++ | ||
|
||
await walletDb.sequenceToNoteHash.del([account.prefix, [sequence, noteHash]]) | ||
|
||
await walletDb.setNoteHashSequence(account, noteHash, transactionValue.sequence) | ||
} | ||
} | ||
|
||
this.log(`\tRepaired ${incorrectSequences} incorrect sequenceToNoteHash mappings`) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"name": "@ironfish/sdk", | ||
"version": "0.0.29", | ||
"version": "0.0.30", | ||
"description": "SDK for running and interacting with an Iron Fish node", | ||
"author": "Iron Fish <[email protected]> (https://ironfish.network)", | ||
"main": "build/src/index.js", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.