Custodial markets
This commit is contained in:
+33
-2
@@ -20,6 +20,8 @@ import { StateClient } from '../shared/rpc-client.ts';
|
||||
import { createBackup,restoreBackup } from '../server/recovery.ts';
|
||||
import { Ledger } from '../server/testnet/ledger.ts';
|
||||
import { Market } from '../server/market/store.ts';
|
||||
import { CUSTODY_POLICY, custodyMessage, type CustodyCommand, type CustodyPage, type CustodyActivity } from '../shared/custody.ts';
|
||||
import { CustodyMarket } from '../server/market/custody.ts';
|
||||
|
||||
const root = fileURLToPath(new URL('../', import.meta.url));
|
||||
const wikipediaMock = resolve(root, 'tests', 'mock-wikipedia.mjs');
|
||||
@@ -88,7 +90,9 @@ test('native RandomX HTTP: three blocks, mined transfer, peer gossip/sync and du
|
||||
WIKIDECK_DATA_DIR: dataDir, RANDOMX_BINARY: binary,
|
||||
WIKIDECK_PEERS: peer ?? '', WIKIDECK_ALLOW_PRIVATE_PEERS: peer ? '1' : '0',
|
||||
PUBLIC_ORIGIN: 'http://127.0.0.1:3001', WIKIDECK_PAYMENT_MODE: 'mock',
|
||||
WIKIDECK_MARKET_FEE_BPS: '250', WIKIDECK_MARKET_CONFIRMATIONS: '2' },
|
||||
WIKIDECK_MARKET_FEE_BPS: '250', WIKIDECK_MARKET_CONFIRMATIONS: '2', WIKIDECK_CUSTODY_MODE: peer ? 'off' : 'sandbox',
|
||||
// This integration burst now includes signed custody reads/replay probes; admission limits have dedicated tests.
|
||||
WIKIDECK_RPC_WRITES_PER_SECOND: '50' },
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
let output = '';
|
||||
@@ -207,6 +211,18 @@ test('native RandomX HTTP: three blocks, mined transfer, peer gossip/sync and du
|
||||
const alice = wallet(), bob = wallet();
|
||||
assert.notEqual(alice.owner, bob.owner);
|
||||
let first = await start(firstDir);
|
||||
const custody = await json<CustodyPage>(first.base, '/api/custody');
|
||||
assert.equal(custody.info.mode, 'sandbox'); assert.equal(custody.info.liveDeposits, false);
|
||||
const custodyTerms: Omit<CustodyCommand, 'signature'> = { version: 1, mode: 'sandbox', policy: CUSTODY_POLICY,
|
||||
network: NETWORK, chainId: CHAIN_ID, custodianId: custody.info.custodianId, actor: bob.owner,
|
||||
publicKey: bob.publicKey, nonce: randomUUID(), expiresAt: Date.now() + 60000, action: { type: 'mock-credit' } };
|
||||
const custodyCredit = { ...custodyTerms, signature: bob.signed(custodyMessage(custodyTerms)) };
|
||||
const credited = await json<CustodyActivity>(first.base, '/api/custody/command', 200, custodyCredit);
|
||||
assert.equal(credited.availableAtomicXmr, '1000000000000');
|
||||
assert.deepEqual(await json(first.base, '/api/custody/command', 200, custodyCredit), credited);
|
||||
await request(first.base, '/api/custody/command', 400, { ...custodyCredit, actor: alice.owner });
|
||||
await request(first.base, '/api/custody/command', 400, { ...custodyCredit, mode: 'live' });
|
||||
assert.match((await request(first.base, '/api/custody/command', 200, custodyCredit)).headers.get('cache-control') ?? '', /no-store/);
|
||||
const health = await request(first.base, '/healthz');
|
||||
assert.deepEqual(await health.json(), { status: 'ok', network: NETWORK });
|
||||
assert.equal(health.headers.get('cache-control'), 'no-store');
|
||||
@@ -289,6 +305,8 @@ test('native RandomX HTTP: three blocks, mined transfer, peer gossip/sync and du
|
||||
|
||||
// A truly independent process reconstructs the canonical chain over HTTP and checks real work.
|
||||
const second = await start(secondDir, first.base);
|
||||
assert.deepEqual(await json(second.base, '/api/custody'), { enabled: false });
|
||||
await request(second.base, '/api/custody/command', 503, custodyCredit);
|
||||
const synced = await waitFor('Second node canonical sync', () => snapshot(second.base),
|
||||
state => state.tip === block2.hash && state.peers === 1);
|
||||
assert.deepEqual(synced.blocks, [block1, block2]);
|
||||
@@ -373,7 +391,13 @@ test('native RandomX HTTP: three blocks, mined transfer, peer gossip/sync and du
|
||||
assert.equal(existsSync(join(firstDir, 'testnet-node.lock')), false);
|
||||
}
|
||||
const backupDir=join(directory,'stopped-pair-backup'),drillDir=join(directory,'isolated-restore-drill');
|
||||
await createBackup(firstDir,backupDir);await restoreBackup(backupDir,drillDir);
|
||||
const backupManifest = await createBackup(firstDir,backupDir);await restoreBackup(backupDir,drillDir);
|
||||
assert.ok(backupManifest.files.some(f=>f.name==='custody-sandbox.sqlite'));
|
||||
const drillCustody = await CustodyMarket.open(drillDir, { feeBps: 250, card: () => undefined });
|
||||
try {
|
||||
assert.equal(drillCustody.id, custody.info.custodianId);
|
||||
assert.equal(drillCustody.audit().assetsAtomicXmr, '1000000000000');
|
||||
} finally { drillCustody.close(); }
|
||||
const drillLedger=await Ledger.open(drillDir,engine!); // Revalidate real RandomX proofs from the copied backup.
|
||||
try {
|
||||
assert.deepEqual(drillLedger.snapshot(),{...canonical,peers:0});
|
||||
@@ -387,6 +411,13 @@ test('native RandomX HTTP: three blocks, mined transfer, peer gossip/sync and du
|
||||
}finally{db.close();}
|
||||
}finally{drillLedger.close();}
|
||||
first = await start(firstDir); // Ledger.open revalidates every persisted block using native RandomX.
|
||||
const restartedCustody = await json<CustodyPage>(first.base, '/api/custody');
|
||||
assert.equal(restartedCustody.info.custodianId, custody.info.custodianId);
|
||||
const balanceTerms: Omit<CustodyCommand, 'signature'> = { ...custodyTerms, nonce: randomUUID(),
|
||||
expiresAt: Date.now() + 60000, action: { type: 'activity', offset: 0 } };
|
||||
const restoredBalance = await json<CustodyActivity>(first.base, '/api/custody/command', 200,
|
||||
{ ...balanceTerms, signature: bob.signed(custodyMessage(balanceTerms)) });
|
||||
assert.equal(restoredBalance.availableAtomicXmr, '1000000000000');
|
||||
const restored = await snapshot(first.base);
|
||||
assert.deepEqual(await pagedClient.load(),restored);
|
||||
const restoredMarket = await json<{ info: MarketInfo }>(first.base, '/api/market');
|
||||
|
||||
Reference in New Issue
Block a user