refactor: replace WASM-based PoW with a high-performance native Go implementation and add context support for cancellation.

This commit is contained in:
CJACK
2026-04-07 01:20:01 +08:00
parent e7d561694a
commit da778a18fb
11 changed files with 31 additions and 27 deletions

View File

@@ -1,6 +1,7 @@
package pow
import (
"context"
"encoding/base64"
"encoding/binary"
"encoding/hex"
@@ -9,7 +10,7 @@ import (
"strconv"
)
// Challenge 对应 /api/v0/chat/create_pow_challenge 返回 data.biz_data.challenge。
// Challenge 对应 /api/v0/chat/create_pow_challenge 返回 dem data.biz_data.challenge。
type Challenge struct {
Algorithm string `json:"algorithm"`
Challenge string `json:"challenge"`
@@ -27,7 +28,7 @@ func BuildPrefix(salt string, expireAt int64) string {
// SolvePow 搜索 nonce ∈ [0, difficulty) 使得 DeepSeekHashV1(prefix+str(nonce)) == challenge。
// prefix 预吸收进 state,循环内零分配。
func SolvePow(challengeHex, salt string, expireAt, difficulty int64) (int64, error) {
func SolvePow(ctx context.Context, challengeHex, salt string, expireAt, difficulty int64) (int64, error) {
if len(challengeHex) != 64 {
return 0, errors.New("pow: challenge must be 64 hex chars")
}
@@ -59,6 +60,13 @@ func SolvePow(challengeHex, salt string, expireAt, difficulty int64) (int64, err
var numBuf [20]byte
for n := int64(0); n < difficulty; n++ {
// Periodically check if context is canceled to avoid wasting CPU
if n&0x3FF == 0 {
if err := ctx.Err(); err != nil {
return 0, err
}
}
v := uint64(n)
pos := 20
if v == 0 {
@@ -123,7 +131,7 @@ func BuildPowHeader(c *Challenge, answer int64) (string, error) {
}
// SolveAndBuildHeader 端到端: Challenge → x-ds-pow-response header string。
func SolveAndBuildHeader(c *Challenge) (string, error) {
func SolveAndBuildHeader(ctx context.Context, c *Challenge) (string, error) {
if c.Algorithm != "DeepSeekHashV1" {
return "", errors.New("pow: unsupported algorithm: " + c.Algorithm)
}
@@ -131,7 +139,7 @@ func SolveAndBuildHeader(c *Challenge) (string, error) {
if d == 0 {
d = 144000
}
answer, err := SolvePow(c.Challenge, c.Salt, c.ExpireAt, d)
answer, err := SolvePow(ctx, c.Challenge, c.Salt, c.ExpireAt, d)
if err != nil {
return "", err
}

View File

@@ -1,6 +1,7 @@
package pow
import (
"context"
"encoding/base64"
"encoding/hex"
"encoding/json"
@@ -36,7 +37,7 @@ func TestSolvePow(t *testing.T) {
{"abc123salt", 1700000000, 12345, 20000},
} {
h := DeepSeekHashV1([]byte(BuildPrefix(tc.salt, tc.expire) + strconv.FormatInt(tc.answer, 10)))
got, err := SolvePow(hex.EncodeToString(h[:]), tc.salt, tc.expire, tc.diff)
got, err := SolvePow(context.Background(), hex.EncodeToString(h[:]), tc.salt, tc.expire, tc.diff)
if err != nil || got != tc.answer {
t.Errorf("salt=%q answer=%d: got=%d err=%v", tc.salt, tc.answer, got, err)
}
@@ -45,7 +46,7 @@ func TestSolvePow(t *testing.T) {
func TestSolveAndBuildHeader(t *testing.T) {
t0 := DeepSeekHashV1([]byte("salt_1712345678_777"))
header, err := SolveAndBuildHeader(&Challenge{
header, err := SolveAndBuildHeader(context.Background(), &Challenge{
Algorithm: "DeepSeekHashV1", Challenge: hex.EncodeToString(t0[:]),
Salt: "salt", ExpireAt: 1712345678, Difficulty: 2000,
Signature: "sig", TargetPath: "/api/v0/chat/completion",
@@ -74,6 +75,6 @@ func BenchmarkSolve(b *testing.B) {
h := DeepSeekHashV1([]byte("realisticsalt_1712345678_72000"))
ch := hex.EncodeToString(h[:])
for i := 0; i < b.N; i++ {
_, _ = SolvePow(ch, "realisticsalt", 1712345678, 144000)
_, _ = SolvePow(context.Background(), ch, "realisticsalt", 1712345678, 144000)
}
}