Canonical indexes and recoverable market observation
This commit is contained in:
+17
-13
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url';
|
||||
import { mkdir, open, unlink } from 'node:fs/promises';
|
||||
import { z } from 'zod';
|
||||
import { NETWORK, CONSENSUS } from '../../shared/testnet.ts';
|
||||
import { testnetOwnerOf, transactionCardIds } from '../../shared/testnet.ts';
|
||||
import { transactionCardIds } from '../../shared/testnet.ts';
|
||||
import { CHAIN_ID, blockSchema, tradeSchema, transferSchema, transactionSchema } from './consensus.ts';
|
||||
import { RandomX } from './randomx.ts';
|
||||
import { Ledger } from './ledger.ts';
|
||||
@@ -56,11 +56,10 @@ let custody: CustodyMarket | undefined;
|
||||
try {
|
||||
if (custodyConfig === 'sandbox') custody = await CustodyMarket.open(dataDir, { feeBps: paymentConfig.feeBps,
|
||||
card: (hash, owner, sequence) => {
|
||||
const s = ledger.snapshot(), b = s.blocks.find(block => block.tokenId === hash);
|
||||
if (!b || testnetOwnerOf(s, hash) !== owner || s.blocks.length + 1 - b.height < CONSENSUS.coinbaseMaturity ||
|
||||
s.transfers.filter(tx => transactionCardIds(tx).includes(hash)).length !== sequence ||
|
||||
s.pendingTransfers.some(tx => transactionCardIds(tx).includes(hash))) return undefined;
|
||||
return { title: b.article.title };
|
||||
const nft = ledger.nft(hash);
|
||||
if (!nft || nft.owner !== owner || nft.confirmations < CONSENSUS.coinbaseMaturity || nft.sequence !== sequence ||
|
||||
ledger.pendingTransactions().some(tx => transactionCardIds(tx).includes(hash))) return undefined;
|
||||
return { title: nft.block.article.title };
|
||||
} });
|
||||
} catch(e) {market.close();peers.close();ledger.close();engine.close();await lock.close();await unlink(lockPath);throw e;}
|
||||
const app = express();
|
||||
@@ -138,6 +137,9 @@ app.get('/api/decks/:address', rateLimit({windowMs:60000,limit:60,standardHeader
|
||||
res.status(400).json({error:'Invalid deck page'});return;
|
||||
}
|
||||
res.setHeader('Cache-Control','no-store');
|
||||
if(req.query.tip!==undefined && req.query.tip!==ledger.summary().tip){
|
||||
res.status(409).json({error:'Canonical tip changed; restart deck pagination.'});return;
|
||||
}
|
||||
res.json(ledger.deck(req.params.address,offset,limit));
|
||||
});
|
||||
// Optional live data is intentionally not used by genesis, block validation or NFT ownership.
|
||||
@@ -156,13 +158,15 @@ app.get('/p2p/blocks',(req,res)=>{
|
||||
});
|
||||
app.get('/p2p/mempool',(_req,res)=>res.json({transactions:ledger.pendingTransactions()}));
|
||||
app.get('/api/nfts/:id', (req,res)=>{
|
||||
const s=ledger.snapshot();const block=s.blocks.find(b=>b.tokenId===req.params.id);
|
||||
if(!block){res.status(404).json({error:'NFT not found on the canonical chain'});return;}
|
||||
const owner=testnetOwnerOf(s,block.tokenId)??block.owner;
|
||||
const sequence=s.transfers.filter(tx=>transactionCardIds(tx).includes(block.tokenId)).length;
|
||||
res.json({network:NETWORK,chainId:CHAIN_ID,tokenId:block.tokenId,owner,sequence,blockHash:block.hash,
|
||||
confirmations:s.blocks.length-block.height+1,article:block.article,statsSnapshot:block.statsSnapshot,
|
||||
stateRoot:s.blocks.at(-1)?.stateRoot});
|
||||
if(typeof req.params.id!=='string'||!/^[a-f0-9]{64}$/.test(req.params.id)){
|
||||
res.status(400).json({error:'Invalid NFT identifier'});return;
|
||||
}
|
||||
const nft=ledger.nft(req.params.id);
|
||||
if(!nft){res.status(404).json({error:'NFT not found on the canonical chain'});return;}
|
||||
const block=nft.block;
|
||||
res.json({network:NETWORK,chainId:CHAIN_ID,tokenId:block.tokenId,owner:nft.owner,sequence:nft.sequence,blockHash:block.hash,
|
||||
confirmations:nft.confirmations,article:block.article,statsSnapshot:block.statsSnapshot,
|
||||
stateRoot:ledger.block(ledger.summary().tip)?.stateRoot});
|
||||
});
|
||||
const templateLimit=rateLimit({windowMs:60000,limit:20,standardHeaders:'draft-8',legacyHeaders:false});
|
||||
app.post('/api/mining/template', templateLimit, async (req,res)=>{
|
||||
|
||||
Reference in New Issue
Block a user