Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion contrib/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ WORKDIR /srv/explorer/source
SHELL ["/bin/bash", "-c"]

RUN source /root/.nvm/nvm.sh \
&& npm install && (cd prerender-server && npm run dist) \
&& npm install \
&& npm test \
&& (cd prerender-server && npm run dist) \
&& DEST=/srv/explorer/static/bitcoin-mainnet \
npm run dist -- bitcoin-mainnet \
&& DEST=/srv/explorer/static/bitcoin-testnet \
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
"prerender-server": "cd prerender-server && npm start",
"postinstall": "(cd client && npm install) && (cd prerender-server && npm install)",
"dist": "./build.sh",
"test": "node --require @babel/register --test test/*.test.js",
"l10n:fetch": "./lang/util/fetch-transifex.sh",
"l10n:update-strings": "./lang/util/update-strings.sh"
},
"author": "Nadav Ivgi",
"license": "MIT",
"browserslist": "> 0.5%",
"devDependencies": {
"@babel/register": "^7.12.10",
"browserify-middleware": "^8.1.1",
"express": "^4.17.1",
"glob": "^7.1.6",
Expand Down
52 changes: 52 additions & 0 deletions test/block-signatures.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const test = require("node:test");
const assert = require("node:assert/strict");

const { parseBlockSignatures } = require("../client/src/lib/block-signatures");

test("parses a signblock witness", () => {
const block = {
ext: {
signblock_witness: [
[],
[0x01],
[0x02],
[0x52, 0x53, 0xae],
],
},
};

assert.deepEqual(parseBlockSignatures(block), {
requiredSignatures: 2,
totalSigners: 3,
signatureCount: 2,
source: "signblock_witness",
});
});

test("parses a legacy block proof", () => {
const signature = `09${"00".repeat(9)}`;
const block = {
proof: {
challenge: "5253ae",
solution: `00${signature}${signature}`,
},
};

assert.deepEqual(parseBlockSignatures(block), {
requiredSignatures: 2,
totalSigners: 3,
signatureCount: 2,
source: "challenge",
});
});

test("returns source-tagged errors for malformed signature data", () => {
const result = parseBlockSignatures({
ext: {
signblock_witness: [[0x00], [0x51, 0x51, 0xae]],
},
});

assert.equal(result.error.source, "signblock_witness");
assert.match(result.error.message, /dummy must be empty/);
});
57 changes: 57 additions & 0 deletions test/deduce-blinded.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const test = require("node:test");
const assert = require("node:assert/strict");

const { deduceBlinded } = require("../client/src/lib/deduce-blinded");

test("deduces a single blinded output", () => {
const tx = {
vin: [
{ prevout: { asset: "asset-a", value: 7 } },
{ prevout: { asset: "asset-a", value: 4 } },
],
vout: [
{ asset: "asset-a", value: 6 },
{ asset: null, value: null },
],
};

deduceBlinded(tx);

assert.deepEqual(tx.vout[1], { asset: "asset-a", value: 5 });

tx.vin[0].prevout.value = 100;
deduceBlinded(tx);
assert.deepEqual(tx.vout[1], { asset: "asset-a", value: 5 });
});

test("deduces a single blinded input using bigint amounts", () => {
const tx = {
vin: [
{ prevout: { asset: null, value: null } },
{ prevout: { asset: "asset-a", value: 3n } },
],
vout: [{ asset: "asset-a", value: 8n }],
};

deduceBlinded(tx);

assert.deepEqual(tx.vin[0].prevout, {
asset: "asset-a",
value: 5n,
});
});

test("rejects inconsistent balances instead of guessing a blinded value", () => {
const tx = {
vin: [
{ prevout: { asset: "asset-a", value: 10 } },
{ prevout: { asset: "asset-b", value: 5 } },
],
vout: [{ asset: null, value: null }],
};

assert.throws(
() => deduceBlinded(tx),
/unexpected remainder while deducing blinded tx/,
);
});
36 changes: 36 additions & 0 deletions test/fees.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const test = require("node:test");
const assert = require("node:assert/strict");

const {
feerateCutoff,
getConfEstimate,
} = require("../client/src/lib/fees");

test("calculates fee cutoff at block size boundaries", () => {
assert.equal(
feerateCutoff([
[10, 500000],
[5, 499999],
]),
0,
);
assert.equal(
feerateCutoff([
[10, 500000],
[5, 500000],
]),
10,
);
assert.equal(feerateCutoff([[10, 1000000]]), null);
});

test("selects a confirmation target by numeric order", () => {
const estimates = {
25: 1,
10: 5,
2: 10,
};

assert.equal(getConfEstimate(estimates, 6), "10");
assert.equal(getConfEstimate(estimates, 0.5), -1);
});
52 changes: 52 additions & 0 deletions test/privacy-analysis.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const test = require("node:test");
const assert = require("node:assert/strict");

const getPrivacyAnalysis =
require("../client/src/lib/privacy-analysis").default;

test("skips privacy analysis for coinbase transactions", () => {
const tx = {
vin: [{ is_coinbase: true }],
vout: [],
};

assert.deepEqual(getPrivacyAnalysis(tx), []);
});

test("detects equal-output coinjoins only with explicit amounts", () => {
const vin = [
{
prevout: {
value: 2000,
scriptpubkey: "input-a",
scriptpubkey_type: "v0_p2wpkh",
},
},
{
prevout: {
value: 2000,
scriptpubkey: "input-b",
scriptpubkey_type: "v0_p2wpkh",
},
},
];
const vout = [1000, 1000, 900, 800].map((value, index) => ({
value,
scriptpubkey: `output-${index}`,
scriptpubkey_type: "v0_p2wpkh",
}));

assert.deepEqual(
getPrivacyAnalysis({ vin, vout }),
["coinjoin-equal-outputs"],
);

const confidentialVin = [
{ ...vin[0], prevout: { ...vin[0].prevout, value: null } },
vin[1],
];
assert.deepEqual(
getPrivacyAnalysis({ vin: confidentialVin, vout }),
[],
);
});