Files
carrotcoin/docs/protocol-v0.md
2025-12-13 23:41:07 +01:00

13 KiB

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.

Version fields

Every packet starts with a 4-byte header containing two version fields. (A 2-byte "protocol version" and a 2-byte "capable version".)
Participants should fill both fields with 0 when sending messages. When receiving a messages with "protocol version" != 0, the message should be ignored. The "capable version" must not be checked for incoming messages, so messages are processed regardless of the value they contain as "capable version".

This is the current behaviour for all "protocol version 0" participants and should allow to extend the protocol in the future, if this becomes necessary.

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
  • sent or played amount, decreasing
  • sender pubkey, increasing
  • id, increasing

These sorting criteria form a 4-tuple.

Only one transaction per (sender pubkey, id) tuple stays in the list. If a transaction with the same (sender pubkey, id) tuple but greater transaction fee or same fee but greater amount is received, it replaces the current transaction. In other cases (smaller fee or neither the fee nor the amount increased), the new transaction is ignored.

By choosing different ids, one sender can put multiple transactions into the list.

Each sender 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.

At most one (the next pending) gambling reveal transaction can be part of the list and will be the first one, before all other transactions.

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
is reveal transaction (bool) 1
transaction fee (BE) 8
amount (BE) 8
sender / player 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.

The field "is reveal transaction" is 0x01 for the first transaction if it is a reveal transaction and 0x00 for all other transactions. Reveal transactions have "transaction fee", "amount", "sender / player pubkey" and "id" set to nullbytes.

If the list contains less than 1024 entries, set "is reveal transaction", "transaction fee", "amount", "sender / player 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 (dec) 1
difficulty sum of second 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 2^28 if only one block is known or as 0 if no block is known.

partner IPv6 and partner port may be nullbytes (no partner included).

block request

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 1 (dec) 1
block hash 32

A block request is sent from node A to node B in order to transfer a block from node B to node A.
Node B should answer with a "block transfer" message that includes the requested block (as given by "block hash")

If "block hash" consists of 32 nullbytes, node A wants node B to send the newest block of B's blockchain.

block transfer

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 2 (dec) 1
block 293

A "block transfer" message is sent back in response to a "block request" message.

open transaction list hash request

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 3 (dec) 1
list position (0 <= x < 1024) (BE) 2

open transaction list hash response

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 4 (dec) 1
list position (0 <= x < 1024) (BE) 2
"open transaction" hash value 32

open transaction request

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 5 (dec) 1
list position (0 <= x < 1024) (BE) 2

open transaction response

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 6 (dec) 1
list position (0 <= x < 1024) (BE) 2
transaction 149

Client to Node message packet formats

Mining task request (Client -> Node)

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 7 (dec) 1
padding (nullbytes) 253

The node should answer to a "Mining task request" with a "Mining task response"

Mining task response (Node -> Client)

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 8 (dec) 1
transaction 149
previous hash 32
timestamp (unix time in seconds, BE) 8
difficulty sum (BE) 32
threshold 32

The node tells the miner "timestamp", "previous hash", "difficulty sum" and "transaction" for the new block.

The miner fills "nonce", "message" and "miner pubkey" on its own.

When a miner finds a block, it sends a "block transfer" message to the node.

Transaction request (Client -> Node)

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 9 (dec) 1
transaction 149

The transaction can be of any type. (Payment, gambling, gambling reveal)

The node should answer to a "Transaction request" with a "Transaction request received" if the contained transaction is formally correct (see "validity / transaction" in the blockchain specification).

To validate a gambling reveal transaction, the node will first ask the client for the associated proof (see "Associated revealing proof request" and "Associated revealing proof response" messages) before sending back a "Transaction request received" response.

A response is always sent back for valid transaction data structures, even if the transaction cannot be applied to the blockchain (e.g. because the sender used the transaction id before or has not enough money). For gambling reveal transactions, the request is confirmed if the proof was received, the proof hash matches and all numbers are correctly in range. (0 < I < n/2) The check if the reveal proof matches the oldest not yet revealed commitment block, is done after confirming with "Transaction request received".

Transaction request received (Node -> Client)

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 10 (dec) 1

Reveal mining task request (Client -> Node)

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 11 (dec) 1
padding (nullbytes) 32

The node should answer to a "Reveal mining task request" with a "Reveal mining task response"

Reveal mining task response (Node -> Client)

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 12 (dec) 1
commitment hash 32

The commitment hash is either 32 nullbytes ("nothing to do for reveal miners at the moment") or it contains the hash of the oldest not yet revealed gambling commitment block.

See blockchain.md / section Gambling for the mathematical background what to do with the commitment hash "H".

When the miner is done forming a proof, he is expected to create a gambling reveal transaction and send it to a node using a "Transaction request" message. It should also be ready to receive and answer "Associated revealing proof request" messages from that node.

General packet formats

These packets can be used in both situations (For Client <-> Node communication and for Node <-> Node communication.)

Ping

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 13 (dec) 1
ASCII string "R u carrotcoin?" 15
nonce (arbitrary value) 8

The ASCII string "R u carrotcoin?" is fixed and messages with a different content in this part of the message should be ignored.

When receiving a valid Ping message, a Pong message with the same nonce value must be sent back to the sender.

Pong

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 14 (dec) 1
ASCII string "I m carrotcoin!" 15
nonce (same value as in the Ping) 8

An answer message to a Ping request. See Ping for implementation details.

Associated revealing proof request

As described in the blockchain specification, a reveal transaction requires an "associated revealing proof" to be fully validated.

There are 3 possible situations when a participant A transfers a reveal transaction to a participant B:

  1. A reveal mining client (A) finished calculating the proof and sends the transaction to some node (B).
  2. A node (A) further spreads this transaction to another node (B).
  3. A node (A) transfers a block with a reveal transaction to another node (B).

In each case, if B does not know the associated revealing proof, it needs to ask A for it with the following message:

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 15 (dec) 1
parts bitfield 1
associated revealing proof (hash) 32

The associated revealing proof described in the blockchain has a total length of 5376 bytes. For transmission, it is equally divided into 6 parts with 896 bytes each. These parts are numbered from "part 0" (the first 896 bytes) to "part 5" (the last 896 bytes).

A sha256 hash value of the entire 5376 byte datastructure is the identifier that is used inside the transaction and used in this request to identify the proof being requested.

The "parts bitfield" describes which parts should be sent back. 0x01 means "part 0", 0x02 means "part 1", ..., 0x20 means "part 5". To request all 6 parts (which might be a typical request), the "parts bitfield" will have value 0x3f. If a retransmission is needed, the "parts bitfield" can describe exactly, which parts are still missing.

When node A sent a reveal transation to node B, it should answer such associated revealing proof requests from B with all required parts, each part transmitted as an individual UDP packet of type "Associated revealing proof response".

Associated revealing proof response

content size (bytes)
protocol version = 0 (BE) 2
capable version = 0 (BE) 2
type = 16 (dec) 1
part number 1
associated revealing proof (hash) 32
proof partial data 896

This message is sent back as response to an associated revealing proof request. See above for implementation details.

The "part number" describes where this part belongs to and has a value from 0 to 5 (inclusive).

The "associated revealing proof (hash)" identifies the entire 5376-byte proof and is the same as in the request.

The "proof partial data" contains the actual information (1/6 of the entire proof in each message).