OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / test / unit / api-fork-proofs.test.js

155 lines · javascript ref:
import test from 'brittle'
import {
  MAX_FORK_PROOF_EVIDENCE_FIELD_BYTES,
  MAX_FORK_PROOF_EVIDENCE_PER_RECORD,
  MAX_FORK_PROOF_RECORDS,
  buildForkProofsPayload,
  buildForkProofsRoutePayload,
  resolveForkProofReadRoute
} from 'p2p-hiverelay/core/relay-node/api-fork-proofs.js'

function record (key = 'a'.repeat(64), overrides = {}) {
  return {
    hypercoreKey: key,
    discoveredAt: 10,
    blockIndex: 7,
    evidence: [
      { fromRelay: ' relay-a ', block: 'block-a', signature: 'sig-a', secret: 'hidden' },
      { fromRelay: 'relay-b', block: 'block-b', signature: 'sig-b' }
    ],
    operatorAcknowledged: false,
    resolution: null,
    resolutionNote: 'do-not-leak',
    secretToken: 'do-not-leak',
    ...overrides
  }
}

test('api fork proofs: route helper maps exact public proof list route', (t) => {
  t.alike(resolveForkProofReadRoute('GET', '/api/forks/proofs'), {
    kind: 'fork-proof-list'
  })

  t.is(resolveForkProofReadRoute('POST', '/api/forks/proofs'), null)
  t.is(resolveForkProofReadRoute('GET', '/api/forks/proofs/extra'), null)
  t.is(resolveForkProofReadRoute('GET', '/api/forks/proof'), null)
})

test('api fork proofs: route payload helper dispatches public proof list', (t) => {
  const route = resolveForkProofReadRoute('GET', '/api/forks/proofs')
  const out = buildForkProofsRoutePayload({
    route,
    forkDetector: {
      list () {
        return [record('A'.repeat(64))]
      }
    }
  })

  t.is(out.ok, true)
  t.is(out.payload.count, 1)
  t.is(out.payload.proofs[0].hypercoreKey, 'a'.repeat(64))
  t.alike(out.headers, { 'Cache-Control': 'public, max-age=30' })

  t.alike(buildForkProofsRoutePayload({ route: null }), {
    ok: false,
    status: 404,
    payload: { error: 'unknown fork-proof read route' }
  })
})

test('api fork proofs: missing detector returns empty bounded payload', (t) => {
  const out = buildForkProofsPayload()
  t.is(out.ok, true)
  t.alike(out.payload, {
    schemaVersion: 1,
    proofs: [],
    count: 0,
    total: 0,
    truncated: false,
    maxProofs: MAX_FORK_PROOF_RECORDS
  })
  t.alike(out.headers, { 'Cache-Control': 'public, max-age=30' })
})

test('api fork proofs: sanitizes public records without raw store fields', (t) => {
  const out = buildForkProofsPayload({
    forkDetector: {
      list () {
        return [record('A'.repeat(64), {
          resolvedAt: 20,
          resolution: 'rotated'
        })]
      }
    }
  })

  t.is(out.payload.count, 1)
  t.alike(out.payload.proofs[0], {
    hypercoreKey: 'a'.repeat(64),
    blockIndex: 7,
    evidence: [
      { fromRelay: 'relay-a', block: 'block-a', signature: 'sig-a' },
      { fromRelay: 'relay-b', block: 'block-b', signature: 'sig-b' }
    ],
    discoveredAt: 10,
    operatorAcknowledged: false,
    resolution: 'rotated',
    resolvedAt: 20
  })
  t.absent(JSON.stringify(out.payload).includes('resolutionNote'))
  t.absent(JSON.stringify(out.payload).includes('secretToken'))
  t.absent(JSON.stringify(out.payload).includes('do-not-leak'))
})

test('api fork proofs: caps records and per-record evidence', (t) => {
  t.is(MAX_FORK_PROOF_RECORDS, 200)
  t.is(MAX_FORK_PROOF_EVIDENCE_PER_RECORD, 16)
  t.is(MAX_FORK_PROOF_EVIDENCE_FIELD_BYTES, 8192)
  const records = []
  for (let i = 0; i < 205; i++) {
    const evidence = []
    for (let j = 0; j < 18; j++) {
      evidence.push({ fromRelay: 'relay-' + j, block: 'block-' + j, signature: 'sig-' + j })
    }
    records.push(record(String(i % 10).repeat(64), { evidence }))
  }

  const out = buildForkProofsPayload({
    forkDetector: { list: () => records }
  })

  t.is(out.payload.total, 205)
  t.is(out.payload.count, 200)
  t.is(out.payload.truncated, true)
  t.is(out.payload.proofs.length, 200)
  t.is(out.payload.proofs[0].evidence.length, 16)
  t.is(out.payload.proofs[0].evidenceTruncated, true)
})

test('api fork proofs: skips invalid or oversized proof records', (t) => {
  const out = buildForkProofsPayload({
    maxEvidenceFieldBytes: 8,
    forkDetector: {
      list () {
        return [
          record('not-hex'),
          record('b'.repeat(64), { blockIndex: -1 }),
          record('c'.repeat(64), { evidence: [{ fromRelay: 'a', block: 'short', signature: 'sig' }] }),
          record('d'.repeat(64), {
            evidence: [
              { fromRelay: 'relay-a', block: 'too-long-block', signature: 'sig-a' },
              { fromRelay: 'relay-b', block: 'block-b', signature: 'sig-b' }
            ]
          }),
          record('e'.repeat(64))
        ]
      }
    }
  })

  t.is(out.payload.total, 5)
  t.is(out.payload.count, 1)
  t.is(out.payload.proofs[0].hypercoreKey, 'e'.repeat(64))
})