In this challenge, you are tasked with the simulation of mining process of a block, which includes validating and including transactions from a given set of transactions.
The repository contains a folder mempool
which contains JSON files.
These files represent individual transactions, some of which may be invalid. Your goal is to successfully mine a block by including only the valid transactions, following the specific requirements outlined below.
Your primary objective is to write a script that processes a series of transactions, validates them, and then mines them into a block. The output of your script should be a file named output.txt
that follows a specific format.
- You are provided with a folder named
mempool
containing several JSON files. Each file represents a transaction that includes all necessary information for validation. - Among these transactions, some are invalid. Your script should be able to discern valid transactions from invalid ones.
Your script must generate an output file named output.txt
with the following structure:
- First line: The block header.
- Second line: The serialized coinbase transaction.
- Following lines: The transaction IDs (txids) of the transactions mined in the block, in order. The first txid should be that of the coinbase transaction
The difficulty target is 0000ffff00000000000000000000000000000000000000000000000000000000
. This is the value that the block hash must be less than for the block to be successfully mined.
- At first the mempool is itreated and transactions are verified on the basis of their script types (
p2tr
transactions are added in block with only basic checks like sufficient gas-fees) and inserted in the valid-mempool. - Transactions with gas fees less than 1500 sats are rejected.
- Then a map of all valid-transaction which includes
txid
,transaction
,wtxid
,tx_weight
andfees
is created for each of them. - Then the wtxid commintment is created from all the wtxids of the valid transactions as mentioned in learn me a bitcoin.
- Then the coinbase transaction is hard-coded.
- Then the merkel root is created using the txids of all valid transactions withtthe txid if coinbase at the top.
- Then a valid-block-header is created by implementing the POW algorithm by continuously increasing the nonce once on each failure.
- Finally the valid-block header is created and, coinbase tx and all txids are inserted in the output.txt.
The code is divided into two main parts block_mine
and validation_checks
.
The core verification logic of p2pkh
, p2sh
, p2wpkh
, p2wsh
transactions are implemented here.
- In
input_verification_p2pkh
, the script_sig_asm and script_pubkey_asm are extracted from the input of the transaction being verified and then passedscript_execution
HASH160
ofPublic key
inscript_sig_asm
is verified withpubkeyhash
in the script_pub_key- Now the
signature
andpublic_key
are pushed in the stack and the opcodes in the script_sig_asm are executed in sequence. - The
verify_ecdsa
function is then used to verify the signature against the pubic key and the message created from the transaction as per the consensus rules. - I refered to this repository for
trimmed_tx
creation for signature verification.
There are 3 types of p2sh transactions: native p2sh
, p2sh-p2wpkh
, p2sh-p2wsh
- The scripts are executed in a stack.
- Sequence of script execution:
script_sig
,script_pub_key
,inner_redeem_script
. - The logic for all opcodes present in scripts are implemented in
p2sh.rs
- The
trimmed_tx
creation is same as thep2pkh
just instead ofscript_sig_asm
,inner_redeem_script
is used.
- Scripts are executed in the stack.
- All relevant
opcodes
logic implementation are inp2sh.rs
. script_sig
andscript_pub_key
are executed in the same way.- Here instead of
inner_redeem_script
, witness is executed. signature
andpublic key
are pushed in the stack.- Now
OP_DUP
,OP_HASH160
are executed implicitely.All relevantopcodes
logic implementation are inp2sh.rs
. - Now
inner_redeem_script
opcodes are executed. - Again
OP_EQUALVERIFY
andOP_CHECKSIG
are excuted implicitely.
- Scripts are executed in the stack.
- All relevant
opcodes
logic implementation are inp2sh.rs
. script_sig
andscript_pub_key
are executed in the same way.- Here also instead of
inner_redeem_script
, witness is executed. - All the elements except the last element in the
witness
are pushed in the stack. - Now the
witness-script
is executed which is the last element in the witness. - Each opcode is iterated and executed, the final result is procured.
SIGNATURE
verification for segwit p2sh
transactions are refrenced from BIP143.
- This verification is not implemented using stack.
- The
signature
andpublic key
are extracted from the witness as there are only two elements in allp2wpkh
transactions. HASH160
ofpublic key
is verified against thepubkeyhash
inscript_pub_key
.- Now the
signature
is verified against themessage
andpublic key
usingverify_ecdsa
function.
- Scripts are executed in the stack.
- All relevant
opcodes
logic implementation are inp2wsh.rs
. - All elements in the
witness
except the last element which is thewitness script
are pushed in the stack. - Now the
witness-program
which is the last element is thescript_pub_key
is cross-verified with theSHA256
ofwitness-script
. - Now after this verfication all the opcodes in the
witness-script
is executed in the sequence and the final result is procured.
- Logic of
OP_CHECKSIG
andOP_MULTICHECKSIG
. verify_tx
method which redirects transctions on the basis of their types.all_transaction_verification
iterates through the mempool and executesverify_tx
for each transaction while also checking for double spends.
The core logic of block mining is implemented here.
- The transactions which are valid under the consensus rules are put in the valid-mempool directory.
- Now in
create_txid_tx_map
thevalid-mempool
directory is iterated and each valid transaction is seriliased into raw transactions. - Now as the transactions are iterated in the valid-mempool, their
txid
,transaction
,wtxid
,tx_weight
andfees
is insert in a vector in the descending order of theirgas-fees
/tx-weight
. - Method to serialise a transaction into its raw transaction format is referenced from learnmeabitcoin.
- The
merkel_root
andcoinbase_transaction
logic is implemented here.
- Here a
valid_block_header
is created using POW against the block_header_hash and the target bits.
At the end the valid_block_header
, raw coinbase_tx
, txids
are inserted in the output.txt.
A valid block is created with:
- BLOCK WEIGHT := 3994072
- FEE := 21619204
- SCORE: 101
- NUMBER OF TRANSACTIONS: 4453
Effieciency of my solution could have been improved from the following changes:
- Making a single
opcode
registry for all transaction types and not implementing theopcode
logic in each tx verification file. - Could not include
p2sh
transactions inoutput.txt
because of some bugs at the last moment.
- Github repo - p2pkh verification
- BIP143 - for signature verification of segwit transactions.
- Learn me a bitcoin - for block-header and coinbase transaction composition