Skip to content

Commit e005e25

Browse files
committed
refactor: remove updateChannel, inline get/set/delete everywhere
1 parent cee4155 commit e005e25

File tree

6 files changed

+114
-143
lines changed

6 files changed

+114
-143
lines changed

src/tempo/server/Sse.test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { describe, expect, test } from 'vitest'
33
import type { Challenge } from '../../Challenge.js'
44
import * as Credential from '../../Credential.js'
55
import type { ChannelState, Storage } from '../stream/Storage.js'
6-
import { updateChannel } from '../stream/Storage.js'
76
import { from } from './Sse.js'
87

98
const channelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
@@ -24,11 +23,8 @@ function memoryStorage(): Storage<ChannelState> {
2423
}
2524
}
2625

27-
function seedChannel(
28-
storage: Storage<ChannelState>,
29-
balance: bigint,
30-
): Promise<ChannelState | null> {
31-
return updateChannel(storage, channelId, () => ({
26+
async function seedChannel(storage: Storage<ChannelState>, balance: bigint): Promise<ChannelState> {
27+
const state: ChannelState = {
3228
channelId,
3329
payer: '0x0000000000000000000000000000000000000001' as Address,
3430
payee: '0x0000000000000000000000000000000000000002' as Address,
@@ -42,7 +38,9 @@ function seedChannel(
4238
units: 0,
4339
finalized: false,
4440
createdAt: new Date(),
45-
}))
41+
}
42+
await storage.set(channelId, state)
43+
return state
4644
}
4745

4846
function createRequestWithCredential(): Request {
@@ -160,10 +158,12 @@ describe('Sse.from', () => {
160158

161159
await new Promise((r) => setTimeout(r, 30))
162160

163-
await updateChannel(storage, channelId, (current) => {
164-
if (!current) return null
165-
return { ...current, highestVoucherAmount: current.highestVoucherAmount + 2000000n }
166-
})
161+
const current = await storage.get(channelId)
162+
if (current)
163+
await storage.set(channelId, {
164+
...current,
165+
highestVoucherAmount: current.highestVoucherAmount + 2000000n,
166+
})
167167

168168
const secondChunk = await readNext
169169
expect(secondChunk).toContain('event: mpay-need-voucher\n')

src/tempo/server/Stream.test.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
InvalidSignatureError,
1616
} from '../../Errors.js'
1717
import type { ChannelState, Storage } from '../stream/Storage.js'
18-
import { memoryStorage, updateChannel } from '../stream/Storage.js'
18+
import { memoryStorage } from '../stream/Storage.js'
1919
import type { StreamReceipt } from '../stream/Types.js'
2020
import { signVoucher } from '../stream/Voucher.js'
2121
import { charge, settle, stream } from './Stream.js'
@@ -250,9 +250,8 @@ describe('stream server Method', () => {
250250
request: makeRequest(),
251251
})
252252

253-
await updateChannel(storage, channelId, (ch) =>
254-
ch ? { ...ch, settledOnChain: 5000000n } : null,
255-
)
253+
const ch = await storage.get(channelId)
254+
if (ch) await storage.set(channelId, { ...ch, settledOnChain: 5000000n })
256255

257256
await expect(
258257
server.verify({
@@ -925,8 +924,11 @@ describe('stream server Method', () => {
925924
describe('monotonicity and TOCTOU (unit tests)', () => {
926925
const testChannelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
927926

928-
function seedChannel(storage: Storage<ChannelState>, overrides: Partial<ChannelState> = {}) {
929-
return updateChannel(storage, testChannelId, () => ({
927+
async function seedChannel(
928+
storage: Storage<ChannelState>,
929+
overrides: Partial<ChannelState> = {},
930+
) {
931+
const state: ChannelState = {
930932
channelId: testChannelId,
931933
payer: '0x0000000000000000000000000000000000000001' as Address,
932934
payee: '0x0000000000000000000000000000000000000002' as Address,
@@ -945,7 +947,9 @@ describe('monotonicity and TOCTOU (unit tests)', () => {
945947
finalized: false,
946948
createdAt: new Date(),
947949
...overrides,
948-
}))
950+
}
951+
await storage.set(testChannelId, state)
952+
return state
949953
}
950954

951955
test('charge does not allow highestVoucherAmount to decrease', async () => {
@@ -961,13 +965,13 @@ describe('monotonicity and TOCTOU (unit tests)', () => {
961965
const storage = memoryStorage()
962966
await seedChannel(storage, { settledOnChain: 3000000n })
963967

964-
await updateChannel(storage, testChannelId, (current) => {
965-
if (!current) return null
968+
const current = await storage.get(testChannelId)
969+
if (current) {
966970
const settledAmount = 2000000n
967971
const nextSettled =
968972
settledAmount > current.settledOnChain ? settledAmount : current.settledOnChain
969-
return { ...current, settledOnChain: nextSettled }
970-
})
973+
await storage.set(testChannelId, { ...current, settledOnChain: nextSettled })
974+
}
971975

972976
const ch = await storage.get(testChannelId)
973977
expect(ch!.settledOnChain).toBe(3000000n)
@@ -977,13 +981,13 @@ describe('monotonicity and TOCTOU (unit tests)', () => {
977981
const storage = memoryStorage()
978982
await seedChannel(storage, { settledOnChain: 1000000n })
979983

980-
await updateChannel(storage, testChannelId, (current) => {
981-
if (!current) return null
984+
const current = await storage.get(testChannelId)
985+
if (current) {
982986
const settledAmount = 5000000n
983987
const nextSettled =
984988
settledAmount > current.settledOnChain ? settledAmount : current.settledOnChain
985-
return { ...current, settledOnChain: nextSettled }
986-
})
989+
await storage.set(testChannelId, { ...current, settledOnChain: nextSettled })
990+
}
987991

988992
const ch = await storage.get(testChannelId)
989993
expect(ch!.settledOnChain).toBe(5000000n)
@@ -993,13 +997,14 @@ describe('monotonicity and TOCTOU (unit tests)', () => {
993997
const storage = memoryStorage()
994998
await seedChannel(storage, { highestVoucherAmount: 5000000n, spent: 2000000n, units: 3 })
995999

996-
const channel = await updateChannel(storage, testChannelId, (existing) => {
997-
if (!existing) return null
1000+
const existing = await storage.get(testChannelId)
1001+
if (existing) {
9981002
const nextHighest =
9991003
3000000n > existing.highestVoucherAmount ? 3000000n : existing.highestVoucherAmount
1000-
return { ...existing, highestVoucherAmount: nextHighest }
1001-
})
1004+
await storage.set(testChannelId, { ...existing, highestVoucherAmount: nextHighest })
1005+
}
10021006

1007+
const channel = await storage.get(testChannelId)
10031008
expect(channel!.highestVoucherAmount).toBe(5000000n)
10041009
expect(channel!.spent).toBe(2000000n)
10051010
expect(channel!.units).toBe(3)

src/tempo/server/Stream.ts

Lines changed: 55 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import {
3838
} from '../stream/Chain.js'
3939
import { createStreamReceipt } from '../stream/Receipt.js'
4040
import type { ChannelState, Storage } from '../stream/Storage.js'
41-
import { deductFromChannel, updateChannel } from '../stream/Storage.js'
41+
import { deductFromChannel } from '../stream/Storage.js'
4242
import type { SignedVoucher, StreamCredentialPayload, StreamReceipt } from '../stream/Types.js'
4343
import { parseVoucherFromPayload, verifyVoucher } from '../stream/Voucher.js'
4444

@@ -236,12 +236,9 @@ export async function settle(
236236
const settledAmount = channel.highestVoucher.cumulativeAmount
237237
const txHash = await settleOnChain(client, escrowContract, channel.highestVoucher)
238238

239-
await updateChannel(storage, channelId, (current) => {
240-
if (!current) return null
241-
const nextSettled =
242-
settledAmount > current.settledOnChain ? settledAmount : current.settledOnChain
243-
return { ...current, settledOnChain: nextSettled }
244-
})
239+
const nextSettled =
240+
settledAmount > channel.settledOnChain ? settledAmount : channel.settledOnChain
241+
await storage.set(channelId, { ...channel, settledOnChain: nextSettled })
245242

246243
return txHash
247244
}
@@ -369,19 +366,16 @@ async function verifyAndAcceptVoucher(parameters: {
369366
throw new InvalidSignatureError({ reason: 'invalid voucher signature' })
370367
}
371368

372-
const updated = await updateChannel(storage, channelId, (current) => {
373-
if (!current) throw new ChannelNotFoundError({ reason: 'channel not found' })
374-
if (voucher.cumulativeAmount > current.highestVoucherAmount) {
375-
return {
376-
...current,
377-
deposit: onChain.deposit,
378-
highestVoucherAmount: voucher.cumulativeAmount,
379-
highestVoucher: voucher,
380-
}
381-
}
382-
return current
383-
})
384-
if (!updated) throw new ChannelNotFoundError({ reason: 'channel not found' })
369+
const updated =
370+
voucher.cumulativeAmount > channel.highestVoucherAmount
371+
? {
372+
...channel,
373+
deposit: onChain.deposit,
374+
highestVoucherAmount: voucher.cumulativeAmount,
375+
highestVoucher: voucher,
376+
}
377+
: { ...channel, deposit: onChain.deposit }
378+
await storage.set(channelId, updated)
385379

386380
return createStreamReceipt({
387381
challengeId: challenge.id,
@@ -451,30 +445,32 @@ async function handleOpen(
451445
throw new InvalidSignatureError({ reason: 'invalid voucher signature' })
452446
}
453447

454-
const updated = await updateChannel(storage, payload.channelId, (existing) => {
455-
if (existing) {
456-
if (voucher.cumulativeAmount < existing.settledOnChain) {
457-
throw new VerificationFailedError({
458-
reason: 'voucher amount is below settled on-chain amount',
459-
})
460-
}
448+
const existing = await storage.get(payload.channelId)
461449

462-
if (voucher.cumulativeAmount > existing.highestVoucherAmount) {
463-
return {
464-
...existing,
465-
deposit: onChain.deposit,
466-
highestVoucherAmount: voucher.cumulativeAmount,
467-
highestVoucher: voucher,
468-
authorizedSigner,
469-
}
470-
}
471-
return {
472-
...existing,
473-
deposit: onChain.deposit,
474-
authorizedSigner,
475-
}
450+
let updated: ChannelState
451+
if (existing) {
452+
if (voucher.cumulativeAmount < existing.settledOnChain) {
453+
throw new VerificationFailedError({
454+
reason: 'voucher amount is below settled on-chain amount',
455+
})
476456
}
477-
return {
457+
458+
updated =
459+
voucher.cumulativeAmount > existing.highestVoucherAmount
460+
? {
461+
...existing,
462+
deposit: onChain.deposit,
463+
highestVoucherAmount: voucher.cumulativeAmount,
464+
highestVoucher: voucher,
465+
authorizedSigner,
466+
}
467+
: {
468+
...existing,
469+
deposit: onChain.deposit,
470+
authorizedSigner,
471+
}
472+
} else {
473+
updated = {
478474
channelId: payload.channelId,
479475
payer: onChain.payer,
480476
payee: onChain.payee,
@@ -489,9 +485,8 @@ async function handleOpen(
489485
finalized: false,
490486
createdAt: new Date(),
491487
}
492-
})
493-
494-
if (!updated) throw new VerificationFailedError({ reason: 'failed to create channel' })
488+
}
489+
await storage.set(payload.channelId, updated)
495490

496491
return createStreamReceipt({
497492
challengeId: challenge.id,
@@ -534,17 +529,15 @@ async function handleTopUp(
534529
feePayer,
535530
})
536531

537-
const updated = await updateChannel(storage, payload.channelId, (current) => {
538-
if (!current) throw new ChannelNotFoundError({ reason: 'channel not found' })
539-
return { ...current, deposit: onChainDeposit }
540-
})
532+
const updated = { ...channel, deposit: onChainDeposit }
533+
await storage.set(payload.channelId, updated)
541534

542535
return createStreamReceipt({
543536
challengeId: challenge.id,
544537
channelId: payload.channelId,
545-
acceptedCumulative: updated?.highestVoucherAmount ?? channel.highestVoucherAmount,
546-
spent: updated?.spent ?? 0n,
547-
units: updated?.units ?? 0,
538+
acceptedCumulative: updated.highestVoucherAmount,
539+
spent: updated.spent,
540+
units: updated.units,
548541
})
549542
}
550543

@@ -651,23 +644,21 @@ async function handleClose(
651644
txHash = await closeOnChain(client, methodDetails.escrowContract, voucher)
652645
}
653646

654-
const updated = await updateChannel(storage, payload.channelId, (current) => {
655-
if (!current) return null
656-
return {
657-
...current,
658-
deposit: onChain.deposit,
659-
highestVoucherAmount: voucher.cumulativeAmount,
660-
highestVoucher: voucher,
661-
finalized: true,
662-
}
663-
})
647+
const updated = {
648+
...channel,
649+
deposit: onChain.deposit,
650+
highestVoucherAmount: voucher.cumulativeAmount,
651+
highestVoucher: voucher,
652+
finalized: true,
653+
}
654+
await storage.set(payload.channelId, updated)
664655

665656
return createStreamReceipt({
666657
challengeId: challenge.id,
667658
channelId: payload.channelId,
668659
acceptedCumulative: voucher.cumulativeAmount,
669-
spent: updated?.spent ?? channel.spent,
670-
units: updated?.units ?? channel.units,
660+
spent: updated.spent,
661+
units: updated.units,
671662
...(txHash !== undefined && { txHash }),
672663
})
673664
}

src/tempo/server/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
export type { ChannelState, ChannelStorage, Storage } from '../stream/Storage.js'
2-
export { memoryStorage, updateChannel } from '../stream/Storage.js'
1+
export type { ChannelState, Storage } from '../stream/Storage.js'
2+
export { memoryStorage } from '../stream/Storage.js'
33
export { charge } from './Charge.js'
44
export * as Sse from './Sse.js'
55
export { settle, stream } from './Stream.js'

src/tempo/stream/Sse.test.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { Address, Hex } from 'viem'
22
import { describe, expect, test } from 'vitest'
33
import { formatNeedVoucherEvent, formatReceiptEvent, parseEvent, serve } from './Sse.js'
44
import type { ChannelState, Storage } from './Storage.js'
5-
import { updateChannel } from './Storage.js'
65
import type { NeedVoucherEvent, StreamReceipt } from './Types.js'
76

87
const channelId = '0x0000000000000000000000000000000000000000000000000000000000000001' as Hex
@@ -204,11 +203,11 @@ describe('serve', () => {
204203
for (const v of values) yield v
205204
}
206205

207-
function seedChannel(
206+
async function seedChannel(
208207
storage: Storage<ChannelState>,
209208
balance: bigint,
210-
): Promise<ChannelState | null> {
211-
return updateChannel(storage, channelId, () => ({
209+
): Promise<ChannelState> {
210+
const state: ChannelState = {
212211
channelId,
213212
payer: '0x0000000000000000000000000000000000000001' as Address,
214213
payee: '0x0000000000000000000000000000000000000002' as Address,
@@ -222,7 +221,9 @@ describe('serve', () => {
222221
units: 0,
223222
finalized: false,
224223
createdAt: new Date(),
225-
}))
224+
}
225+
await storage.set(channelId, state)
226+
return state
226227
}
227228

228229
test('emits message events for each generated value', async () => {
@@ -280,10 +281,12 @@ describe('serve', () => {
280281

281282
await new Promise((r) => setTimeout(r, 30))
282283

283-
await updateChannel(storage, channelId, (current) => {
284-
if (!current) return null
285-
return { ...current, highestVoucherAmount: current.highestVoucherAmount + 2000000n }
286-
})
284+
const current = await storage.get(channelId)
285+
if (current)
286+
await storage.set(channelId, {
287+
...current,
288+
highestVoucherAmount: current.highestVoucherAmount + 2000000n,
289+
})
287290

288291
const secondChunk = await readNext
289292
expect(secondChunk).toContain('event: mpay-need-voucher\n')

0 commit comments

Comments
 (0)