From 61c36d9e5d5bea6c4de58badceddc741303c72d2 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Wed, 16 Nov 2022 15:25:18 -0500 Subject: [PATCH 01/15] Remove CurrencyUtils.isValid*() (#2498) * Remove CurrencyUtils.isValid These have nothing to do with our currency. They have everything to do with user input validation that is more like isValidFee(). Let's keep our currency conversion code separate from our user input. If any input should be done in CurrencyUtils it's to ensure the values are within valid ranges. * Fixed build --- ironfish-cli/src/commands/accounts/pay.ts | 15 ------ .../transactions/sendTransaction.test.ts | 4 +- .../routes/transactions/sendTransaction.ts | 53 +++++++------------ ironfish/src/utils/currency.test.ts | 7 --- ironfish/src/utils/currency.ts | 18 ------- 5 files changed, 21 insertions(+), 76 deletions(-) diff --git a/ironfish-cli/src/commands/accounts/pay.ts b/ironfish-cli/src/commands/accounts/pay.ts index a42865e4de..f2a184904b 100644 --- a/ironfish-cli/src/commands/accounts/pay.ts +++ b/ironfish-cli/src/commands/accounts/pay.ts @@ -75,10 +75,6 @@ export class Pay extends IronfishCommand { } if (flags.amount) { - if (!CurrencyUtils.isValidIron(flags.amount)) { - this.error(`A valid amount is required`) - } - amount = CurrencyUtils.decodeIron(flags.amount) } @@ -94,17 +90,10 @@ export class Pay extends IronfishCommand { }, )) as string - if (!CurrencyUtils.isValidIron(input)) { - this.error(`A valid amount is required`) - } - amount = CurrencyUtils.decodeIron(input) } if (flags.fee) { - if (!CurrencyUtils.isValidIron(flags.fee)) { - this.error(`A valid fee is required`) - } fee = CurrencyUtils.decodeIron(flags.fee) } @@ -175,10 +164,6 @@ export class Pay extends IronfishCommand { }, )) as string - if (!CurrencyUtils.isValidIron(input)) { - this.error(`A valid amount is required`) - } - fee = CurrencyUtils.decodeIron(input) } diff --git a/ironfish/src/rpc/routes/transactions/sendTransaction.test.ts b/ironfish/src/rpc/routes/transactions/sendTransaction.test.ts index a289f4b137..45b686e3bc 100644 --- a/ironfish/src/rpc/routes/transactions/sendTransaction.test.ts +++ b/ironfish/src/rpc/routes/transactions/sendTransaction.test.ts @@ -109,7 +109,7 @@ describe('Transactions sendTransaction', () => { await expect(routeTest.client.sendTransaction(TEST_PARAMS)).rejects.toThrowError( expect.objectContaining({ message: expect.stringContaining( - 'Please wait a few seconds for your balance to update and try again', + 'Your balance is too low. Add funds to your account first', ), status: 400, code: ERROR_CODES.INSUFFICIENT_BALANCE, @@ -127,7 +127,7 @@ describe('Transactions sendTransaction', () => { await expect(routeTest.client.sendTransaction(TEST_PARAMS_MULTI)).rejects.toThrowError( expect.objectContaining({ message: expect.stringContaining( - 'Please wait a few seconds for your balance to update and try again', + 'Your balance is too low. Add funds to your account first', ), status: 400, code: ERROR_CODES.INSUFFICIENT_BALANCE, diff --git a/ironfish/src/rpc/routes/transactions/sendTransaction.ts b/ironfish/src/rpc/routes/transactions/sendTransaction.ts index d82a087c5e..b8a4b0a731 100644 --- a/ironfish/src/rpc/routes/transactions/sendTransaction.ts +++ b/ironfish/src/rpc/routes/transactions/sendTransaction.ts @@ -92,53 +92,38 @@ router.register( ) } - // Check whether amount and fee are valid or not - if (!CurrencyUtils.isValidOre(transaction.fee)) { - throw new ValidationError( - `Invalid transaction fee, ${transaction.fee}`, - undefined, - ERROR_CODES.VALIDATION, - ) - } - let sum = BigInt(transaction.fee) - transaction.receives.map((receive) => { - if (!CurrencyUtils.isValidOre(receive.amount)) { - throw new ValidationError( - `Invalid transaction amount, ${receive.amount}`, - undefined, - ERROR_CODES.VALIDATION, - ) + const receives = transaction.receives.map((receive) => { + return { + publicAddress: receive.publicAddress, + amount: CurrencyUtils.decode(receive.amount), + memo: receive.memo, } - sum += BigInt(receive.amount) }) - // Check that the node account is updated - const balance = await node.wallet.getBalance(account) + const fee = CurrencyUtils.decode(transaction.fee) + const sum = receives.reduce((m, c) => m + c.amount, fee) - if (balance.confirmed < sum && balance.unconfirmed < sum) { - throw new ValidationError( - `Your balance is too low. Add funds to your account first`, - undefined, - ERROR_CODES.INSUFFICIENT_BALANCE, - ) + if (fee < 1n) { + throw new ValidationError(`Invalid transaction fee, ${transaction.fee}`) + } + + for (const receive of receives) { + if (receive.amount < 0) { + throw new ValidationError(`Invalid transaction amount, ${receive.amount}`) + } } + // Check that the node account is updated + const balance = await node.wallet.getBalance(account) + if (balance.confirmed < sum) { throw new ValidationError( - `Please wait a few seconds for your balance to update and try again`, + 'Your balance is too low. Add funds to your account first', undefined, ERROR_CODES.INSUFFICIENT_BALANCE, ) } - const receives = transaction.receives.map((receive) => { - return { - publicAddress: receive.publicAddress, - amount: BigInt(receive.amount), - memo: receive.memo, - } - }) - try { const transactionPosted = await node.wallet.pay( node.memPool, diff --git a/ironfish/src/utils/currency.test.ts b/ironfish/src/utils/currency.test.ts index 3b4ce26099..505097d130 100644 --- a/ironfish/src/utils/currency.test.ts +++ b/ironfish/src/utils/currency.test.ts @@ -59,11 +59,4 @@ describe('CurrencyUtils', () => { expect(CurrencyUtils.renderOre(100000000n)).toEqual('100000000') expect(CurrencyUtils.renderOre(1n, true)).toEqual('$ORE 1') }) - - test('isValidIronAmount returns the right value', () => { - expect(CurrencyUtils.isValidIron('0.0000000000001')).toBe(false) - expect(CurrencyUtils.isValidIron('100000000000000000000000000')).toBe(false) - expect(CurrencyUtils.isValidIron('0.00000001')).toBe(true) - expect(CurrencyUtils.isValidIron('10.000001')).toBe(true) - }) }) diff --git a/ironfish/src/utils/currency.ts b/ironfish/src/utils/currency.ts index cd396d4a54..3bb288a525 100644 --- a/ironfish/src/utils/currency.ts +++ b/ironfish/src/utils/currency.ts @@ -69,24 +69,6 @@ export class CurrencyUtils { return ore } - - static isValidIron(amount: string): boolean { - try { - const ore = this.decodeIron(amount) - return this.isValidOre(this.encode(ore)) - } catch (e) { - return false - } - } - - static isValidOre(amount: string): boolean { - try { - const ore = this.decode(amount) - return ore >= MINIMUM_ORE_AMOUNT && ore <= MAXIMUM_ORE_AMOUNT - } catch (e) { - return false - } - } } export const ORE_TO_IRON = 100000000 From af62ec8f0468a7a59dc79609477dd9bbb1ab816a Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Wed, 16 Nov 2022 16:27:31 -0500 Subject: [PATCH 02/15] Encode hard fork into invalid blocks (#2598) * Encode hard fork into invalid blocks This should prevent some re-orging. * Moved to hard code --- ironfish/src/blockchain/blockchain.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ironfish/src/blockchain/blockchain.ts b/ironfish/src/blockchain/blockchain.ts index 574a5e2faf..c6ff484b0a 100644 --- a/ironfish/src/blockchain/blockchain.ts +++ b/ironfish/src/blockchain/blockchain.ts @@ -63,6 +63,12 @@ import { export const VERSION_DATABASE_CHAIN = 10 +// TODO: Remove this during network reset +const HARD_FORK_HASH = Buffer.from( + '00000000000006ce61057e714ede8471d15cc9d19f0ff58eee179cadf3ba1f31', + 'hex', +) + export class Blockchain { db: IDatabase logger: Logger @@ -552,6 +558,11 @@ export class Blockchain { isInvalid(headerOrHash: BlockHeader | BlockHash): VerificationResultReason | null { const hash = Buffer.isBuffer(headerOrHash) ? headerOrHash : headerOrHash.hash + // TODO: Remove this during network reset + if (hash.equals(HARD_FORK_HASH)) { + return VerificationResultReason.DOUBLE_SPEND + } + const invalid = this.invalid.get(hash) if (invalid) { return invalid From 09ab579b210cc88443baf1b5dd16f7761f68df52 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Thu, 17 Nov 2022 11:47:38 -0500 Subject: [PATCH 03/15] Add consensus parameters to strategy (#2596) Need this for adjusting the mining reward using consensus parameters --- ironfish/src/blockchain/blockchain.ts | 4 ++-- ironfish/src/node.ts | 6 +++++- ironfish/src/strategy.test.slow.ts | 14 +++++++++++--- ironfish/src/strategy.test.ts | 7 +++++-- ironfish/src/strategy.ts | 12 +++++++++--- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/ironfish/src/blockchain/blockchain.ts b/ironfish/src/blockchain/blockchain.ts index c6ff484b0a..71a1253c30 100644 --- a/ironfish/src/blockchain/blockchain.ts +++ b/ironfish/src/blockchain/blockchain.ts @@ -11,7 +11,6 @@ import { GENESIS_BLOCK_SEQUENCE, MAX_SYNCED_AGE_MS, TARGET_BLOCK_TIME_IN_SECONDS, - TestnetParameters, } from '../consensus' import { VerificationResultReason, Verifier } from '../consensus/verifier' import { Event } from '../event' @@ -164,6 +163,7 @@ export class Blockchain { logAllBlockAdd?: boolean autoSeed?: boolean files: FileSystem + consensus: ConsensusParameters }) { const logger = options.logger || createRootLogger() @@ -179,7 +179,7 @@ export class Blockchain { this.orphans = new LRU(100, null, BufferMap) this.logAllBlockAdd = options.logAllBlockAdd || false this.autoSeed = options.autoSeed ?? true - this.consensus = new TestnetParameters() + this.consensus = options.consensus // Flat Fields this.meta = this.db.addStore({ diff --git a/ironfish/src/node.ts b/ironfish/src/node.ts index ea1683a7bc..eb89f07be4 100644 --- a/ironfish/src/node.ts +++ b/ironfish/src/node.ts @@ -5,6 +5,7 @@ import { BoxKeyPair } from '@ironfish/rust-nodejs' import os from 'os' import { v4 as uuid } from 'uuid' import { Blockchain } from './blockchain' +import { TestnetParameters } from './consensus' import { Config, ConfigOptions, @@ -225,8 +226,10 @@ export class IronfishNode { } const workerPool = new WorkerPool({ metrics, numWorkers: workers }) + const consensus = new TestnetParameters() + strategyClass = strategyClass || Strategy - const strategy = new strategyClass(workerPool) + const strategy = new strategyClass({ workerPool, consensus }) metrics = metrics || new MetricsMonitor({ logger }) @@ -238,6 +241,7 @@ export class IronfishNode { autoSeed, workerPool, files, + consensus, }) const accountDB = new WalletDB({ diff --git a/ironfish/src/strategy.test.slow.ts b/ironfish/src/strategy.test.slow.ts index 986bb569c5..bf80c72902 100644 --- a/ironfish/src/strategy.test.slow.ts +++ b/ironfish/src/strategy.test.slow.ts @@ -10,6 +10,7 @@ import { Transaction as NativeTransaction, TransactionPosted as NativeTransactionPosted, } from '@ironfish/rust-nodejs' +import { TestnetParameters } from './consensus/consensus' import { MerkleTree } from './merkletree' import { NoteLeafEncoding } from './merkletree/database/leaves' import { NodeEncoding } from './merkletree/database/nodes' @@ -153,7 +154,7 @@ describe('Demonstrate the Sapling API', () => { it('Does not hold a posted transaction if no references are taken', async () => { // Generate a miner's fee transaction const workerPool = new WorkerPool() - const strategy = new Strategy(workerPool) + const strategy = new Strategy({ workerPool, consensus: new TestnetParameters() }) const minersFee = await strategy.createMinersFee(BigInt(0), 0, generateKey().spending_key) expect(minersFee['transactionPosted']).toBeNull() @@ -163,7 +164,11 @@ describe('Demonstrate the Sapling API', () => { it('Holds a posted transaction if a reference is taken', async () => { // Generate a miner's fee transaction - const strategy = new Strategy(new WorkerPool()) + const strategy = new Strategy({ + workerPool: new WorkerPool(), + consensus: new TestnetParameters(), + }) + const minersFee = await strategy.createMinersFee(BigInt(0), 0, generateKey().spending_key) await minersFee.withReference(async () => { @@ -183,7 +188,10 @@ describe('Demonstrate the Sapling API', () => { it('Does not hold a note if no references are taken', async () => { // Generate a miner's fee transaction const key = generateKey() - const strategy = new Strategy(new WorkerPool()) + const strategy = new Strategy({ + workerPool: new WorkerPool(), + consensus: new TestnetParameters(), + }) const minersFee = await strategy.createMinersFee(BigInt(0), 0, key.spending_key) expect(minersFee['transactionPosted']).toBeNull() diff --git a/ironfish/src/strategy.test.ts b/ironfish/src/strategy.test.ts index e885fac664..d099c5a2e3 100644 --- a/ironfish/src/strategy.test.ts +++ b/ironfish/src/strategy.test.ts @@ -2,7 +2,7 @@ * 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 { IRON_FISH_YEAR_IN_BLOCKS } from './consensus' +import { IRON_FISH_YEAR_IN_BLOCKS, TestnetParameters } from './consensus' import { Strategy } from './strategy' import { WorkerPool } from './workerPool' @@ -10,7 +10,10 @@ describe('Miners reward', () => { let strategy: Strategy beforeAll(() => { - strategy = new Strategy(new WorkerPool()) + strategy = new Strategy({ + workerPool: new WorkerPool(), + consensus: new TestnetParameters(), + }) }) // see https://ironfish.network/docs/whitepaper/4_mining#include-the-miner-reward-based-on-coin-emission-schedule diff --git a/ironfish/src/strategy.ts b/ironfish/src/strategy.ts index 3b5d91ecd0..8f495cd5f3 100644 --- a/ironfish/src/strategy.ts +++ b/ironfish/src/strategy.ts @@ -2,7 +2,11 @@ * 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 { GENESIS_SUPPLY_IN_IRON, IRON_FISH_YEAR_IN_BLOCKS } from './consensus' +import { + ConsensusParameters, + GENESIS_SUPPLY_IN_IRON, + IRON_FISH_YEAR_IN_BLOCKS, +} from './consensus' import { Transaction } from './primitives/transaction' import { MathUtils } from './utils' import { WorkerPool } from './workerPool' @@ -12,12 +16,14 @@ import { WorkerPool } from './workerPool' */ export class Strategy { readonly workerPool: WorkerPool + readonly consensus: ConsensusParameters private miningRewardCachedByYear: Map - constructor(workerPool: WorkerPool) { + constructor(options: { workerPool: WorkerPool; consensus: ConsensusParameters }) { this.miningRewardCachedByYear = new Map() - this.workerPool = workerPool + this.workerPool = options.workerPool + this.consensus = options.consensus } /** From 2dd6c9d9de56ef8401777e5cb1b842ddf39196e0 Mon Sep 17 00:00:00 2001 From: King <40714633+aditya-manit@users.noreply.github.com> Date: Fri, 18 Nov 2022 23:59:37 +0530 Subject: [PATCH 04/15] fix config validator (#2606) Co-authored-by: Aditya Kumar Verma --- ironfish/src/fileStores/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ironfish/src/fileStores/config.ts b/ironfish/src/fileStores/config.ts index da843bf35d..0899efb4c9 100644 --- a/ironfish/src/fileStores/config.ts +++ b/ironfish/src/fileStores/config.ts @@ -259,7 +259,7 @@ export const noWhitespaceBegEnd = yup .string() .matches(reNoWhitespaceBegEnd, 'Path should not contain leading or trailing whitespace.') -export const isUrl = yup.string().url('Invalid URL') +export const isUrl = yup.string().url() export const ConfigOptionsSchema: yup.ObjectSchema> = yup .object({ From 96b599d3b5126fe3763b2c73536176d9b0f7f563 Mon Sep 17 00:00:00 2001 From: Hugh Cunningham <57735705+hughy@users.noreply.github.com> Date: Fri, 18 Nov 2022 10:30:29 -0800 Subject: [PATCH 05/15] adds accounts:repair command (#2558) * adds accounts:repair command adds a cli command intended to fix balance and note indexing issues in the wallet without the need for a full rescan/reset of the wallet. repairs the balance by recomputing it from 0 and adding all unspent notes. uses the chain to determine if each note has been spent and changes to spent if the note is marked as unspent repairs sequenceToNoteHashes by ensuring that all notes that are on chain have the sequence of the transaction that created the note. any sequence to note hash mapping that does not have a note is removed. repairs nonChainNoteHashes by removing any note hashes for notes that are on chain. repairs nullifierToNoteHash by removing any nullifier that maps to a note that is not in the wallet or maps to a note that is not on the chain. * adds missing log message, fixes lint * adds check that transactions are in blocks - if a transaction is marked as on chain but is not contained in the block that it references, fail with an error and prompt users to run accounts:rescan - specifies the command to run for rescan in error messages * improves rescan messaging - reuses constant for rescan message * narrows the scope of repairs in accounts:repair only repair the three known issues that we have identified (and fixed) in the wallet: 1. notes marked as unspent, but actually spent on chain 2. nullifierToNoteHash has mapping from nullifier to note that has been deleted 3. sequenceToNoteHash has mapping from incorrect sequence to note * don't update balance for expired transactions * fixes lint * removes db transactions unnecessary and eat up memory * updates accounts:repair - sets note to unspent if marked as spent, but not spent on chain - deletes nullifierToNoteHash entry if note does not have a nullifier - sets sequenceToNoteHash or nonChainNoteHash from transaction sequence --- ironfish-cli/src/commands/accounts/repair.ts | 192 +++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 ironfish-cli/src/commands/accounts/repair.ts diff --git a/ironfish-cli/src/commands/accounts/repair.ts b/ironfish-cli/src/commands/accounts/repair.ts new file mode 100644 index 0000000000..c1c8a67664 --- /dev/null +++ b/ironfish-cli/src/commands/accounts/repair.ts @@ -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 => Promise.resolve(input.trim()), + required: false, + description: 'Name of the account to repair the database for', + }, + ] + + async start(): Promise { + 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 { + 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 { + 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 { + 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`) + } +} From e435c31da9b71bbfa23f8dc43fec1fdcde052908 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Fri, 18 Nov 2022 15:27:38 -0500 Subject: [PATCH 06/15] Use the assigned schema validation results (#2610) * Use the assigned schema validation results If you use any transformers in yup, we don't use the return value. So we can't use things like default(), or trim(). * Remove uneeded if check * Remove invalid test * Fix bug --- ironfish/src/fileStores/config.test.ts | 30 ----------- ironfish/src/fileStores/config.ts | 20 +++----- ironfish/src/fileStores/fileStore.test.ts | 19 +++++++ ironfish/src/fileStores/keyStore.test.ts | 62 +++++++++++++++++++++++ ironfish/src/fileStores/keyStore.ts | 7 ++- 5 files changed, 93 insertions(+), 45 deletions(-) create mode 100644 ironfish/src/fileStores/fileStore.test.ts create mode 100644 ironfish/src/fileStores/keyStore.test.ts diff --git a/ironfish/src/fileStores/config.test.ts b/ironfish/src/fileStores/config.test.ts index bf85980270..800dca630c 100644 --- a/ironfish/src/fileStores/config.test.ts +++ b/ironfish/src/fileStores/config.test.ts @@ -11,7 +11,6 @@ import { isPort, isUrl, isWholeNumber, - noWhitespaceBegEnd, } from './config' function valid(schema: yup.ObjectSchema, obj: unknown) { @@ -106,44 +105,15 @@ describe('ConfigOptionsSchema::numbers', () => { // Tests the string validations in the config schema describe('ConfigOptionsSchema::strings', () => { type Config = { - s1: string - s2: string url1: string } const schema: yup.ObjectSchema> = yup .object({ - s1: noWhitespaceBegEnd, - s2: noWhitespaceBegEnd, url1: isUrl, }) .defined() - { - const obj = { - s1: '/usr/bin/nvim', - s2: String.raw`C:\ironfish\is best`, - } - it('isPath', () => { - expect(valid(schema, obj)).toBe(true) - }) - } - { - const obj = { - s1: ' /usr/bin/nvim', - } - it('isNotPathLeadingWhitespace', () => { - expect(valid(schema, obj)).toBe(false) - }) - } - { - const obj = { - s1: '/usr/bin/nvim ', - } - it('isNotPathTrailingWhitspace', () => { - expect(valid(schema, obj)).toBe(false) - }) - } { const obj = { url1: DEFAULT_EXPLORER_BLOCKS_URL, diff --git a/ironfish/src/fileStores/config.ts b/ironfish/src/fileStores/config.ts index 0899efb4c9..763f2bd34c 100644 --- a/ironfish/src/fileStores/config.ts +++ b/ironfish/src/fileStores/config.ts @@ -246,19 +246,11 @@ export type ConfigOptions = { feeEstimatorPercentileHigh: number } -// Matches either an empty string, or a string that has no leading or trailing whitespace. -const reNoWhitespaceBegEnd = /^[^\s]+(\s+[^\s]+)*$|^$/ - // config number value validators export const isWholeNumber = yup.number().integer().min(0) export const isPort = yup.number().integer().min(1).max(65535) export const isPercent = yup.number().min(0).max(100) -// config string value validators -export const noWhitespaceBegEnd = yup - .string() - .matches(reNoWhitespaceBegEnd, 'Path should not contain leading or trailing whitespace.') - export const isUrl = yup.string().url() export const ConfigOptionsSchema: yup.ObjectSchema> = yup @@ -266,7 +258,7 @@ export const ConfigOptionsSchema: yup.ObjectSchema> = yup bootstrapNodes: yup.array().of(yup.string().defined()), databaseName: yup.string(), databaseMigrate: yup.boolean(), - editor: noWhitespaceBegEnd, + editor: yup.string().trim(), enableListenP2P: yup.boolean(), enableLogFile: yup.boolean(), enableRpc: yup.boolean(), @@ -277,7 +269,7 @@ export const ConfigOptionsSchema: yup.ObjectSchema> = yup enableTelemetry: yup.boolean(), enableMetrics: yup.boolean(), getFundsApi: yup.string(), - ipcPath: noWhitespaceBegEnd, + ipcPath: yup.string().trim(), miningForce: yup.boolean(), logPeerMessages: yup.boolean(), // validated separately by logLevelParser @@ -291,10 +283,10 @@ export const ConfigOptionsSchema: yup.ObjectSchema> = yup nodeWorkersMax: yup.number().integer().min(-1), p2pSimulateLatency: isWholeNumber, peerPort: isPort, - rpcTcpHost: noWhitespaceBegEnd, + rpcTcpHost: yup.string().trim(), rpcTcpPort: isPort, - tlsKeyPath: noWhitespaceBegEnd, - tlsCertPath: noWhitespaceBegEnd, + tlsKeyPath: yup.string().trim(), + tlsCertPath: yup.string().trim(), maxPeers: isWholeNumber, minPeers: isWholeNumber, targetPeers: yup.number().integer().min(1), @@ -309,7 +301,7 @@ export const ConfigOptionsSchema: yup.ObjectSchema> = yup poolAccountName: yup.string(), poolBanning: yup.boolean(), poolBalancePercentPayout: isPercent, - poolHost: noWhitespaceBegEnd, + poolHost: yup.string().trim(), poolPort: isPort, poolDifficulty: yup.string(), poolAttemptPayoutInterval: isWholeNumber, diff --git a/ironfish/src/fileStores/fileStore.test.ts b/ironfish/src/fileStores/fileStore.test.ts new file mode 100644 index 0000000000..8daf6ec0b2 --- /dev/null +++ b/ironfish/src/fileStores/fileStore.test.ts @@ -0,0 +1,19 @@ +/* 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 { NodeFileProvider } from '../fileSystems' +import { getUniqueTestDataDir } from '../testUtilities' +import { FileStore } from './fileStore' + +describe('FileStore', () => { + it('should load file store', async () => { + const dir = getUniqueTestDataDir() + const files = await new NodeFileProvider().init() + + const store = new FileStore<{ foo: string }>(files, 'test', dir) + await store.save({ foo: 'hello' }) + + const loaded = await store.load() + expect(loaded).toMatchObject({ foo: 'hello' }) + }) +}) diff --git a/ironfish/src/fileStores/keyStore.test.ts b/ironfish/src/fileStores/keyStore.test.ts new file mode 100644 index 0000000000..38248e9f8d --- /dev/null +++ b/ironfish/src/fileStores/keyStore.test.ts @@ -0,0 +1,62 @@ +/* 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 * as yup from 'yup' +import { NodeFileProvider } from '../fileSystems' +import { getUniqueTestDataDir } from '../testUtilities' +import { KeyStore } from './keyStore' + +describe('KeyStore', () => { + it('should load file store', async () => { + const dir = getUniqueTestDataDir() + const files = await new NodeFileProvider().init() + + const store = new KeyStore<{ foo: string }>(files, 'store', { foo: 'bar' }, dir) + + expect(store.get('foo')).toEqual('bar') + store.set('foo', 'baz') + expect(store.get('foo')).toEqual('baz') + await store.save() + + await store.load() + expect(store.get('foo')).toEqual('baz') + }) + + it('should use schema', async () => { + const dir = getUniqueTestDataDir() + const files = await new NodeFileProvider().init() + + const schema = yup + .object({ + foo: yup.string().strict(true), + }) + .defined() + + const store1 = new KeyStore<{ foo: number }>(files, 'store', { foo: 0 }, dir) + const store2 = new KeyStore<{ foo: string }>(files, 'store', { foo: 'bar' }, dir, schema) + + store1.set('foo', 5) + await store1.save() + await expect(store2.load()).rejects.toThrowError('foo must be a `string`') + }) + + it('should use schema result', async () => { + const dir = getUniqueTestDataDir() + const files = await new NodeFileProvider().init() + + const schema = yup + .object({ + foo: yup.string().trim(), + }) + .defined() + + const store = new KeyStore<{ foo: string }>(files, 'store', { foo: 'bar' }, dir, schema) + store.set('foo', ' hello ') + + await store.save() + expect(store.get('foo')).toEqual(' hello ') + + await store.load() + expect(store.get('foo')).toEqual('hello') + }) +}) diff --git a/ironfish/src/fileStores/keyStore.ts b/ironfish/src/fileStores/keyStore.ts index 9d3bb49232..70e3116041 100644 --- a/ironfish/src/fileStores/keyStore.ts +++ b/ironfish/src/fileStores/keyStore.ts @@ -48,10 +48,15 @@ export class KeyStore> { // Validate file store if we have a schema if (this.schema) { - const { error } = await YupUtils.tryValidate(this.schema, data) + const { error, result } = await YupUtils.tryValidate(this.schema, data) + if (error) { throw new Error(error.message) } + + if (data != null) { + Object.assign(data, result) + } } this.keysLoaded.clear() From 730c5a25944e2c50199afaa87b43fde8758476c9 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Fri, 18 Nov 2022 16:16:39 -0500 Subject: [PATCH 07/15] Fixed config values schema (#2611) I also re-wrote the tests because they were very strange code. It looks like this code came in from open source contribution. --- ironfish/src/fileStores/config.test.ts | 142 ------------------------- ironfish/src/fileStores/config.ts | 44 ++++---- ironfish/src/utils/yup.test.ts | 35 ++++++ ironfish/src/utils/yup.ts | 5 + 4 files changed, 59 insertions(+), 167 deletions(-) delete mode 100644 ironfish/src/fileStores/config.test.ts create mode 100644 ironfish/src/utils/yup.test.ts diff --git a/ironfish/src/fileStores/config.test.ts b/ironfish/src/fileStores/config.test.ts deleted file mode 100644 index 800dca630c..0000000000 --- a/ironfish/src/fileStores/config.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* 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 * as yup from 'yup' -import { mockFileSystem } from '../network/testUtilities/mockHostsStore' -import { - Config, - ConfigOptionsSchema, - DEFAULT_EXPLORER_BLOCKS_URL, - isPercent, - isPort, - isUrl, - isWholeNumber, -} from './config' - -function valid(schema: yup.ObjectSchema, obj: unknown) { - return schema.isValidSync(obj) -} - -// Tests the number validations in the config schema -describe('ConfigOptionsSchema::numbers', () => { - type Config = { - int1: number - int2: number - port1: number - port2: number - percent: number - } - - const schema: yup.ObjectSchema> = yup - .object({ - int1: isWholeNumber, - int2: isWholeNumber, - port1: isPort, - port2: isPort, - percent: isPercent, - }) - .defined() - - { - const obj = { - int1: 0, - int2: 42, - } - it('isWholeNumber', () => { - expect(valid(schema, obj)).toBe(true) - }) - } - { - const obj = { int1: false } - it('boolIsNotInteger', () => { - expect(valid(schema, obj)).toBe(false) - }) - } - { - const obj = { int1: 4.2 } - it('floatIsNotInteger', () => { - expect(valid(schema, obj)).toBe(false) - }) - } - { - const obj = { int1: -1 } - it('isNotPosInteger', () => { - expect(valid(schema, obj)).toBe(false) - }) - } - { - const obj = { port1: 1, port2: 65535 } - it('isPortRange', () => { - expect(valid(schema, obj)).toBe(true) - }) - } - { - const obj = { port1: -1 } - it('isNotPort', () => { - expect(valid(schema, obj)).toBe(false) - }) - } - { - const obj = { percent: 0 } - it('isPercentLow', () => { - expect(valid(schema, obj)).toBe(true) - }) - } - { - const obj = { percent: 100 } - it('isPercentHigh', () => { - expect(valid(schema, obj)).toBe(true) - }) - } - { - const obj = { percent: '10%' } - it('stringIsNotPercent', () => { - expect(valid(schema, obj)).toBe(false) - }) - } - { - const obj = { percent: 101 } - it('outOfRangePercent', () => { - expect(valid(schema, obj)).toBe(false) - }) - } -}) - -// Tests the string validations in the config schema -describe('ConfigOptionsSchema::strings', () => { - type Config = { - url1: string - } - - const schema: yup.ObjectSchema> = yup - .object({ - url1: isUrl, - }) - .defined() - - { - const obj = { - url1: DEFAULT_EXPLORER_BLOCKS_URL, - } - it('isUrl', () => { - expect(valid(schema, obj)).toBe(true) - }) - } - { - const obj = { - url1: '192.168.1.0', - } - it('ipIsNotUrl', () => { - expect(valid(schema, obj)).toBe(false) - }) - } -}) - -// Tests the default config options against the schema -describe('ConfigOptionsSchema', () => { - const configOptions = Config.GetDefaults(mockFileSystem(), 'foo') - - it('ConfigDefaults', () => { - expect(valid(ConfigOptionsSchema, configOptions)).toBe(true) - }) -}) diff --git a/ironfish/src/fileStores/config.ts b/ironfish/src/fileStores/config.ts index 763f2bd34c..90c9990bad 100644 --- a/ironfish/src/fileStores/config.ts +++ b/ironfish/src/fileStores/config.ts @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import * as yup from 'yup' import { FileSystem } from '../fileSystems' +import { YupUtils } from '../utils' import { KeyStore } from './keyStore' export const DEFAULT_CONFIG_NAME = 'config.json' @@ -246,13 +247,6 @@ export type ConfigOptions = { feeEstimatorPercentileHigh: number } -// config number value validators -export const isWholeNumber = yup.number().integer().min(0) -export const isPort = yup.number().integer().min(1).max(65535) -export const isPercent = yup.number().min(0).max(100) - -export const isUrl = yup.string().url() - export const ConfigOptionsSchema: yup.ObjectSchema> = yup .object({ bootstrapNodes: yup.array().of(yup.string().defined()), @@ -281,39 +275,39 @@ export const ConfigOptionsSchema: yup.ObjectSchema> = yup nodeName: yup.string(), nodeWorkers: yup.number().integer().min(-1), nodeWorkersMax: yup.number().integer().min(-1), - p2pSimulateLatency: isWholeNumber, - peerPort: isPort, + p2pSimulateLatency: YupUtils.isPositiveInteger, + peerPort: YupUtils.isPort, rpcTcpHost: yup.string().trim(), - rpcTcpPort: isPort, + rpcTcpPort: YupUtils.isPort, tlsKeyPath: yup.string().trim(), tlsCertPath: yup.string().trim(), - maxPeers: isWholeNumber, - minPeers: isWholeNumber, + maxPeers: YupUtils.isPositiveInteger, + minPeers: YupUtils.isPositiveInteger, targetPeers: yup.number().integer().min(1), telemetryApi: yup.string(), accountName: yup.string(), generateNewIdentity: yup.boolean(), - defaultTransactionExpirationSequenceDelta: isWholeNumber, - blocksPerMessage: isWholeNumber, - minerBatchSize: isWholeNumber, - minimumBlockConfirmations: isWholeNumber, + defaultTransactionExpirationSequenceDelta: YupUtils.isPositiveInteger, + blocksPerMessage: YupUtils.isPositiveInteger, + minerBatchSize: YupUtils.isPositiveInteger, + minimumBlockConfirmations: YupUtils.isPositiveInteger, poolName: yup.string(), poolAccountName: yup.string(), poolBanning: yup.boolean(), - poolBalancePercentPayout: isPercent, + poolBalancePercentPayout: YupUtils.isPercent, poolHost: yup.string().trim(), - poolPort: isPort, + poolPort: YupUtils.isPort, poolDifficulty: yup.string(), - poolAttemptPayoutInterval: isWholeNumber, - poolSuccessfulPayoutInterval: isWholeNumber, - poolStatusNotificationInterval: isWholeNumber, - poolRecentShareCutoff: isWholeNumber, + poolAttemptPayoutInterval: YupUtils.isPositiveInteger, + poolSuccessfulPayoutInterval: YupUtils.isPositiveInteger, + poolStatusNotificationInterval: YupUtils.isPositiveInteger, + poolRecentShareCutoff: YupUtils.isPositiveInteger, poolDiscordWebhook: yup.string(), - poolMaxConnectionsPerIp: isWholeNumber, + poolMaxConnectionsPerIp: YupUtils.isPositiveInteger, poolLarkWebhook: yup.string(), jsonLogs: yup.boolean(), - explorerBlocksUrl: isUrl, - explorerTransactionsUrl: isUrl, + explorerBlocksUrl: YupUtils.isUrl, + explorerTransactionsUrl: YupUtils.isUrl, }) .defined() diff --git a/ironfish/src/utils/yup.test.ts b/ironfish/src/utils/yup.test.ts new file mode 100644 index 0000000000..a926f083ba --- /dev/null +++ b/ironfish/src/utils/yup.test.ts @@ -0,0 +1,35 @@ +/* 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 { DEFAULT_EXPLORER_BLOCKS_URL } from '../fileStores/config' +import { YupUtils } from './yup' + +describe('YupUtils', () => { + describe('schemas', () => { + it('isWholeNumber', () => { + expect(YupUtils.isPositiveInteger.isValidSync(0)).toBe(true) + expect(YupUtils.isPositiveInteger.isValidSync(42)).toBe(true) + expect(YupUtils.isPositiveInteger.isValidSync(false)).toBe(false) + expect(YupUtils.isPositiveInteger.isValidSync(-1)).toBe(false) + expect(YupUtils.isPositiveInteger.isValidSync(-1)).toBe(false) + }) + + it('isPercent', () => { + expect(YupUtils.isPercent.isValidSync(0)).toBe(true) + expect(YupUtils.isPercent.isValidSync(100)).toBe(true) + expect(YupUtils.isPercent.isValidSync('10%')).toBe(false) + expect(YupUtils.isPercent.isValidSync(101)).toBe(false) + }) + + it('isUrl', () => { + expect(YupUtils.isUrl.isValidSync('192.168.1.0')).toBe(false) + expect(YupUtils.isUrl.isValidSync(DEFAULT_EXPLORER_BLOCKS_URL)).toBe(true) + }) + + it('isPort', () => { + expect(YupUtils.isPort.isValidSync(1)).toBe(true) + expect(YupUtils.isPort.isValidSync(65535)).toBe(true) + expect(YupUtils.isPort.isValidSync(-1)).toBe(false) + }) + }) +}) diff --git a/ironfish/src/utils/yup.ts b/ironfish/src/utils/yup.ts index 2584ea29ce..a5842b5909 100644 --- a/ironfish/src/utils/yup.ts +++ b/ironfish/src/utils/yup.ts @@ -12,6 +12,11 @@ export type YupSchemaResult> = UnwrapProm > export class YupUtils { + static isPositiveInteger = yup.number().integer().min(0) + static isPort = yup.number().integer().min(1).max(65535) + static isPercent = yup.number().min(0).max(100) + static isUrl = yup.string().url() + static async tryValidate( schema: S, value: unknown, From c577890a4e523b5b10a7850e1598f52ad6905e00 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Fri, 18 Nov 2022 17:11:58 -0500 Subject: [PATCH 08/15] Disable mining rewards in consensus for Phase 2 at block 277000 (#2597) * Disable mining rewards at block 277000 * Add a test --- .../__fixtures__/blockchain.test.ts.fixture | 70 +++++++++++++++++++ ironfish/src/blockchain/blockchain.test.ts | 20 ++++++ ironfish/src/consensus/consensus.ts | 6 ++ ironfish/src/strategy.test.ts | 10 ++- ironfish/src/strategy.ts | 4 ++ 5 files changed, 108 insertions(+), 2 deletions(-) diff --git a/ironfish/src/blockchain/__fixtures__/blockchain.test.ts.fixture b/ironfish/src/blockchain/__fixtures__/blockchain.test.ts.fixture index 5fe733bada..d49070dc0d 100644 --- a/ironfish/src/blockchain/__fixtures__/blockchain.test.ts.fixture +++ b/ironfish/src/blockchain/__fixtures__/blockchain.test.ts.fixture @@ -1868,5 +1868,75 @@ } ] } + ], + "Blockchain does not grant mining reward after V3_DISABLE_MINING_REWARD": [ + { + "id": "29b775ff-ead1-4bd2-b7aa-af92714922ff", + "name": "test", + "spendingKey": "e513465f9213ba0ed31b9737bb6b342cbc954a3484b5e179906a0fd58c5e3325", + "incomingViewKey": "ff4f5e9ac1ec57def4ea77eab0717759277dfaae2cf40821eceba0ed4a8e2407", + "outgoingViewKey": "c92029f3aac586ab97429a57d832717a6d8912de3e2448835b71a822e988cf6c", + "publicAddress": "36a995ab772edf57b8fac3b79a8aae9edd5dfdd60ef82cf035db2a0873b53f4bcbdd5778ca130298b96337" + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "69E263E931FA1A2A4B0437A8EFF79FFB7A353B6384A7AEAC9F90AC12AE4811EF", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:P8rqlkk2exaMxGoe5AmkK2+cj6iv+sUsJNg1bXvc+SM=" + }, + "size": 4 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12167378078913471945996581698193578003257923478462384564023044230", + "randomness": "0", + "timestamp": 1668725306390, + "minersFee": "-2000000000", + "work": "0", + "hash": "6B85750A385456C0B98D544B20BB90D03286E711714B602983E95FE59E11EC29", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAALCa6bInu5vjZdq5Sr0RbOPKfcC3M8vruHIrQEty2HXNxuSROOz8KVeXNBO+qLvr5bcjOHgV/zG2iIXIyHsGZKS00gYJQHlm1TzuT5E4G1A17FMhmtMItZKqa7xY8QBfPgAwZWRtNZURpYeAyIN467q3QOiBvMJy7NXmu9W/4B+SliUBxGswE5jJI8sQMJ8f5oiM3aViGvPipN9L1gvi1g2FIahOz8n9Fx8KUpHg/DBnN8QCDJAbGisxCTuQl0swkFlviJ9hv8p97ehr6Srqgry0j5s1aYT6uuhFnEOOQGfmfReVsxBdwfc6Fq5lCPYNheZhZ3lOmAvLr3aUDSd4lAV120YnuxaG0SGszC5+OKpvHEymPf/eiio90ud/8kD4xK6BCeQdwFtaBdaO1GKvMn1EmtBBldyntyzq0JlnlXQ74wtpNoSr0DcCo9NtGi4vt5vqJVnE/3niFMDazMz1PRAlPya6OVb/YGFqc9DeUaaaWnGgeXvveh25PzJiUH6bRjwUs0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwEOMcafnHkIPx21WcopObHhDUByhVMvO0zVHsjC8W7DGq2veWvoptfMw1kpFWwngiiv4MazjqQFEacO1vn2FzCw==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "6B85750A385456C0B98D544B20BB90D03286E711714B602983E95FE59E11EC29", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:CF6fn1dy7aLLNRzMdTji9hZ2HVKQynk6jrWJC/3Jmm8=" + }, + "size": 5 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12131835591833296355903882315508391652467087441833704656133504637", + "randomness": "0", + "timestamp": 1668725306564, + "minersFee": "0", + "work": "0", + "hash": "975E845A21543AC75161D09386D2B36696029D4C10BF52E8CDF9D52B994C0D72", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAILkVVqXNUC92/giUIjQt7oT3vgm6bu6/ubb3yqqCj8LmZlP5ymkFLnTIXYGjJfelKLnimgKFFhyKbWw/e3ut6L2+Mes6HIZdVrcxLPj4ZzU7yKC2F4xvOGOGvbmJe8jXAlHv4FdVDwcaQb7jls8+oi2Ae8kobFhfAvH2Xdhz6d+R1/F8EfQjMjW18So+NHMgKi06ehmB6FGbXkpfDd5R8N/HwnAqKqUoGdVl7MsTCiyut5XHSxAuFanU8WAECMVfutHRLvTx6TlnNrdjaZNwxdm5XZjEfnfAUrWSWiODG+LLHVuhw4ye4aKpEhdOVHm2uZlad1ONlKlj61TCn4vClYZkkb3BvKoF6VZx8pEdRDwju8Byze00CAkaziCTkCyuG+JUqbuC04oDENG3d4PW6KNCRcgRXlbFFzJLqB7kJ3F9V0q2rFXyrOnKdLM4EYFPul/Rl2QHHM0gITfyK8RKb1k+0XbFbxStncUe/zPF9Er+eUMJw6FxtDDRBAn/RA9HxDDq0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwGpURf4Kdm8EgH1jtft5tPQQtEkCxp7cMK3O75ewIVDL0RIvjl6DUP5d3TOy48aR/ipEjyZS14quSkF+drhL9CQ==" + } + ] + } ] } \ No newline at end of file diff --git a/ironfish/src/blockchain/blockchain.test.ts b/ironfish/src/blockchain/blockchain.test.ts index c9e8d1aee9..fcc6841a36 100644 --- a/ironfish/src/blockchain/blockchain.test.ts +++ b/ironfish/src/blockchain/blockchain.test.ts @@ -1002,4 +1002,24 @@ describe('Blockchain', () => { isFork: false, }) }) + + it('does not grant mining reward after V3_DISABLE_MINING_REWARD', async () => { + const { node } = await nodeTest.createSetup() + node.chain.consensus.V3_DISABLE_MINING_REWARD = 3 + const account = await useAccountFixture(node.wallet) + + const block1 = await useMinerBlockFixture(node.chain, 2, account) + expect(block1.minersFee.fee()).toEqual(-20n * 10n ** 8n) + expect(block1.minersFee.spendsLength()).toEqual(0) + expect(block1.minersFee.notesLength()).toEqual(1) + await expect(node.chain).toAddBlock(block1) + + const block2 = await useMinerBlockFixture(node.chain, 3, account) + expect(block2.minersFee.fee()).toEqual(0n) + expect(block2.minersFee.spendsLength()).toEqual(0) + expect(block2.minersFee.notesLength()).toEqual(1) + await expect(node.chain).toAddBlock(block2) + + await node.wallet.updateHead() + }) }) diff --git a/ironfish/src/consensus/consensus.ts b/ironfish/src/consensus/consensus.ts index c1f13a02c8..3a62870cef 100644 --- a/ironfish/src/consensus/consensus.ts +++ b/ironfish/src/consensus/consensus.ts @@ -87,6 +87,11 @@ export class ConsensusParameters { */ V2_MAX_BLOCK_SIZE = 0 + /** + * All mined blocks give 0 mining reward + */ + V3_DISABLE_MINING_REWARD = Number.MAX_SAFE_INTEGER + isActive(upgrade: number, sequence: number): boolean { return sequence >= upgrade } @@ -97,5 +102,6 @@ export class TestnetParameters extends ConsensusParameters { super() this.V1_DOUBLE_SPEND = 204000 this.V2_MAX_BLOCK_SIZE = 255000 + this.V3_DISABLE_MINING_REWARD = 278500 } } diff --git a/ironfish/src/strategy.test.ts b/ironfish/src/strategy.test.ts index d099c5a2e3..93546c8083 100644 --- a/ironfish/src/strategy.test.ts +++ b/ironfish/src/strategy.test.ts @@ -2,7 +2,7 @@ * 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 { IRON_FISH_YEAR_IN_BLOCKS, TestnetParameters } from './consensus' +import { ConsensusParameters, IRON_FISH_YEAR_IN_BLOCKS } from './consensus' import { Strategy } from './strategy' import { WorkerPool } from './workerPool' @@ -12,7 +12,7 @@ describe('Miners reward', () => { beforeAll(() => { strategy = new Strategy({ workerPool: new WorkerPool(), - consensus: new TestnetParameters(), + consensus: new ConsensusParameters(), }) }) @@ -33,4 +33,10 @@ describe('Miners reward', () => { const minersReward = strategy.miningReward(IRON_FISH_YEAR_IN_BLOCKS + 1) expect(minersReward).toBe(19 * 10 ** 8) }) + + it('miner reward is 0 after V3 activation', () => { + strategy.consensus.V3_DISABLE_MINING_REWARD = 1000 + expect(strategy.miningReward(999)).toBe(20 * 10 ** 8) + expect(strategy.miningReward(1005)).toBe(0) + }) }) diff --git a/ironfish/src/strategy.ts b/ironfish/src/strategy.ts index 8f495cd5f3..c6b67ca0f6 100644 --- a/ironfish/src/strategy.ts +++ b/ironfish/src/strategy.ts @@ -43,6 +43,10 @@ export class Strategy { * @returns mining reward (in ORE) per block given the block sequence */ miningReward(sequence: number): number { + if (this.consensus.isActive(this.consensus.V3_DISABLE_MINING_REWARD, sequence)) { + return 0 + } + const yearsAfterLaunch = Math.floor(Number(sequence) / IRON_FISH_YEAR_IN_BLOCKS) let reward = this.miningRewardCachedByYear.get(yearsAfterLaunch) From 2954fef2f4138f2a7ec5c37b198d0a208a680b15 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Fri, 18 Nov 2022 17:30:27 -0500 Subject: [PATCH 09/15] Fix config:edit --remote crashing (#2612) This would crash because the directory passed to mkdtempdir has a slash so it thinks its 2 folders that don't exist. --- ironfish-cli/src/commands/config/edit.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ironfish-cli/src/commands/config/edit.ts b/ironfish-cli/src/commands/config/edit.ts index 86252ff73e..427b749bc6 100644 --- a/ironfish-cli/src/commands/config/edit.ts +++ b/ironfish-cli/src/commands/config/edit.ts @@ -44,7 +44,7 @@ export class EditCommand extends IronfishCommand { const output = JSON.stringify(response.content, undefined, ' ') const tmpDir = os.tmpdir() - const folderPath = await mkdtempAsync(path.join(tmpDir, '@ironfish/sdk')) + const folderPath = await mkdtempAsync(path.join(tmpDir, '@ironfish-sdk-')) const filePath = path.join(folderPath, DEFAULT_CONFIG_NAME) await writeFileAsync(filePath, output) From 12266d444b7857a66f88225f4110e901273d95aa Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Fri, 18 Nov 2022 17:31:24 -0500 Subject: [PATCH 10/15] Add validation in KeyStore.set() (#2613) --- ironfish/src/fileStores/keyStore.test.ts | 50 ++++++++++++++++++++---- ironfish/src/fileStores/keyStore.ts | 12 ++++++ ironfish/src/utils/yup.ts | 30 ++++++++++++++ 3 files changed, 84 insertions(+), 8 deletions(-) diff --git a/ironfish/src/fileStores/keyStore.test.ts b/ironfish/src/fileStores/keyStore.test.ts index 38248e9f8d..64cc785bf3 100644 --- a/ironfish/src/fileStores/keyStore.test.ts +++ b/ironfish/src/fileStores/keyStore.test.ts @@ -22,7 +22,7 @@ describe('KeyStore', () => { expect(store.get('foo')).toEqual('baz') }) - it('should use schema', async () => { + it('should validate schema in load', async () => { const dir = getUniqueTestDataDir() const files = await new NodeFileProvider().init() @@ -40,7 +40,7 @@ describe('KeyStore', () => { await expect(store2.load()).rejects.toThrowError('foo must be a `string`') }) - it('should use schema result', async () => { + it('should use schema result in load', async () => { const dir = getUniqueTestDataDir() const files = await new NodeFileProvider().init() @@ -50,13 +50,47 @@ describe('KeyStore', () => { }) .defined() - const store = new KeyStore<{ foo: string }>(files, 'store', { foo: 'bar' }, dir, schema) - store.set('foo', ' hello ') + const store1 = new KeyStore<{ foo: string }>(files, 'store', { foo: 'bar' }, dir) + const store2 = new KeyStore<{ foo: string }>(files, 'store', { foo: 'bar' }, dir, schema) - await store.save() - expect(store.get('foo')).toEqual(' hello ') + store1.set('foo', ' hello ') + await store1.save() + expect(store1.get('foo')).toEqual(' hello ') - await store.load() - expect(store.get('foo')).toEqual('hello') + await store2.load() + expect(store2.get('foo')).toEqual('hello') + }) + + it('should validate schema in set', async () => { + const dir = getUniqueTestDataDir() + const files = await new NodeFileProvider().init() + + const schema = yup + .object({ + foo: yup.number(), + }) + .defined() + + const store = new KeyStore<{ foo: number }>(files, 'store', { foo: 0 }, dir, schema) + + expect(() => store.set('foo', 'Hello world' as unknown as number)).toThrowError( + 'this must be a `number` type', + ) + }) + + it('should use schema result in set', async () => { + const dir = getUniqueTestDataDir() + const files = await new NodeFileProvider().init() + + const schema = yup + .object({ + foo: yup.string().trim(), + }) + .defined() + + const store = new KeyStore<{ foo: string }>(files, 'store', { foo: '' }, dir, schema) + + store.set('foo', ' trim me ') + expect(store.get('foo')).toEqual('trim me') }) }) diff --git a/ironfish/src/fileStores/keyStore.ts b/ironfish/src/fileStores/keyStore.ts index 70e3116041..ddc40aafcf 100644 --- a/ironfish/src/fileStores/keyStore.ts +++ b/ironfish/src/fileStores/keyStore.ts @@ -97,6 +97,18 @@ export class KeyStore> { } set(key: T, value: TSchema[T]): void { + const schema = this.schema?.fields[key] + + if (schema) { + const { error, result } = YupUtils.tryValidateSync(schema, value) + + if (error) { + throw error + } + + value = result as TSchema[T] + } + const previousValue = this.config[key] Object.assign(this.loaded, { [key]: value }) diff --git a/ironfish/src/utils/yup.ts b/ironfish/src/utils/yup.ts index a5842b5909..c1d7396ad3 100644 --- a/ironfish/src/utils/yup.ts +++ b/ironfish/src/utils/yup.ts @@ -11,6 +11,10 @@ export type YupSchemaResult> = UnwrapProm ReturnType > +export type YupSchemaResultSync> = ReturnType< + S['validate'] +> + export class YupUtils { static isPositiveInteger = yup.number().integer().min(0) static isPort = yup.number().integer().min(1).max(65535) @@ -42,4 +46,30 @@ export class YupUtils { throw e } } + + static tryValidateSync( + schema: S, + value: unknown, + options?: yup.ValidateOptions, + ): + | { result: YupSchemaResultSync; error: null } + | { result: null; error: yup.ValidationError } { + if (!options) { + options = { stripUnknown: true } + } + + if (options.stripUnknown === undefined) { + options.stripUnknown = true + } + + try { + const result = schema.validateSync(value, options) as YupSchemaResultSync + return { result: result, error: null } + } catch (e) { + if (e instanceof yup.ValidationError) { + return { result: null, error: e } + } + throw e + } + } } From 0217841726615a54c48eb48c875d5663337b72a6 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Fri, 18 Nov 2022 17:33:54 -0500 Subject: [PATCH 11/15] Improve RPC uploadConfig() errors (#2614) It didn't mention the key that was causing the issue. Now it will print out the key with the invalid value. --- ironfish/src/rpc/routes/config/uploadConfig.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ironfish/src/rpc/routes/config/uploadConfig.ts b/ironfish/src/rpc/routes/config/uploadConfig.ts index e59609c27d..16f973b214 100644 --- a/ironfish/src/rpc/routes/config/uploadConfig.ts +++ b/ironfish/src/rpc/routes/config/uploadConfig.ts @@ -69,7 +69,7 @@ export function setUnknownConfigValue( } if (typeof sourceValue !== typeof targetValue) { - value = convertValue(sourceValue, targetValue) + value = convertValue(sourceKey, sourceValue, targetValue) } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -89,12 +89,12 @@ function stringToStringArray(value: string): string[] | null { return parsedValue.map((v) => v.trim()) } -function convertValue(sourceValue: unknown, targetValue: unknown): unknown { +function convertValue(sourceKey: string, sourceValue: unknown, targetValue: unknown): unknown { if (typeof sourceValue !== 'string') { throw new ValidationError( - `Could not convert ${JSON.stringify(sourceValue)} from ${typeof sourceValue} to ${String( - typeof targetValue, - )}`, + `${sourceKey} has an invalid value: Cannot convert ${JSON.stringify( + sourceValue, + )} from ${typeof sourceValue} to ${String(typeof targetValue)}`, ) } @@ -132,8 +132,8 @@ function convertValue(sourceValue: unknown, targetValue: unknown): unknown { } throw new ValidationError( - `Could not convert ${JSON.stringify(sourceValue)} from ${typeof sourceValue} to ${String( - targetType, - )}`, + `${sourceKey} has an invalid value: Could not convert ${JSON.stringify( + sourceValue, + )} from ${typeof sourceValue} to ${String(targetType)}`, ) } From 6d485055a75fbd93f3e4106f7c25bd37525b3d06 Mon Sep 17 00:00:00 2001 From: Hugh Cunningham <57735705+hughy@users.noreply.github.com> Date: Fri, 18 Nov 2022 14:37:49 -0800 Subject: [PATCH 12/15] fixes useAccountFixture to match createAccount logic (#2609) the useAccountFixture used createAccount to create the account in a fixture, but importAccount when deserializing the fixture. one problem with this is that createAccount and importAccount set the head hash stored for an account differently. createAccount sets the head hash to the head of the chainProcessor -- we don't need to scan earlier blocks if we just created the account. importAccount sets the head hash to null -- we don't know when this account was created, so we need to scan the whole chain. this leads to different behavior in tests when generating the fixtures vs. when reusing them. these changes update useAccountFixture to set the head hash to the chainProcessor's hash after adding the account so that the head hash will match what it would have if we had created the account. there is another problem with the fixture: we use UUIDs when creating and importing accounts. so if we import an account from its data, the account's id in the wallet will be different. this _should_ be ok, since tests should not depend on the UUID of the account. - updates useAccountFixture to set head hash to chainProcessor hash during deserialization - fixes tests that depended on head hash being set to null on creation --- ironfish/src/testUtilities/fixtures.ts | 6 +- .../__fixtures__/wallet.test.ts.fixture | 76 +++++++++---------- ironfish/src/wallet/wallet.test.ts | 12 ++- 3 files changed, 53 insertions(+), 41 deletions(-) diff --git a/ironfish/src/testUtilities/fixtures.ts b/ironfish/src/testUtilities/fixtures.ts index 14b508a4b7..423f6d81c4 100644 --- a/ironfish/src/testUtilities/fixtures.ts +++ b/ironfish/src/testUtilities/fixtures.ts @@ -131,7 +131,11 @@ export async function useAccountFixture( }, deserialize: async (accountData: AccountValue): Promise => { - return wallet.importAccount(accountData) + const account = await wallet.importAccount(accountData) + + await wallet.updateHeadHash(account, wallet.chainProcessor.hash) + + return account }, }) } diff --git a/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture b/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture index 813a6db79f..dec5ee85ba 100644 --- a/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture +++ b/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture @@ -131,12 +131,12 @@ ], "Accounts scanTransactions should update head status": [ { - "id": "8ee44142-3dfa-409d-a5c2-21e39f121e9d", + "id": "3c0d151b-54a2-43ce-ab57-ca22b7d85b3c", "name": "accountA", - "spendingKey": "6a3d9df99303acd708da6e9ff0eb0f3029d523a5c7e68c2068ed98b540b1db6c", - "incomingViewKey": "4516a9868fd1e21775db95ca5d936e43a3892243b2bd7a787fd7e85d85f71e07", - "outgoingViewKey": "b25124f391a53e2472ea435896c0bf5d3a624c4b1626f24732f04cbb7f58926d", - "publicAddress": "26063d1e7c95ece8fd1980137d6644d8a661f3b2c673ecaf366a149e10d27622d19b8e9fb13f498730bb04" + "spendingKey": "697f7fe6617f3c65184deab02d180c3d05c81ace4008288214eec1917a688467", + "incomingViewKey": "1f1efc98334f0b7daf49552ac74fff6e605242bc347358e114e922ccd2a73503", + "outgoingViewKey": "22d39f3138b56c310d729bd2ba4f9406fb08e32f73b27c699a07be1318a949bd", + "publicAddress": "3422d69a5b58f5a2bf79a828dbda81bf69db1f0e3ba2ab4f1ee5442a6c4dd955ac3400015abbce3c927ced" }, { "header": { @@ -145,7 +145,7 @@ "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:xy0R/B84AW9aNTqE/tU/amcmbmjh5x929cPqrmtG2EQ=" + "data": "base64:f8LIwv3UIm6u7ftpVjzp9TRK5HC7gab5oqGrrdS1nVA=" }, "size": 4 }, @@ -155,35 +155,35 @@ }, "target": "12167378078913471945996581698193578003257923478462384564023044230", "randomness": "0", - "timestamp": 1664904614749, + "timestamp": 1668789736249, "minersFee": "-2000000000", "work": "0", - "hash": "456FCDFE78AC7BC3A3EEA654FA7D50FDCB63DB70D38F251666987B77F014B805", + "hash": "C6830C15EFA0A3DD53CBCEECC431D3BAFA2EE74A7197436670B7CDF759131DC1", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAISg9EjKHjJ1cF0MPDq2Td7POddfP6IWkC/4vPLM0Rcxbp3rLfLrBeM2bc8qsnyBkZW90Xcx44W0kWxnamUQyUTkg6vd7bPzm46F9kYJjYjWU3oyJG/Ly4SI4HYgOoD7uBGUw3gcb65lXnTZzncjRZscGXCXzxhFeP1hUbIsT0gXUG7jfLOO3BeagdLYkuYemJOwKVHHxtafQYopkknfHWrYxk/Kn7JWRsWP/mXmIwsL8s3Tv2WJpfHaHkW3bcNaMWcskigwjNwc7DTkTpG0lhVsq3cagZ1M5TqB/GqEf0NY40yOxqAqoB1GNly7AO+sYbyZ+Mtkhfg96xesQIN1TURf/cj19rcf9xZb6F1HR2mrBUEUb/ToJ6r9ivkf26qXALjREQmScUJVOwj4lkxBqK2JGHTqxYfBuaWFFKIcJCSeS6Jep4h3VwckDj3UWBVJjV3PyelJ3uBcEdWmRhKt7+C9sWGoXS6WZU6DTwXQgjsBhry+MEn73d3ro/5XbifO5a5SKkJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwE5g1f8oXsRUxL03cZ9c7m6tvtUwXWjzD4IQsoXd4YLScEKp2+eJXBT9HVfMd/J1cNPGeF2VlIJN225mHJTjdDA==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAJUnWLbIssOrlW/E8nvK9iz4+4FVGW4XECacLfnq6Lebr16jndVNZFDrwxMbRESN75Vgejbb4GQ+rGr8bb7+jJ/qnMipTjHTVHzWj/Lhv4MsZYTQE6FBo7aKfwBHnwRZ5QvTaSIIzdpl7I9sfvPND1qozxV5uEBPDUPKA/YbWVtdxY3fnLCtYlOJ/CFXp49FjYY3NnwQYcN5VaJX0mjlLJwieK7Y8vSe3ktcWEARkmR8b6osY6MD/ADG1R0MTTPgJKUwFuHCdwauk//SXHnlfBw7z7bbA7N6oI7Wzl4ML2bW56lijJhrjYvaaPvzd+wgefXmTQo+eeddHsTkl+b5zEtqqF0m0rUyxZ7XuwNR3voNsbntgQ+gdmQ/hi7l20OQRtQZmOLs1S5ijEB4dZZZ/ijie+FmZ/MDONZkw24+Vfwr71JL/JT4bMRo8Ttk3lVRBuFd5RBtA9MRPEC6j8wbmjmKpq5h1wmr0Ad/RPkRBoXFxlsrkwPjiSjYjaCN65jZsVMcMkJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw7wmI6zNEUVXK/I0G4lGVCCAjg5FsybxPymvKa1Gn5ISJiAxftvhjoyuho4EOjdQVAqE/v4pVC0grOC38kBrbAA==" } ] }, { - "id": "bdcf2802-b188-4eed-951f-d5e9844f48a7", + "id": "12e2f5db-0b05-4282-97a3-0f536dacf858", "name": "accountB", - "spendingKey": "ab2fcb4707d1ec9802d27596de909093b84242242223651742a4f5c2e916e010", - "incomingViewKey": "90a7c9cf7f93d6280ae63e254213822d1aac3cdfa2c004cab3bfcaf28284f901", - "outgoingViewKey": "46f1b968b5404c0f98cbd25628eab2a6d7017a13c71e926b2057446f0b58eff2", - "publicAddress": "b143ced5708cd709fd11eb27285c7d5b5e67d5a64ebdaf56d0139412905ea1b78ae136481d9570a7d0430e" + "spendingKey": "0399edd5b941a82e09e2c887c8a19f0b2b546febba4591004a605cb047566288", + "incomingViewKey": "a6c8b838c4c3d61465d3ad76b8db2bc9f7ed776a6a032de4ac83907e90530b03", + "outgoingViewKey": "9d8ccc086d0c1518419c62073834013a2f8548920f685f239b57a508f61dc40f", + "publicAddress": "3f0ad6a112bbca6a462015028fd2b9bc4d22637c3b3a2adeafe31bf666c9579ad4c5bfddb221178caa5dce" }, { "header": { "sequence": 3, - "previousBlockHash": "456FCDFE78AC7BC3A3EEA654FA7D50FDCB63DB70D38F251666987B77F014B805", + "previousBlockHash": "C6830C15EFA0A3DD53CBCEECC431D3BAFA2EE74A7197436670B7CDF759131DC1", "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:4Kl/2w/mmzFwiV2wLrasdHAqocYPD8Q0ViGw0Nt0eV4=" + "data": "base64:azvZrdvk4LSKPFi0KUqXTNMGqhVmB/inRM5dQqnQXT8=" }, "size": 5 }, @@ -193,16 +193,16 @@ }, "target": "12131835591833296355903882315508391652467087441833704656133504637", "randomness": "0", - "timestamp": 1664904614977, + "timestamp": 1668789736555, "minersFee": "-2000000000", "work": "0", - "hash": "6CA2A7B8FB87FAEA6B83372D159F30A81B72AEBD49992CDE57EBFE773CB6768F", + "hash": "B93B87B040C20BF213423BB558DBEF16DFD79B5ACD7B6E57E47BAB08B6B8A471", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKY9z7fvbYcLZS+yWH4DvhL1v3fMnUQIACpSNzvCI6CbTZiP4MbCbLcNXC5LfFtuaIn996BZFAmnH7xHyC7YH9waWgGwwogGGjubZCrximP/lx8+2cXNuLb7TP+zZ018dxGEWBNw4r2t2FAIwp5t8DcHVLAVbU0BDy84kT3HTO00+WO0H04Z9JkAp5RW8R9WjITafkaAo0SKIPtFdCgTjOCw3tXT/uF02tyhuekuR+G+skhU27Dn6P32VkR0WiJabXJSAP8mAcVv3lSIR3VZ6B2dTwI5yJDcASqtiC/M6ebhs0VAQ3XOd0scI+5J8byn/RKaI1fcLpOsry9OaeWwMGt+J9t7T58XgZ3yn0/uqbGq4jVT3TpWeB24k/EMQkGmyQS+pz/Twh5wXl8m910ZKtwM9s6NwjbEDurdbBcQvyc6nqRiRoMz/gw2v2IWsKGMrG0EhMeLPAatruDlQ6fy8IEBaY+5UM2LJHtu0Hw5VcKiWVCdTN+NjjJBpWmumQfi7Ug0nkJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw9eKq42/6b4cmobAkGsX4puK0Jqi63crEoK1hHMJ1Zc3t9VyMhaao3eBwwLA9H7+TDyoo6g7xNUM/u+HtKn30CA==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAIz+9BUPBwSG+YVTI9Dh0EVlYhZrhg71k1rFXZ2SBFNV62kHf64lS5xEA3UunnN3WJTBqY1LT2ocaLeA6VJZVE9rb5+swVBa4YUow7RxBVTweS5LNkwKcRInx0/VZt98RAAhuTPma5QvqA/eGPK6Y+63KJmZwWdXpbzXUCKFzWzObv2mUi0zOiYQfHYJvjCQIqymHnEjdrCX0Z5J3sB6AJ0ism5214h/V/YW1cq8etDLxhIxIHfwzUDAT+iV8FcfqHZuhfYScSFk3HxtBTWa9uDWfxpAHy+KDp1VKXsQCWa/b4Sam/ymZ+bcChL1uLQv6VoY+Zyix4sE0F4rLzs3a1q0VgG+fS2hnijU4ukQEy6xp9wXxyDD6S+Muf4WjYJpyEvcNH3j3v97wtNOAIi6Kbm6xLfzbIBKIS5Zezsz9eOBKtwiMaBYlD09GpI+GUUItmifs+cBKVaOpDxnk9Pyq7raZ2/ni5uzfhwdfT3xqyPJIWVZW6VZV/0AklDUK8vpBBVaVUJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwq1FfWK1+aSnvzcoIrJYDxowM309NsBvD9aPuft0mrUIsCxYrMZ4DId3QQPXZktDvnkzqR27IyvR7m8ezlEoTAA==" } ] } @@ -755,12 +755,12 @@ ], "Accounts loadHeadHashes should properly saturate headStatus": [ { - "id": "c3090b6f-b2c2-447a-8e4a-6e0f7d3c7515", + "id": "969b9483-b589-4e3a-9db9-51109d56f1ba", "name": "accountA", - "spendingKey": "57d76051f95c20389bde635f22ea6560736b55a6881599464faf4f5aaac143e8", - "incomingViewKey": "2df39a6ce9016474075ad1e86c2b6256973df5499edbcbda29233f573463ca01", - "outgoingViewKey": "e8dbf6d7216d3283802e5ecaeba8d37e5afdfa64b19cabd2a285c366329f1008", - "publicAddress": "cc32490099cf219c2107517ac2f6302520d52f400d0254a3bf4bcfccca4d1b4608b29ce052348805c9ef02" + "spendingKey": "7241ccab63c24998e6bb255d16f3dca243ba69e9f93f11f28189d7182be17599", + "incomingViewKey": "0f838f4022dd350c75e7976f9236281167851f2e6e4e38c366b74813ce1daa04", + "outgoingViewKey": "da7b7975d9f004e2f4c84a24895d9162f23a16a93b7fe860560f8675ab8e9420", + "publicAddress": "0e723c28212a798edc9bb4be944d23c6f26a3c0ce67b342de335a304ceacc0a5e88ffcb8aa2152449501a6" }, { "header": { @@ -769,7 +769,7 @@ "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:ieixotzRnyTDOy6uH3FcBbRkYP+GPkvGyK3oHwBochA=" + "data": "base64:ii6R/yZCmJrWnp8sRm+dlJ3uwezNYojfFlZofnWt628=" }, "size": 4 }, @@ -779,35 +779,35 @@ }, "target": "12167378078913471945996581698193578003257923478462384564023044230", "randomness": "0", - "timestamp": 1664904619315, + "timestamp": 1668789548886, "minersFee": "-2000000000", "work": "0", - "hash": "28B45837967B656DCF2FDD138A508C82881287593FF5AADBD160143E4FA81D0A", + "hash": "4C86627AE81D6CBE3CB0AC68890B78C5C20B4F98935010B9D95ABB508B4294C1", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAJnDU4OFhfS1Gt65a/Sc9vB91hTRlae3cz0nNUJJmpPA+kjTiNwdgiyWyJ4yWFNFp6ZmycP1k1NI6WxxFdRUBKW301Ajqc3MB45fFlzLpEf9vV74YLkJFxLXdzbvrWVLhhL2dSyG87PJIqH6mdLUCu7Msl7iY+I6soT7kgXKgATP7eXKcE/35T/J48YVMEeCVqOByDKwtFJ+ALST1E+fAQyszq+OTjT829oSW3RQz11QsvuPQWqqLEPiLB3RKqvOqOflWYjLpw/UZjifmm0aQvJCORJqxCgwhN9NOTOUCWHjTJ34myALXjEvzmV36SUsmQXo/UeSYXsaxs4RCxJFXVzFchgvgXm2rcKb5lfPgu6VKw+UOm5xHfvv81xNjcpfO7mCoVssQObXgj39ltWoT/yayERYrigFqGLdWNFYfTOWJVaOfLLUwI0+InAoeJbjyYHCOHeCm0lI4N9VDYRhZfvj64+45+s3MsVQ5mbtbUJtK+EL8SJmQ+OorLteYmWQ3ew/cEJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwu892hDBP8GQmhsi4j6LAGeORyJmLsdh8rvh69HXCvLuIfFvRyCsqcY9ICIL8GQhQZcRB39ak1PuLogLWSmXUBw==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKQY6d+3dySS7rnmxpIwogNZAr8V9GwvmYfHzuvfzS5Y7MWfc27ak/lLcws7c1S+tJDwmVN0mfhstptu49BeGld8r8R+4c6ZUyrte+/FXWHHI+c4czr2GX0Avo5GE8akdguxwnldEXJeH1q+6OD01jKU4PXtJhXOuhH97idTnX0GfPpwFl3ibK+bNhTp5/1njJRyDRlCwrh6h9oKJBHiGCOjtZCxSrAdZBRUg0Cv9XY9XphfH+M51Njr6AhRd+vlvW2MboWtsbq4ZBUVlcAFYq87pg7HzYfuakST8iUS9oPnWPD1WX+ogncQMGi+aLBk2Ou5FmGjWWcMApGwTWXuIDSzkYcsKm/KzOlN5OBqE+jmrBABuTaJR2uTb+ZUswcPpXOrRkhc5L5Uh4DC9lx7Z9LSrbYUwJ87RlwghKqpq6HMFKeBCFzqZRReW0DerV+piM/GbFrIYOlL/jy2dH7gkBsGoHzq/AuxPGHuRdChTeFAn/7uzL97MHGkyjsrh+gQacW5QEJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwZjnXXMCL4YCQN9zh/fFNC5itrbIyd2swJ/sbff4yJme5Wx/bLWKQ0gXdZdqtKi6m1Ij2nHUMcZWRF6lPSv2sCA==" } ] }, { - "id": "57ee69fc-42b7-4a28-9da2-2b1e54cf6e5c", + "id": "954c9249-6e29-45f9-89e8-8bdb70dac32c", "name": "accountB", - "spendingKey": "71117a5a9e15e6198d17e13a8231e7703a3813477981189ed751fc5cd01982b4", - "incomingViewKey": "8f150e801ce93f974182b41eb2b8dc3343596ad60320468e4efd99a69695c406", - "outgoingViewKey": "93c4f59f363fe271cc4831f707a74b6690d5e38433b3e3125299e7af5c3e3ca2", - "publicAddress": "1ece944a9f53edca1041cac2fa486fd541574ef6598a189500848bde4a22e95b6a5a12e1aa2dff96c9074c" + "spendingKey": "dc06f20189f795f678da6c24c2fd1b65403f462cd84021b40cd3a0d3c1d4de7b", + "incomingViewKey": "f32b6dfc57e7aedacf96905ada064090915f3f0cc76826da6a71109e7cdb9501", + "outgoingViewKey": "f0b6d3dc2e16418a05df2b9ce5847e2f39c6108eb840c21aa935d109393b4ebd", + "publicAddress": "08c61e88dba7f54a764ed1104e3d4dce316ca573bfd619526d0247841a3fbd87163fa742c3509d0615cfa4" }, { "header": { "sequence": 3, - "previousBlockHash": "28B45837967B656DCF2FDD138A508C82881287593FF5AADBD160143E4FA81D0A", + "previousBlockHash": "4C86627AE81D6CBE3CB0AC68890B78C5C20B4F98935010B9D95ABB508B4294C1", "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:N9vt31UHGH42NBa6GtMcuO2ortS9IPNDkjrgjCbSNxU=" + "data": "base64:dDVGmtCyUR8Duu4mukhUt+VuOIhm8cTT2qNiB6qMRBI=" }, "size": 5 }, @@ -817,16 +817,16 @@ }, "target": "12131835591833296355903882315508391652467087441833704656133504637", "randomness": "0", - "timestamp": 1664904619585, + "timestamp": 1668789549191, "minersFee": "-2000000000", "work": "0", - "hash": "5E4020F1C688BD7571F20DD6BE60E588839FDA1E2B979BB874D94AF4CA0812A1", + "hash": "E0A03CBDD3A735227822BBC64E2255D613A142DDD344338EE027F83669A500E0", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKDSMisKnqmAjroVMV6giYwbwiRMeHaDYtriNMv1PU5+VdCyFD6fdRKdyjuHid6TF6M2GtljVv6MjeycGdbgaKBWKh5IHTXv9aXMSBSM1ty0Iz6nscmgWs8gtCp5dJ6gFwBx6GvYouVJgV/F17t6/336x2RHkH5dmkdRzJqjmVTgCUfDyGbSbHt17eEfH/J8drRoPQ5BnNRGnh+ZWQaHyhx2ubhWVI3I0Lq48ndKgAuvhAE3fmSGSQcQJJ8P4zco0QKYBO3nYOuQdVDa8mWKRSqUA8AN7RZISzNp+2R2/e6DJDfkUIv3NnZuUqhuv1z85VUb3vSVqPj7fBpsMKMZk0On/e/2dBdiaTxYyf65bzh+EKwfIDC1WyzI+danD6FImVjS0s4lBsDhV45q1ffVQtv7/oFey2uu0ATtR3KSZICilTFoVpZ7qkAo2N6HgPZJeFokhu3rW0HFl8HwSsEAt6XQe7hnRUcvq//ZdNjuC9UJQxuefQlRxJTMP7kJ7bY4xcSS/EJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwn3prcrdS6IYy1wUXj9ni+ypszTwZC+RlzptMKpyTox/iGl20KDqNRh9/uFOelQSsO2XyQlwqzJVNYNPWuOw2Bw==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAI/k7SCFJFSqP3u6ke5Tl1Mm7t4yJWZrdIIpugIUPD/5klHqozmoTOZX09hB8z04OpBiWLPEtGQhYhhXKQ1N8QVMEQKAVyaavQteBqpBeDZL9X1Qlh2hBDF4ot9CZaAWiRVn1MTOPuKVTZCPZR/+p6opdxEZd+iE5QV17I7CZ+JyrGlcQt7RT5nmly0y86jiFaIpOLXIHm633130LYVqjRlE3o5E4SZDCN0vcm9shTC8UI8JbsRs4u1d77EmF2ve2RNFAtsIVw/xEisA1v368amtwZb8MNKS9m7seJ2Mwv1vWGaql6mkov2hkDRlw1JKXaUL8EPJBTyJBiR2uYYvVykPmVIFiSf8iC1uNED4CpZPlpKPl3jU8UlfCi3cBwGtiCGHYt4jT8evC0ulpNQUte3S3PmNPahzmvDmFiZ4UAuSjIBJJ3I3bGlMLXuThLy5XPJ8BgjiAUTPqJGJ3rMb6DlDdsVRdaMKuxFEDaUutTfC3I7LiFdjA8ldlA6KGvt8K2SUw0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwSBUIX4abDP9W0/BGbfbyFe8rFqR0JKIfZXhXA60gPNyh4vJTSXnoMVl6Kqj3oJDtUGB5Ls7nCTSTYYrGxWmqCw==" } ] } diff --git a/ironfish/src/wallet/wallet.test.ts b/ironfish/src/wallet/wallet.test.ts index 7df86f54e6..3df70f9779 100644 --- a/ironfish/src/wallet/wallet.test.ts +++ b/ironfish/src/wallet/wallet.test.ts @@ -307,7 +307,11 @@ describe('Accounts', () => { await expect(node.chain).toAddBlock(block1) await node.wallet.updateHead() - const accountB = await useAccountFixture(node.wallet, 'accountB') + // create a second account and import it so that its head hash is null + const { node: nodeB } = await nodeTest.createSetup() + const toImport = await useAccountFixture(nodeB.wallet, 'accountB') + const accountB = await node.wallet.importAccount(toImport) + const block2 = await useMinerBlockFixture(node.chain, 2, accountA) await expect(node.chain).toAddBlock(block2) @@ -466,7 +470,11 @@ describe('Accounts', () => { await node.wallet.updateHead() - const accountB = await useAccountFixture(node.wallet, 'accountB') + // create a second account and import it so that its head hash is null + const { node: nodeB } = await nodeTest.createSetup() + const toImport = await useAccountFixture(nodeB.wallet, 'accountB') + const accountB = await node.wallet.importAccount(toImport) + const blockB = await useMinerBlockFixture(node.chain, 2, accountA) await node.chain.addBlock(blockB) From 8374ef1d69ad7cafbfb32b691445f60c97fdc757 Mon Sep 17 00:00:00 2001 From: Hugh Cunningham <57735705+hughy@users.noreply.github.com> Date: Fri, 18 Nov 2022 17:35:32 -0800 Subject: [PATCH 13/15] Fix/sync expired (#2617) * avoids re-syncing expired transactions in wallet if we receive a transaction message from a peer for a transaction that has already expired we will sync that transaction and add its notes to the wallet. since the transaction record in the database has not changed we do not add the transaction to pendintTransactionHashes and it never re-expires in the wallet. this results in the balance updating to include notes that do not exist. updates syncTransaction to check whether an off-chain transaction is expired before syncing it. if the transaction has a blockHash but would other be expired, such as when syncing during a re-org, we still sync the transaction. adds tests of both cases. * fixes tests of expired transactions tests previously relied on creating transactions that were already expired --- .../__fixtures__/wallet.test.ts.fixture | 448 +++++++++++++++--- ironfish/src/wallet/wallet.test.ts | 154 +++++- ironfish/src/wallet/wallet.ts | 10 + 3 files changed, 531 insertions(+), 81 deletions(-) diff --git a/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture b/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture index dec5ee85ba..a71bc01ef9 100644 --- a/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture +++ b/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture @@ -957,20 +957,20 @@ ], "Accounts expireTransactions should expire transactions for all affected accounts": [ { - "id": "6f43737c-a6e0-4e10-9854-1938b22ba12b", + "id": "597dddf9-7d06-48cf-a290-ca83dd0cd46b", "name": "accountA", - "spendingKey": "208318800506734d6cbdaba79ddc4f017f4d3ff545db161ab6f78f9b46cde2a9", - "incomingViewKey": "3ff72fc345c78c7afe7d9ef4f8d888fd9b9f7f702320fe648bea314d7affe604", - "outgoingViewKey": "1cdf6db8c25584edc6b8feb876d1d6959981ea977b8c63c07b56d2d650ab56a5", - "publicAddress": "b930d40866a9f503acdd5c7fb0d8d52062cae104f3102f9de04ccc25f79bf6a0f1347443bdacb4d6afaa4b" + "spendingKey": "4071e41cd2b305a2542da6b86ec1f22777d2fe3a384f858c992d122f91ce7d11", + "incomingViewKey": "75618a5104e0c0f3a1038f3cd48413b09b61681b45e739dea6d4aa4b12581907", + "outgoingViewKey": "f461c3231d55573ea20a93a7f369b39914cf5680b2ee74db0230e2b3b492d4ea", + "publicAddress": "2458afee28b59b385186d752fc210ca46efb6c52ed725b5e40b2d3b64e0379eaedc3425671308a769bf523" }, { - "id": "c01578db-fe60-49d1-bd92-82455fa4d32d", + "id": "daf2f9d0-f568-4266-94ed-96a7ba0d0d42", "name": "accountB", - "spendingKey": "1d0821ef5f6fb751954fea048a959c3da33d39711c1388735d642e7363f19726", - "incomingViewKey": "1243b930df1df6e8e575159b0ac980713d818e65b09399a8397dd8bd81582c02", - "outgoingViewKey": "4f0fa40709891be0b82b74eec434d669cbc29b61b9abaf50d62215dd051b34cb", - "publicAddress": "7af0b1d19c68ac26a8cf335ee41677f538f762a73405283b6b1ca3f5afd67b15077333ce5ff18f34c62e35" + "spendingKey": "d9592d430f1687153662845917d605ad580782d7ca4127e07fd531e1012cd99f", + "incomingViewKey": "89d771f772094b40c209c51adfcfb49bd0a762b316dd032726c8a23a3efa8500", + "outgoingViewKey": "01b272a19f9d61db383386346d5b4e18ddaa2efcedbf874f805ee1d45ea73f93", + "publicAddress": "215e436fbb76db30ba7d9a3b63efe750334b35c56d82a69942b613dd9cbe3f9c08f5bcfa4d4cfc772df765" }, { "header": { @@ -979,7 +979,7 @@ "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:oFM+O858O4/dbut65FiHepvzrBl6+dUG4+KX25DVGCI=" + "data": "base64:WFPS4RAHuXMvB+rXVqej9pbG5PmsIVK+pVX7VLoo0ko=" }, "size": 4 }, @@ -989,31 +989,31 @@ }, "target": "12167378078913471945996581698193578003257923478462384564023044230", "randomness": "0", - "timestamp": 1664904624515, + "timestamp": 1668626721258, "minersFee": "-2000000000", "work": "0", - "hash": "87C8079BE7E4BCACBCCBC51BE89D4639A1900C1B7C039CB1348D127881CFBED2", + "hash": "205E4CE138ED4B660A4584BF5786C5A402F83B099D9219031E9DE4CA6702C8D1", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAIP74bl5suPEHSS7+A+Xjhj0dH9pEjOR041OLgik7eCOVSvMw8GBVkMF61a577xOtY4UfJqwXJm9gk2EG3HAMpwZ8W4ARyOdPxp2scNERmn/FvTmC/bJMKZaheNQOIJ2SQKgWFcEp5WzcRxz7BGYdY3a7Xny64zirgoI9DMUV1HjrQIRqUi/0xkQAmec/fpezpD6jWnTjQhQ1glLedtV48nhwmK159OLyc3Rx4cRQg/ZCzASC8CfRE0Frm+anRwMLlWFbQTCPEM4sUL/fOcw7vd+V0GEa1qbLeiSUFm01DzwVDU6K1i/+v6R7RWQDGS4JZiM29ztZxa4fzuJL8piFmme83aBYrZeweqcgY6UeUALOpOpH4X9PpojVEXVxXpcELYNSKle0CRGjZpvuzSaGad5y24ewlX2PtfBb8Q2jEAMXBCRIH9/Bp2C6e46ANCxjJcyWoEhhTzOxctXQRPeg+J7cJRVX22uP+Ea7BiGzYu6pn/LEMiLWpn3XWzitMLIFADkX0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwFqX9ev24SNR+PI51M/bwkVJV8aqcAvL3OBNt3hQQCjrA2/uzENUDQnQbkVqQOTbbf4HFjhsz/G4eD4U6XhF7Dg==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKPxQYdx5bO/cj1q86S1YcpQiDXO9dxt082WdpZulgtb94rFIq5H/sY++qQmB/L+ybUUSuvEPYcYqi80bYhIoVbQyKZTPsoDnTPmWGkcKxl/t+EIrZZo30qXj9mYvJ+yMxHN2AmABWVePCGCrmYsOfeugvn2rP/HFG+0R18u7m+TTYZ3LmB/QfGvgLdyylsEWKtBeQRwP3q7aL/PSW+ZpTRr0lmRSxkqRa6bD9yXFYA9hXmafLEAsz4SsDyRWkSkX7uOFcfLFE3/FzOMB2qgaXmCjQSqKUMNfPXfk4aaDUk/1DEF5x6gHEHb1L3RWhq8DdxWWBuCdRG/sg0AoLbuxAp6+BtIxNA37NEA1u0uHgw74QJqisq56XqITCojgH4Q44sG/oN0uGyQumEu0DdzmfjGdrkRa0vBkOZ+gOzaDIl+vIRFM1UnGSKpJo625vvcvjDl4+NwoCatG9OyBjfXVNwL4zRSGgim7qUKygGKLwBZadKjh+OP7U4ONnen74xcWnF+nEJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwzQuiANhRltBZZkXYzV6HOFOKcoiZ2RuSn9ydTivtPLO5vJk9GLz6JYmlw47EUIbIUCroXQM7GiDX5/qpJFxuAg==" } ] }, { "type": "Buffer", - "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAQAAAJdaF3twTwjbkx/PuSdYcg74OKINGCU2+GhlrEWjWdRQjjcd6I/WVodKQOv6W8bQ57Nh1X7giHgEDTqyz4TfDvC0hFJHjQyPO6+Qtozvv0Yc5ceLZGXJnrRb5mj7CBSdVQfP2XjG3Sigz7Z3w0Evn5CDAdWGePf7GbYNUZRsFx1sgFqjPCHpoxZGY+5uyupmf4Uh7bi1BOAJWi68Yz/uFiA2dIdrIf19tyiPhGSJkhlYaqrvzUHMMYIZVEMJaRWoJP9XGT9vvUfUeEA0cSfhqDo8C/ja0s1283U0ekd01hHra9mbGRhBCSE5jUq/n9We+SZOAlmq0rsnNELtLspLi4GgUz47znw7j91u63rkWId6m/OsGXr51Qbj4pfbkNUYIgQAAABrG3oZMEGFK7cK8hR+9xet0aHwFAZRBb8EHYDmV1IcxfBN+iz1XI9Wu2oLRBAgZb1l8a5DinmYv+gY9gC2QxTyyxAolIplf4JuqK9RuAIqeWaVkSKJz7ReUTSDzVhRlwSwUyHM8R+0xk7Wrz6DelrsxV+iKirHmv9HQ/PCha0n2qs37E5nsgIsFTXkHSL0UdGBPDS+8gX+bxfPbXcrXITHi+VCOEyd5sbCmUdHP3AQDx9hHgLeaXVfL53hP02BJkIDGpi4zC4GVVJ51FZ8wW+aai+Evae8ytnPlp09R9JjCmoKDMOWqBTojAUfsUwj2iOjsnpVFDa6y0+P8CUH3oBoJCQD+aheM1VjD6DTz5nE/5YhV7dydF302gd4WrCdKvGa6g8Jfxji4x+71UsEWl00KklFKXtOTrpTvZVQUaqrHKAsgOrOw8bfdGn/ELfGj9yIBbtI+W4zqsJd6xeJf19Vz09AP+ZKNlD76Vb2pU0FDwNYwRtTsdt83DEuTtWxQ8x5SDLMA8IM/+L5S052MwfuIP8kcNaVNJ1wBTA901GtSYa6NCc3Xm22V5O2H4f1wKQniZL/Rvih7bdD89hE0FldrZ4DOfjPcgQa2jWQsiGGYTkTKkO+xnt2SmDhHZOV783MEE5ddsoPV2Xbo2ziX9FjBdIMf7/1+horiAk5vQrjXTgq2RtdexQK2FPsE+urFAOaOCOwRHoy2WWK2/4bNl/DR37ONJ/SSQvgx5VsRwYp7Crn5aTHz0y+4XMBFVEsaWI9VFruZhChK2XQjJLU4c7qriBq5sb30iZnSUfvhOd3mzn+qa+itg2hAov+zFhFGiVsRvnZny9h5ZgIn3qIsmq9SIPQx4bPu3yiXCAg5nPxo287FgsQQleM6rFetaXzIvft+pVUX6HM6eNjrTMgu18uuEELv1QpMOWmkkIN5xmQdBGxXaAd8z5yyGnxrirhyAHCXVwW1tkA/36D4SY7VHS5fq2s7cqY2LmIN9bm6a3Fk+tmpczappcfUcM1I6bwfX6i1IFEla9BWPTMD19EQ6jN+jVc7pcbrEY71mZOmivTXgIjcVtQxPfzcgPnpu2dmU0NIhEU098WstxXEnm2DviDxiMy45FWAtsxjPMJv0eOkbVc6cN0jt4hw6R6CWIJuweqA5GvdgTyRyJ1UqiM5nbOGEjc60BMXisUv0cf8Nw3bwB/NyICqy9cK41SU9E0Usdome2beNEI0dIp6g3zaGryUx8ldJV0lwzqnzIXzX4QGVBb8pOVZybetgYcWMo4LFM64NC637jlCmINOu7d4g/mNFfzoSFVw4oXYQCYyoz+YNeYoONr1LwvvVqCu1lfUtG4yXe7HHX9SEcxspZmbOveIq07+wNyx6gyhI7FgB9bHb3s9OrPrYDgaE5KyR77UeuxZWyyVeQhCmhQ8OG34Y/SkPTxPa8+WmogUAh2PwrDWVXIkHu8Cg==" + "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAILPggBHAp3It8PLhuG4r/ZP8kkKoFMT6vzv4wg7NDztM25eAL+j48YfmwZzkpfuDa9Qzo0KSXADIAPjDdPmj3MWrMeUm7uq3aCyeBzFU2qDyFcgwC9vL+FH7K6cxP0IfhGxrAUawEU+PH0zt4GKks0m4PWAU5QQe8A0z0Cl3+KStPS7uydlrgnOSkuF4WeCIKNenErtyNuWog0au/smfj2Gd0dxHLuT0XisGlZKo9yg8egoK0QMRA20WPxhgEio8fNIOPDaFkEeIQnQKERNLl3wajqVlmTKBPdt/eQEOc/NrlFkkJ+DiF5g5nt7ye6vhkXHZ1by0LQANSMckh+ibRdYU9LhEAe5cy8H6tdWp6P2lsbk+awhUr6lVftUuijSSgQAAAAjQtyT8hXRQL2ZRNA6sdw5NHdj3Eyn4tQ5LToF+ClM0e62C3+gY9s2L8IYVUCSMsoLeQo/9+jYPnzghDQ/rooT838iFcop80LEDGRj2atykZCtlmNunJo2cx03/7eq1QWt6Em5kmqsHtreGMDgZL12Jwvd8gFCmRSpkc3kVaZB3FCY+GLzeZb6PYg394J4J5WIxH+TQ8nPfTe707/Bb9OVmB+JD4TvDRZoLNwn/NIeBaZDMhd7EdRJAfGusW0EPLgUA8dWZGFeG+xjX5YAEN6XOceffudmrcq0nUFn527b797EL6TzdMQoloE8x7tqBGmB7jIrthb054cQNMTHMYYsGp6VFpJgFYiSyUaRgofWfrH0xU/Z3F92+JCyFuU+CVz9DQt+mfO6NvZai0xVGnA7Lagkw3otOSzn+83RGX80C1PUBq/ZSiWJYWkjANzDaEVnKNetzwh1TaKZdYiOMg0xokv+Gzm7Hcsy6Nm0usqJYj7h8LF7JrAvTpBQvr6eDsEva+AXV4JST62zEJVTACZ9Y6VZNaoHWwuKODXZI/wdZ4Bsiz4ekKhuAoVjJN6O5gbJxk+V02kO9GkAS60AmzIUtPF0oSO4JlIvrYiqP3bcvhaOHwx7KOM7DGsLQQnKWEtM3inAOrRYbzbB/1l765Wesp5SaBBSbdQKZgUXzgQlmEMdZFNhb/oaM0KHmocaHaKN/3Ar0T5Wea88d98qib2RnY3DHTnYcPxQz7p2haoDiud/tq9+vUG7tmYsqfkZ9Krq9PoCC8WKRIX+l7bMsh/qGgRg4eZ2gC2E2IbAMnUGdW+FSJYbs6YiZv2KNM53zsPeGtSU5OAbZZ8ry9Eqj+JkSK1xsFRradxEosWe+qljUwsUqwNiU9kwugHA2jvvlae7FIWs94Xu9cwidL9XNoJ7kKC9IJ4ZDnT2hfqQw4ibk8WdQ4a+siMKeYdIai91iQkUeymgY8DzBiWLyhrAl00J/jHq2EoPQZEFsxzWAhwbeUzmSy4rRucbjwjzx6lSGOycitAVRMCckrbiHh6bOG0yCKKm8PSHWTDBapI2jYkYKCfB1xjHwYTUyt4ILLuvaG181AdTXU5yf+MizUoBGC+tFBrawtYHymZCUyt+fy+OjnfM63aHtrIfSBmO2g1T/uCGqpdg7Lx38nNtbDe5cCoajTntHmhQEpH1piWziK2txW7zPIh0a+Zl0ze/DkGcrOj6EPuOgOh4HD14XvDMEPgqcsfGGdJU83mHSguMw2IQ8utNkmGjalgGon0yCB4VD33BLvBdMBgRo7XJb9s01IarSLAzuQ1sMjViU4dX9Yods0g4POb5JOj0Fj3EYPNvzzRQAgIVv4EXhCSoai4/n2im8WRP3jrorDjiafgbqtmbgM8F+473og7fFGdiil0IqKJJIAmZlNOUowkIG6hN0cRk9nvEiSsLIoMF1MsC7El3jFbSiB+jBw==" }, { "header": { "sequence": 3, - "previousBlockHash": "87C8079BE7E4BCACBCCBC51BE89D4639A1900C1B7C039CB1348D127881CFBED2", + "previousBlockHash": "205E4CE138ED4B660A4584BF5786C5A402F83B099D9219031E9DE4CA6702C8D1", "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:l/TQRCIjU/cYbX1mLhUhvWWa4WGRiF9vg08EC/di0k0=" + "data": "base64:5WjFPDoak0VM1Wcj0LLqBGw6kP/q9D5+FxrE4ucIR1Q=" }, "size": 5 }, @@ -1023,36 +1023,36 @@ }, "target": "12131835591833296355903882315508391652467087441833704656133504637", "randomness": "0", - "timestamp": 1664904626478, + "timestamp": 1668626723250, "minersFee": "-2000000000", "work": "0", - "hash": "506FF9016038BAB09E4387223B6C3B4CABF6F7118F255CB13C0D81943E09AEDD", + "hash": "F5DF01F112018283949C881F58E8F09E129FD26051CE9D94D3729531E26AB6AE", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAImUfSlvMEL1OWIc34GE3b6hW+AJBO19KVDHNFs9RUCTfuuFRfAk7e06WiOpKA5n27Glko0l81yg+arn4Wqc9EfdIoSmKapWtipJuU/5Fmad3Dw3IiDW5/7f/MsIkvEmPBGb+UPU41FlakhO+e7tPGBL/RvPKs49E3RmGC4SPh/EQOX3qL8jqGNJrNtSXlNvzKXIrZG+KGease6Rj/E/zLbEN3AjMTEQ5Nho6ys58Kkrjyvj0ZhALxwDqN6kynBdb7meQWpNrJ51RRbyLwttldoTK621iFx0cVdOAanhOga1Kp9XSUJz2Xrbj8lvcONxqo6AtnEc1fzg8L/XjSZClh5anr3zIOhynVlLmqu4Ry1SPhPGGjOiATmTBduYMtI1DHKOFS3fqD7oGOUrkNzYy3LmLScupLfDEJeZwj+QOlX5zMMnQlgYv7ybFy6BKJOeTzD1Q/H900D0DUApPjIFN3p8VX9UNeoAT0y/PP0XfmLRHHvt4Y1aO1FhtT30p6KD8JGF7kJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBceVDfHBxLzbXoMRQ8nM5G4tVf9Nw17P6mA947GbF5NjmdHOn3PhbMjWDeddPriW3kHHGNhMZ9JH0dfaRutQCA==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAJOd1KjxjmhzTucGQEVYj42HwXmyYNl5s0pOP3smU4xJz1p58P9DK3o+tYfaPEPaRYuudl+3a9KFbK1pYrIId9IaZVe1+fLVwlXKuM4JRXb14hhNiZhOgdRkS89n5WMiEAzFC1rNnOh4wuBAU0Tw96EuA9x1Ty/kU2aVgxYqShpIvlL9vzEBmGN28INp1gkvRpldHl7kb4iWzI6l768EvZ5jB3pAZKKPU4g9OZVgTVzR+nPIM36xoy1Vz75sXRYQ2nE4huqtMBU+bmT+wpHuTjSyERUTVDzIGpSarxGtP2Rp7TDDtX2iB6wCiiHJsreCYnse+MmU9wttU8VP0KUXfUtEmvSF1Qwe1X8fkOundUZp7nSoz77zCR2tt+OZ5ossYg/NbKZz8lNW7wxqLXK2V4IEH5y5Eq3EWWGVG7diBx67CN+08zpvK3gIBO62LnN/RB/wQyCIA9lkYR0sMurLXRDcFzm4mVhEswboL9etE4xfanmbx9JpajbrEJf9CcwuC7HL9EJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw3J851lxlvI+rysGDz6GeV9IHYerw6HBb4rU8zDRsACJdyThrKhGwbxk0xFNOyEugx8/XBMTreZfFtjTP2fSCBg==" } ] } ], "Accounts expireTransactions should only expire transactions one time": [ { - "id": "a93d1cc9-ba22-4a37-91c7-d820b6d0fdaa", + "id": "1d045393-9ef9-4794-990d-8f89360b5581", "name": "accountA", - "spendingKey": "03b66b02e9823270357d44f2912cce626323c5dc5d7b9b17b5c2e41fc9618edd", - "incomingViewKey": "e4a9c225987c854be983ba63110bd5f6932484c31c82feef200b049b219a1904", - "outgoingViewKey": "5f32a7eaab2f3512a06b82a43fef24559a58a97967b20ebd9b9a5d16db6b32db", - "publicAddress": "f095b181d569563f0f1fcf3988fd663e5dc28e10afdc6ddd3046b9c7176620a06546606ddcb89bd9570f31" + "spendingKey": "4bb2ecc160d4f87f548d582793d39c92cc4ab70bca08cf5671841ba60c4073fe", + "incomingViewKey": "45eabdb1f4519806d5d34b4a8f4ffe39eb28db1b15cef025b23e65b95233cd02", + "outgoingViewKey": "1393f9e41e20e510914da149cbe9da78cd2c3da77d02b375beace069e2556fef", + "publicAddress": "c66fb2043cda33350166b2ba6ba50f7e18370a47b1bda78831bb925c68f5fc0247a0c0722f007dd432fe3d" }, { - "id": "f1f528f8-a0da-40ce-be40-a0f36594c4d3", + "id": "3e5cd345-3aa8-42c2-8535-6902f23145ae", "name": "accountB", - "spendingKey": "76ec1ad3022bbb938d5996de39267e768d21fbb98223ed96c69a9183b35e9b71", - "incomingViewKey": "9f9710f869e787defe37ff659c80ce636e97c773178ab277066103fdb437f904", - "outgoingViewKey": "002ac2a77d501659cf3f09253bc4a07bc79faef0810cb80bf6083da20ed1f540", - "publicAddress": "36f2d64a60779d7154f593c65a5f20be37d84c35a53f871ce08567d5cebdb8b314ab029ad555c1b5ffe10c" + "spendingKey": "1e0452ab759b9a55d88e2dc75a40a480b597f63365834fd565e5ebb3994ee51c", + "incomingViewKey": "bef6ed1af4456f81cd7377ba28d1ce9c3efb59e2295c707f2d75b21790d48c00", + "outgoingViewKey": "dc7822ed1b4f6374f11e50cd44152c6992743608fb58fb32105faf2729b2ad8e", + "publicAddress": "e8540f95e090ba6efe921ba5e3c66f7c8190bf7ef72aa892506555f4a8f866cb0dd858ac2565f83f71ee66" }, { "header": { @@ -1061,7 +1061,7 @@ "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:8SDFRAclRvU4K9UjnRRN0XGR+0YZJL9u96g8Y6RNJ28=" + "data": "base64:i7hAQCzZi36wj8fds4aIhed6UvvbIpEwRxpdSl5CZhU=" }, "size": 4 }, @@ -1071,31 +1071,31 @@ }, "target": "12167378078913471945996581698193578003257923478462384564023044230", "randomness": "0", - "timestamp": 1664904626777, + "timestamp": 1668626828562, "minersFee": "-2000000000", "work": "0", - "hash": "9F849026BC2B02747E1B20A620FECF40D5E3DB187033C27B89D3255C384A4318", + "hash": "5A3746950A7693B27C534BBBC6831949F3E5776422523839560D8AD7F2F1EAFC", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKLru16Zq0BCINivnIxTLDzh2deGmYbV9a9x0tVHEB0H33r1OrOd1BWlD9B342KqHaAIkYAW9IIbZ1mbUur69Aorwd2bIr+gsZflvuiz4+XrfNdry82D8HNE7V5C5E6XUgpqMUmCwSpEewqyOOWIJHn0RdwfnfQOFUit7Q5IlWeQRSyKoNHTTQAKSkwcyHq1ZpdSAEVePsGyol67CuM8EXMn6U33lfI3g5GlKRDuzCx6+L+qmJxAjYltepwrivNMjlfQ7peuHZzVY8jEcBa0ttc+sftqN0uwefcR7JeO7SnAr749IVrarFmgZCVAGa6JaEACphrYtrzDyLICwOgCkjYK2fkxCWTmhf/Leu2/92N0nag+NJUzVPdMGgQ+kY1KVTmksQ17LwYlsQZCCNlcc7dbd9zFZLO/zt8eRxE0q/7jX/puZ2Qh8hRn/p6n7+EYBk50x2bILMBq2yzc/zG4Nau00bO7xzdn5SxmrMPs5cY62Fmvu7G5695a6tYAt6NxhJyEG0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwycVwvmvafrroYAbWDrk/eQzR+B6MVv3cthklYPEcU5OHbyYWPutN+fW7yXepgHV+JpzwVD7wSK69NQIPLYebBw==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKVnSZ2PnuMaPQmZTxud7Xv+V6+lUguovelc7ylwAJARIzz3JvKp/wvYf6oI1xVolIrcJ/h6wk5/6IZGDq3wLkm4Ny23YCVa761Bkv99dHeJKnQu9YviWQhAmU2fFjXlkBR0QP+vxLVcHafi+QGqRxpDFzrlEFL+81U//zCLxnaaazwPvsE9ytkK/Tki6EiUBaUAalKuvXi1JL/G+lCovjxrVzPVFzskg/GUZbFKs02Lm+wxjbBe/aelXC6yiPU6pno2EFvxDNeuZImTavbQdDv5YQXshmzpBsqo5NCDrGs67lZfYaPUjGJcUBfmg/uPLy+n42Cc3qJnwWhMQBvsLG6qSPmPpSeArel5MTtFt/f8JFhOXUXuRlUi6TeFlOAmGj+FKrEaj51/ME9lo8BrtAEjcngyNkjWgznmBEX39LnW1uhJqBnlzelMOnjtxmRF+wQ4EMg5ttgA5Wi6dxs2qmy4zvfUHZ8owkda4YvLfE01Pgj15A0WQ60OCiJclBpUvcD9lkJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwjP2sUEISKlDHujzyAK5eu0T6jSHcUGKRGX+3ZD8IiCs8QXSLz9uOSSHpdhsfQuhv2CxLku8l2zO2eCC+5cVjAw==" } ] }, { "type": "Buffer", - "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAQAAALa4xERhwAQuFLB1lG+MVD274mZYclMbBmox8ZMy31hXXOQopkgUe4Zwm1xwhRmtdLIohTGQe2t+OwYFllyQd6FV5yOmXKwrE5XEeY7q9LapQdHq65zeOdqY683Oh2Mu0QPo6SMdAYF/dUnXxGf2dW3ebLV9mS9JfGEpdGcQ6EbuW5pZdhx0Ny2oMcZo21dntqhOSEZH6H8r0Acshli15+s+8ds+2AriofIspRoQCp/qrtyFdZSyuqbUTeGIEK/nQmu3iNvqtnVk31kbOhABzuk18fV62Rjxqigs+WeQPdEGBGHcweZQuoLL+wSsdnCbJwsH7LUIVl/T8XtLVEmox0TxIMVEByVG9Tgr1SOdFE3RcZH7Rhkkv273qDxjpE0nbwQAAAAJd3nrvE0V4l08a55hGNhTVFNw4yHWL52TD6m4WtcrisRO9OQzpMZKk6KGW0g5VJTKNkL4mQsXDO+r9Tcyqh5XALZARFqULis/p1IebWaClMd95W1BME284xAqZ2zdzACYK4/GfS0ihve6zTCHt/CaVrlfevP6bjKUaWqDcvcrBTBMCUzMRMH1PycXGqRo4jaIP3uJ2bkSVu8D+renmybRhFcG5GKNUTL4k9JpGNuBsSuV6YxeJndHwFfd3o4T6YkUCOT8d1NQpJez+PL6GVz28ZxdPjL52uFSS5EcW5br9NyB8qaKao0Huf0V4NrVHweTJT9DrMrLTGa91ulBbZgHlU1VeCPbawbqBSFY/LN96j9Y4ek0Shvoso0xOa2H5T2E3jZAbbTmK2O7ZNBN3H7r5wEJ8kYtimbKRh0LPgYR24twBVMtTGOX/EkqVcmmplCI6wOghfsmRSWXUiWZMPRaFAmD4TrnhdbsXNzm4JrnjSs3HK/HDZDDRiz6kx1e1aKjvpTJxdIQejmYsvM8PlvuwqULPCXbqeG6dGV/gxYqr49UeArL6dRakFExZSe0j1zZDuMtfZoQ9MJJkVj97T6xkJ6tIsBaTOX8Ovcf/lM/wQh+X+45kSZXRxb0AtDinDt6himWklgXgFqNo/jytR5JJDQ+BVIbVy+hNbI/z4flDbfkcEHIrZcwDuBxO5egYEbHXHK7M7IEE32Inn533o72yYfmsOp32tT1q7t0jnQa6cpWtbUPn0ufjcSn9pkmII83mltrC83y7l7YilriC8NEJ5+eGy/nfr23ZkYQTeSrwuNmPZM2C5HIN6JKXkDYVfhS23KGEHaIch3HzuuLm6drBQgw/UcEw8PgcDIkROet6QvuNge34Oz6L3i51UJ9hyDcNgU4zYmi/XSYV1hz1ohcieWbclltQ5O87nhGkm6wHvZ8m5LEHT4WZvVua0nBpR8BRdnH+3wyZY5E/gl2XEneIQwtdRTv1LV22gN4VTgpXWwkfkaThM+4WHsqxKINvZ4Sv4TZOmJCGVW85gKEoYlWIpOKjQ5yJi3Uole7AbGXcjfK7YPMQrEuC4eZF+UkLy4q2gJ3tmCMrhAG+bu/AdwIJMAspybQ/9kLnbel2+Tj6ecoPnziYV5tvGn3Dp9d6msNm8fqVzsA9HfgIkRYkdzTXTC795uj/ybgyMDpSl2PvmY2MfxutRQdFyLeZQLba4kmVRZZ0T9G+Px1vx5EZxOrry0OOp+PS5jCnmxNxFRv1ae7I+9dLrZkZrUTmHkIqR8NyGQA4S4xoqcX/9vg2hgfgSI9N64F4fX9HIaYfO2EypqMtMVQ5roHjernvpTICuxsO2ItbaZ7ZLCBl+xjIaFYI+asf0hWjUcx9uKxVjG8SJ+58oGrpqIZK/O7bP6VIGjGFy4sCxCkzN1509MvskMq3p3EVWtPajXQ+/WovTQdc6MiNbrADA==" + "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAIRNEASgRFhI/FHantZVgyJJmHCXAQIEZLTVzAbV/0DE2jGMDc+PgQ0EmvY9oNb28pRWRo/piNJwXdOgfJoJ94Igfln7Od7BofwZbs412peuRY9MGdnQ5KQbBmX4jx9bjw701Fwa6rR+gxhlQ/lMzg6ckzjHwwl+Q4bBaLILFw20OsLhJneOJmi7PHDMfIFIzZjQk967x5b43Ng4qH+jB3KplMGCleg+0h7Z+JqsvRop0WFRfOAb0qRjFqzKfERpoyWwMHM6dhL5qO3PCG8p87x5UyiwTPDDm91iHw9sGe3qiqw/QcGIq+FFp5cvU8DnFGMOC3UCbzPtI4EtX2ZpvKSLuEBALNmLfrCPx92zhoiF53pS+9sikTBHGl1KXkJmFQQAAABot0i4S3BgX8GYCWqfO4stfAKErv/eryA2OpjXstmetIlrDuut3dAI7IL4EILHqUeYiBn1WaG/Mk87dRiJxMtfHAsa+KA0oF09M+ySXC3eYiM4c6u9DOxP25i9NLBGsQSjes+CWWK8NDZOPScp4JY7TtrbRfwKPYNIi7OonGLD7NWz3CCgEOAbcmdwYvijfROOX8gbzVsqKA5r1qOdPPukX+Q92cg+5NwUk4mUEDQ+Vgd3J+nec/LfGHtg8WR760YTf4mfYh3EPjd9ZYwsCfge6vZe66T2buJP2lo+mMlQEssszo5RdkSANuUtFUbEnUWjWC1JnD3GrBVlqVbmMik95IbMO40BMJ8u8j/YumYlw3B4nFrpcEz/tFzYil5ot0VFU+H75FD8aNqDpUl6l2r8LEBycWQ/21NjkpIQ5hSxV9baTQEElC03zuXdGgTkbVz/+pShN3Z2gm7z3+YUJ81nkGhy59HvNpfvoU5XmB2KQ4qR4DFauHb9dq7WuiejVZ/TYTX4U6bmnQ2LIjQRCsv9QnxSTbeVsmqc5zE6AlHN2AJ7cZnvr9fpbovHTAaRjA6n0pPZnGSIc60N4EQduUfWskCAX91DX2DxtXgBH+oSwabFf1VQZTxvLl76DDyf54ZDndyOy3ydRXn7hv3wljTrpBdrciZtd8+XK4UeleLh8jnXrSBwlBMTPmryfAqjSzRsfSiQAw9d1Fgs7ES/aHdGyKXsLVP2cxD3uKJ5Xwq/IwsKgKNV7DQMQYizJHjYzIjQY3eDvGPCG8jQi1zxwwoFiiPztgC9oZ2goauiVE9qZeRvzqW8Idj/OMlrsnSQnO+PEnMvjzz8vGyX4PCUgpuqSlDs1/5kjcozTVMm9pxwo38SxA69sWoMxSiC4crCWxjdPnTRvPBs34qfEqyTZu+dUYX/CBXyE1rfccQAbaMMBcksTIjiPiCDUPGFOXsaWVBau4QrfgvKSLAvYvOTxrR0za9SKeqLqR305zcdJ5ntDLu40UwV/O9a3EFlVfmJu7ba3pOu8C1L3sRecENH4x41jQa8lOK7K0bP7bWOz+MjwBxILcbo25R+lA4zplCecJc01x25g8cJbPgLmZmXCv5Wt87FeKTX8qc297767rKMqktCp0bNAagH5WeS02onI6y/sM6orgI/6LSJXExyQha+aV4HbPZ5fRsyCtcemJ8PUwgg8OFiMq912wtaRdxt/rl1MYcV5NmBDiDhuncxgsT+EqC8OCzSYERBbb0P5M8txGAOsGRxaMhHTzokeC+MQOUjjfOHCktE2Ovh2QIhhn8jeR66bEnUoUykKDN8QYWaKAABxU6//1NrfCIfT/81peddW9Om7xiX5LUWyWT2d+l2JBHH5ViYQ8IzEI2NCmtCFzJNm66LMbHiiM4NNJqVje6VHt5guSLveMYM0h5FzKmEOvDsZIYYZas7YacZeOOD5ctYidyuBQ==" }, { "header": { "sequence": 3, - "previousBlockHash": "9F849026BC2B02747E1B20A620FECF40D5E3DB187033C27B89D3255C384A4318", + "previousBlockHash": "5A3746950A7693B27C534BBBC6831949F3E5776422523839560D8AD7F2F1EAFC", "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:3N4PaL82UGpiiTvt+M97h9fwyx+3GMkVtCMcaN6g0zo=" + "data": "base64:kdHzL95TkO4fnu/fmMOVN16zOEWrZNzOnoeADTn/xSE=" }, "size": 5 }, @@ -1105,16 +1105,16 @@ }, "target": "12131835591833296355903882315508391652467087441833704656133504637", "randomness": "0", - "timestamp": 1664904628687, + "timestamp": 1668626830514, "minersFee": "-2000000000", "work": "0", - "hash": "1BA40B6A69E6BFD548062E63BEDFF8ECE004C4320694CA8F3638C9C673C91872", + "hash": "B46E9DCD7B93C778D4A1275FA198549883AE8EBABCB680955D8330DC48EBD50D", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAIZDtfXtvqXwhyRym9ZlWTUbwfCylmsSaF0ah5TfChP3IXd0n5ozBK8WNqy0j7atfoKZyU45G5FyKBlcAQqRYh0MTRl1s3wO+CIjFXZMrUEHQRHJ8kcs1Iqevg7aP8g/hgWZ02SFWqWmAL+3DioCztNyBBffaCPOAggk8uYVIClRqlFwNONZxDllV9ucb4YWQrfLJu8M7eglLvq6NxSjJbYzjQwvJD3cj203+dhhG2WFzdzHtqTk8oQf1NhVmrcSpsmppcKj5P3SXLyLRPN8n7s2P5LgPt0mrcWoC3RTLmFeVrhiHYtSrKHNCokBDpeQLEVvHEWDWScuZI/94nlqGkzgyAF50D4l8yYYB3UqnyvMqtywm5kuFH8NDj/9KVvKGnwuqVjnctFN04oHNTtIbd8lm9ZBvVH62bjZADObr5nU14KQy4ovy0TYQOCx0KIfcy5jppjPpsMiaK6N074kfARAtq7eUuSpy1t0IEe/fzSWvv090ZUYKoCY21whtc182l54n0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw67FzzzprNCMT38HU99oizdAd5RsCvowvbJ6wzyVb1bvX/R6slRjis/LG6PmUNGgwLmWFgH1BMywc9u2IcNlvAw==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAIPy6nDFgv7jHC+uvxpXZju6VVaN+aoXSGnnsKd7qD/eoloTWSqaEQuUAVGTuUpa2LYUUT786DXTnCrnxKgjAf+xUoUJLQ131i75OItHnDC83Sjrfm51VT9SJOzdf2wVIQOLjdfBuIe9jBy+yMtvADGs99u8CLVSiD+RuyWDcTf66z3sJu93zqi3oHrT4gtH9bBnklFRsKDgIySLsAVb3EFSv47NWsQYccoYUP+EQWkuplnW4Huu6eL88cy4ksfATHL6uG1ogbhb3lfPDEHu6HCnQ5QfPkVkItZTJcbGpJ4SPuv0P/muMtDnC2eym4VKKQBJEEw9kr5fm8+gW6HKhS/wLA6ySmpPsuDVbnw/qj5/KcvYlknqT9GAax5LACTJQOikGnlMS70gldNdHf9ZXHUyFqh+yJFZzyJ/QTC7qmwfCHfs1B+armbjF9PdPGpx+qnSRGE3Zzyqb0pGZ1Sp5st1ne6Unf5g88iSGv3yBsivDoIg4KQcgWSeV7QydNcEl7QBDkJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwUPK/kj/byEJLgGaUlwSqE2RMy4ynpoKzS8GJbEZUNZBd5h88flxvfNLMFKfi6km/CVDf+l+IZpvaUqsMThpFBA==" } ] } @@ -1253,20 +1253,20 @@ ], "Accounts getTransactionStatus should show expired transactions as expired": [ { - "id": "aac2c8fd-b294-4aad-a2bb-70df208d315d", + "id": "f60631d0-8a18-470c-8257-21743172d330", "name": "a", - "spendingKey": "9bdf2100baac4dfeae698b707b842f7c272208f83b50154fe73875b65812beca", - "incomingViewKey": "779a0231efec00546586e70d61af9e1ef6aa0956d1e29033f34606d23777e904", - "outgoingViewKey": "75a6496182cd0590324ce6f8518fbfacbead32f4560b951814ab82f1ed3f9d9b", - "publicAddress": "48de26e6712d613763841ea8d0482cfe8c0dcfba2242022d1c2eb76362b6b1bfaa2f426794522d875e9155" + "spendingKey": "b9d7d6842aad03f48910ef33e52480324b51fe717abbb39d49017a825dda0028", + "incomingViewKey": "bfb0adf532e76630cf9ba22d78084babb79688e43ab357633427978322a26c02", + "outgoingViewKey": "1f1d2d10149b136f0cc43cdcbd76474786a60c00d14803f06bb93221c0b1d6a1", + "publicAddress": "25d57d370fc5bd2598531e331b0f201a1578bad826e1a71b14a70cd208d808847fbd40e1a7d5ce6ec5b0ab" }, { - "id": "9b68e5c8-f4e6-4acb-a771-00aedbc4e9b0", + "id": "e4799d41-7122-4992-bd75-998f2adc270a", "name": "b", - "spendingKey": "93277df51f2df0a4e1f85b7ce2d4f3a1bea1432da6760d322bc7d50580c4be17", - "incomingViewKey": "c7d182d9b7db734c3d25e06158a38ad3e0dcc4afad0f6b9e3047be68b65d9901", - "outgoingViewKey": "cdb1a8fb3f473cf9fecb4703c4dc6f1958c52d4a93cddf861fc21e6ae2f4923e", - "publicAddress": "cba55541e8c8b95409b36ff5aa12df5fe59c4c4dbe02d4c120efe6e92abe1ce122e8e87bbeaf5196447453" + "spendingKey": "0b9ea82f0c303f987effd2b4ab6ef141176f105a2439b82f6de25a5bc1d4247e", + "incomingViewKey": "3022e6c03e6559ca6f176e8a96a8995897f667f7bd3ccf4fe59d21c90cbba903", + "outgoingViewKey": "39f8932d5e025eb720a599d671a8a1e02892b49431f4fab951a8198f67db0ffa", + "publicAddress": "8de0ba153b3059aeb9395984aa7ee88cd680ce380fc63bd5f76b78b99acf56683315840ea35ce345081aa0" }, { "header": { @@ -1275,7 +1275,7 @@ "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:I6kUDI5UjCZKTtwb3/oiC/qEbrFzQpo2Mg3/8PQPhFQ=" + "data": "base64:w313F1yGuoQ1BGxQR5+cLb1zhobfFE0zcYd+thVv/Eg=" }, "size": 4 }, @@ -1285,22 +1285,52 @@ }, "target": "12167378078913471945996581698193578003257923478462384564023044230", "randomness": "0", - "timestamp": 1664904631601, + "timestamp": 1668627048629, "minersFee": "-2000000000", "work": "0", - "hash": "F42073FC0FE2A79D1819134E7C4B0D6C172A543A404CEEB7DE91B09C588F51CE", + "hash": "9EF2440FCA2A95EA7A6DFAA5F8EB5E8E7512463D662FC619F7C93E1835C516D2", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAALnRFSQhn5Q7fijPnmbP3tSPFhwP75Dp/NS0kFWr16UdCQMvKnWuSaF+K6oYQ9OUPZQdDYBxRlaoA/O//YJFWUl6y+gTZp9it6wzVGNhSNsPak1RgnnAU9c9n7H5RDbP5RRcA2YFB1NqsTrQb/8SE3UBgW0Pm/hyUEIqbeOz+mpCXdg+C4OsQOL0M5iwe0jeU7kchM4nfsyk/z0klD2dLHZ0YLXVxbVpPR+r6w1d17TuDEGrosE7Ne9v3/M/Ddt1o1oBBEqq/owxlX/Vmy2vZUFycj3mxAKWyTEESSUyLWQenXZyPf6rj/kKVE6ExpHe3fU/6X0URvskZcMPHtvXJTgyDKSs4PAu5uG1JH3aMCya1l4rRg4mainpo+t3Le5dN6Kx3MVUHmp1KFAEeMvD9si79YZz5am/+dm8LrysSzdSJ4Zd5MRLqP802KG0Nm53xxo/eNNPb0JW+mds109mTQKOcxTwN7g/sNfCp4irr1ai8OSFKwh56nvvTK1rZgUXqkvzYUJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwYyt1K3HPRTfvCC2Awv6g+jeSiQ4O494NuHuRtjT72ryIo1APZdlnNzEmnPN95PLL6/YfMFgkfSVkrELHccRFCQ==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAALh3VDhj5gC3UKfavibINyHBwaMS+4WhA4OUGzNwA0zFIndCd71D4qXbLlZiGm7J2YHoR4nep+Xbtfo8Mu15+ChBxkkTvwtMb1V9T9PYnG8dYsKO1Vq5hM5Rww7e85rokBZSlHWakZrH0XdN6q5KRnnqVjH+I2rRQ/MwMAlNG3+yoIZPlxx7RwICu2dR2GiIKJRL9ZUPe8JFJ+9NfU/W6o4hd8yUCsfg7dfQCjSNJ2SGuDK9A50hxehCqFqhvB3L1r925iZ6aMX8eUoHNVdA2LTEIYLcvlKARacEQ2Vh1BukQzjZ5x5l76H2dZS8H3Nizxqzs5V+pYqziGDGkkFPHkpKoaPz+LKhBt2Y2cTu22lvx56KaugpI+CWl8Z3BZLh4l0MWNeBIziXIsVnAeh5fA/Iw4dqAfAMrKQrnCm5vWb7RUaZroUc8D5c9HTKyybvQLHlfWZZ9em4xEka+MoLeSc0JnKaHGkKhr7KBLYkaNYMY1oSi+mKwzlkisOhw94lWt7nRUJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwbAlFS3EMmAVKtPseuwbVVXSZbPF83eHhxGF73UVjFwBgDcDnXVJyL6VjohHzL+PCCLggfm5GZmMIPnW95GJHAA==" } ] }, { "type": "Buffer", - "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAQAAAJAKeOnUkaaT2Y6H52m3BJEZSPpNh2pF/a5I9yR0Xf2dCYCm2K6Lj/ZVB9yl9YIBAoFrzDd8mBbwGeexwYbbyZmUosLpP6QpONciuTuMd1ykOex2k3k9svLPCj29r+U0LRVjTHGmhOV6CIglvqALd+0f8gs2zR8BwDZ/KfEO1iINx58lN8c9ddj51dwGirxYP5QtSu0wbGTaYR7vIf/nIuXC0H1R8VuIpASX+LAUFrtmhLkmDQ4L1lSTyi3m1NT2aheLHfWWwMZkFAMnqiuVYg9lJ8mpXc9cXNRhQlkaAX4AsBuIpJTT6YzRXL35fmn0jSmF4HQrBuKW7Id7JfIoCOMjqRQMjlSMJkpO3Bvf+iIL+oRusXNCmjYyDf/w9A+EVAQAAACvMex+2DeWU/y2S/wxUuPwoiyY4a6y1nztv/OAWV5NkSBq0JQIg/92X7tgnh46DMepyVqP9bx+Bz0jwmSmW+Nrpbu+jQ5MuwMhfXzA/9yYqgdbTAJtcCgPo3OBAEsKTQmXxG7mncb1tQwrxfrLgBDEDchfTSQmlsYrEJ47qYAGziUS1rQMftbQw7y6badXDYmSCKzW8VCCydTIwxbOydwjHQ4f1VNUbdJ8PPtTRkS8Nrc733Gydn64GGvVRRNtb/4Xgdg1zLEjFn4ukvQjBpODoJ8wz2na29ebnmtzwW6oRWzwX2UXEYXpfbkS2/pmIDWPh0JeV/UyFfvo0dxaD//4Me96pNpLt5ATCQrH+U/ciomz3pA8w7/sdY0BLys0h4FBsZNr0xSJcMLeMnahZ5OOSStGFQDxZPiPxdCUo7zDr5uZk4TAhkMmAuNK1R40twdoCcXH/L9zHmi9NsWmcRddDkn5IYwH/oLHl8mRFB1O0jYc+raGZafRPWkY+QucC0SzbVD54O7/Gl5t8URWB9yklViHYsqtFAvemQh8yflc1wHegIAmsX7n2xHYA9LHc2VWuAZ4BCMYGl5L1ncXXccmJYKKwj1m5w1JXPHF+tSp2IdxQFsBo8dm3xQggXfIS3KBPnKDra8Nal/d1opsuI2EoAM4BOk9r+6ov5/iusl7KFj1sTnI2r7MpfmI8WL55pUOt5Lxtxq8fFM4KUaKNXbZ+2JOOKcfwWXif0QWa8TWCm0gT7GUcUIP81SqczJ0yUVxPTKbB6Bq2QbAWS7FJgt39RT3CP/rFuyBBI90gvFH+PQHxbGpoNOPa2A0YQvUzp0Sy1JV0Z7W3AEzpGhnTaUdxYF+ffEAVVyGWyDBuJcogVwzUgpjpO7Cw1oOsN1fDCEiyMveaFDWp0WixwXkPNchK2FTf9XSEajkqsJNFXANiZhIM6UQ4P4SQpnyTY8DffP9Uf9AEc6Z6HdkM6mpJKsVSZsnJ/lD4f3FXJ5vGe6nQuyxKAtTyQsWJIyam3m8RkyKE7UmTG21dTG7H/d/3hZ/rlTql4O7rUjQt+3ZU3SABSEfMzSFPqszwI1kKeULblX+UAKm0indAFJWRVqgaJKd4XtLu3taChnCFtiv99CYWjaiyMiwYaKixHv2bLh26oqQZrRiM5j69Xx4vBXHtH65HQwI8vn5vp4nNmPCvbiax/IhS69l3aYbjtS6/bJ/v8bQ0TDUUnLAhUBsi3lRpsGa5J/zgMkPgXG4DMzF8qIMjTKBsoY2XvMMTSFYhZrCpzfUhMJYqI8Aty52tlrO7SGtMYPA06J6vrNAPNo06c+VcBdFZoa4fWCLD+bAp52cCfbpIlMkBHEJmHsIO90CAIqu3XbTjUZKf7/NLS5wUWSOODVxEn1q7PRgGxz7dxXpmN3jHBjD1CSIF0gXZ3sOhohOwWvfWR9J1fHBu9Hgc8nU0HNzuN5tAQ==" + "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAJIuk5BXzjAyhPFU6Pz+6/rEqvjeu9Rvu8+fhLeBSPyK2pFuYlhPtQAVkuHRw72Yk5GX5q7a9D0XPbYuIRU6/kJkNYeAFrDvoNgKp/5JRk+EF3N5+wuuiBCeILFx18TYpBd1oznHzWqdxNp763YxusjA/gKmsgW65IpSp7QMFT+FgZrFZF3HvrTxx0YP/E5slbXVshYepDvhRQLOLxle3yDghAzLaTRozaV3Me1GGqsqTTQXrEKmJ6v5KpaHJMCKqR4Q3MHNlGVuEOKx+8SbIGmWrQ1xvEDIDkcgPufphRw29pUsa8IbgFOnOwy6kRqZQDTQMrV5AEGZf3WTmqbf1WnDfXcXXIa6hDUEbFBHn5wtvXOGht8UTTNxh362FW/8SAQAAACe9umMTOADa+FpbayINUJQfsBcFJ6oi5IYdgcQDJpCKIWwOchNlv9kkVEmPdtBSmVty085rsrfba2iQT8hhq3ouYmLDGmTvgJjvUPIMYP1UwXP25pv/LCYbG+oO9FE+wGSMZubq/LbCgsNm8qwIs7Lo2B6H2Vbwtut1OlghNG8G3h0iVmJ5K5u+GYDpT4lM6KgAhN2GCorJFporuQpS1Wo6TGl/JGwoAFt6o7q8fbyq1JLxlFqUW8qoJX6SkeS1P4BrWxdNZzslm8WB7ShsLCk6OChZQpDCdEsugl4S+3Zg5TMucPvqaNhlNsyGy5mkMOzyjJ5CUFTB9mp4i1uFc8gAY6eVUKzXzOaJO9gbu5x1p2attJ0hUQUfMp8Vhu99wXLNZhBrTP/3g/n5IaTy3ZpmC4vkL3aBHnr+q7vCqxg0op/jk9zdW20MnWhvrlhdGJZG+pxhshKmlmLiQIa2ctQc5WQsWOWqUsUeuqBEUqBAOa9SNfNoHLnx/UwtRnFgV1L2655DbBoGSKZ2DvpPgWHWYy878f9iMtA7VA//ho5y82sJ9NEUU0Y6VHjd4AmNt3xUF3Ai67EBv9+Pu02HRLWqHfC5DkHE4p4+oN59xfYp46bBV6URd4XqBDZspAB3TZdapiYaWH73ZoonwnN7rgarkHI+isLSyqAC3Rl3F/NM7risE8SR+0khuEX0EVQEfswxsHHFys5fBZXjvTWv7sSZZG8S4t0BbjvZJ9ZRGlJyLQ306Y2Y3fIRAcQdtF3sxEQ4pHk/pjGt73xvpHNUzXpdRUTspEAGcHzuUP7/ophcHTEQKMAEovkb9bTOLK7u7CJSx+LxfmX2DevW8aoa25fL84m9NF7ZKWJrZ3ncyKx4Q7XjgaCKOZbCTGSr91AQFKsO3CK4kx5hqqUpdxPKt69WSqfXp/zAeLumHstWyvSuXAHlqAeQeOR7pXwXsT+Na+D15fvGy2S6D5A5uonj1C4iN/g/AfrT+yTe5Q+ciK1BpxudSlYu6wN1T7c/4qVpXycto589riWxEquyDXFSBEc3s5wuFOyqlsKGB37tadVmJCafcn8cesC09cyN39A0UM7kgCTq5VLQ2akDWroeQcsBEzfaYfnLPkKa+tiNeDuVC/dMVAPmRZsa81+qQ5ANJsUzyEAqq1/cPDzM0gpSwv0NQyEknS2qfC4NtTdnzXg/erQ+mKQSMcba9FtlUqHDuKw5H0puM25ZwtuWV5mkd16ksQS6DTE+kOCw7Be+VSeFpMhqMs4oVC6aRlLMyv4Od2lAiigaO//l5tmBtbrnDYZiRwlhhqkp6n4mjlKIgZYF7yPo36/2Zboxh8dk7o63EsTw58cMlniS3pFx6Qjqn6wY8ESVghkM+cAHVfwMqDpsotc7QrkItwbWA2lK5iWb7RX/76aqqzx//7CNDFlKAZ8OCIqGqeBFDxesyelMlpYf4te+LobAQ==" + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "9EF2440FCA2A95EA7A6DFAA5F8EB5E8E7512463D662FC619F7C93E1835C516D2", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:9bZRImyVXqVxt2/naWKbLhLRfqRyx/40quyPMfnlhi8=" + }, + "size": 5 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12131835591833296355903882315508391652467087441833704656133504637", + "randomness": "0", + "timestamp": 1668627050647, + "minersFee": "-2000000000", + "work": "0", + "hash": "06C1B25E7B9B9F65B50A6AF889F3A1D0BB35699AF52DD5C69AAC60871BFF435B", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKUUY1mOk47S+iljLvhrajrqaLEpSNzlVlP4ccmIa79NW0fucKiA0UBP8E8fJrI5sJlGTzbL/B/jQAjPFfJA+Goas2PisYYve1x2d7WxWh/omRjXKDEZBSZZ7E2PtPFT6RMgeDB6drQ3eTECXfxzNgm5zJAdx+cOdmSHYh7QTSiC6BzYOY2MVgfrPm+l1kuYo5W7BQ5bP9mbtPpI4cQi/40IjDTFJ2pHvWK4vRmiFPe9Po+QSCiiPezrrDnbroP6xnAzJcSjleN0UJsSP8xSRg84xbJcL41akTzoPc5AlnocvBh7It61Ai6Lx2jjcr8dnFXXQPa1ITOqLDiiW7o4Aynr51BhMAHjq7T/VzxPISMhUTI1dTl8mSPZ17a+DNttz3nmIy4bbEUdwLZM95ckm2V6yg6W7jeD6TY58MyuyjVr9R/lieaAEUmXtBEEfMDHmuWaxZsPe61v0ZhZ3rAnWrFCLlwmmefCQ4i6AAn4bP1G4bQnmfCq+vfPZHL4i6+zlP6Bw0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwFQG3sdGLf3js4DiLr7ORDLyAg4athkRPY14NLMoN01v+puxawDLfFUjbNLMG3a/uiO36V92o4TVMrwhUsuwwDA==" + } + ] } ], "Accounts getTransactionStatus should show transactions with 0 expiration as pending": [ @@ -1411,12 +1441,12 @@ ], "Accounts rebroadcastTransactions should not rebroadcast expired transactions": [ { - "id": "15915bed-e0a0-4bc5-bbc6-950e924b51a8", + "id": "60a1eeb3-d45c-4065-840d-ce3cd53c4a76", "name": "accountA", - "spendingKey": "7903ac5a9fbbe84521317cfa3f28386615d681f182b66be485b4dba0ccd6886b", - "incomingViewKey": "8dfcf0ea59349c9908baafb248a64498fc19fc04308dd23ec923cc6448b09a01", - "outgoingViewKey": "c0fde6dd85aac5a36aa2e2c88ad7b7db7faabaa250df03d470f8139d4ad417c0", - "publicAddress": "d42774ebec0f3010fc947ed4108ed7112aa508a505d8cbf4aa16707e34b2213e98af47c1d8c4e90d7255dc" + "spendingKey": "731984456f6004ef634e862890992690f71a31dc4419025702c348c4ec6e59f6", + "incomingViewKey": "d550ad35ff3a5023cab77b38e3c82fbc9864753aa695ec9f9a6a43db330f4f04", + "outgoingViewKey": "ba9e4e63356caa732b7bc1e10e42b0ba202838663aef58ba640c925790c73e68", + "publicAddress": "54946f2898adc047661b480a62c3aba0622bb1216a99a1881cf5724b1039579c80f2af500484e39d57c34f" }, { "header": { @@ -1425,7 +1455,7 @@ "noteCommitment": { "commitment": { "type": "Buffer", - "data": "base64:0WuD0nnAutnbui4HwtF3cxEn1GmgS70QCTsC/LLSukE=" + "data": "base64:DVRgMXYj6ya5mea6AIae/VtZ3g4jlRUf8RQS5JcPxVA=" }, "size": 4 }, @@ -1435,22 +1465,52 @@ }, "target": "12167378078913471945996581698193578003257923478462384564023044230", "randomness": "0", - "timestamp": 1666400789561, + "timestamp": 1668627262843, "minersFee": "-2000000000", "work": "0", - "hash": "B6A4C9228E63E6B64FFC24595C369DEA219E8D80F710A57BC741E67A98542521", + "hash": "85C8E1FA9CF0CB15257972FC1B39D674434843AA63366E4F60C0B85260A99AA9", "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" }, "transactions": [ { "type": "Buffer", - "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAJXGD36MeXkc6YXOWIOioCMt5fEL1vt76w3YmUAXAds6xw7AXgljNpg0EbHl6fRgEKBFQULSTUm1u0Q2RfX8POukHaVutc/yOVuAaL9QyXiL6OW7V7XSpwzgjydfl2YLPxh/wwcI+SGmdteScJSCsVJ/YEq6z5zA8ivlf/m2khv/sQyNpwMfWwE89fJrSMqCMZk+29V4fLtvdvi2MM+el3PJIGP81EQXwNUK7bLTzva+DW7DorEY/Hda91leVZSXA73f/Q1nUdrUfsFI7woCqWcPcdcOjhYi8bOJx9XTjfUERb9iQqT4HF2oUbnVKAJnuIVO2rZo39cqecNiSZFpPx1RElLS/7gyiKtkOx+0eH1EPQwN9AWtKb6eHvEUBmGjvwzr82am/8jm6a2xIILVO+/YeyU9xxdh1FRgBBw6mO0mE8iD5no1ciQSaAPLRIStmaXy8C1RhGSccaf4+hck9BUoL5n8ZVwcC9NKexgMJ9pkcCnktojN/k/YbHQb/ZULgSzbjEJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwESPv8O0LjmNE6fy5Z/NXCxny9KULoU9qnspBXjaG6GPdgKygUN4DCLxsE8d1UYw+Cy3x52jnX2Uq6yq1wuvOBw==" + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAALgV//Ude+U5sVMSn+yXJ6z9UVoaISjKRk++ElA4ohA48nRmWkPF8C+G9bvLZ9GZ1aF2xMjaBBP1CPuLYGBJ3bAiYgFad6LJVBD/nywkS5CCgJlWxbc1Kcskp5sjwGiirgRoq/Xdr5N1PU8dUCvcjyCBLSBPot8XZbg81wst1RATbhkdUQtw9tl3MUnb/exkS7C48HmO3YEcVEt3wxYZWC/L1UlxyO4K0wIDaCAZIiXX1OeB0DmnvZXE7NvkEnAJIErTbj6wM3XcHHDiF7ba1UsRAErYRubaAX6sUeYj0hkACBdONjbtG/rTX26zOjbs9JPWEjjJuOfjWtV8RPRDq1SUEv8EVaiKeSQ55VAvIUg2JbRP56aWv2D/sRMNNVV6jrD6+LPXGEOtQgNezz5eB3ZRm2VwHA1gOndbzYw1DGPGPI5lz0ua30g10bdiTVVEdKHpt7yuC3gw/W3dV1ZaG5OT3WjHnra21hTwqm2/IOhTKUp8MS39qReXYcqXHP2/VYekR0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw4vQVerjJrho/YW2kNYgqzbK6pSoDeoH6yjDlKmVpbBooack6lTK9Yt1eh90t2UIxFhmDR2dowfVpsHjawvR9AQ==" } ] }, { "type": "Buffer", - "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAKMD1lnr5ctlApxRJyAXxaSaFFdkiwBMRnWnWBhLFrxWrnpf8BWiu4wbJ9dxju3247U+uWyDbmczb/k+jdh3QlA4aASVjh7LYGP9JkQq50qX71/rFGqAjarq/SdfjWeS3BDy3wQape8AXAJn+sy/LsgoCXMFag2Upcn2mPxCBs/iyflJgQh7OZwQ78DSU7lacJJapkRhysaUO/NUSWyrXB5gwdJMqefbYTrifuMVVnXX3i3afOEJzZH1frnJG7cNdG212sOX1/fFUbenrAZFukP8osZgO/bY1Og7QON9pQwW7Gwnsz36QnGWoA2314/rssys4GW4CX40Jh2PvxnI6afRa4PSecC62du6LgfC0XdzESfUaaBLvRAJOwL8stK6QQQAAADoAYCyb6Hwphi5lDu+jeaPFFi7lVRZb0UqT1I7lIRhVjK0Cr2HXY0EhCCmmyNtL5CeWMSA+NI3n3PzyFS8U4CP8KJ+lqxECfF4nmnUOBKuOxEdhE0WfsTt/ud5q/pTsAGJdbRq/4dE+somnIlAFzEAGMPtw9/JOKsHkQ6KxHCpZoT4RuJo5u5ldsFUQqXXrSuYTDSnhoS2c4cKoThXq6yBiYIgXITVL68oretyXC+Kc4JGAQkKJOx6CVjeu5vynpkW8asOGXE/JZZP1iTfg/VBmJv+AHYWW+6GzSUOymMOzeqXYwp0I95Bj0iXb8Hg4dexHxO132nmEnqC8/u+KJd2HL5kpa42x+hIHy9BXUTuJ4p5ZRxMCDWVWo3+nGjkAu8Pk7wRjXKrACMzS3Kn1cLTUXEFLWw5hV8I/CylMyj6hHvZolcuYows93cyixF24bKejx1zKWuT44qUwXJ95gE8X0MgRqEg9QBFHBIpIBQAdc/5z3XS5LF7c5a9xON4W5F7QoLZ4x05wXPbOcA7D3IR+4w9EvCK2ixsmVFkWSzjRIIoiSRbqa3Ry+7xlfj4lBBdAC2BIMJIpcU3CA+j3j4GDOOzTmsW9zMG4wEKSVh11dh69IQkMvd0KiXIgyP4R9J18987s4ecXYZY6Gr45UcLdafCizyCN+pD6gOIJ/G1NARcDeIuVdw1npmk/6xKnxceAapzMOXm/QWIzIoDVS3fFsMY/eF3Yyfpw2c7OI/NgZn2spgYaTTgGX/s50SW0uQbW6I+p/5R7ziCNp2xrx0xu8S8Jx5oR4AVU1F8Wxl/vkMbpbEl7ke+bku1Gu7uorNjNML4NAmCFfveKuE/c1e9WhetjYH45zyL2AEppAiVKszOagFEpTwzvop6i/YEhzRwqtbNENTROBeT1/rslYgPPtQ3pOxkfq9stxNTcqpR/xJoNZVs8TTQldrNMYVQ2en/oCLzG5jeF38pgUHxTtOBDbPNQK6XokB1x7L5J9GfhB7YwoX3TkUjPSiX+EFuGqSmzrmL3OaVaESm3vkpWPAsFLIpbJCVtUX/zD01ndEo41r294Y0qPib0mELYoXzb5WGQTiLMnlMyaqDenwASLPWZBjeur0cRG3bx3YR/AKGkvdpiEcINoclKYmKq6155pvq9B8IR1VXkO/b/LzCyxasLbInN4rhHyTGytVw74Pfj+yoCZ694VP7X3lwktIuOous2YM4q9ygT0oe75y7qVajKHkgSZNfyl6UzyARHSbBZ4f5+HL7brAF5CXZGiAzmdrtwCQUfBb5jl52ibsmoBXEt29+08db854abPK3n/cdbmrpRcoZ6Tv9jlZw2PdqIqK6KqiU4/QufYxSdvqhw10O+Nh5ciSZEtXiQXztRxEBth8qMeXWXHrsVHOb1yRzsSSyeIpEHfMN2/5yoZCUq8AFnjNlkAz5Co12XTVtXGthsGhmy8AqAg==" + "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAI7w7E6C+4Z2Ph7i7bODVpuDA6R2iqBSK7HaxjdqWHWL2l/AcovsQhkKJQEtZubwTovzm6G5fpzazpMPr4Drv7YbBXWONrX8ZWtadNZ/HklOM3/SK6CHBGun/cZ03XM5kQiMEmmnRxi+x6ep1MnpxIYvrITBtvWKmgtk4UUO/7TtvlT/hD4meEiVF2a6T/6l2LlbFSY3ndsuYdPWqG9xI7/+VlrSIjex0atn7Yxi/BwYE10KprpyvtuO1HCDVptgkw6GQSjFA9V9QpkMcejrBe9xv7dNJstv2xC8MSO6P/fJawals8PCloy3Yq6IeToa64PRP4B6oGTLG0Dv8JLdAuwNVGAxdiPrJrmZ5roAhp79W1neDiOVFR/xFBLklw/FUAQAAADO5rmMb9aWW1M8YRP0o7UutKKkNXsGbclXg8zsv/WFY1NgTrlygSHt0z39PnY0vFfefOv9DZgQ1iFJfRaJ7TQFFFJs2oVJJJXSx9qHIMKyYIO5/9aBIhrj2wgAcB7vgwSAHtj81SGXkESjzo3M5aIO2MDTDm/+2FIblsPZXyGX+1IJWNVMd4TfF+BxrFWEzaKCOMD9IOFwffZTBcpM4rCDL8hZyvyd9Ie3kR2reHbKzxea1XW/3ji5nA/nFLAwLfgKpO6AhB+W0VxC6wYjM3g8qM/OMwuG4RJ1FBckVD6Po3YvRtjQ5gdHStg8RANg1CaE9hKFhxJpGkDVzEJCAQDIq8OyA7RNVoSLwXQoe9oktIC9NUh919qTmRvzn8dfqTdA2nrp33a91dBzA2OJ5agCdgVij1mdVptyq2XAmFoV50d1WrWiKyd2CrqzXzoHQLpkwjA/swEfjl3EWXDpbxhjtf4Ju65WJ8/9DzH6amY00o1itcpJhddhkV3r2wg6wYTjfAAWNkilsBouRXp2GTlwM0A02W/WOhlFUGX2XknAgaFJd7DHAV6l2OF2UHN+mvoC4X9shIloRJakaUpWrWnTl52clVx2BeIA/Z/u0fTyU7uquoyTlWjWCxeKYILwEWlN4Xg6b54RFVpXktNok7jGWoRhSCFaGcMpkLNhRmVXai1dmuDreexUBoub2Ev9CYO1Eqy3prITmW6Owb3NCWh5WufkwxAXitpaKWKvzbk2V/5BI7YcOCXna/Kyw7wXWNgiJCCE9uGfbadpqYLOydcQpzgMxQQKKpXqifoCcORiPS7Lx483oiU/a3txyrSuyRizsYoZ3h0VADI2YKAFhHe+o9j6ObO26hQt/7uLPm23yVeG8w0SIdVUNiOvDCC2ZcJwQpx+OSM4E+D4l17Cecf5JUb/rypWAYojs0P2zVszR/jqKbYDSXPNx70fXtntIoePr3CtRFgHnPjRhdIbpZOz7/bxKpMpGkKcQzfKAO7bqG0rHVFhEtVCvgdEYsVMEMS3tkLwZV+DpFCo0V3ruBMiJWVx7uU/Wcn/rFMYCkHtAcF5Th4PP9hdSRYtW6a4Y2aHJW+6FeVEyOaPVC0iDXef4fo95YObpsb2GJOi/luEjlHvGL9QXKOvuOmR+qMk2AsN370iLWjtx6uY+fhmua4mGMcl4nrxbibYb8NSQAWt4WuVaUI+SS4OeC45qDjeoh1LdWxGJvpZ+ROJHSS7ZMLp0AzceSGVzt6cEVP39f+sk6mayWYmlsS293nK+LMVsf9+qGDxkAqYZh3mSsVfMJWokxXtgNJpvmv68U3NyDvQ/Be1DCKlepS0wy6+mlhUbkpz+YpuB42QB9QrYwd4HAdN/f9dAAxNp+Ybw6do3nynm2Xacf+gBYWm5Kz0dvFX34R/I13An7cxt1s3PO48nzDdgyMCJdBkN5hokZU8Yyitz4x9GLfaCQ==" + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "85C8E1FA9CF0CB15257972FC1B39D674434843AA63366E4F60C0B85260A99AA9", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:7Fs5HvJ6MiIBEJEMPhcBUHrSgLLiSq0QaVwyKq794AA=" + }, + "size": 5 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12131835591833296355903882315508391652467087441833704656133504637", + "randomness": "0", + "timestamp": 1668627264795, + "minersFee": "-2000000000", + "work": "0", + "hash": "DCBA4CAD9A37B88B71DB8197EA71F46901B65730FFB71C5E8A0AB37FC6ECD9F7", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAALlyco/++JN5pNKBm+Njkudexm9H3VlAthZr0HZvBp7kSAP7YK2DbSbQxKfnorSXKovBktJFn5LBmqAdcy4mj648CDci/VIp0sDX6OD8DXZV5zy7fm6XJ/pypLZPGi0NIAmHE7iqXlhq7XPEQvD+VDV6Px5Us6+MWbVvJD0uc2bivL7EodVRMLWOjAmfw76LeqsipWxiotiHUv3evyV0qTyWUubP2hYYQ3IB4cCtaXHO53R89Ynz9TTSp0NaCTaSifV26jjNenJlA1tTpS53w7l/aTRzhYcKV/wSIlU1AFxAZIXkLfEWxbj4rjy6eYoh+zXcUkB7ofyR7/pEftmKFSJzO9q0UJT4OD+Y7BhuqeX2iuk/KD7z/+MNoI376HnsOwTxC2273pv4pkOInpZbKtIA/1yAvEipJUZmgnnsWUA6bhF/pUjywvin6P7N1y/mcmC8bsRPcSfuuzbnhsKk8HYJ5iZ2E/+694DTab3kF1BdiRhPfIwrQ42pX0dshJdudsEhM0JlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwoYV+Jdyn8PT/OU9XtwVjj1zYj3t5UbcLmttstn0Yo/IyhNOT2QpkcAzIhPlxC5xWxxeyNzZR1GhY07jEPxrSCQ==" + } + ] } ], "Accounts should update sequenceToNoteHash for notes created on a fork": [ @@ -1976,5 +2036,263 @@ "type": "Buffer", "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAJK0tTF/S534GiGdcNnQrG/R8OfjCg/PMBszgBlL+46DiZ+rd6YY3ukPODQPeeWJP4+9n3kuu0mhz0ZQ6RuOZTlPId3pOwmOCbMRaAsOzdvc8UJmxxYYGAIVxYbq4FFpqAvul+GPUBaoFM73S5L6TKTAZVIyX2kbAsItsa5mEPeqa0NGegXvYsqNl2Hyq6Xe34+J0XwU6E1GtHzk8i+ag/m3LaE/IgfUF+7feKCXkikL6VFDzpO5YW8RFesM+TC5CqnQ/u0mwYi5ZbBjcj3eUpplj1HGRv9Y3RIhGLnl7DiZ4mf0lPoE9AqHy2UwLGeE4vVuPyQUploRItzK/G6sRDaSWjEL6d69d3MShZuB+1871SWQTMVEqWydDhJbf5JIOwcAAABZzP98KK/mXIHL6EvEFYevR0rnebfcr+7XBojv+tVp9Bw34rRorsh0SDp9Ef68oEeZAWFTaIHRfLfJ6D4Fp9GDHz0r4FKx6jYzSNVCyGYEY3EdAlFCq0bUVzmy+bnt/waq3zc3Q8eMdKKrVdYM0nxBPl2Re/35UeIKeGVvv5Rek6rz8jgiM5z9w16ujUmjHtG0bj9gHVXbjHgkUp1a9yaTD8djgl0Z8ri6w5kmulPmOWZ1h8l9eUST1f14Yb1R7ogGdIRYwwweHm7BQ32gYqQONO0SspF0d1IHwuPVO+uL+xvisZXEFIUr+aFbQc0GPhK59cC4p0yf2lXX2rdfLsIDRxcwcpG0MhxUAhxd0PKEBZ4PlHmWZ4K7qyWVxKpOUuNENcTT+heLe3vtxXIaDAf63G2jLkOCIsiRQe/VrHLgvrPdiLhTsWojNpXXGs+vqyt04hmY/whtqIVCWHDbv3tYtgTa2TATs/lZOhg8sAZdezWYP/vahkNH8N8cSI6KK1ztYsxlwYzbmDcFnKtzvRb37tj2vMcQt5s5OVxX6uclJJHWyxbMNSGWHBFkmDFS3RMrKYFLVkinDFK/50xM1EYPYdbAqnUP8BihDWsW/XJDAsasKnfBPWJbpwbLJ+XqXMmifqD7AIYpxvkm/9hg7GLbRcFb91fGuTMW7Gs9Grr5QIt8VX13w42RPiHsqMaFzk97jTkDY92QMjM93x0UAX8d14bGF78D8OXktMR5qATwOUlN8IP7D4LqZHL2hSr4WifhoKvt1G8uxGqW2uKFqC4/eASusoXDQAHD/LCm9qmfGhgvVaUPXZoxa45DLzN3r6iwqfMVyRhStc54x3UJgLWKU07J0arSliwXSBtEpcOx9E9MnAEV3JjsDcDeGMuiwNQX0bFYYJ9e/Ct6U+gFtYyLVX+Q2MhKy1ZfUrkTPdAoh0DL/LI2YYCne4bDav67flGNQvtGesXMfbPtFNOaO6BH7u2cmT+7NoggiEkb8lnYSW5/kdDrWSf8F1IzjRNQV+6OxF3U/z0jqbMRL8ea/+xLjKG8kV3oGZK8LLX+yEIbma0Hztg7QwyOs5vLm/MqO3kvsQYMQFQLOYqRrsR0ZW2dmHJAKWCoI0WYubdhu7Be8ZfRRXef9MFXGVDNQRc2XdLOdN/QRKaWroX53A4hbSoibtKIuCXBSMS5HGzQGer9ZrwRrHg11CCtM96Gx0o5wTAwfndF76Ky18s/v9Ep6wmWFEnchSs4y9Vkfr1HHOQp82enCqzRARCicTBfTjnD0tM0VlCOe2i8dRzqcIJi9wUlEtqdN3Uo/nVv126MbY8Qs9ibfgHvcdlJeqo7QxiFVxNoVaXG0EEu6Qe2Efbl6s7fy7bGf4XxGcI0dL4Bc0MVyQ0G/t8n0b/qY4cBgpibBW7y82Bnz6/OAxCqHXht3qK0iwJ87Mdi/8pddFiQMNpTwpzy659nCw==" } + ], + "Accounts syncTransaction should not re-sync expired transactions": [ + { + "id": "342c4b96-1c65-4952-8ac8-ccb6ba915f96", + "name": "a", + "spendingKey": "ac87281ae3431d7c5cf165d485f090987edd0e56e7e0b676f47978ed8742caa4", + "incomingViewKey": "f761c0d69339b1994eabc0ba47e4599ed27b8e336f35c8ca4e7e4449f254b703", + "outgoingViewKey": "085559a9f67196f72044cc07ba9c447438e33eb533ce04f4d12337ef2446d406", + "publicAddress": "6b0564b39b4567df3d1cae40f1b5064a19c135f84545eec88ee24edbf0e481375bccd8c506babc5787412f" + }, + { + "id": "073f281f-f1e4-4c09-88dd-9a26bbee91e8", + "name": "b", + "spendingKey": "3aec07d97698e32147a768095dec590fda0660d7c860f7214733f2812d034453", + "incomingViewKey": "192ddb45beda9e400e24a725bf19d196dbd3c1bfbcdbe940468ce1e9bc14eb03", + "outgoingViewKey": "13528ee22d66c81d01b6dcdf61c36d46c8066c784a338791c55d8c8fe5e2f62c", + "publicAddress": "d69f5ab43ed3fc34dc6bee13cc2535dafe5b88890f9db72120934e587662395f15bba57446d6c197218f2e" + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "69E263E931FA1A2A4B0437A8EFF79FFB7A353B6384A7AEAC9F90AC12AE4811EF", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:KJa16xhnRB0d12lzqjvOPrV7GuViQVRyw6iouqaxXwo=" + }, + "size": 4 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12167378078913471945996581698193578003257923478462384564023044230", + "randomness": "0", + "timestamp": 1668623108035, + "minersFee": "-2000000000", + "work": "0", + "hash": "982DF8976A8AED9070F52FBF47943C18D6C1E40CB283E95F7961CD634D5DD0EA", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAIqe3zkHh9sNN7wb7sGJ0izU2C68bnQKr6HMOGftLw43yZdnMY1entOeNhkZTOzKN4ZyQYbv3ULnKWoXAislEXgMTJ6T0Ic9VtHKZF4JsXijj6FEHGCrP4K7iIuugVEuMgouS2p6nKU7fublE1fPcayknqRup6SMUUtYQYe0a9SwQO6fk2Y/8M+qisD8PIohPYLIDqtdmrxfVpT7Hja8DmM4zbn4p6megfvzeoh1QWH652Bk6h128KS9AMBiGRTqMTBNGWwm1PQg16mahJrlNmcZJXEn2VP4uIGePfHSXegBqlpdbw0xJpAYZZOwH6ccYCWR3hMtoRCjZRtrQF5opwvxx72qjtrE9vmuu2Owypcw+CIIoX2V1/z3+3WSwdSWud2iV+AC7aEC4GE+AmHzHB3fc1B76b04HZst1Y8wMerwBcaMERQe/TLvLrXJ4rq74qLhQCBX0eCgoSG4taX1kILRuOmu9Xo9VWyFt3aKLCuDq3BKToZ888pMmWzbEez8SumfskJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwfJpGRNBgzmEPFPtUkK922gD9RVpxFQfECiKFDdpAV20sTfPAwIZ86A+XjdSG8aJ6u1NWZejnuX4ugSB5JeXKCQ==" + } + ] + }, + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAwAAAKeJYcNANLzvZceD38lszNbv7EtE3/XT+Z4viiv6CbRT1tj5m6IbSb+ohLrL21zeRqe70UMtEPQao4DKzPcdZW/h1Jz5TdDYYqtNEXt2OkoBNvVBvBlz3MV//m1DDZ3cNRjtVQGEvUc12x4ZtEwbFQ77cbOEMcAgarOxoz/70m7C2ZFr3sdC8jkEyStTMKsmAbFJHQAfRCVIl4EIkJauntHbfWuIAZcBTno0EYUVFg1TBEYWCg24kRIgof9Wqj6bCDpluwQUMOioQ//EzCwhc7fxrHSIPsslwHmRVkRH4GQ9Z2KNonRFYLybu7sFgdHjKdHOUsCddMAUyV7lcYj4a1UolrXrGGdEHR3XaXOqO84+tXsa5WJBVHLDqKi6prFfCgQAAAAOAyXH8R7gQStvQF+3pn1chCv6jQtwX7+eSQDa0OH0eqXpgb9g28GWrOwPPcNvFRxkUvsVYWK0/YIBf9/BviBVFarBZO2LVpyKj3PCAeykqCYYzgJY4d41M4bSmnzQrwKuiJ0lzUQ8gjgnWx3GIl1mu7b8pEEsCfu0YgxAufCLZDsG+AC8XrdlJRO50wHPX/6nJJ5WtmH4/pryw6KHJwUE+QSv6S7W/R4uIDcTTgvL1WOVYZAqQMbXImbJEyRFXbcXvcSzt+BxuPV0atxXPC6kQ2eJEFdomwfiXGHEKkT5xKYi9y7Ng0cbIq8R3hawMlCECAS4Jqt3UTAy097ALimqECtxYJODCbpJCFR2oG9ylqp45uOQPuWuDw4s/CuzzB98MvJHeLsT1yV8d+23E7J434pV8uJEyUyzp+NmUprWPp0v+drIhVkeTRmd6wfxIunG1BlEPZK8Qs9WLnAx9sAJpXV9sYN7FXwT3/fuZkuIRcGR7jLNm4vSk9jX8lfi480pSVqw4JeJyXv6OYs7V2CP6oiV9daWNJFxLqAWd8EoFI6Xd5Bu69uhNhsD30Jkmda15UMZzv0BFx9YeIgRje3owNiFjjvNeL6za6RJEkEbqt2Cqyf5df/wGAEiK1f6POlPHgFMKaraNBEbSw+qKWbxnapekZqJqqj2Kvh/8A2E/vVOWEFLmqYgDM3UYE4aoZhLRdOD8gjHwa6L8BrcSbBhMwlUvUbA0iEUGZzIX2UOtXllro6b6WfoGK3vpanc30s9yZQw6xSPGx7afLLs9VA9beDdWCyLN9OGp7ep7UGzZmxqYqARbExQyvSfXLPqfr0em64ilcZia/ZyPo8x8R4NoJ/thLVfN9IgzVZvy9Uonu8IIAL28nY6Z3395BPaZoRnXjrDSMXWVxgZuuw19T/b6JKzimC7ofvKbzlHK5jcv6DnU5Y9zkZyNCAyBYnNfGZeUujVOQvXtHvnxkX/HRztKgBtADl+S/jnkjuHIrgnrz8tVPA4k7iTe8QEWA0BX9Ljm/tQxot9/PUe/x+G41rMC7hB4rFVr5UNSevAA/HIajzrB4hfceInLbQIuPtnO4tsDgn9UAocLUqv3l1NJFqoUgmvWWet/ywkHZRrcuBogvsPYwOLr0iRbEwVB2TF9hzDQYuVbpvwJDnfgmlJBzYFPcBtmO2f7mxGl1xie9nYAsVR17V4es5J0EzUAmHFHafGQ7gixPt0zsbKbCLRDzkxSa9rY2z26EAk/5CqWCSBMImGmkJFVkopar+6nlIMsnGQznNZrXHxM/bkZ/ttZAsLSbDJnx/oPllH+GSgbVKcbIwbJWhmRdVyY3AIPdskVB0p6frWnNfHGQjceQYcw23cdQl43GL8P0TWPa/1EQeZdbd/m/D5+J0Mv6Z6RqEozDAenc1QmkI8E7g0KNga2pFNgH8BHNO+Qewrdx78DqmcQfsYt06OBA==" + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "982DF8976A8AED9070F52FBF47943C18D6C1E40CB283E95F7961CD634D5DD0EA", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:IJK5K6KxbCMxXQKpeVQrR2Wh+9UklEtZgL6e6HfAiDk=" + }, + "size": 5 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12197156292513823761691382189788914489539181949881055812746363805", + "randomness": "0", + "timestamp": 1668623221258, + "minersFee": "-2000000000", + "work": "0", + "hash": "D1C17791BAED4E689771E9E7F889BD768326EFDB9AF1C143C54A36E09764AB85", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKI/PU/eI+e2nNTrVktzD5wkAEx1tCsTHPFr/rNiIWP1t+5IbuNbENxxzvCa6kyECbcFI4OMn51UFWs2geJ4JFhbE/5Vlzd864wYd02ebCHJwfCoMp2EUCUcjq4DPI50YAobzXb3hJeh/B0lSyZF0CI8jQnOPFM9U0NKIWk5cQlp3WYc5AeggoWSpyg9gD4w2KaGq8tgydh96LHSkjNgmTiFxP8IuFZ2/h+wBj4g5YaNifkE5YFzUp5X7nDO3kALu/hpvIBSZkGfNI7Lyi9ujaEwzOvF5nGX3xZDu1LzYrWMkRFPkplctjyXUtDUSpluK51gSnc7696/IhhXr0RL2nAGqp7CJ7lCyFrB7a14vfFfeHWg9dtQAuiuCiRaKJz2QH1JM4fWrngy68W6G+Yt51+8pSHXhVoINL6SzKAIbrEesbLb7SBBH/F81qWkJhj9KoNP1tX6SBE58D8+Ko8OC90A/ZicTfKxjhp6Qb34WA02dtazFpAEO8tHwR/aHc28Sy0+xEJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAy4mi4XFBxZObeRbTMkFAnyB3ohwLPCDxYPMR+5b91D7n8vn3UdHqvToiB0BBizIlgtCZgWw8gJbuwmtl+68Ag==" + } + ] + } + ], + "Accounts syncTransaction should re-sync expired transactions if they were added on blocks": [ + { + "id": "f54d9f05-cac6-4731-a43f-18227886b2c5", + "name": "a", + "spendingKey": "047ce39876fafcd8dffe47b2845801e3fd204efa3b2912927d1b99f0336a9d1a", + "incomingViewKey": "944b8d84b230236775070c259c38de31ae310421fa90205f59d6c3a57d361901", + "outgoingViewKey": "ec40574aab219fd745c66076093090a03e1797d5911a0bad81e03beea2e6519a", + "publicAddress": "6944d39c8a6a0cd7028647e20251b90f13df2aa5ecb5a10a3af79f011cefb59c53007c3daa09a25a6067df" + }, + { + "id": "b60ea6e6-cedd-4000-9ad3-8cbabf85e357", + "name": "b", + "spendingKey": "8e2ae4fad16156cdb30c26cca5a02dbed5666a3667c21eb4e296c65047d568b9", + "incomingViewKey": "e92e805d44e280d5a5bbb293d4823e9fdfff45d3e6df8b65bd87633f37e9f305", + "outgoingViewKey": "95869029a7f97d06206af8395420a40231e976b8bf64e18f40b21d5ac585ecdb", + "publicAddress": "e129738ce8833902c6570f0761c4b0c9ebd5bb4a48021bd68b99ff10d9b38c76b52525003da9d5190db10b" + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "69E263E931FA1A2A4B0437A8EFF79FFB7A353B6384A7AEAC9F90AC12AE4811EF", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:5vJPuCjSQ2OSg71hmOGHDRkKCjel/TTGDAL8udFCFUA=" + }, + "size": 4 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12167378078913471945996581698193578003257923478462384564023044230", + "randomness": "0", + "timestamp": 1668625049699, + "minersFee": "-2000000000", + "work": "0", + "hash": "6A4A770B1CCC97E0840ED79AF70A91FB40049B65264D39703D9AF889CD89E0D7", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKx+q53GqTkR6a6cYZVPI12nNQi1Mh0w14/ListLlDQmVXdpkPJ+9ccBWGnTUi4B+4KAiJaI0IO1kIQ9bjB5EC2NGPnx3zzbxuHpe0AiVHLUh9EVeAv0MFhyBcHLEzIAxgRGTyR3HD47p+CNGxy1DrafaKAKqPXovllrqytBlncm8K+nf8gh+n8avKXZSCySV6ruRDcQCEL2n8qmdQjsSc02nF/HGgB89E/rskQX1uN4wAzV81lecg9gWkLezouZabFhAWrJxUKEWxzUqEUk1mPP+3TmbtjwNIVBTfwBhYLuOnCHW81c7HAlHFKh8bNxnpSofnnXNwek3BG3/k1fwxtu/VOGALpUgzjrWt4OdSGwpXEH0W83SR6u+mGzP88WAMaNWrChhPFj/6DzSuy1NQiSU0miOPFZXCDmNtwKVButSmLSE9vNo6aMj+qRZ20bhvBVzte7RMl5JTB74FUE3oGNJmFbd3xe8OkUYYG+EuqXPjrW6guthE09A4GDclQcp0ibfkJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw7ZgmhVXtAqMqnfilE9aa2Vxyn/9ncR3iFv73fJpNLZvvqMjEHK/sKjihrWZnKZmey/0UqvdZZ1zp341x3ZTqAA==" + } + ] + }, + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAABAAAAKKK262X0/FXlxCKLjtX5L2o09oYwDvt8RnIGwXMujxduMEm4W3XKPy9Suh62hbpV5i59QcjducnaRzSmlbdZ19LPivJXMl0b43e3lPWYml+ztzLKPKaa6eijtK/SUmeexV+P5yFbwfcrosA0a0w0M10SrehCIMX1a1WYs25wcBYQ/jENeccCp+kMSiSeTuncqY9N69stKro5KJBpPEhoHQnvgbMaB+qkFNAFTLFda3S/Tp9Gl1hFR4PrD3MDAZp7foMbT1lj/ZqsrxgnJTq6U1kiXf+JAIQHmH/Lox5ZzvmTWM6VP6yOBIajwTA5lcRehz8Pryri+18P2B0sUKAJTfm8k+4KNJDY5KDvWGY4YcNGQoKN6X9NMYMAvy50UIVQAQAAACYU0yBS4Q99vAB/Rk+AMZaJa29S6Iarm5rJO+K7eSinCre3Qg7mFdBvCBtEtcWV+ueWFuo1dMfSHVZtz2LGMcvKNh3bS0LZ73uxHXR2NudSH4mPBYsp1hEZOyDKray+QGEiy2QqZCqgDiV2FO0FEJ0d1lcufQ5QIn2GMeJnxKgg0ppWyi06qklTxN9knI/Z2CyNDPZOTbhBQ+gFfcZtVR1tL737Vq3/eIQdmEbSdIyZa/vRE+EQqffkKGtBjcsDG4L5adDSBDqNncFXuEsqDte9FNh7lksaslbI8m3X/TWo+kVi63acuqypkdkpuIqlxCUDomT8fbfX39K/I4h8Sc0wbp/e3CDgiYAOlb3oddW9p/flRavlC4/Sky2qFt8z/EQo2S06IIBLMTnvHeM9W8etirIs/1eAGFjdMubB3OpSKqyPtDHBOjCXlBZRFPgYWv9ckUXF5vzIWUeA78uctlNMigpBtQdXUg9lv6VAsc4eAQ1K4z4z45WVbEFQIhEj+3PxMojmS5zgWwVgKX8FAc1f2PrgyQd/0AGPTL8280yEFVskaJctnOv/K6yFm2UHrm59aQeMyqQUpl/ykT/6W9KbVIZgPXSpHZqyUZmsAIkcL3SdhlPh4nHHVZQrnxHAv7Ejnu6BTEpAfozuovl5d+XKzaMqreZ6FvUD/EX0Eli39E7JbJv4S1Anru2ZANDjOpcpquOaX7W7D9aTk9/5eAOjam3jnWwUns/1QkALuRoioQoSow1rsGlfP3cizC+ngba0lXT0M/P+/mwzxUq/6PsoxF3V79G8q2EkKftW5KKqQM6aLWBroI+X8TltG50bLVRdsRtZRjoyobgawZwirgaqGMJHLUKTW22FNM4spFTOUCwfgqEVL3QaA6BigwRX7d5HZbetcN3xY6WrtPKBWOXSEtTiylXSESIzF5Hno1UdQ9LW4bKzL35Qv1ujsJHHa/t12hHTCQN62WHG6uHX0A6IzNNoQBcISdXzMs8xtwnm76v0B25GSU93joKfK5HIUL2zUA0APMbxIUm9gkMVcg3/czIKFGGBa6ufZ4oDb/WNuIQH7/bV4WaKMSwGKeBaJiQNQBLnBwtOoHKzMPsl698bAntvxFp1TrXtL9BLcpsQwQG0gWSRpsFkiZ9E8urALNGQVwocm3q+z/OLHp+siRBZQkEDVmZEC2OVlXBvhVz2/BJPBr5wqmdTWJ5ucE5UHZx5NBF1hcTvH4dQ99nniPItcLWFUiy9X7jmh4RA3IPlf+Q6DekJaQQVkObtdt6h1WYLz15sLBOw/M5glAxXbnhLclp1u008dJPTZBuCm9h4p/Bj7R9NP9Zs+yg/S9i3X6EjzDzs8yWOaggnd53FrA48u6HgYR6IRikFxPHI3y0K/Fs1p1F+pvAybOFHfTL99x7+rPIiQB8qyBrYTi8j6lLtT37T+T2tWT23o1ze1K6V8ZfCHDHDQ==" + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "6A4A770B1CCC97E0840ED79AF70A91FB40049B65264D39703D9AF889CD89E0D7", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:gpK2emgyNhvwL1igdCVJHmbUf2wKDjPOvFyPz/zdnjI=" + }, + "size": 5 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12131835591833296355903882315508391652467087441833704656133504637", + "randomness": "0", + "timestamp": 1668625051713, + "minersFee": "-2000000000", + "work": "0", + "hash": "47A942E32171E628EEA23054F398472887B2BEFA9BBBDDA22B9FA83B7BD2946F", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAALOh2awjhAL5yJ6rL7IOfzwhu7L58dvqSzEpcSiptmyMSeDeMokPZd58mG7zMy2pBIXUTXNwGAYY7vUy0VmS25jKYOfGBrwqT82nPTtn8Tvf8L9r1kPfD+OT9ezwIxAjiQWZR+GNmPi393JM2V0EWKQMpU4EFl8RNlNs8RNh2pIfnfk4o8BBxf9hfgXuTLYkVLjxgP7nocJGp2C8HDIYShnml1mHWwWiHHgLamqxBMZSy/SLINNYqo30jziANGry23p26ykqZC2MZRcVe8uiy6r63M2V3QIfsyOAbiID+nYRU7PnCbT4bhZnFKiMcJUSTYcQxziW1G+CZEfz3FVkMzxCp/s0o17gFjJe+tFQuaHKWSXdGrlpqOZFk0kr3e0on8r3yFpK/hLXOkCozIKN3VwQBM5HRa4iJxgfQ43fH1fQMKdFzyAcqp0PqR+GIUw8xzZrMpCbUGfC0OwVXT6ZqXJyHMCPrp2yGfE46wxLL3QcBWm7dAkih59MBX0h+mPxMDNwjUJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwapRjVUrzxGXD7G3UlMOv0DE8c9FLeVXyutkA1ybJOeEvcRuG9Vqs1wJz4KjZs9HadnHL5BQiMdO1/YGnjP2gBg==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "6A4A770B1CCC97E0840ED79AF70A91FB40049B65264D39703D9AF889CD89E0D7", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:Fzqwy18Pyn4nEAinM8jo5TJEQMFwUiVSsPYfexlK71Y=" + }, + "size": 7 + }, + "nullifierCommitment": { + "commitment": "5B642E5E5D37ADDCA38FDCAD3368CEEFB1B7E3D3732436735A3BB9EE83A7752D", + "size": 2 + }, + "target": "12131835591833296355903882315508391652467087441833704656133504637", + "randomness": "0", + "timestamp": 1668625051965, + "minersFee": "-2000000000", + "work": "0", + "hash": "674EE8EFB862D6A1E0F7114BB94E83C62DC5083B952A18A1A62116A3E1ACFDB4", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAALCbXcAO/OwRK4UbvonSg703cHhVwRUzWFU8TG66P0trX8cCml/hd2vIINPkJqVK2o4kkEpiH6TM12IB5YVZq5nrAus7zAy2X5eglw80anQlxXRKElixPacyC+vlhYdjxhbnEpV/n6PzS/oTJEDkOYvDEuRr2An0hWViwXPzWmxvutzvyp082CooUx0KHzCyh4DRsNKEKc7Buqd7ex4CFUvm4BfpBUPW8VL6LDa7H5ucCvIkEhM2Fm1vI1iIVaMWhgLXlyWWSgokoDrYJ9ny7elO9qf9qhk9REwUyhpJuWC49nfPfaGBIiwnUV7EGKgFkdLHYH+PjjiwuinLkHGWGwh+bw5cNt05p7hdmuIxJKDbNVWE6laE7ZI6l3iZvF6N40pYzhYBBcP+bgr2CmU21M+Dj3emg6+tPq2QRe8b9duJsyWQv3ECkthdj9i67NGPks0kIMUGOzbvWMaS9uwFeJ2CyRvjD4uefdebhMT7l0aq4fSNvHGp+bUxEILaxxniXY6SqEJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwHBc60wVNSESDHitpoh30eUWEYHHMgi3GGGqpbSapl495fFqeJtkXr0L8VBdKbXKyrQzf9K1xeRID5KiBkAJHAg==" + }, + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAABAAAAKKK262X0/FXlxCKLjtX5L2o09oYwDvt8RnIGwXMujxduMEm4W3XKPy9Suh62hbpV5i59QcjducnaRzSmlbdZ19LPivJXMl0b43e3lPWYml+ztzLKPKaa6eijtK/SUmeexV+P5yFbwfcrosA0a0w0M10SrehCIMX1a1WYs25wcBYQ/jENeccCp+kMSiSeTuncqY9N69stKro5KJBpPEhoHQnvgbMaB+qkFNAFTLFda3S/Tp9Gl1hFR4PrD3MDAZp7foMbT1lj/ZqsrxgnJTq6U1kiXf+JAIQHmH/Lox5ZzvmTWM6VP6yOBIajwTA5lcRehz8Pryri+18P2B0sUKAJTfm8k+4KNJDY5KDvWGY4YcNGQoKN6X9NMYMAvy50UIVQAQAAACYU0yBS4Q99vAB/Rk+AMZaJa29S6Iarm5rJO+K7eSinCre3Qg7mFdBvCBtEtcWV+ueWFuo1dMfSHVZtz2LGMcvKNh3bS0LZ73uxHXR2NudSH4mPBYsp1hEZOyDKray+QGEiy2QqZCqgDiV2FO0FEJ0d1lcufQ5QIn2GMeJnxKgg0ppWyi06qklTxN9knI/Z2CyNDPZOTbhBQ+gFfcZtVR1tL737Vq3/eIQdmEbSdIyZa/vRE+EQqffkKGtBjcsDG4L5adDSBDqNncFXuEsqDte9FNh7lksaslbI8m3X/TWo+kVi63acuqypkdkpuIqlxCUDomT8fbfX39K/I4h8Sc0wbp/e3CDgiYAOlb3oddW9p/flRavlC4/Sky2qFt8z/EQo2S06IIBLMTnvHeM9W8etirIs/1eAGFjdMubB3OpSKqyPtDHBOjCXlBZRFPgYWv9ckUXF5vzIWUeA78uctlNMigpBtQdXUg9lv6VAsc4eAQ1K4z4z45WVbEFQIhEj+3PxMojmS5zgWwVgKX8FAc1f2PrgyQd/0AGPTL8280yEFVskaJctnOv/K6yFm2UHrm59aQeMyqQUpl/ykT/6W9KbVIZgPXSpHZqyUZmsAIkcL3SdhlPh4nHHVZQrnxHAv7Ejnu6BTEpAfozuovl5d+XKzaMqreZ6FvUD/EX0Eli39E7JbJv4S1Anru2ZANDjOpcpquOaX7W7D9aTk9/5eAOjam3jnWwUns/1QkALuRoioQoSow1rsGlfP3cizC+ngba0lXT0M/P+/mwzxUq/6PsoxF3V79G8q2EkKftW5KKqQM6aLWBroI+X8TltG50bLVRdsRtZRjoyobgawZwirgaqGMJHLUKTW22FNM4spFTOUCwfgqEVL3QaA6BigwRX7d5HZbetcN3xY6WrtPKBWOXSEtTiylXSESIzF5Hno1UdQ9LW4bKzL35Qv1ujsJHHa/t12hHTCQN62WHG6uHX0A6IzNNoQBcISdXzMs8xtwnm76v0B25GSU93joKfK5HIUL2zUA0APMbxIUm9gkMVcg3/czIKFGGBa6ufZ4oDb/WNuIQH7/bV4WaKMSwGKeBaJiQNQBLnBwtOoHKzMPsl698bAntvxFp1TrXtL9BLcpsQwQG0gWSRpsFkiZ9E8urALNGQVwocm3q+z/OLHp+siRBZQkEDVmZEC2OVlXBvhVz2/BJPBr5wqmdTWJ5ucE5UHZx5NBF1hcTvH4dQ99nniPItcLWFUiy9X7jmh4RA3IPlf+Q6DekJaQQVkObtdt6h1WYLz15sLBOw/M5glAxXbnhLclp1u008dJPTZBuCm9h4p/Bj7R9NP9Zs+yg/S9i3X6EjzDzs8yWOaggnd53FrA48u6HgYR6IRikFxPHI3y0K/Fs1p1F+pvAybOFHfTL99x7+rPIiQB8qyBrYTi8j6lLtT37T+T2tWT23o1ze1K6V8ZfCHDHDQ==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "674EE8EFB862D6A1E0F7114BB94E83C62DC5083B952A18A1A62116A3E1ACFDB4", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:sw/BOT1qKt0haulAQpK/Cq8PmFv0j00Jt09Xly7Wchc=" + }, + "size": 8 + }, + "nullifierCommitment": { + "commitment": "5B642E5E5D37ADDCA38FDCAD3368CEEFB1B7E3D3732436735A3BB9EE83A7752D", + "size": 2 + }, + "target": "12096396928958695709100635723060514718229275323289987966729581326", + "randomness": "0", + "timestamp": 1668625052206, + "minersFee": "-2000000000", + "work": "0", + "hash": "55E433E655E2E2171780DE7AB4775F2B22C8C4265B4DC1BFC34765A4FF150A19", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAKa6Urh/4D7PBlcaYXGNpfoRzKGZwDcgF7IdRz1sPS8f0d4PjlgprvnWl1jiRgRhbLHkZfUPFUq5QvPAfb8SSXlpdXhjuSSvgw7xVphwaJPQ5vt2oMi2Z8Y812wm+j4vIBfYjUEe3yakz7fmpi50rtIDWLTxCwrV/S2pG6LHiCZ1to0xnbjRiBeRBsr0F4V12aHyUIYfrFgU7fzgfbCPFMXJw2zuPAs1ocIKv6DfAMgXUrI/l8/mXA30rxA2IWLQ+lRo9Y4xQ1IJqMEsQOag2d7kP6Jl2xP0Bk2nLJowJk1I/GV9QVLLQKVbYl6KiitJgVsCSZTiccvG1udwSgSAO0kuuOP0p++NjBx/athi7YseTsM5bs8Fa61KZj6tQ3vX2VxN6tkERkNaWsycsmwv6GgJvHuIhWgNs3jGN7Hw7fLJ9WNX24p/obwgkO48J/sHZlolHNGu0YHPTesUiuoIT27CcRExK4qhXXbjixEOiL7zk+aTyRK4TKOBjexKI4lYlCW8PkJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw8CvPwd9x0fIo8GdDRlOZCTbbGcaQiCe4z7Hpv/NhWvA354Q9hbFO1tYXnx0kaKlkQdsEdyz6xGW74CkB8/CqBg==" + } + ] + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "69E263E931FA1A2A4B0437A8EFF79FFB7A353B6384A7AEAC9F90AC12AE4811EF", + "noteCommitment": { + "commitment": { + "type": "Buffer", + "data": "base64:zYrDLiBNTIi7+KW3bK7S1DFsoSeDCeOaIupX+DKmiSM=" + }, + "size": 4 + }, + "nullifierCommitment": { + "commitment": "E2484D0BF38F29EFFD63EF9D5A61202F198129862B12845182A4CA77AA557A4B", + "size": 1 + }, + "target": "12167378078913471945996581698193578003257923478462384564023044230", + "randomness": "0", + "timestamp": 1668624886293, + "minersFee": "-2000000000", + "work": "0", + "hash": "693C9B56C8DD815B5B76D5F12817CD045C88D681751393918986BA9B3335CD49", + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AAAAAAAAAAABAAAAAAAAAABsyoj/////AAAAAIj9MsNnVsqh34s9kvUvYGYEdb0Tzl3X7Yp0K2CG9EjnW6SouTgIJ1nQsdka5USKEKQkTcfgbZjZWurnVVU/iMrmO5EwSGHYBPCedzOXZo9kXnC8a0g9xA7xfa553K8MRQj7G8EvN+WNzYXgv8oU/ygI1vEm8q0NJ5y6tduhqXmeDfI+ExFLpIGWRliz9800N4FP+yZ4+0umyUGBR8yyuUBI7dWFbV7RpswpHhNA5nxqEYMSO1QzCsn/4dtf/LdsJL2pH1GkWd7fbI2oEWaBVvGjitel/RdYS6soUaqz3FqfujvBJK+LdABP2xf2w0yDuZygOE5aO9biKzUr+bhE8yViJZSdnfSnYHpsaj2+X1oZU8uyxpnOJMWfsiBZMgyzRdEopllKjC/DlzY/5RFKLXP/HYqKnBdD96k19QNQk1+4LbQ0l/7AiKIWYl7G+2DgpS73piT+gkT1J8/+IpwonK2Qbmgrm6aF1GhJtfEh7y9LOfF6OY4+jeE3P5ihAWwQJCefWUJlYW5zdGFsayBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw2lVGgqksrWuaiHvnCZ0S8v6ky04sOcc7sZ1jL8MiGlh4d0oUQAEwdegBd/QslqyaK/moEkHEFwGC21JEWUzLAg==" + } + ] + } ] } \ No newline at end of file diff --git a/ironfish/src/wallet/wallet.test.ts b/ironfish/src/wallet/wallet.test.ts index 3df70f9779..133042545f 100644 --- a/ironfish/src/wallet/wallet.test.ts +++ b/ironfish/src/wallet/wallet.test.ts @@ -577,15 +577,17 @@ describe('Accounts', () => { const accountA = await useAccountFixture(node.wallet, 'accountA') const accountB = await useAccountFixture(node.wallet, 'accountB') - const block1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await node.chain.addBlock(block1) + const block2 = await useMinerBlockFixture(node.chain, 2, accountA, node.wallet) + await node.chain.addBlock(block2) await node.wallet.updateHead() - await useTxFixture(node.wallet, accountA, accountB, undefined, undefined, 1) + const tx = await useTxFixture(node.wallet, accountA, accountB, undefined, undefined, 3) - const block2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await node.chain.addBlock(block2) + const block3 = await useMinerBlockFixture(node.chain, 3, accountA, node.wallet) + await node.chain.addBlock(block3) + + await accountA.getTransaction(tx.hash()) await node.wallet.updateHead() @@ -620,8 +622,8 @@ describe('Accounts', () => { const accountA = await useAccountFixture(node.wallet, 'accountA') const accountB = await useAccountFixture(node.wallet, 'accountB') - const block1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await node.chain.addBlock(block1) + const block2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) + await node.chain.addBlock(block2) await node.wallet.updateHead() @@ -631,11 +633,11 @@ describe('Accounts', () => { accountB, undefined, undefined, - 1, + 3, ) - const block2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await node.chain.addBlock(block2) + const block3 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) + await node.chain.addBlock(block3) await node.wallet.updateHead() @@ -774,8 +776,8 @@ describe('Accounts', () => { const accountA = await useAccountFixture(node.wallet, 'a') const accountB = await useAccountFixture(node.wallet, 'b') - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) + const blockA2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) + await expect(node.chain).toAddBlock(blockA2) await node.wallet.updateHead() @@ -785,9 +787,14 @@ describe('Accounts', () => { accountB, undefined, undefined, - 1, + 3, ) + const blockA3 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) + await expect(node.chain).toAddBlock(blockA3) + + await node.wallet.updateHead() + const transactionValue = await accountA.getTransaction(transaction.hash()) Assert.isNotUndefined(transactionValue) @@ -870,8 +877,8 @@ describe('Accounts', () => { const accountA = await useAccountFixture(node.wallet, 'accountA') - const block1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await node.chain.addBlock(block1) + const block2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) + await node.chain.addBlock(block2) await node.wallet.updateHead() // create expired transaction @@ -881,9 +888,13 @@ describe('Accounts', () => { accountA, undefined, undefined, - 2, + 3, ) + const block3 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) + await node.chain.addBlock(block3) + await node.wallet.updateHead() + const transactionValue = await accountA.getTransaction(transaction.hash()) Assert.isNotUndefined(transactionValue) @@ -900,4 +911,115 @@ describe('Accounts', () => { expect(broadcastSpy).toHaveBeenCalledTimes(0) }) }) + + describe('syncTransaction', () => { + it('should not re-sync expired transactions', async () => { + const { node: nodeA } = await nodeTest.createSetup() + + const accountA = await useAccountFixture(nodeA.wallet, 'a') + const accountB = await useAccountFixture(nodeA.wallet, 'b') + + const blockA2 = await useMinerBlockFixture(nodeA.chain, 2, accountA, nodeA.wallet) + await expect(nodeA.chain).toAddBlock(blockA2) + await nodeA.wallet.updateHead() + + // Create a transaction that will expire + const tx = await useTxFixture(nodeA.wallet, accountA, accountB, undefined, undefined, 3) + + await expect(nodeA.wallet.getBalance(accountA)).resolves.toMatchObject({ + confirmed: BigInt(0), + unconfirmed: BigInt(0), + pending: BigInt(1999999999), // change from transaction + }) + + // Mine a new block at sequence 3, expiring transaction + const blockA3 = await useMinerBlockFixture(nodeA.chain, 3, accountB, nodeA.wallet) + await expect(nodeA.chain).toAddBlock(blockA3) + expect(nodeA.chain.head.hash.equals(blockA3.header.hash)).toBe(true) + + await nodeA.wallet.updateHead() + + await accountA.expireTransaction(tx) + + // none of the transaction's notes are in accountA's wallet + for (const note of tx.notes()) { + await expect(accountA.getDecryptedNote(note.merkleHash())).resolves.toBeUndefined() + } + + await expect(nodeA.wallet.getBalance(accountA)).resolves.toMatchObject({ + pending: BigInt(2000000000), // minersFee from blockA1 + }) + + // re-sync expired transaction + await nodeA.wallet.syncTransaction(tx, {}) + + // none of the expired transaction's notes should be in accountA's wallet + for (const note of tx.notes()) { + await expect(accountA.getDecryptedNote(note.merkleHash())).resolves.toBeUndefined() + } + + // balance should not have changed + await expect(nodeA.wallet.getBalance(accountA)).resolves.toMatchObject({ + pending: BigInt(2000000000), // minersFee from blockA1 + }) + }) + + it('should re-sync expired transactions if they were added on blocks', async () => { + const { node: nodeA } = await nodeTest.createSetup() + const { node: nodeB } = await nodeTest.createSetup() + + const accountA = await useAccountFixture(nodeA.wallet, 'a') + const accountB = await useAccountFixture(nodeA.wallet, 'b') + + const blockA2 = await useMinerBlockFixture(nodeA.chain, 2, accountA, nodeA.wallet) + await expect(nodeA.chain).toAddBlock(blockA2) + await expect(nodeB.chain).toAddBlock(blockA2) + await nodeA.wallet.updateHead() + + // Create a transaction that will expire + const tx = await useTxFixture(nodeA.wallet, accountA, accountB, undefined, undefined, 4) + + await expect(nodeA.wallet.getBalance(accountA)).resolves.toMatchObject({ + confirmed: BigInt(0), + unconfirmed: BigInt(0), + pending: BigInt(1999999999), // change from transaction + }) + + // Mine a new block at sequence 3, expiring transaction + const blockA3 = await useMinerBlockFixture(nodeA.chain, 3, accountB, nodeA.wallet) + await expect(nodeA.chain).toAddBlock(blockA3) + expect(nodeA.chain.head.hash.equals(blockA3.header.hash)).toBe(true) + + await nodeA.wallet.updateHead() + + await accountA.expireTransaction(tx) + + // none of the transaction's notes are in accountA's wallet + for (const note of tx.notes()) { + await expect(accountA.getDecryptedNote(note.merkleHash())).resolves.toBeUndefined() + } + + await expect(nodeA.wallet.getBalance(accountA)).resolves.toMatchObject({ + pending: BigInt(2000000000), // minersFee from blockA1 + }) + + // mine the transaction on a fork + const blockB3 = await useMinerBlockFixture(nodeB.chain, 3, undefined, undefined, [tx]) + await expect(nodeB.chain).toAddBlock(blockB3) + const blockB4 = await useMinerBlockFixture(nodeB.chain, 4) + await expect(nodeB.chain).toAddBlock(blockB4) + + // re-org nodeA to the fork, and re-sync the transaction + await expect(nodeA.chain).toAddBlock(blockB3) + await expect(nodeA.chain).toAddBlock(blockB4) + expect(nodeA.chain.head.hash.equals(blockB4.header.hash)).toBe(true) + + await nodeA.wallet.updateHead() + + // balance should include the transaction + await expect(nodeA.wallet.getBalance(accountA)).resolves.toMatchObject({ + pending: BigInt(1999999999), // change from transaction + }) + }) + }) }) diff --git a/ironfish/src/wallet/wallet.ts b/ironfish/src/wallet/wallet.ts index 37cea395e5..663a4bf184 100644 --- a/ironfish/src/wallet/wallet.ts +++ b/ironfish/src/wallet/wallet.ts @@ -405,6 +405,16 @@ export class Wallet { params: SyncTransactionParams, accounts?: Array, ): Promise { + if ( + !('blockHash' in params) && + this.chain.verifier.isExpiredSequence( + transaction.expirationSequence(), + this.chainProcessor.sequence ?? 1, + ) + ) { + return + } + const initialNoteIndex = 'initialNoteIndex' in params ? params.initialNoteIndex : null const decryptedNotesByAccountId = await this.decryptNotes( From 61b69deb4928f9a8b6f3fc3780b10b859daec2a8 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Sat, 19 Nov 2022 17:00:25 -0500 Subject: [PATCH 14/15] Change V3_DISABLE_MINING_REWARD to 279900 (#2620) --- ironfish/src/consensus/consensus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ironfish/src/consensus/consensus.ts b/ironfish/src/consensus/consensus.ts index 3a62870cef..c2f16486a8 100644 --- a/ironfish/src/consensus/consensus.ts +++ b/ironfish/src/consensus/consensus.ts @@ -102,6 +102,6 @@ export class TestnetParameters extends ConsensusParameters { super() this.V1_DOUBLE_SPEND = 204000 this.V2_MAX_BLOCK_SIZE = 255000 - this.V3_DISABLE_MINING_REWARD = 278500 + this.V3_DISABLE_MINING_REWARD = 279900 } } From 359038e98a55e7bef10591b0b3a3935d5b4b8b13 Mon Sep 17 00:00:00 2001 From: Jason Spafford Date: Sat, 19 Nov 2022 17:16:16 -0500 Subject: [PATCH 15/15] Bump versions to 53 (#2621) --- ironfish-cli/package.json | 4 ++-- ironfish/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ironfish-cli/package.json b/ironfish-cli/package.json index f008095dae..9840f8fefb 100644 --- a/ironfish-cli/package.json +++ b/ironfish-cli/package.json @@ -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 (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", diff --git a/ironfish/package.json b/ironfish/package.json index be0ae9424e..0f857e1f14 100644 --- a/ironfish/package.json +++ b/ironfish/package.json @@ -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 (https://ironfish.network)", "main": "build/src/index.js",