From 3fcf4f705c5e49170c5d887a50d0da05a7726ece Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Mon, 5 Oct 2026 19:16:47 +0000 Subject: [PATCH] Proving v1: the harness passes (21 checks), the bench-log entry with the step 1 GPU memory, RAM and SM-target numbers, the CPU chain of 2 and verify-segment Co-Authored-By: Claude Fable 5.1 --- docs/bench-log.md | 38 +++ tools/proving-v1/net.mjs | 2 +- tools/proving-v1/pc2-prover-cost.ps1 | 10 +- tools/proving-v1/report-2026-10-05.json | 332 ++++++++++++++++++++++++ 4 files changed, 379 insertions(+), 3 deletions(-) create mode 100644 tools/proving-v1/report-2026-10-05.json diff --git a/docs/bench-log.md b/docs/bench-log.md index 890bc1ee..ec821672 100644 --- a/docs/bench-log.md +++ b/docs/bench-log.md @@ -1586,3 +1586,41 @@ The 3-node run (`tools/txgen/relay-net.mjs`, new; this Mac, load 7 to 8 at the e Reading. Every transaction given to A was mined by B or C within 6 s, two thirds of them within 3 s, with no skipped copy: the hold on block-added kept B's and C's parallel blocks from carrying the same transfer. The afternoon run on the live devnet, through one node with the cooldown, had p50 40.7 s and p90 110.8 s with 50-s quiet stretches; here the 1.5 s p50 is one fast-time block plus the relay and the executor's lag. The pool depth matching on all three nodes at every sample is the convergence. Not measured here: a transaction flood above the per-peer rate (the bucket is unit-tested only), a 13 peer in the fleet (the digest check and the version gate are the evidence), and the hold's 30-s expiry on a block that never reaches the chain (not seen in 149 chain blocks). Commands: `IGNEUMD=vendor/igneum-node/target-txgossip/release/igneumd IGNEUM_MINER=vendor/igneum-node/target-txgossip/release/igneum-miner tools/lock/with-lock.sh run node tools/txgen/relay-net.mjs --rate 2 --duration 120 --wallets 16 --fund 2`; the Mac binaries from the fork worktree with `CARGO_TARGET_DIR=vendor/igneum-node/target-txgossip cargo build --release -j 4 -p kaspad -p igneum-miner --features kaspad/igneum-pow` under the build lock (an APFS clone of `target-036`, 2 min 15 s to clone, 5 min 06 s to build); the suites with `node tools/build-job.mjs run --target 1ccfe586 --node vendor/igneum-node-txgossip --targets linux --node-tests "igneum-exec kaspa-p2p-flows" --no-app`. +## 5 October 2026 (evening), proving v1: segment records, the chain rule, the unproven rule; what was measured tonight (proving engineer) + +Branches `proving-v1` (main repository, worktree `igneum-wt-proving-v1`; fork `vendor/igneum-node-pv1` from a24ab01a). Rules: spec 7.8; plan `docs/plans/proving-v1.md`. Every row names its command. The live devnet was in a degraded state the whole evening: from 18:35Z the RTX 5090 workers on PC 1 and PC 2 exited at start on a pack seed mismatch (`the epoch seed bytes do not give the pack's IGNEUM_SEEDW_INIT`, restart 60+ on PC 2 by 19:05Z, another agent's branch `pack-loop`), the Mac app node was down from 17:45Z, so PC 2 mined 3.4 MH/s from its iGPU and PC 2's prover was the only prover; the coordinator held every PC 2 measurement at 19:00Z until the fleet mines again. + +### Step 1, the prover default and its cost + +| What | Measured | +|---|---| +| The default rule (`app/igneum-app/src/provedefault.rs`) | `cargo test --release -p igneum-app provedefault` on this Mac (the app crate, build lock, 19:05Z): 5 passed (a 5090 with WSL2 on Windows is on; Windows without WSL2 off with the Set up hint; Linux needs no WSL2 and the 12 GB gate holds, a 10 GB 3080 and a 16 GB AMD card stay off; Apple silicon off; the biggest qualifying card is named) | +| Mining alone against mining with the prover (PC 2 job `prover-cost-pc2-pv1`, `tools/proving-v1/pc2-prover-cost.ps1`, 5 + 5 min, published 18:40:48Z, ran 18:41:13Z) | VOID: the job waited 20 min for the 5090 worker to hash and it never did (the pack fault above); "mining alone" was 0 MH/s. Re-run after the coordinator's go. The job's `/api/state` read also came back empty on PC 2 (`cards=::0`, every sample) while `igneum_getProvingStatus` on 127.0.0.1:26790 answered; the re-run script prints the URL file and the error | +| GPU memory during proving (the same job, phase B: the prover on for 5 min, 298 one-second `nvidia-smi --query-gpu=memory.used` samples, the 5090 worker dead so the card held nothing else) | memory.used min 1,654 MiB, max 13,816 MiB, utilisation mean 2.7%, power max 190.6 W. The shards were the devnet's empty shards (0 pgas); the peak on a full shard at `S_p` is the chain job's row (held). Read: a 16 GB card clears tonight's peak, a 12 GB card does not, and the 24 GB of a 4090 has 10 GB of headroom | +| Shards per minute with the mining worker dead | the node's `paidShards` 510 -> 518 over the 5-min phase: 1.6 shards a minute from one 5090 through the app's loop (export, cut, prove, sign, submit) | +| Host RAM (Windows `Win32_OperatingSystem` and the `vmmem` working set, sampled every 15 s) | host used 25,550 MB of 63,132 MB at the end; the WSL2 VM's working set 7,915 MB (2,334 MB used of 30,914 MB inside the distribution) | +| The SP1 GPU server's compiled targets (`cuobjdump --list-elf /root/.sp1/bin/sp1-gpu-server` inside PC 2's Ubuntu-24.04, CUDA 12.8, driver 610.47) | `sp1-gpu-server` 6.8.1 (251,306,680 bytes, sha256 c2642ad1c42e85d8525159cf0c7cd5200d8766c9be1283f452a1f9bf9fea725c, the asset `sp1_gpu_server_v6.8.1_x86_64.tar.gz` the SDK downloads, `sp1-cuda-6.8.1/src/server.rs`): one ELF each for sm_80, sm_86, sm_89, sm_90, sm_100 and sm_120; `strings` finds compute_120 PTX as well. So sm_89 (Ada: RTX 4090, 4080) is compiled in natively, no JIT; so are Ampere (3090, 3060), Hopper, Blackwell datacentre (sm_100) and consumer (sm_120, the 5090). Nothing for AMD (no HIP path in SP1) | + +### Step 2, aggregated chains + +| What | Measured | +|---|---| +| The new host (`--mode chain`, `aggregate`, `verify-segment`) against every fixture natively | `igneum-prove-host --mode native` on the Mac for the 12 fixtures of `proving/fixtures/` (9 block, 3 fee-switch), host built from this branch 19:06Z: every one MATCHES (the package gate's native half); `--mode id`: shard `0x2b1a81cb...`, aggregator `0x474678f3...`, the 0.3.9 pin, unchanged | +| Eight consecutive live fixtures | `igneum_exportSegments 0x0..0x13cb4` on node 1's exec RPC (127.0.0.1:26790, read-only, 20:06 BST, tip 81,076): 71,042,616 bytes, 81,077 segments, 28 accounts, 0.5 s; `igneum-prove-export export.json block-.json` for 81046..81053: replayed 81,077 segments from genesis in 1.8 s each, every state root equal to the node's; one shard a block, 0 pgas (no transactions on the devnet tonight), `proving/fixtures/chain/` | +| Chain of 2 on the Mac CPU (the known-finished case of `--mode chain` before the GPU; M5 Max under the live nodes, the harness and two builds) | `SP1_PROVER=cpu igneum-prove-host --mode chain --chain block-81046.json,block-81047.json --out results.json` under the run lock, 19:07:48Z to 19:11:28Z: setup 12.2 s; block 81046: shard 0 compressed 55.4 s (1,272,897 bytes, verify 0.036 s), aggregate 52.0 s (1,272,909 bytes, verify 0.031 s), chain_len 1, agg_vk zero; block 81047: shard 41.3 s, aggregate WITH the previous block proof 59.1 s, chain_len 2, agg_vk = the pinned aggregator id; end to end 207.9 s; final proof 1,272,909 bytes, statement 0x232276f4... The recursion over the previous proof cost 7 s more than the first aggregation on this CPU | +| `--mode verify-segment` on that proof (the node's path: SP1 light verifier, pinned aggregator key) | VERIFIED in 0.032 s (0.27 s wall, three runs: 0.033, 0.032, 0.032); known-failed: a wrong statement NOT VERIFIED (0.032 s); the shard verifier (`--mode verify`) on the segment proof NOT VERIFIED, "program id 0x474678f3... IS NOT OURS 0x2b1a81cb..." | +| Chain of 8 on the RTX 5090 (N = 2, 4, 8) | HELD with step 1 (`tools/proving-v1/pc2-chain.ps1`, package `igneum-prove-wsl2-pv1.zip` eb6dccf8..., 1.5 MB, built from this branch with the gate's native half run above) | + +### Step 3, coverage + +| What | Measured | +|---|---| +| A 3-minute window at 18:57Z on node 1 (`node tools/proving-v1/coverage.mjs --minutes 3`, chain blocks 80754..80839, 86 blocks) | 4 blocks with a paid shard (4.7%), 4 fully proven, 4 of 86 shards; on-chain latency (carrier timestamp minus block timestamp) n 4: min 36 s, p50 39 s, max 44 s; 0 content blocks. One prover (PC 2), the Mac verifier node down, PC 2 producing few blocks (3.4 MH/s): the degraded state above, not the fleet's number | +| The 30-minute window | waits for the fleet (the coordinator's go) | + +### Step 4, the rule + +| What | Measured | +|---|---| +| Unit tests | `cargo test --release -p kaspa-consensus-core -p igneum-exec --lib -- proving config::params::tests::override_params_carry_the_proving_v1 config::params::tests::consensus_digest` on this Mac (target `vendor/igneum-node/target-pv1`, 19:09Z): consensus core 13 passed (the segment record round trip, signature and the three nested sections; the credit split; the params switch and the digest that moves only once the switch is set), exec 8 passed (the segment grid and the split; the record checks: alignment, block, chain length, the veto naming the field, the deadline, the window; the chain rule both ways; the unproven restart; the shard side at 90%; the pool offering the segment section). The six full node suites go to PC 2 as a build job when the fleet is back | +| The fast-time 3-node harness (`tools/proving-v1/net.mjs`, 29950+, suffix 956, every node in trust mode, three vmine voters, v0 at DAA 60, v1 at DAA 120, 4 blocks a segment, unproven after 60 DAA, a tenth to the aggregator; fork b177718e built on this Mac) | run 2, 19:13:01Z to 19:16:19Z, under the run lock: PASSED, 21 checks in 197.3 s (`tools/proving-v1/report-2026-10-05.json`). v1 start = chain block 119 on all three nodes; the native statement identical on all three. Known-finished: segment 119..122's fresh-chain record submitted to n1 at t=131.1 s, relayed, verified (trust) and PAID on n0 1.0 s later at chain block 129, 253,611,648,000,000,000 wei = a tenth of the four credits, the same on every node, the payout address holding it. Chain rule: segment 123..126's fresh-chain record refused ("does not chain to segment 119..122 ... proven (record paid at chain block 129)"), the continuing one (chain_len 8) accepted and paid. Known-failed: segment 127..130 left without a record: a fresh-chain record for 131..134 refused while 127..130 was pending ("pending until DAA 191"); at DAA 192 the status read unproven, a late record for 127..130 refused ("unproven: carried after the deadline"), the fresh-chain record for 131..134 accepted and paid with chain_len 4; `segmentsInWindow` proven 3, unproven 1. The shard side: a v1 shard's `shardWei` = 90% of its block's credit. Run 1 (19:10Z) failed in its own tooling (the signer's argument order), fixed | diff --git a/tools/proving-v1/net.mjs b/tools/proving-v1/net.mjs index fd7d7271..6ba40332 100644 --- a/tools/proving-v1/net.mjs +++ b/tools/proving-v1/net.mjs @@ -122,7 +122,7 @@ async function waitExecuted(n, number) { // signs a segment record over the given public values with v0's key; the proof bytes are a placeholder (trust mode) function signSegment(first, last, hash, pv, tag) { const proof = Buffer.from(`igneum-proving-v1-harness-${tag}-${first}-${last}`); - const sg = run(MINER, ['sign-segment-record', 'v0', CHAIN_NAME, hash, String(first), String(last), PAYOUT, pv, sha256(proof)]); + const sg = run(MINER, ['sign-segment-record', 'v0', CHAIN_NAME, String(first), String(last), hash, PAYOUT, pv, sha256(proof)]); if (sg.code !== 0) throw new Error(`sign-segment-record failed: ${sg.out}`); const signed = JSON.parse(sg.out.trim().split('\n').pop()); return { record: signed.record, proof: '0x' + proof.toString('hex'), keyHash: signed.keyHash, statement: signed.statement }; diff --git a/tools/proving-v1/pc2-prover-cost.ps1 b/tools/proving-v1/pc2-prover-cost.ps1 index a21565ea..82aa21d9 100644 --- a/tools/proving-v1/pc2-prover-cost.ps1 +++ b/tools/proving-v1/pc2-prover-cost.ps1 @@ -7,9 +7,15 @@ # 5. leaves the prover ON # Every number is a RESULT line; the per-sample lines are SAMPLE lines. Read with `node tools/jobs.mjs `. $ErrorActionPreference = 'Continue' -$base = (Get-Content (Join-Path $env:LOCALAPPDATA 'igneum\app\app.url') -Raw).Trim().TrimEnd('/') +$urlFile = if ($env:IGNEUM_APP_DIR) { Join-Path $env:IGNEUM_APP_DIR 'app.url' } else { Join-Path $env:LOCALAPPDATA 'igneum\app\app.url' } +if (-not (Test-Path $urlFile)) { $urlFile = Join-Path $env:LOCALAPPDATA 'igneum\app\app.url' } +$base = (Get-Content $urlFile -Raw).Trim().TrimEnd('/') function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') } -function State { try { Invoke-RestMethod -Uri "$base/api/state" -TimeoutSec 10 } catch { $null } } +$script:stateErr = '' +function State { try { Invoke-RestMethod -Uri "$base/api/state" -TimeoutSec 20 } catch { $script:stateErr = "$_"; $null } } +"RESULT app_url_file $(Stamp) $urlFile exists=$(Test-Path $urlFile) base_len=$($base.Length)" +$probe = State +"RESULT state_probe $(Stamp) ok=$($null -ne $probe) version=$($probe.version) cards=$(($probe.mining.cards | Measure-Object).Count) err=$script:stateErr" function Prove($on) { try { (Invoke-RestMethod -Method Post -Uri "$base/api/prove" -ContentType 'application/json' -Body (@{on=$on} | ConvertTo-Json -Compress) -TimeoutSec 10) | ConvertTo-Json -Compress } catch { "error: $_" } } function Rpc($port, $method, $params) { try { (Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:$port" -ContentType 'application/json' -Body (@{jsonrpc='2.0'; id=1; method=$method; params=$params} | ConvertTo-Json -Compress -Depth 6) -TimeoutSec 20).result } catch { $null } diff --git a/tools/proving-v1/report-2026-10-05.json b/tools/proving-v1/report-2026-10-05.json new file mode 100644 index 00000000..440a3041 --- /dev/null +++ b/tools/proving-v1/report-2026-10-05.json @@ -0,0 +1,332 @@ +{ + "v0": 60, + "v1": 120, + "segment": 4, + "unproven": 60, + "share_bps": 1000, + "steps": { + "status": { + "v0": "0x3c", + "v1": { + "activationDaa": "0x78", + "active": false, + "aggregatorId": null, + "aggregatorShareBps": "0x3e8", + "paidSegmentWei": "0x0", + "paidSegments": 0, + "pool": { + "entries": 0, + "failed": 0, + "pending": 0, + "verified": 0 + }, + "segmentBlocks": "0x4", + "segmentsInWindow": { + "pending": 0, + "proven": 0, + "unproven": 0 + }, + "shardProgramId": null, + "start": null, + "unprovenDaa": "0x3c" + } + }, + "v1_start": { + "start": 119, + "tipDaa": 128 + }, + "case1": { + "segment": [ + 119, + 122 + ], + "wei": "253611648000000000", + "paidSecs": 1.008, + "carrier": "0x81" + }, + "case2": { + "segment": [ + 123, + 126 + ], + "refused": "segment 123..126 does not chain to segment 119..122 (chain_len 4), which is proven (record paid at chain block 129)", + "paid": { + "carrierNumber": "0x87", + "chainLen": "0x8", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "payout": "0x4343434343434343434343434343434343434343", + "wei": "0x38505a6ce4a8000" + } + }, + "case3": { + "unproven": [ + 127, + 130 + ], + "restarted": [ + 131, + 134 + ], + "status": { + "activationDaa": "0x78", + "active": true, + "aggregatorId": null, + "aggregatorShareBps": "0x3e8", + "paidSegmentWei": "0xa8f1428e9a42800", + "paidSegments": 3, + "pool": { + "entries": 3, + "failed": 0, + "pending": 0, + "verified": 0 + }, + "segmentBlocks": "0x4", + "segmentsInWindow": { + "pending": 15, + "proven": 3, + "unproven": 1 + }, + "shardProgramId": null, + "start": "0x77", + "unprovenDaa": "0x3c" + } + } + }, + "checks": [ + { + "name": "the node carries the v1 parameters", + "ok": true, + "detail": { + "activationDaa": "0x78", + "active": false, + "aggregatorId": null, + "aggregatorShareBps": "0x3e8", + "paidSegmentWei": "0x0", + "paidSegments": 0, + "pool": { + "entries": 0, + "failed": 0, + "pending": 0, + "verified": 0 + }, + "segmentBlocks": "0x4", + "segmentsInWindow": { + "pending": 0, + "proven": 0, + "unproven": 0 + }, + "shardProgramId": null, + "start": null, + "unprovenDaa": "0x3c" + } + }, + { + "name": "every node agrees on the v1 start", + "ok": true, + "detail": 119 + }, + { + "name": "segment 0 is aligned at the start and pending", + "ok": true, + "detail": { + "first": "0x77", + "last": "0x7a", + "status": { + "deadline_daa": 183, + "status": "pending" + } + } + }, + { + "name": "the native statement is the same on every node", + "ok": true, + "detail": "0x000000000000116f000000" + }, + { + "name": "the aggregator share is a tenth of the segment credits", + "ok": true, + "detail": { + "expectedWei0": "253611648000000000", + "creditSum0": "2536116480000000000" + } + }, + { + "name": "known-finished: segment 0 record accepted by n1", + "ok": true, + "detail": { + "accepted": true, + "block": "0xe03d6896eff5476fffb90d066efd77feb0e2eb9c527b967423b74bb5948f36d2", + "first": "0x77", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "last": "0x7a", + "new": true, + "reason": "accepted" + } + }, + { + "name": "known-finished: segment 0 paid on n0 (relayed over p2p, verified in trust mode, carried)", + "ok": true, + "detail": { + "paid": { + "carrierNumber": "0x81", + "chainLen": "0x4", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "payout": "0x4343434343434343434343434343434343434343", + "wei": "0x38502733df10000" + }, + "secs": 1.008 + } + }, + { + "name": "every node paid segment 0 the same", + "ok": true, + "detail": [ + "0x38502733df10000", + "0x38502733df10000", + "0x38502733df10000" + ] + }, + { + "name": "the payout address holds the aggregator share", + "ok": true, + "detail": { + "balance": "253611648000000000" + } + }, + { + "name": "segment 1 names segment 0 as its proven previous", + "ok": true, + "detail": { + "carrierNumber": "0x81", + "chainLen": "0x4", + "first": "0x77", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "last": "0x7a", + "proofHash": "0xed42fb45a37c81f151b2fde1b2b9b35ce0c76f7b59145eaa428f6760b739cae4", + "proofInPool": true + } + }, + { + "name": "chain rule: a fresh-chain record for segment 1 is refused while segment 0 is proven", + "ok": true, + "detail": { + "accepted": false, + "block": "0x43b605649b1d40550fc280a520950a328b25e733b4efe9cc0a204e31e9351022", + "first": "0x7b", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "last": "0x7e", + "new": false, + "reason": "segment 123..126 does not chain to segment 119..122 (chain_len 4), which is proven (record paid at chain block 129)" + } + }, + { + "name": "chain rule: the continuing record (chain_len 8) is accepted", + "ok": true, + "detail": { + "accepted": true, + "block": "0x43b605649b1d40550fc280a520950a328b25e733b4efe9cc0a204e31e9351022", + "first": "0x7b", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "last": "0x7e", + "new": true, + "reason": "accepted" + } + }, + { + "name": "segment 1 paid with chain_len 8", + "ok": true, + "detail": { + "carrierNumber": "0x87", + "chainLen": "0x8", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "payout": "0x4343434343434343434343434343434343434343", + "wei": "0x38505a6ce4a8000" + } + }, + { + "name": "segment 2 is pending with a deadline", + "ok": true, + "detail": { + "deadline_daa": 191, + "status": "pending" + } + }, + { + "name": "known-failed: segment 3 cannot start a fresh chain while segment 2 is pending", + "ok": true, + "detail": { + "accepted": false, + "block": "0x4f502ffcbe86530352096707a93074ee8e1d43e3d2e94b06b8c71735c9eb0b46", + "first": "0x83", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "last": "0x86", + "new": false, + "reason": "segment 131..134 does not chain to segment 127..130 (chain_len 4), which is pending until DAA 191" + } + }, + { + "name": "known-failed: segment 2 is unproven after its deadline", + "ok": true, + "detail": { + "deadline_daa": 191, + "status": "unproven" + } + }, + { + "name": "known-failed: a late record for segment 2 pays nothing (refused as unproven)", + "ok": true, + "detail": { + "accepted": false, + "block": "0xb46575c11a6e42efd2cdbc8a450c0f169c069409a1f6e107c7418cea9c594623", + "first": "0x7f", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "last": "0x82", + "new": false, + "reason": "unproven: the record is carried at DAA 194, after the segment's deadline DAA 191" + } + }, + { + "name": "segment 3 restarts the chain with a fresh-chain record after the unproven segment", + "ok": true, + "detail": { + "accepted": true, + "block": "0x4f502ffcbe86530352096707a93074ee8e1d43e3d2e94b06b8c71735c9eb0b46", + "first": "0x83", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "last": "0x86", + "new": true, + "reason": "accepted" + } + }, + { + "name": "segment 3 paid with chain_len 4", + "ok": true, + "detail": { + "carrierNumber": "0xc1", + "chainLen": "0x4", + "keyHash": "0xc379ba2cdb239d2884d6bdb391d243ddfa869ab95ec4e72372e0e31fc9025fa0", + "payout": "0x4343434343434343434343434343434343434343", + "wei": "0x3850c0edd68a800" + } + }, + { + "name": "the status counts proven and unproven segments", + "ok": true, + "detail": { + "pending": 15, + "proven": 3, + "unproven": 1 + } + }, + { + "name": "a v1 shard is paid 90% of its block share (one shard a block here)", + "ok": true, + "detail": { + "number": "0xc3", + "shardWei": "0x7ebcd81877b9c00", + "credit": "0x8cd1d3a96895800" + } + } + ], + "ok": true +} \ No newline at end of file