Skip to content

Instantly share code, notes, and snippets.

@eddmann
Last active July 24, 2023 13:55
Show Gist options
  • Save eddmann/0af11a2436202cd994ecf73f70d49674 to your computer and use it in GitHub Desktop.
Save eddmann/0af11a2436202cd994ecf73f70d49674 to your computer and use it in GitHub Desktop.
Bitcoin Internals: How Blocks use Merkle Trees in JavaScript
const fetchLatestBlock = () =>
fetch(`https://blockchain.info/q/latesthash?cors=true`)
.then(r => r.text());
const fetchMerkleRootAndTransactions = block =>
fetch(`https://blockchain.info/rawblock/${block}?cors=true`)
.then(r => r.json())
.then(d => [d.mrkl_root, d.tx.map(t => t.hash)]);
const toBytes = hex =>
hex.match(/../g).reduce((acc, hex) => [...acc, parseInt(hex, 16)], []);
const toHex = bytes =>
bytes.reduce((acc, bytes) => acc + bytes.toString(16).padStart(2, '0'), '');
const toPairs = arr =>
Array.from(Array(Math.ceil(arr.length / 2)), (_, i) => arr.slice(i * 2, i * 2 + 2));
const hashPair = (a, b = a) => {
const bytes = toBytes(`${b}${a}`).reverse();
const hashed = sha256.array(sha256.array(bytes));
return toHex(hashed.reverse());
};
const merkleRoot = txs =>
txs.length === 1 ? txs[0] : merkleRoot(toPairs(txs).reduce((tree, pair) => [...tree, hashPair(...pair)], []));
fetchLatestBlock()
.then(fetchMerkleRootAndTransactions)
.then(([root, txs]) => {
const isValid = merkleRoot(txs) === root;
console.log(isValid);
});
@changtimwu
Copy link

I wrote a typescript + nodejs variant. Not concise at all. Just for practice.
https://gist.github.com/changtimwu/a40002009c4d8ca960fa0ad403731fd0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment