@leofcoin/chain 1.10.6 → 1.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/exports/chain.js CHANGED
@@ -1115,6 +1115,87 @@ class Jobber {
1115
1115
  }
1116
1116
  }
1117
1117
 
1118
+ const MAX_RESPONSE_DEPTH$1 = 3;
1119
+ const asLastBlockMessage = async (blockInput, claimedHash) => {
1120
+ const block = new BlockMessage(blockInput);
1121
+ const hash = await block.hash();
1122
+ if (claimedHash && hash !== claimedHash) {
1123
+ throw new Error(`lastBlock hash mismatch: expected ${claimedHash}, got ${hash}`);
1124
+ }
1125
+ return new LastBlockMessage({ hash, index: block.decoded.index });
1126
+ };
1127
+ const resolveLegacyHash = async (hash) => {
1128
+ const blockData = await globalThis.peernet?.get?.(hash, "block");
1129
+ if (!blockData) throw new Error(`unable to resolve lastBlock hash: ${hash}`);
1130
+ return asLastBlockMessage(blockData, hash);
1131
+ };
1132
+ const resolveLastBlockMessage = async (result, depth = 0) => {
1133
+ if (depth > MAX_RESPONSE_DEPTH$1) throw new Error("lastBlock response nesting exceeds limit");
1134
+ if (result instanceof Uint8Array) {
1135
+ let codec;
1136
+ try {
1137
+ codec = new Codec(result);
1138
+ } catch {
1139
+ }
1140
+ if (codec) {
1141
+ if (codec.name === "peernet-response") {
1142
+ const ResponseMessage = globalThis.peernet?.protos?.["peernet-response"];
1143
+ if (!ResponseMessage) throw new Error("peernet-response codec is not registered");
1144
+ const wrapped = new ResponseMessage(result);
1145
+ if (wrapped?.decoded?.response === void 0) throw new Error("peernet-response has no response payload");
1146
+ return resolveLastBlockMessage(wrapped.decoded.response, depth + 1);
1147
+ }
1148
+ if (codec.name === "last-block-message") return new LastBlockMessage(result);
1149
+ if (codec.name === "block-message") return asLastBlockMessage(result);
1150
+ }
1151
+ const candidate = new TextDecoder().decode(result);
1152
+ if (candidate) return resolveLegacyHash(candidate);
1153
+ }
1154
+ if (typeof result === "string") return resolveLegacyHash(result);
1155
+ if (result && typeof result === "object") {
1156
+ const response = result.decoded?.response ?? result.response;
1157
+ if (response !== void 0) return resolveLastBlockMessage(response, depth + 1);
1158
+ if ("hash" in result && "index" in result) return new LastBlockMessage(result);
1159
+ if ("previousHash" in result && "index" in result) return asLastBlockMessage(result);
1160
+ }
1161
+ throw new Error(`invalid lastBlock payload: ${typeof result}`);
1162
+ };
1163
+
1164
+ const MAX_RESPONSE_DEPTH = 3;
1165
+ const decodeResponsePayload = async (result, depth = 0) => {
1166
+ if (depth > MAX_RESPONSE_DEPTH) throw new Error("peernet response nesting exceeds limit");
1167
+ if (result instanceof Uint8Array) {
1168
+ let codec;
1169
+ try {
1170
+ codec = new Codec(result);
1171
+ } catch {
1172
+ }
1173
+ if (codec?.name === "peernet-response") {
1174
+ const ResponseMessage = globalThis.peernet?.protos?.["peernet-response"];
1175
+ if (!ResponseMessage) throw new Error("peernet-response codec is not registered");
1176
+ const wrapped = new ResponseMessage(result);
1177
+ return decodeResponsePayload(wrapped.decoded.response, depth + 1);
1178
+ }
1179
+ try {
1180
+ return JSON.parse(new TextDecoder().decode(result));
1181
+ } catch {
1182
+ return result;
1183
+ }
1184
+ }
1185
+ if (result && typeof result === "object") {
1186
+ const response = result.decoded?.response ?? result.response;
1187
+ if (response !== void 0) return decodeResponsePayload(response, depth + 1);
1188
+ }
1189
+ if (typeof result === "string") {
1190
+ try {
1191
+ return JSON.parse(result);
1192
+ } catch {
1193
+ return result;
1194
+ }
1195
+ }
1196
+ return result;
1197
+ };
1198
+
1118
1199
  const debug$1 = createDebugger("leofcoin/state");
1119
1200
  class State extends Contract {
1120
1201
  constructor(config) {
@@ -1194,42 +1275,6 @@ class State extends Contract {
1194
1275
  get resolving() {
1195
1276
  return this.#resolving;
1196
1277
  }
1197
- async #resolveLastBlockMessage(result) {
1198
- if (result instanceof Uint8Array) {
1199
- try {
1200
- let payload = result;
1201
- for (let i = 0; i < 3; i += 1) {
1202
- try {
1203
- const wrapped = await new globalThis.peernet.protos["peernet-response"](payload);
1204
- if (wrapped?.decoded?.response === void 0) break;
1205
- payload = wrapped.decoded.response;
1206
- } catch {
1207
- break;
1208
- }
1209
- }
1210
- if (payload !== result) return this.#resolveLastBlockMessage(payload);
1211
- return new LastBlockMessage(result);
1212
- } catch {
1213
- const candidate = new TextDecoder().decode(result);
1214
- if (candidate) {
1215
- const blockData = await globalThis.peernet.get(candidate, "block");
1216
- if (blockData) return new BlockMessage(blockData);
1217
- }
1218
- }
1219
- }
1220
- if (typeof result === "string") {
1221
- const blockData = await globalThis.peernet.get(result, "block");
1222
- if (blockData) return new BlockMessage(blockData);
1223
- }
1224
- if (result && typeof result === "object") {
1225
- const response = result.decoded?.response ?? result.response;
1226
- if (response !== void 0) return this.#resolveLastBlockMessage(response);
1227
- if ("hash" in result && "index" in result) {
1228
- return new LastBlockMessage(result);
1229
- }
1230
- }
1231
- throw new Error(`invalid lastBlock payload: ${typeof result}`);
1232
- }
1233
1278
  get contracts() {
1234
1279
  return this.#machine.contracts;
1235
1280
  }
@@ -1674,21 +1719,9 @@ class State extends Contract {
1674
1719
  compatiblePeerCount += 1;
1675
1720
  const task = async () => {
1676
1721
  try {
1677
- let result = await peer.request(node.encoded);
1722
+ const result = await peer.request(node.encoded);
1678
1723
  const resultType = result instanceof Uint8Array ? `bytes:${result.length}` : typeof result;
1679
1724
  debug$1(`lastBlock result type: ${resultType}`);
1680
- console.log({ result });
1681
- if (result instanceof Uint8Array) {
1682
- for (let i = 0; i < 3; i += 1) {
1683
- try {
1684
- const wrapped = await new globalThis.peernet.protos["peernet-response"](result);
1685
- if (wrapped?.decoded?.response === void 0) break;
1686
- result = wrapped.decoded.response;
1687
- } catch {
1688
- break;
1689
- }
1690
- }
1691
- }
1692
1725
  return { result, peer };
1693
1726
  } catch (error) {
1694
1727
  const peerId = peer?.peerId || peer?.id || peer?.address || "unknown";
@@ -1712,7 +1745,7 @@ class State extends Contract {
1712
1745
  console.log({ promises });
1713
1746
  promises = await Promise.all(
1714
1747
  promises.map(async (item) => ({
1715
- value: (await this.#resolveLastBlockMessage(item.value)).decoded,
1748
+ value: (await resolveLastBlockMessage(item.value)).decoded,
1716
1749
  peer: item.peer
1717
1750
  }))
1718
1751
  );
@@ -1733,10 +1766,11 @@ class State extends Contract {
1733
1766
  });
1734
1767
  let node2 = await globalThis.peernet.prepareMessage(data2);
1735
1768
  try {
1736
- let message2 = await peer.request(node2.encoded);
1737
- message2 = await new globalThis.peernet.protos["peernet-response"](message2);
1769
+ const message2 = await decodeResponsePayload(await peer.request(node2.encoded));
1770
+ const blocks = message2?.blocks;
1771
+ if (!Array.isArray(blocks)) throw new Error("knownBlocks response does not contain a blocks array");
1738
1772
  const MAX_WANTLIST_SIZE = 1e3;
1739
- const incoming = message2.decoded.response.blocks.filter((block) => !this.knownBlocks.includes(block));
1773
+ const incoming = blocks.filter((block) => !this.knownBlocks.includes(block));
1740
1774
  const remaining = MAX_WANTLIST_SIZE - this.wantList.length;
1741
1775
  if (remaining > 0) this.wantList.push(...incoming.slice(0, remaining));
1742
1776
  } catch (error) {
@@ -1816,28 +1850,20 @@ class State extends Contract {
1816
1850
  this.#chainState = "loaded";
1817
1851
  return true;
1818
1852
  }
1819
- promiseRequests(promises) {
1820
- return new Promise(async (resolve, reject) => {
1821
- const timeout = setTimeout(() => {
1822
- resolve([{ index: 0, hash: "0x0" }]);
1823
- debug$1("sync timed out");
1824
- }, this.requestTimeout);
1825
- console.log({ promises });
1826
- promises = await Promise.allSettled(promises);
1827
- console.log({ promises });
1828
- promises = promises.filter(({ status }) => status === "fulfilled");
1829
- clearTimeout(timeout);
1830
- if (promises.length > 0) {
1831
- promises = promises.map(async ({ value }) => {
1832
- const node = await new globalThis.peernet.protos["peernet-response"](value.result);
1833
- return { value: node.decoded.response, peer: value.peer };
1834
- });
1835
- promises = await Promise.all(promises);
1836
- resolve(promises);
1837
- } else {
1838
- resolve([]);
1839
- }
1840
- });
1853
+ async promiseRequests(promises) {
1854
+ let timeout;
1855
+ const settled = await Promise.race([
1856
+ Promise.allSettled(promises),
1857
+ new Promise((resolve) => {
1858
+ timeout = setTimeout(() => resolve(null), this.requestTimeout);
1859
+ })
1860
+ ]);
1861
+ clearTimeout(timeout);
1862
+ if (settled === null) {
1863
+ debug$1("sync timed out");
1864
+ return [];
1865
+ }
1866
+ return settled.filter(({ status }) => status === "fulfilled").map(({ value }) => ({ value: value.result, peer: value.peer }));
1841
1867
  }
1842
1868
  get canSync() {
1843
1869
  if (this.#chainSyncing) return false;
@@ -2905,42 +2931,6 @@ class Chain extends VersionControl {
2905
2931
  throw error;
2906
2932
  }
2907
2933
  }
2908
- async #resolveLastBlockMessage(result) {
2909
- if (result instanceof Uint8Array) {
2910
- try {
2911
- let payload = result;
2912
- for (let i = 0; i < 3; i += 1) {
2913
- try {
2914
- const wrapped = await new globalThis.peernet.protos["peernet-response"](payload);
2915
- if (wrapped?.decoded?.response === void 0) break;
2916
- payload = wrapped.decoded.response;
2917
- } catch {
2918
- break;
2919
- }
2920
- }
2921
- if (payload !== result) return this.#resolveLastBlockMessage(payload);
2922
- return new LastBlockMessage(result);
2923
- } catch {
2924
- const candidate = new TextDecoder().decode(result);
2925
- if (candidate) {
2926
- const blockData = await globalThis.peernet.get(candidate, "block");
2927
- if (blockData) return new BlockMessage(blockData);
2928
- }
2929
- }
2930
- }
2931
- if (typeof result === "string") {
2932
- const blockData = await globalThis.peernet.get(result, "block");
2933
- if (blockData) return new BlockMessage(blockData);
2934
- }
2935
- if (result && typeof result === "object") {
2936
- const response = result.decoded?.response ?? result.response;
2937
- if (response !== void 0) return this.#resolveLastBlockMessage(response);
2938
- if ("hash" in result && "index" in result) {
2939
- return new LastBlockMessage(result);
2940
- }
2941
- }
2942
- throw new Error(`invalid lastBlock payload: ${typeof result}`);
2943
- }
2944
2934
  async #decodeKnownBlocksResponse(response) {
2945
2935
  if (!response) return null;
2946
2936
  if (Array.isArray(response)) {
@@ -3073,7 +3063,7 @@ class Chain extends VersionControl {
3073
3063
  if (lastBlockRaw === void 0 || lastBlockRaw === null) {
3074
3064
  throw new Error(`invalid lastBlock payload: ${typeof lastBlockRaw}`);
3075
3065
  }
3076
- const lastBlockMessage = await this.#resolveLastBlockMessage(lastBlockRaw);
3066
+ const lastBlockMessage = await resolveLastBlockMessage(lastBlockRaw);
3077
3067
  console.log(lastBlockMessage);
3078
3068
  lastBlock = lastBlockMessage.decoded;
3079
3069
  } catch (error) {