Define a first peer-to-peer network protocol version

This commit is contained in:
2024-02-11 17:22:56 +01:00
parent c1af21b442
commit b67e01f6dc
2 changed files with 96 additions and 6 deletions

110
docs/blockchain.md Normal file
View File

@@ -0,0 +1,110 @@
# Protocol of the carrotcoin cryptocurrency
The carrotcoin cryptocurrency is a bitcoin-like currency with proof-of-work, created just for learning purposes.
# Blockchain
The network should stabilize at around 1 block every 5 minutes.
Blocks are hashed with SHA256 and need to start with a certain number of zeros (or, more precise, be below a given value depending on the difficulty)
ed25519 keys are used to validate transactions.
## block datastructure
| content | size (bytes) |
|---|---|
| nonce | 8 |
| timestamp (unix time in seconds, BE) | 8 |
| previous hash | 32 |
| message (arbitrary) | 32 |
| difficulty sum (BE) | 32 |
| miner pubkey | 32 |
| transaction (optional) | 148 |
If no transaction is included, its 148 bytes are all null.
The first block has block id 0 and a "previous hash" value of 32 null bytes.
## transaction datastructure
1 carrotcoin (cc) consists of 100 cents
| content | size (bytes) |
|---|---|
| id (arbitrary) | 4 |
| sender (pubkey) | 32 |
| receiver (pubkey) | 32 |
| amount (BE, in cents) | 8 |
| transaction fee (BE, in cents, can be zero) | 8 |
| signature (signed by sender, over transaction fields before signature) | 64 |
## transactions
For every block, the miner gets a reward of 1,00 cc. (100 cents)
If a transaction is included, the following happens additionally:
- The sender needs to pay "amount" + "transaction fee"
- The receiver gets "amount"
- The miner gets "transaction fee" on top of the reward.
## calculating difficulty
The "difficulty sum" field (included in each block) is the cumulative sum of all block difficulty values, beginning with the first block.
The block difficulty value is not directly stated in each block but can be calculated by subtracting the "difficulty sum" of the previous block from the "difficulty sum" of the current block.
To calculate the block difficulty value, the following blocks are relevant:
- The current block for which to calculate the difficulty: [B-0]
- The previous block: [B-1]
- The block that is 10 steps back in the chain: [B-10]
Then apply the following formula: (The slash / means integer division)
```
D = [B-1].difficulty_sum - [B-10].difficulty_sum
T = [B-0].timestamp - [B-10].timestamp
calculated_difficulty = D * 3000 / 9 / T
block_difficulty = max(calculated_difficulty, 2^28)
[B-0].difficulty_sum = [B-1].difficulty_sum + block_difficulty
```
Note the max() operation: A difficulty can never be lower than 2^28 (=268435456). This is a strict lower bound.
For the first block, the "difficulty sum" value is set to 2^28.
Early in the chain, when less than 11 blocks have been mined, we make assumptions for blocks "before" the first block:
- Each of these "before" blocks had a block difficulty of exactly 2^28
- The timestamp difference between each two blocks before the first block is exactly 300 seconds.
## validity
### transaction
A transaction is valid if its signature is valid and it contains an amount of at least 1 cent (0,01 cc).
The "signature" field must be an ed25519 signature over the concatenation of all previous fields (id + sender pubkey + receiver pubkey + amount + transaction fee), and must be valid when validated with the "sender" pubkey.
### transaction in a block
A transaction that is stored in a block must fulfill the following criteria (in addition to the valid signature):
- There was never another transaction with the same ("id", "sender") pair anywhere in the block chain before.
- Following the balances in the block chain, the "sender" key has enough money for both payments. (amount + transaction fee)
The mining reward of the current block is not counted. A miner can not use his fresh mined money in a transaction in the same block where he mined it, only in the following blocks.
### block
A block is valid if all of the following criteria are fulfilled:
- The "previous hash" field contains a SHA256 hash value of a previous valid block. (Or is completely filled with nullbytes, in case of the first block.)
- The "timestamp" field is greater than the timestamp of the previous block (if there is any). Equal timestamps are not allowed.
- The "timestamp" field is less than or equal to the current time. This needs to be decided by each node based on the local clock.
- The "difficulty sum" must be precisely calculated, as specified in `calculating difficulty`
- The "transaction" is either:
- Completely empty (148 nullbytes)
- or: A valid `transaction in a block` as described above.
- The SHA256 hash of the entire block, when interpreted as an BE integer, multiplied by the block difficulty, is less than 2^256.
See `calculating difficulty` what "block difficulty" means. (which is not directly given in the block.)