Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Rahul/ifl 2399 move spendposttime to utils #4859

Merged
merged 2 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
121 changes: 2 additions & 119 deletions ironfish-cli/src/commands/wallet/notes/combine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { Asset } from '@ironfish/rust-nodejs'
import {
BenchUtils,
CreateTransactionRequest,
CurrencyUtils,
EstimateFeeRatesResponse,
RawTransaction,
RawTransactionSerde,
RpcClient,
RpcResponseEnded,
TimeUtils,
Transaction,
} from '@ironfish/sdk'
Expand All @@ -21,6 +18,7 @@ import { IronFlag, RemoteFlags } from '../../../flags'
import { getExplorer } from '../../../utils/explorer'
import { selectFee } from '../../../utils/fees'
import { fetchNotes } from '../../../utils/note'
import { getSpendPostTimeInMs } from '../../../utils/spendPostTime'
import {
displayTransactionSummary,
TransactionTimer,
Expand Down Expand Up @@ -74,121 +72,6 @@ export class CombineNotesCommand extends IronfishCommand {
}),
}

private async getSpendPostTimeInMs(
client: RpcClient,
account: string,
forceBenchmark: boolean,
): Promise<number> {
let spendPostTime = this.sdk.internal.get('spendPostTime')

const spendPostTimeAt = this.sdk.internal.get('spendPostTimeAt')

const shouldbenchmark =
forceBenchmark ||
spendPostTime <= 0 ||
Date.now() - spendPostTimeAt > 1000 * 60 * 60 * 24 * 30 // 1 month

if (shouldbenchmark) {
spendPostTime = await this.benchmarkSpendPostTime(client, account)

this.sdk.internal.set('spendPostTime', spendPostTime)
this.sdk.internal.set('spendPostTimeAt', Date.now())
await this.sdk.internal.save()
}

return spendPostTime
}

private async benchmarkSpendPostTime(client: RpcClient, account: string): Promise<number> {
const publicKey = (
await client.wallet.getAccountPublicKey({
account: account,
})
).content.publicKey

const notes = await fetchNotes(client, account, 10)

CliUx.ux.action.start('Measuring time to combine 1 note')

const feeRates = await client.wallet.estimateFeeRates()

/** Transaction 1: selects 1 note */

const txn1Params: CreateTransactionRequest = {
account: account,
outputs: [
{
publicAddress: publicKey,
amount: CurrencyUtils.encode(BigInt(notes[0].value)),
memo: '',
},
],
fee: null,
feeRate: null,
notes: [notes[0].noteHash],
}

/** Transaction 2: selects two notes */

const txn2Params: CreateTransactionRequest = {
account: account,
outputs: [
{
publicAddress: publicKey,
amount: CurrencyUtils.encode(BigInt(notes[0].value) + BigInt(notes[1].value)),
memo: '',
},
],
fee: null,
feeRate: null,
notes: [notes[0].noteHash, notes[1].noteHash],
}

const promisesTxn1 = []
const promisesTxn2 = []

for (let i = 0; i < 3; i++) {
promisesTxn1.push(this.measureTransactionPostTime(client, txn1Params, feeRates))
promisesTxn2.push(this.measureTransactionPostTime(client, txn2Params, feeRates))
}

const resultTxn1 = await Promise.all(promisesTxn1)
const resultTxn2 = await Promise.all(promisesTxn2)

const delta = Math.ceil(
(resultTxn2.reduce((acc, curr) => acc + curr, 0) -
resultTxn1.reduce((acc, curr) => acc + curr, 0)) /
3,
)

CliUx.ux.action.stop(TimeUtils.renderSpan(delta))

return delta
}

private async measureTransactionPostTime(
client: RpcClient,
params: CreateTransactionRequest,
feeRates: RpcResponseEnded<EstimateFeeRatesResponse>,
) {
const response = await client.wallet.createTransaction({
...params,
feeRate: feeRates.content.fast,
})

const bytes = Buffer.from(response.content.transaction, 'hex')
const raw = RawTransactionSerde.deserialize(bytes)

const start = BenchUtils.start()

await client.wallet.postTransaction({
transaction: RawTransactionSerde.serialize(raw).toString('hex'),
broadcast: false,
})

return BenchUtils.end(start)
}

private async selectNotesToCombine(spendPostTimeMs: number): Promise<number> {
const spendsPerMinute = Math.max(Math.floor(60000 / spendPostTimeMs), 2) // minimum of 2 notes per minute in case the spentPostTime is very high

Expand Down Expand Up @@ -349,7 +232,7 @@ export class CombineNotesCommand extends IronfishCommand {

await this.ensureUserHasEnoughNotesToCombine(client, from)

const spendPostTime = await this.getSpendPostTimeInMs(client, from, flags.benchmark)
const spendPostTime = await getSpendPostTimeInMs(this.sdk, client, from, flags.benchmark)

let numberOfNotes = flags.notes

Expand Down
132 changes: 132 additions & 0 deletions ironfish-cli/src/utils/spendPostTime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* 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 {
BenchUtils,
CreateTransactionRequest,
CurrencyUtils,
EstimateFeeRatesResponse,
IronfishSdk,
RawTransactionSerde,
RpcClient,
RpcResponseEnded,
TimeUtils,
} from '@ironfish/sdk'
import { CliUx } from '@oclif/core'
import { fetchNotes } from './note'

export async function getSpendPostTimeInMs(
sdk: IronfishSdk,
client: RpcClient,
account: string,
forceBenchmark: boolean,
): Promise<number> {
let spendPostTime = sdk.internal.get('spendPostTime')

const spendPostTimeAt = sdk.internal.get('spendPostTimeAt')

const shouldbenchmark =
forceBenchmark ||
spendPostTime <= 0 ||
Date.now() - spendPostTimeAt > 1000 * 60 * 60 * 24 * 30 // 1 month

if (shouldbenchmark) {
spendPostTime = await benchmarkSpendPostTime(client, account)

sdk.internal.set('spendPostTime', spendPostTime)
sdk.internal.set('spendPostTimeAt', Date.now())
await sdk.internal.save()
}

return spendPostTime
}

async function benchmarkSpendPostTime(client: RpcClient, account: string): Promise<number> {
const publicKey = (
await client.wallet.getAccountPublicKey({
account: account,
})
).content.publicKey

const notes = await fetchNotes(client, account, 10)

CliUx.ux.action.start('Measuring time to combine 1 note')

const feeRates = await client.wallet.estimateFeeRates()

/** Transaction 1: selects 1 note */

const txn1Params: CreateTransactionRequest = {
account: account,
outputs: [
{
publicAddress: publicKey,
amount: CurrencyUtils.encode(BigInt(notes[0].value)),
memo: '',
},
],
fee: null,
feeRate: null,
notes: [notes[0].noteHash],
}

/** Transaction 2: selects two notes */

const txn2Params: CreateTransactionRequest = {
account: account,
outputs: [
{
publicAddress: publicKey,
amount: CurrencyUtils.encode(BigInt(notes[0].value) + BigInt(notes[1].value)),
memo: '',
},
],
fee: null,
feeRate: null,
notes: [notes[0].noteHash, notes[1].noteHash],
}

const promisesTxn1 = []
const promisesTxn2 = []

for (let i = 0; i < 3; i++) {
promisesTxn1.push(measureTransactionPostTime(client, txn1Params, feeRates))
promisesTxn2.push(measureTransactionPostTime(client, txn2Params, feeRates))
}

const resultTxn1 = await Promise.all(promisesTxn1)
const resultTxn2 = await Promise.all(promisesTxn2)

const delta = Math.ceil(
(resultTxn2.reduce((acc, curr) => acc + curr, 0) -
resultTxn1.reduce((acc, curr) => acc + curr, 0)) /
3,
)

CliUx.ux.action.stop(TimeUtils.renderSpan(delta))

return delta
}

async function measureTransactionPostTime(
client: RpcClient,
params: CreateTransactionRequest,
feeRates: RpcResponseEnded<EstimateFeeRatesResponse>,
) {
const response = await client.wallet.createTransaction({
...params,
feeRate: feeRates.content.fast,
})

const bytes = Buffer.from(response.content.transaction, 'hex')
const raw = RawTransactionSerde.deserialize(bytes)

const start = BenchUtils.start()

await client.wallet.postTransaction({
transaction: RawTransactionSerde.serialize(raw).toString('hex'),
broadcast: false,
})

return BenchUtils.end(start)
}