Skip to content

Commit

Permalink
🔖 Merkle Root Calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
Nishu0 committed May 8, 2024
1 parent ba9caaf commit e65ef5b
Show file tree
Hide file tree
Showing 20 changed files with 706 additions and 585 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"author": "",
"license": "ISC",
"dependencies": {
"@bitcoinerlab/secp256k1": "^1.1.1",
"asn1js": "^3.0.5",
"bitcoinjs-lib": "^6.1.5",
"ecpair": "^2.1.0",
"lodash.clonedeep": "^4.5.0",
Expand Down
7 changes: 6 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
const DIFFICULTY =
export const DIFFICULTY =
"0000ffff00000000000000000000000000000000000000000000000000000000";

export const WITNESS_RESERVED_VALUE =
"0000000000000000000000000000000000000000000000000000000000000000";

export const MAX_VALUE = 0xffffffff;
76 changes: 38 additions & 38 deletions src/features/block/coinbaseTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
import { Transaction } from "../../types";
// import { Transaction } from "../../types";
import { MAX_VALUE, WITNESS_RESERVED_VALUE } from "../../constants";
import { compactSize } from "../encoding/compactSize";
import { Input, Output, Transaction } from "../transaction";

export const ZEROS =
"0000000000000000000000000000000000000000000000000000000000000000";
const MAX_VALUE = 0xffffffff;
const height = 538403;
// export const ZEROS =
// "0000000000000000000000000000000000000000000000000000000000000000";
// const MAX_VALUE = 0xffffffff;
// const height = 538403;
const blockReward = 1250000000;

const coinbaseTemplate = {
version: 0,
locktime: 0,
vin: [
{
txid: ZEROS,
vout: MAX_VALUE,
prevout: null,
scriptsig: "03233708",
scriptsig_asm: "OP_PUSHBYTES_3 233708",
witness: [ZEROS],
},
],
vout: [
{
scriptpubkey: "76a914edf10a7fac6b32e24daa5305c723f3de58db1bc888ac",
scriptpubkey_asm:
"OP_DUP OP_HASH160 OP_PUSHBYTES_20 edf10a7fac6b32e24daa5305c723f3de58db1bc8 OP_EQUALVERIFY OP_CHECKSIG",
scriptpubkey_type: "p2pkh",
value: blockReward,
},
{
//op return push 36 bytes 4 btyes commitment + hash256 of witness merkle root + zeros
scriptpubkey: "6a24aa21a9ed", // add the witness commitment later
scriptpubkey_type: "op_return",
value: 0,
},
],
} as unknown as Transaction;

export const generateCoinbaseTransaction = (
totalFee: number,
commitmentHeader: string
) => {
coinbaseTemplate.vout[1].scriptpubkey = `6a24aa21a9ed${commitmentHeader}`;
coinbaseTemplate.vout[0].value = blockReward + totalFee;
const transaction = new Transaction(0, 0);
const input = new Input({
txid: WITNESS_RESERVED_VALUE,
vout: MAX_VALUE,
prevout: null,
scriptsig: "03233708", //block number is 233708
scriptsig_asm: "OP_PUSHBYTES_3 233708",
witness: [WITNESS_RESERVED_VALUE],
sequence: 0,
is_coinbase: true,
});

const output1 = new Output({
scriptpubkey: "76a914edf10a7fac6b32e24daa5305c723f3de58db1bc888ac",
scriptpubkey_asm:
"OP_DUP OP_HASH160 OP_PUSHBYTES_20 edf10a7fac6b32e24daa5305c723f3de58db1bc8 OP_EQUALVERIFY OP_CHECKSIG",
scriptpubkey_type: "p2pkh",
value: blockReward + totalFee,
});

const output2 = new Output({
scriptpubkey: "6a24aa21a9ed" + commitmentHeader,
scriptpubkey_asm: "OP_RETURN OP_PUSHBYTES_36 aa21a9ed" + commitmentHeader,
scriptpubkey_type: "op_return",
value: 0,
});

transaction.addInput(input);
transaction.addOutput(output1);
transaction.addOutput(output2);

return coinbaseTemplate;
return transaction;
};
7 changes: 4 additions & 3 deletions src/features/block/fee.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Transaction } from "../../types";
import { txWeight } from "../encoding/serializer";
import { Transaction } from "../transaction";

export const totalFee = (txs: Transaction[]) => {
let inputValues = 0;
let outputValues = 0;

for (const tx of txs) {
for (const input of tx.vin) {
if (!input.prevout) continue;
inputValues += input.prevout.value;
}
for (const output of tx.vout) {
Expand All @@ -20,12 +20,13 @@ export const totalFee = (txs: Transaction[]) => {
export const feePerByte = (tx: Transaction) => {
let fee = 0;
for (const input of tx.vin) {
if (!input.prevout) continue;
fee += input.prevout.value;
}

for (const output of tx.vout) {
fee -= output.value;
}

return fee / txWeight(tx);
return fee / tx.weight;
};
4 changes: 1 addition & 3 deletions src/features/block/merkleRoot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Transaction } from "../../types";
import { reversify, sha256 } from "../../utils";
import { txSerializer } from "../encoding/serializer";
import { sha256 } from "../../utils";

export const merkleRoot = (txs: string[]) => {
let curr = txs;
Expand Down
33 changes: 15 additions & 18 deletions src/features/block/mine.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { reversify, sha256 } from "../../utils";
import { Transaction } from "../../types";
import { Transaction } from "../transaction";
import { merkleRoot } from "./merkleRoot";
import { txSerializer } from "../encoding/serializer";
import { ZEROS, generateCoinbaseTransaction } from "./coinbaseTransaction";
import { generateCoinbaseTransaction } from "./coinbaseTransaction";
import { totalFee } from "./fee";
import { DIFFICULTY, WITNESS_RESERVED_VALUE } from "../../constants";

export const mine = (
txs: Transaction[]
Expand All @@ -16,27 +16,25 @@ export const mine = (
"0000ffff00000000000000000000000000000000000000000000000000000000";
const version = Buffer.alloc(4);
version.writeInt32LE(4);
//make it the same as the difficulty

const witnessMerkleRootHash = reversify(
merkleRoot([
ZEROS, //zeros are for the coinbase transaction
...txs.map((tx) =>
reversify(sha256(sha256(txSerializer(tx).serializedWTx)))
),
])
// const witnessMerkleRootHash = merkleRoot([
// ZEROS, //zeros are for the coinbase transaction
// ...txs.map((tx) => sha256(sha256(txSerializer(tx).serializedWTx))),
// ]);
const witnessMerkleRootHash = merkleRoot([
WITNESS_RESERVED_VALUE,
...txs.map((tx) => reversify(tx.wtxid)),
]);
const commitmentHash = sha256(
sha256(witnessMerkleRootHash + WITNESS_RESERVED_VALUE)
);
const commitmentHash = sha256(sha256(witnessMerkleRootHash + ZEROS));
const fees = totalFee(txs);
const coinbaseTransaction = generateCoinbaseTransaction(fees, commitmentHash);

const prevBlockHash =
"0000ffff00000000000000000000000000000000000000000000000000000000"; //make it the same as the difficulty
const prevBlockHash = DIFFICULTY; //make it the same as the difficulty

const merkleRootHash = merkleRoot(
[coinbaseTransaction, ...txs].map((tx) =>
sha256(sha256(txSerializer(tx).serializedTx))
)
[coinbaseTransaction, ...txs].map((tx) => reversify(tx.txid))
);

const time = Buffer.alloc(4);
Expand All @@ -54,7 +52,6 @@ export const mine = (
"hex"
)}${nonceBuf.toString("hex")}`;

// console.log(serializedBlock);
const blockHash = reversify(sha256(sha256(serializedBlock)));
if (
Buffer.from(difficulty, "hex").compare(Buffer.from(blockHash, "hex")) < 0
Expand Down
Loading

0 comments on commit e65ef5b

Please sign in to comment.