The aim of the assignment was to mine a set of transactions in the mempool into a block, while correctly validating them as per the concensus rules.
- At first I iterated through the mempool and verified transaction 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