From b67e01f6dc98d791810040969d73b617242bd405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20F=C3=BCrderer?= Date: Sun, 11 Feb 2024 17:22:56 +0100 Subject: [PATCH] Define a first peer-to-peer network protocol version --- docs/{protocol.md => blockchain.md} | 15 +++-- docs/protocol-v0.md | 87 +++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 6 deletions(-) rename docs/{protocol.md => blockchain.md} (83%) create mode 100644 docs/protocol-v0.md diff --git a/docs/protocol.md b/docs/blockchain.md similarity index 83% rename from docs/protocol.md rename to docs/blockchain.md index 5430b7c..b68d99d 100644 --- a/docs/protocol.md +++ b/docs/blockchain.md @@ -64,8 +64,8 @@ To calculate the block difficulty value, the following blocks are relevant: Then apply the following formula: (The slash / means integer division) ``` D = [B-1].difficulty_sum - [B-10].difficulty_sum -T = [B-1].timestamp - [B-10].timestamp -calculated_difficulty = D * 300 / T +T = [B-0].timestamp - [B-10].timestamp +calculated_difficulty = D * 3000 / 9 / T block_difficulty = max(calculated_difficulty, 2^28) @@ -74,9 +74,9 @@ block_difficulty = max(calculated_difficulty, 2^28) 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 0. +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 take assumptions for blocks "before" the first block: +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. @@ -84,7 +84,7 @@ Early in the chain, when less than 11 blocks have been mined, we take assumption ### transaction -A transaction is valid if its signature is valid. +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 @@ -92,7 +92,8 @@ The "signature" field must be an ed25519 signature over the concatenation of all 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) +- 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 @@ -105,3 +106,5 @@ A block is valid if all of the following criteria are fulfilled: - 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.) diff --git a/docs/protocol-v0.md b/docs/protocol-v0.md new file mode 100644 index 0000000..c888255 --- /dev/null +++ b/docs/protocol-v0.md @@ -0,0 +1,87 @@ +# The carrotcoin protocol + +There are two ways of communication: + +- Node to Node +- Client to Node + +## General + +Node to Node communication happens over IPv6 only. + +When starting a node process, it tries to claim udp port 62039. If this port is not free, any other port is chosen. + +## Node behaviour + +### Peers + +A node keeps a list of "peers". (IPv6 address + port number) + +Each peer has a lifetime counter. + +A node may drop a peer at any time by ignoring it. + +A node may add new peers passively, when it gets contacted from a previously unknown address. + +Within one minute, a node contacts all its peers and decrements the lifetime counter by one. + +- When the counter reaches -1, the node is dropped from the peer list. +- Otherwise, a "heartbeat" message is sent to the peer. + +When a node receives a "heartbeat" message from a peer, this peers lifetime counter is reset to 10. + +At the beginning of each minute, the node creates a random "pairing" of all known peers with a lifetime counter >= 8. + +The "heartbeat" message of a "paired" node includes the address and port number of the partner. + +When a node receives a "heartbeat" message with an included partner, it adds this partner address to its peer list with a lifetime counter of 3. + +### Transactions + +Each node keeps a list of up to 1024 open transactions. (That are valid but not yet part of the blockchain.) + +The list is sorted by the following criteria: + +- transaction fee, decreasing +- sender pubkey, increasing +- id, increasing + +These sorting criteria form a 3-tuple. + +Only one transaction per (sender pubkey, id) tuple stays in the list. If a transaction with the same tuple but greater transaction fee is received, it replaces the current transaction. If the transaction fee is equal or smaller, the new transaction is ignored. + +If one sender created multiple transactions, it must have a large enough balance for all transactions, otherwise the excess ones (as defined by the sorting criteria above) are removed from the list. + +If the list grows above 1024 entries, a node may either remove excess ones or keep them in a local list. Within the Node to Node communication, only the first 1024 entries will be synced. + +Open transactions are hashed in a chain. +The hash of each open transaction is a SHA256, calculated over the following datastructure: + +| content | length | +|---|---| +| previous hash | 32 | +| transaction fee (BE) | 8 | +| sender pubkey | 32 | +| id | 4 | + +The "previous hash" consists of 32 nullbytes for the first transaction in the list. For all other entries, it is the calculated hash value of the open transaction entry directly before in the list. + +If the list contains less than 1024 entries, set "transaction fee", "sender pubkey" and "id" to nullbytes for the hash calculation of all following entries. + +## Node to Node message packet formats + +### heartbeat message + +| content | size (bytes) | +|---|---| +| protocol version = 0 (BE) | 2 | +| capable version = 0 (BE) | 2 | +| type = 0 (BE) | 1 | +| difficulty sum of last known block (BE) | 32 | +| hash value of open transaction # 1023 | 32 | +| partner IPv6 | 16 | +| partner port (BE) | 2 | + +The difficulty sum is sent as 0 if no block is known. + +partner IPv6 and partner port may be nullbytes (no partner included).