Skip to content
55 changes: 24 additions & 31 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"process": "npm:bare-node-process",
"protomux": "^3.10.1",
"protomux-wakeup": "^2.4.0",
"rache": "1.0.0",
"readline": "npm:bare-node-readline",
"ready-resource": "1.1.2",
"repl": "npm:bare-node-repl",
Expand Down
20 changes: 20 additions & 0 deletions src/config/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import b4a from "b4a";
import path from "path";

const DEFAULT_HYPERBEE_CACHE_MAX_ENTRIES = 65_536;
const DEFAULT_MAX_MSB_SIGNED_LENGTH_FUTURE_DELTA = 1_000_000;

export class Config {
#options;

Expand Down Expand Up @@ -41,12 +44,29 @@ export class Config {
}
this.maxTxDelay = maxTxDelay;

const hyperbeeCacheMaxEntries =
this.#select("hyperbeeCacheMaxEntries", options, defaults) ??
DEFAULT_HYPERBEE_CACHE_MAX_ENTRIES;
if (!Number.isSafeInteger(hyperbeeCacheMaxEntries) || hyperbeeCacheMaxEntries < 1) {
throw new Error("Peer: hyperbeeCacheMaxEntries must be a positive safe integer.");
}
this.hyperbeeCacheMaxEntries = hyperbeeCacheMaxEntries;

const maxMsbSignedLength = this.#select("maxMsbSignedLength", options, defaults);
if (!Number.isSafeInteger(maxMsbSignedLength)) {
throw new Error("Peer: maxMsbSignedLength must be a safe integer.");
}
this.maxMsbSignedLength = maxMsbSignedLength;

const maxMsbSignedLengthFutureDelta =
this.#select("maxMsbSignedLengthFutureDelta", options, defaults) ??
DEFAULT_MAX_MSB_SIGNED_LENGTH_FUTURE_DELTA;
if (!Number.isSafeInteger(maxMsbSignedLengthFutureDelta) ||
maxMsbSignedLengthFutureDelta < 0) {
throw new Error("Peer: maxMsbSignedLengthFutureDelta must be a non-negative safe integer.");
}
this.maxMsbSignedLengthFutureDelta = maxMsbSignedLengthFutureDelta;

const maxMsbApplyOperationBytes = this.#select("maxMsbApplyOperationBytes", options, defaults);
if (!Number.isSafeInteger(maxMsbApplyOperationBytes)) {
throw new Error("Peer: maxMsbApplyOperationBytes must be a safe integer.");
Expand Down
6 changes: 6 additions & 0 deletions src/config/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ const configData = {
storeName: "mainnet",
txPoolMaxSize: 1_000,
maxTxDelay: 60,
hyperbeeCacheMaxEntries: 65_536,
maxMsbSignedLength: 1_000_000_000,
maxMsbSignedLengthFutureDelta: 1_000_000,
maxMsbApplyOperationBytes: 1024 * 1024,
enableInteractiveMode: true,
enableBackgroundTasks: true,
Expand All @@ -38,7 +40,9 @@ const configData = {
storeName: "testnet",
txPoolMaxSize: 1_000,
maxTxDelay: 60,
hyperbeeCacheMaxEntries: 65_536,
maxMsbSignedLength: 1_000_000_000,
maxMsbSignedLengthFutureDelta: 1_000_000,
maxMsbApplyOperationBytes: 1024 * 1024,
enableInteractiveMode: true,
enableBackgroundTasks: true,
Expand All @@ -62,7 +66,9 @@ const configData = {
storeName: "peer",
txPoolMaxSize: 1_000,
maxTxDelay: 60,
hyperbeeCacheMaxEntries: 65_536,
maxMsbSignedLength: 1_000_000_000,
maxMsbSignedLengthFutureDelta: 1_000_000,
maxMsbApplyOperationBytes: 1024 * 1024,
enableInteractiveMode: true,
enableBackgroundTasks: false,
Expand Down
15 changes: 12 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ReadyResource from 'ready-resource';
import b4a from 'b4a';
import Hyperbee from 'hyperbee';
import Corestore from 'corestore';
import Rache from 'rache';
import w from 'protomux-wakeup';
const wakeup = new w();
import Protomux from 'protomux'
Expand All @@ -13,7 +14,7 @@ import { MsbClient } from './msbClient.js';
import { handlerFor } from './operations/index.js';
import TransactionPool from './transaction/transactionPool.js';
import { TransactionObserver } from './tasks/transactionObserver.js';
import { Updater } from './tasks/updater.js';
import { Updater, installNonNullAutobaseAck, installSignedAutobaseStore, installSignedCorestoreStorageFactory } from './tasks/updater.js';
export { ensureTextCodecs } from './textCodec.js';
export {default as Protocol} from "./artifacts/protocol.js";
export {default as Contract} from "./artifacts/contract.js";
Expand All @@ -32,7 +33,9 @@ export class Peer extends ReadyResource {
this.config = config;

this.keyPair = null;
this.store = new Corestore(this.config.fullStoresDirectory);
this.store = new Corestore(this.config.fullStoresDirectory, {
globalCache: new Rache({ maxSize: this.config.hyperbeeCacheMaxEntries })
});
this.msbClient = new MsbClient(msb);
this.swarm = null;
this.base = null;
Expand Down Expand Up @@ -75,10 +78,15 @@ export class Peer extends ReadyResource {
}

async _boot() {
installSignedCorestoreStorageFactory(this.store)
installSignedAutobaseStore(this.store, () => this.base?.local?.keyPair ?? null)
this.base = new Autobase(this.store, this.config.bootstrap, {
ackInterval : 1000,
// MAYHEM PATCH: disable Autobase's implicit null ACK; updater appends
// a signed no-op instead so Pear/Bare never encodes a null head.
ackInterval : 0,
valueEncoding: 'json',
open: store => {
installSignedAutobaseStore(store)
this.bee = new Hyperbee(store.get('view'), {
extension: false,
keyEncoding: 'utf-8',
Expand Down Expand Up @@ -108,6 +116,7 @@ export class Peer extends ReadyResource {
await batch.close();
}
})
installNonNullAutobaseAck(this.base)
this.base.on('warning', (e) => console.log(e))
}

Expand Down
28 changes: 26 additions & 2 deletions src/msbClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,35 @@ export class MsbClient extends ReadyResource {
return await this.#msb.network.tryConnect(pubKeyHex, role);
}

async waitForSignedLengthAtLeast(targetSignedLength) {
async waitForSignedLengthAtLeast(targetSignedLength, { pollMs = 1_000 } = {}) {
const core = this.#msb.state?.base?.view?.core ?? null;
if (!core) throw new Error('MSB view core not available.');
if (!Number.isSafeInteger(targetSignedLength) || targetSignedLength < 0) {
throw new Error('Invalid MSB signed length target.');
}
if (!Number.isSafeInteger(pollMs) || pollMs < 1) {
throw new Error('Invalid MSB signed length wait poll interval.');
}
while (core.signedLength < targetSignedLength) {
await new Promise((resolve) => core.once('append', resolve));
await new Promise((resolve) => {
const onAppend = () => {
cleanup();
resolve();
};
const cleanup = () => {
clearTimeout(timer);
if (typeof core.off === 'function') {
core.off('append', onAppend);
} else if (typeof core.removeListener === 'function') {
core.removeListener('append', onAppend);
}
};
const timer = setTimeout(() => {
cleanup();
resolve();
}, pollMs);
core.once('append', onAppend);
});
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/operations/tx/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export class TxOperation {
if(false === this.#validator.validate(op)) return;
// Stall guard: don't allow a writer to pin apply waiting on an absurd MSB height
if (op.value.msbsl > this.#config.maxMsbSignedLength) return;
const localMsbSignedLength = this.#msbClient.getSignedLength();
if (localMsbSignedLength > 0 &&
op.value.msbsl > localMsbSignedLength + this.#config.maxMsbSignedLengthFutureDelta) {
return;
}
// Wait for local MSB view to reach the referenced signed length
await this.#msbClient.waitForSignedLengthAtLeast(op.value.msbsl);
// Fetch MSB apply-op at msbsl by tx key (op.key = tx hash)
Expand Down
Loading
Loading