]> git.codecow.com Git - nano-pow.git/commitdiff
Merge branch 'main' into next/ergonomics
authorChris Duncan <chris@codecow.com>
Fri, 22 May 2026 18:08:30 +0000 (11:08 -0700)
committerChris Duncan <chris@codecow.com>
Fri, 22 May 2026 18:08:30 +0000 (11:08 -0700)
1  2 
package.json
src/lib/generate/webgl/index.ts
src/lib/index.ts
src/utils/cache.ts
test/index.html
tsconfig.json

diff --cc package.json
Simple merge
index 36781bad9b61b5adf96e223b6c1942c22b0f360a,df50b8bf40bf884d37af8873a7e3cafe1253d05c..ab7cbbfd8711a6642f2d97b9818b5fb58ae69d9d
@@@ -2,8 -2,8 +2,8 @@@
  //! SPDX-FileContributor: Ben Green <ben@latenightsketches.com>
  //! SPDX-License-Identifier: GPL-3.0-or-later AND MIT
  
- import { WorkGenerateResponse } from 'nano-pow'
 -import { WorkGenerateResponse } from '#types'
  import { bigintAsUintNArray, bigintRandom, bigintToHex, Logger } from '#utils'
++import { WorkGenerateResponse } from 'nano-pow'
  import { downsampleSource, drawSource, quadSource } from './shaders'
  
  /**
index 938f8ad110b03940476d1d1881b446fee625cedc,bbc0dd5691188d4087a471364c48be40832ac7a2..e290df6bf982bd7e151af911bc6d6f1ac37d41e5
@@@ -4,8 -4,8 +4,8 @@@
  import { NanoPowConfig } from '#lib/config'
  import { NanoPowCpu, NanoPowWasm, NanoPowWebgl, NanoPowWebgpu } from '#lib/generate'
  import { NanoPowValidate } from '#lib/validate'
 -import { WorkErrorResponse, WorkGenerateResponse, WorkValidateResponse } from '#types'
  import { bigintFrom, Cache, Logger, Queue } from '#utils'
++import { WorkErrorResponse, WorkGenerateResponse, WorkValidateResponse } from 'nano-pow'
  
  const logger = new Logger()
  const q = new Queue()
@@@ -15,11 -15,19 +15,20 @@@ export async function generate (hash: u
                try {
                        const { api, debug, difficulty, effort } = await NanoPowConfig(options)
                        LOG: logger.isEnabled = debug
 -                      const cached = Cache.search(hash, difficulty)
 +                      const bigintHash = bigintFrom(hash, 'hex')
 +                      const cached = Cache.search(bigintHash, difficulty)
                        if (cached) {
                                LOG: logger.log('found work in cache')
-                               return cached
+                               const { valid } = NanoPowValidate(bigintFrom(cached.work, 'hex'), bigintFrom(cached.hash, 'hex'), bigintFrom(cached.difficulty, 'hex'), debug)
+                               if (valid === '1') {
+                                       return cached
+                               } else {
+                                       try {
+                                               Cache.delete(hash)
+                                       } catch (err) {
+                                               LOG: logger.log('error deleting invalid work from cache, continuing with generate', err)
+                                       }
+                               }
                        }
                        switch (api) {
                                case 'webgpu': {
index faa460975a4ce2ddb0c5bb20e4b694e02285fb2e,24d0e0eeb737603e14ab742748a5cbf3697f3ddb..779a227bed938030d56cbfefa566f9a9642e0d5b
@@@ -1,50 -1,61 +1,61 @@@
  //! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
  //! SPDX-License-Identifier: GPL-3.0-or-later
  
 -import { WorkGenerateResponse } from "#types"
 -import { bigintFrom } from "#utils"
 +import { WorkGenerateResponse } from 'nano-pow'
  
 -export class Cache {
 +const STORAGE_KEY = 'NanoPowCache'
  
 -      static clear (): void {
 -              this.#removeItem('NanoPowCache')
 -      }
 +let storage: { [key: string]: string } = {}
  
 -      static delete (hash: unknown): void {
 -              const bigintHash = bigintFrom(hash, 'hex')
 -              const item = this.#getItem('NanoPowCache')
 -              if (item == null) return
 -              const cache = JSON.parse(item) as WorkGenerateResponse[]
 -              for (let i = 0; i < cache.length; i++) {
 -                      if (bigintFrom(cache[i].hash, 'hex') === bigintHash) {
 -                              cache.splice(i, 1)
 -                      }
 -              }
 -              this.#setItem('NanoPowCache', JSON.stringify(cache))
 -      }
 +function getItem (key: string): string | null {
 +      if (globalThis?.localStorage) return globalThis.localStorage.getItem(key)
 +      return storage[key]
 +}
  
 -      static search (hash: unknown, difficulty: bigint): WorkGenerateResponse | null {
 -              const bigintHash = bigintFrom(hash, 'hex')
 -              const item = this.#getItem('NanoPowCache')
 -              if (item) {
 -                      const cache = JSON.parse(item) as WorkGenerateResponse[]
 -                      for (const c of cache) {
 -                              if (bigintFrom(c.hash, 'hex') === bigintHash && bigintFrom(c.difficulty, 'hex') >= difficulty) {
 -                                      return c
 -                              }
 -                      }
 +function removeItem (key: string): void {
 +      if (globalThis?.localStorage) return globalThis.localStorage.removeItem(key)
 +      storage = {}
 +}
 +
 +function setItem (key: string, item: string): void {
 +      if (globalThis?.localStorage) return globalThis.localStorage.setItem(key, item)
 +      storage[key] = item
 +}
 +
 +export function clear (): void {
 +      removeItem(STORAGE_KEY)
 +}
 +
- export function search (hash: bigint, difficulty: bigint): WorkGenerateResponse | null {
++export function get (hash: bigint, difficulty: bigint): WorkGenerateResponse | null {
 +      const item = getItem(STORAGE_KEY)
-       if (item) {
-               const cache = JSON.parse(item) as WorkGenerateResponse[]
-               for (const c of cache) {
-                       if (BigInt(`0x${c.hash}`) === hash && BigInt(`0x${c.difficulty}`) >= difficulty) {
-                               return c
-                       }
++      if (item == null) return null
++      const cache: WorkGenerateResponse[] = JSON.parse(item)
++      for (const c of cache) {
++              if (BigInt(`0x${c.hash}`) === hash && BigInt(`0x${c.difficulty}`) >= difficulty) {
++                      return c
                }
 -              return null
        }
 +      return null
 +}
  
- export function store (result: WorkGenerateResponse): WorkGenerateResponse {
 -      static store (result: WorkGenerateResponse): WorkGenerateResponse {
 -              const item = this.#getItem('NanoPowCache')
 -              const cache = JSON.parse(item ?? '[]') as WorkGenerateResponse[]
 -              if (cache.push(result) > 1000) cache.shift()
 -              this.#setItem('NanoPowCache', JSON.stringify(cache))
 -              return result
++export function remove (hash: bigint): void {
 +      const item = getItem(STORAGE_KEY)
-       const cache = JSON.parse(item ?? '[]') as WorkGenerateResponse[]
++      if (item == null) return
++      const cache = JSON.parse(item) as WorkGenerateResponse[]
++      for (let i = 0; i < cache.length; i++) {
++              if (BigInt(`0x${cache[i].hash}`) === hash) {
++                      cache.splice(i, 1)
++              }
+       }
++      setItem('NanoPowCache', JSON.stringify(cache))
++}
 -      static #storage: { [key: string]: string } = {}
 -      static #getItem (key: string): string | null {
 -              if (globalThis?.localStorage) return globalThis.localStorage.getItem(key)
 -              return this.#storage[key]
 -      }
 -      static #removeItem (key: string): void {
 -              if (globalThis?.localStorage) return globalThis.localStorage.removeItem(key)
 -              this.#storage = {}
 -      }
 -      static #setItem (key: string, item: string): void {
 -              if (globalThis?.localStorage) return globalThis.localStorage.setItem(key, item)
 -              this.#storage[key] = item
 -      }
++export function set (result: WorkGenerateResponse): WorkGenerateResponse {
++      const item = getItem(STORAGE_KEY) ?? '[]'
++      const cache: WorkGenerateResponse[] = JSON.parse(item)
 +      if (cache.push(result) > 1000) cache.shift()
 +      setItem(STORAGE_KEY, JSON.stringify(cache))
 +      return result
  }
- export const Cache = { clear, search, store }
 +
++export const Cache = { clear, delete: remove, search: get, store: set }
diff --cc test/index.html
index 882e091f5de5316201f5a38442e2b622ac011865,2c90f01ea754cb04286890d4f01c93b8306e6e34..c0a873f84d786d4d7d31cf57474a8a5e3dd3bdfc
@@@ -44,13 -28,13 +44,13 @@@ SPDX-License-Identifier: GPL-3.0-or-lat
  
                const glSize = (canvas => {
                        const gl = canvas.getContext('webgl2')
-                       const MAX_VIEWPORT_DIMS = gl.getParameter(gl.MAX_VIEWPORT_DIMS)
-                       canvas.height = MAX_VIEWPORT_DIMS?.[0] ?? 0x1000
-                       canvas.width = MAX_VIEWPORT_DIMS?.[1] ?? 0x1000
-                       return Math.min(gl.drawingBufferHeight, gl.drawingBufferWidth)
+                       const MAX_VIEWPORT_DIMS = gl?.getParameter(gl.MAX_VIEWPORT_DIMS) ?? [0x1000, 0x1000]
+                       const size = Math.min(0x2000, ...MAX_VIEWPORT_DIMS)
+                       canvas.height = canvas.width = size
+                       return gl?.drawingBufferHeight < gl?.drawingBufferWidth ? gl?.drawingBufferHeight : gl?.drawingBufferWidth
                })(new OffscreenCanvas(0, 0))
  
 -              function random(size = 64) {
 +              function random (size = 64) {
                        let hex = ''
                        while (hex.length < size) {
                                hex += crypto.randomUUID().replace(/-.*-/g, '')
diff --cc tsconfig.json
index caeff0e7f3cc30675151ee0ab96aef4eef9b0237,120b2158072827d6ffad44cc5eb1aacbc8ab1683..12146e24917e910ff29be36a6aea4065854e3d8d
@@@ -2,12 -2,11 +2,11 @@@
        "compilerOptions": {
                "target": "es2022",
                "module": "es2022",
 -              "moduleResolution": "Bundler",
 +              "moduleResolution": "bundler",
                "declaration": true,
                "emitDeclarationOnly": true,
 -              "declarationDir": "./types",
 +              "declarationDir": "./dist",
                "alwaysStrict": true,
-               "downlevelIteration": false,
                "esModuleInterop": true,
                "forceConsistentCasingInFileNames": true,
                "noErrorTruncation": true,