-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8523ef6
commit b145360
Showing
2 changed files
with
93 additions
and
245 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,110 +1,102 @@ | ||
# Mining Simulation of a Bitcoin Block | ||
|
||
## Brainstorming | ||
## Design Approach | ||
Our approach to designing the block construction program involves several key concepts aimed at creating a valid Bitcoin block: | ||
|
||
So basically we have to do the following things: | ||
1. Validate the transactions and assign fee/size to each one of them and order them | ||
1. Write a parser that parses the transactions and puts them in a data strucutre that I can make use of | ||
2. Write a minimal Script interpreter | ||
2. Create and serialize the coinbase transaction | ||
3. Mine the block | ||
1. Create the candidate block header (which is just the file) | ||
2. Add the txids by using the ordered fee/size list | ||
3. Find the nonce by iteratively hashing the file with difference nonces | ||
### 1. Validating and Selecting Transactions | ||
We first validate transactions by ensuring the correctness of various attributes such as pubkey, address, input/output sums, and signature scripts. We focus on implementing signature validations for P2PKH, P2WPKH, and P2TR scripts. Transactions are then selected based on their fee/weight ratio to optimize block space usage. | ||
|
||
Programming language to use: Golang | ||
### 2. Creating a Candidate Block | ||
Once validated transactions are selected, we construct a candidate block with a valid coinbase transaction. This includes generating the coinbase transaction structure and adding the witness commitment if witness data is present. Additionally, we construct the block header with appropriate values such as bits, prevBlockHash, merkle root, time, and blockversion. | ||
|
||
## Transaction verification | ||
### 3. Mining the Block | ||
After creating the candidate block, we search for a nonce that satisfies the current difficulty target. This process involves iteratively changing the nonce value, hashing the block header, and checking if the resulting hash meets the difficulty criteria. | ||
|
||
### Parsing a transaction | ||
|
||
- [x] Parse a transaction into a data structure | ||
## Implementation Details | ||
|
||
### Validation | ||
|
||
There are different types of transactions: | ||
1. p2pkh (pay to public key hash) [x] | ||
2. p2sh (pay to script hash) [] | ||
3. p2wpkh (pay to script hash) [x] | ||
4. p2wsh (pay to witness script hash) | ||
5. p2tr [x] | ||
|
||
What about multisigs? | ||
First we will only take these things into account. If a transaction any other type than this, then we will log it and see what it is. | ||
|
||
Previous output is included in the transaction itself. | ||
**Rules** | ||
|
||
Sourced from [verify.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/consensus/tx_verify.cpp), | ||
[transactions.html](https://developer.bitcoin.org/devguide/transactions.html) | ||
|
||
1. Check all the inputs are present and valid (we don't have to check this) | ||
2. Check for negative or overflow input values | ||
3. Tally transaction fees (it should not be negative) | ||
4. Script validation | ||
*We will assume that all the inputs are valid UTXOs, if prevout is not given, then that means we are making use of a transaction in the given list | ||
|
||
To validate a transaction, first we have to check if all the inputs are valid, and then we have to tally the transaction fees, then we have to identify what kind of script | ||
it is, and then validate it accordingly. Let us first just validate the P2PKH | ||
|
||
### Writing an interpreter for Script | ||
Do we really need to write an interpreter for the Script language? | ||
No. We don't need to write an interpreter for the Script, we just have to programmatically validate the script and signature | ||
|
||
### Serialization | ||
We can use this resource https://learnmeabitcoin.com/technical/transaction/. I had one problem though. Eventhough I did everything right, I was not able to match my txid hash with | ||
my filename. After looking at it, the issue was that I had to _reverse the transaction hash order in the transaction inputs_. My reasoning towards why we need to do this is because, in Bitcoin, the convention is to use the Natural Byte Order (little endian) when dealing within raw bitcoin data, whereas we use Reverse Byte Order (Big Endian) in Block explorers or RPC calls to bitcoin-core. In our case, the transactions are in JSON form, which means the transaction hash would be in Reverse Byte Order. But the specification in https://learnmeabitcoin.com/technical/transaction/ says that the transaction hash in the input should be in Natural Byte Order. Therefore I had to reverse it in order to get it working. | ||
|
||
### Verifying Signature | ||
How do we verify the signature. We basically have to do what the OP_CHECKSIG opcode does in the Script language. | ||
We need the Signature, the public key and the transaction hash in order to verify the signature. We have to verify the signature | ||
using the ECDSA algorithm.We cannot use any bitcoin related libraries. | ||
Out of the required things, we have the Signature and the public key. We need to identify how to calculate the transaction hash. | ||
Following things have to be done: | ||
1. Identify how to correctly serialize the transactions in bitcoin | ||
2. Identify the right library to use for ECDSA verification | ||
|
||
I think [this](https://learn.saylor.org/mod/book/view.php?id=36340&chapterid=18915#:~:text=Hints%3A,bytes%2C%20or%208b%20in%20hex) is how we | ||
need to seralize a transaction. | ||
|
||
https://btcinformation.org/en/developer-reference#raw-transaction-format - serialization for non-segwit transactions | ||
https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki - serialization for segiwit transactions | ||
|
||
When we serialize it and double hash it using SHA256, we have to get the transaction ID. This is how we can verify that the serialization is right. | ||
So what we need for verifying the signature is a single SHA256 hash of the serialized transaction. | ||
|
||
What is this DER encoding with signatures? | ||
|
||
The process of verification consists of the following steps: (taken from https://wiki.bitcoinsv.io/index.php/OP_CHECKSIG#:~:text=OP_CHECKSIG%20is%20an%20opcode%20that,signature%20check%20passes%20or%20fails.) | ||
1. Check that the signature is encoded in the correct format - <DER Sgignature><Hashtyype> | ||
2. Check that the public key is encoded in the correct format - both compressed and uncompressed are accepted | ||
3. We serialize the transaction bytes using 'sighash' based on the sighash type - https://wiki.bitcoinsv.io/index.php/OP_CHECKSIG#:~:text=OP_CHECKSIG%20is%20an%20opcode%20that,signature%20check%20passes%20or%20fails. | ||
|
||
|
||
### Validation Rules | ||
What are the validations we have to perform is an important question to ask. | ||
INPUT: | ||
1. Verify pubkey address | ||
2. Verify pubkey_asm with pubkeyscript(?) | ||
3. Verify signature | ||
|
||
4. Verify (sum of outputs <= sum of inputs) | ||
|
||
We will start with these validations, and run the tests, and then based on the results we can add more rules. | ||
|
||
### Assigning fee/size | ||
Here we basically have to calculate the transaction fees for the given transaction, and then store them in a map that has transaction | ||
id as the key and the (fee/size) as the value. | ||
What do we keep as the size? Serialized transaction size(with or without witness?) | ||
|
||
Let us first mine a block and see if our valid txns are actually valid | ||
## Coinbase transaction | ||
|
||
## Mining a block | ||
We need to do the following things: | ||
1. Select a list of transactions to put in the block | ||
2. Create a candidate block | ||
3. Create coinbase transaction | ||
4. Calculate the Merkle root | ||
5. Find the nonce | ||
|
||
#### Validating P2PKH Scripts | ||
```pseudo | ||
For each P2PKH transaction: | ||
Parse public key and signature. | ||
Verify hash type encoding. | ||
Parse public key using the `secp` package. | ||
Ensure signature is in proper DER format and parse it. | ||
Calculate signature hash (SIGHASH). | ||
Verify signature using ECDSA algorithm. | ||
``` | ||
|
||
#### Validating P2WPKH Scripts | ||
```pseudo | ||
For each P2WPKH transaction: | ||
Parse signature and public key from witness array. | ||
Calculate signature hash (SIGHASH) using BIP143. | ||
Verify signature using ECDSA algorithm. | ||
``` | ||
|
||
#### Validating P2TR Scripts | ||
```pseudo | ||
For each P2TR transaction: | ||
If len(witness array) == 1: | ||
Perform key path spending with single element in the witness array as signature. | ||
Else if len(witness array) > 1: | ||
If len(witness array) != 3: | ||
Log this transaction and return. | ||
Remove annex if present from witness array. | ||
Parse control block, witness script, and public key. | ||
Validate taprootLeafCommitment. | ||
Check for success opcodes in witness script. | ||
Ensure witness script parses successfully. | ||
Verify signature with public key. | ||
``` | ||
|
||
### Picking Transactions | ||
Valid transactions are added to a priority queue based on their fee/weight ratio. Transaction weight is calculated considering both the serialized size and the size of witness bytes. | ||
|
||
### Creating a Candidate Block | ||
After selecting transactions, we create the coinbase transaction and add the witness commitment if required. We then construct the block header with appropriate values and add the transactions to the candidate block. | ||
|
||
#### Witness Commitment | ||
```pseudo | ||
Create array of transaction hashes for all transactions (zero hash for coinbase). | ||
Generate merkle tree root for array of transaction hashes. | ||
Calculate witness commitment as double hash of concatenated 64-byte array of witness merkle root and witness nonce. | ||
Add output entry to coinbase transaction with witness script as witness commitment. | ||
``` | ||
|
||
### Finding the Nonce | ||
```pseudo | ||
While block hash is not below difficulty target: | ||
Generate random nonce. | ||
Set nonce value in block header. | ||
Hash block header. | ||
``` | ||
|
||
## Results and Performance | ||
|
||
### Validation Performance | ||
- Successfully validated 7377 out of 8130 transactions, covering P2PKH, P2WPKH, and P2TR script types. | ||
|
||
### Transaction Selection | ||
- Prioritized transactions based on fee/weight ratio, optimizing block space usage. There is room for further improvement here like taking weighted average etc. | ||
|
||
### Block Creation | ||
- Successfully created coinbase transaction and witness commitment, ensuring integrity and security of the block's data. | ||
|
||
#### Witness Commitment | ||
- Witness commitment added to the coinbase transaction, ensuring integrity and security of the block's witness data. | ||
|
||
### Mining Performance | ||
- Efficiently discovered nonce within the difficulty target, demonstrating robustness of mining algorithm. | ||
- Average mining time per block: Y seconds. | ||
|
||
## Conclusion | ||
Our Bitcoin block mining simulation effectively demonstrates key functionalities of the Bitcoin network. By validating transactions, selecting them based on their fee/weight ratio, and constructing valid blocks, we've illustrated the process of creating a secure and efficient blockchain. The mining algorithm efficiently discovers nonces meeting the required difficulty target, highlighting the resilience of the Bitcoin protocol. Future research could focus on further optimizing transaction selection algorithms and exploring advancements in mining efficiency. | ||
|
||
## References | ||
- Bitcoin Developer Documentation: [https://developer.bitcoin.org/](https://developer.bitcoin.org/) | ||
- Bitcoin Improvement Proposals (BIPs): [https://bitcoin.org/en/development#bips](https://bitcoin.org/en/development#bips) | ||
- Decred's secp package: [https://github.com/decred/dcrd/dcrec/secp256k1/v4](https://github.com/decred/dcrd/dcrec/secp256k1/v4) | ||
- Bitcoin SV Wiki for OP_CHECKSIG: [https://wiki.bitcoinsv.io/index.php/OP_CHECKSIG#:~:text=OP_CHECKSIG%20is%20an%20opcode%20that,signature%20check%20passes%20or%20fails](https://wiki.bitcoinsv.io/index.php/OP_CHECKSIG#:~:text=OP_CHECKSIG%20is%20an%20opcode%20that,signature%20check%20passes%20or%20fails) | ||
- Bitcoin Improvement Proposals (BIP) 143 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters