zArchive~Protocol Documentation - gridcoin-community/Gridcoin-Wiki GitHub Wiki
This section is under construction. It is heavily based on https://en.bitcoin.it/wiki/Protocol_documentation. This page describes the behavior of the Original Gridcoin wallet. The Gridcoin protocol is specified by the behavior of the reference client, not by this page. In particular, while this page is quite complete in describing the network protocol, it does not attempt to list all of the rules for block or transaction validity.
Type names used in this documentation are from the C99 standard.
Usually, when a hash is computed within Gridcoin, it is computed twice. Most of the time SHA-256 hashes are used, however RIPEMD-160 is also used when a shorter hash is desirable (for example when creating a bitcoin address).
Example of double-SHA-256 encoding of string "hello":
hello
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 (first round of sha-256)
9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50 (second round of sha-256)
For Gridcoin addresses (RIPEMD-160) this would give:
hello
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 (first round is sha-256)
b6a9c8c230722b7c748331a8b450f05566dc7d0f (with ripemd-160)
Merkle trees are binary trees of hashes. Merkle trees in Gridcoin use a double SHA-256, the SHA-256 hash of the SHA-256 hash of something.
If, when forming a row in the tree (other than the root of the tree), it would have an odd number of elements, the final double-hash is duplicated to ensure that the row has an even number of hashes.
First form the bottom row of the tree with the ordered double-SHA-256 hashes of the byte streams of the transactions in the block.
Then the row above it consists of half that number of hashes. Each entry is the double-SHA-256 of the 64-byte concatenation of the corresponding two hashes below it in the tree.
This procedure repeats recursively until we reach a row consisting of just a single double-hash. This is the Merkle root of the tree.
For example, imagine a block with three transactions a, b and c. The Merkle tree is:
d1 = dhash(a)
d2 = dhash(b)
d3 = dhash(c)
d4 = dhash(c) # a, b, c are 3. that's an odd number, so we take the c twice
d5 = dhash(d1 concat d2)
d6 = dhash(d3 concat d4)
d7 = dhash(d5 concat d6)
where
dhash(a) = sha256(sha256(a))
d7 is the Merkle root of the 3 transactions in this block.
Note: Hashes in Merkle Tree displayed in the block explorer are of little-endian notation. For some implementations and calculations, the bytes need to be reversed before they are hashed, and again after the hashing operation.
Gridcoin uses Elliptic Curve Digital Signature Algorithm (ECDSA) to sign transactions.
For ECDSA the secp256k1 curve from http://www.secg.org/sec2-v2.pdf is used.
Public keys (in scripts) are given as 04 where x and y are 32 byte big-endian integers representing the coordinates of a point on the curve or in compressed form given as where is 0x02 if y is even and 0x03 if y is odd.
Signatures use DER encoding to pack the r and s components into a single byte stream (this is also what OpenSSL produces by default).
Transactions are cryptographically signed records that reassign ownership of Gridcoins to new addresses. Transactions have inputs - records which reference the funds from other previous transactions - and outputs - records which determine the new owner of the transferred Gridcoins, and which will be referenced as inputs in future transactions as those funds are respent.
Each input must have a cryptographic digital signature that unlocks the funds from the prior transaction. Only the person possessing the appropriate private key is able to create a satisfactory signature; this in effect ensures that funds can only be spent by their owners.
Each output determines which Gridcoin address (or other criteria) is the recipient of the funds.
In a transaction, the sum of all inputs must be equal to or greater than the sum of all outputs. If the inputs exceed the outputs, the difference is considered a transaction fee, and is redeemable by whoever first includes the transaction into the block chain.
A special kind of transaction, called a coinbase transaction, has no inputs. It is created by minters, and there is one coinbase transaction per block. Because each block comes with a reward of newly created Gridcoins, the first transaction of a block is, with few exceptions, the transaction that grants those coins to their recipient (the minter). In addition to the newly created Gridcoins, the coinbase transaction is also used for assigning the recipient of any transaction fees that were paid within the other transactions being included in the same block. The coinbase transaction can assign the entire reward to a single Gridcoin address, or split it in portions among multiple addresses, just like any other transaction. Coinbase transactions always contain outputs totalling the sum of the block reward plus all transaction fees collected from the other transactions in the same block.
Most Gridcoin outputs encumber the newly transferred coins with a single ECDSA private key. The actual record saved with inputs and outputs isn't necessarily a key, but a script. Gridcoin uses an interpreted scripting system to determine whether an output's criteria have been satisfied, with which more complex operations are possible, such as outputs that require two ECDSA signatures, or two-of-three-signature schemes. An output that references a single Gridcoin address is a typical output; an output actually contains this information in the form of a script that requires a single ECDSA signature. The output script specifies what must be provided to unlock the funds later, and when the time comes in the future to spend the transaction in another input, that input must provide all of the thing(s) that satisfy the requirements defined by the original output script.
A Gridcoin address is in fact the hash of a ECDSA public key, computed this way:
Version = Mainnet: 0x3e; Testnet: #TODO
Key hash = Version concatenated with RIPEMD-160(SHA-256(public key))
Checksum = 1st 4 bytes of SHA-256(SHA-256(Key hash))
Gridcoin Address = Base58Encode(Key hash concatenated with Checksum)
The Base58 encoding used is home made, and has some differences. Especially, leading zeroes are kept as single zeroes when conversion happens.
Almost all integers are encoded in little endian. Only IP or port number are encoded big endian.
See 1.
Field Size | Description | Data type | Comments |
---|---|---|---|
4 | magic | uint32_t | Magic value indicating message origin network, and used to seek to next message when stream state is unknown |
12 | command | char[12] | ASCII string identifying the packet content, NULL padded (non-NULL padding results in packet rejected) |
4 | size | uint32_t | Size of payload in number of bytes |
4 | checksum | uint32_t | First 4 bytes of sha256(sha256(payload)) |
? | payload | uchar[] | The actual data |
Known magic values:
Network | Magic value | Sent over wire as |
---|---|---|
main | 0x70352205 2 | 70 35 22 05 |
testnet | 0xCDF2C0EF 3 | CD F2 C0 EF |
Integer can be encoded depending on the represented value to save space. Variable length integers always precede an array/vector of a type of data that may vary in length. Longer numbers are encoded in little endian.
Value | Storage length | Format |
---|---|---|
< 0xFD | 1 | uint8_t |
<= 0xFFFF | 3 | 0xFD followed by the length as uint16_t |
<= 0xFFFF FFFF | 5 | 0xFE followed by the length as uint32_t |
- | 9 | 0xFF followed by the length as uint64_t |
Variable length string can be stored using a variable length integer followed by the string itself.
Field Size | Description | Data type | Comments |
---|---|---|---|
? | length | var_int | Length of the string |
? | string | char[] | The string itself (can be empty) |
When a network address is needed somewhere, this structure is used. Network addresses are not prefixed with a timestamp in the version message.
Field Size | Description | Data type | Comments |
---|---|---|---|
4 | time | uint32 | the Time (version >= 31402). Not present in version message. |
8 | services | uint64_t | same service(s) listed in version |
16 | IPv6/4 | char[16] | IPv6 address. Network byte order. The original client only supported IPv4 and only read the last 4 bytes to get the IPv4 address. However, the IPv4 address is written into the message as a 16 byte IPv4-mapped IPv6 address (12 bytes 00 00 00 00 00 00 00 00 00 00 FF FF, followed by the 4 bytes of the IPv4 address). |
2 | port | uint16_t | port number, network byte order |
Hexdump example of Network address structure
0000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0010 00 00 FF FF 0A 00 00 01 20 8D ........ .
Network address:
01 00 00 00 00 00 00 00 - 1 (NODE_NETWORK: see services listed under version command)
00 00 00 00 00 00 00 00 00 00 FF FF 0A 00 00 01 - IPv6: ::ffff:a00:1 or IPv4: 10.0.0.1
20 8D - Port 8333
Inventory vectors are used for notifying other nodes about objects they have or data which is being requested.
Inventory vectors consist of the following data format:
Field Size | Description | Data type | Comments |
---|---|---|---|
4 | type | uint32_t | Identifies the object type linked to this inventory |
32 | hash | char[32] | Hash of the object |
The object type is currently defined as one of the following possibilities:
Value | Name | Description |
---|---|---|
0 | ERROR | Any data of with this number may be ignored |
1 | MSG_TX | Hash is related to a transaction |
2 | MSG_BLOCK | Hash is related to a data block |
3 | MSG_FILTERED_BLOCK | Hash of a block header; identical to MSG_BLOCK. Only to be used in getdata message. Indicates the reply should be a merkleblock message rather than a block message; this only works if a bloom filter has been set. |
4 | MSG_CMPCT_BLOCK | Hash of a block header; identical to MSG_BLOCK. Only to be used in getdata message. Indicates the reply should be a cmpctblock message. See BIP 152 for more info. |
Other Data Type values are considered reserved for future implementations.
Block headers are sent in a headers packet in response to a getheaders message.
Field Size | Description | Data type | Comments |
---|---|---|---|
4 | version | int32_t | Block version information (note, this is signed) |
32 | prev_block | char[32] | The hash value of the previous block this particular block references |
32 | merkle_root | char[32] | The reference to a Merkle tree collection which is a hash of all transactions related to this block |
4 | timestamp | uint32_t | A timestamp recording when this block was created (Will overflow in 2106[1]) |
4 | bits | uint32_t | The calculated difficulty target being used for this block |
4 | nonce | uint32_t | The nonce used to generate this block… to allow variations of the header and compute different hashes |
1 | txn_count | var_int | Number of transaction entries, this value is always 0 |
Several uses of CompactSize below are "differentially encoded". For these, instead of using raw indexes, the number encoded is the difference between the current index and the previous index, minus one. For example, a first index of 0 implies a real index of 0, a second index of 0 thereafter refers to a real index of 1, etc.
A PrefilledTransaction structure is used in HeaderAndShortIDs to provide a list of a few transactions explicitly.
Field Name | Type | Size | Encoding | Purpose |
---|---|---|---|---|
index | CompactSize | 1, 3 bytes | Compact Size, differentially encoded since the last PrefilledTransaction in a list | The index into the block at which this transaction is |
tx | Transaction | variable | As encoded in tx messages | The transaction which is in the block at index index. |
See BIP 152 for more information.
A HeaderAndShortIDs structure is used to relay a block header, the short transactions IDs used for matching already-available transactions, and a select few transactions which we expect a peer may be missing.
Field Name | Type | Size | Encoding | Purpose |
---|---|---|---|---|
header | Block header | 80 bytes | First 80 bytes of the block as defined by the encoding used by "block" messages | The header of the block being provided |
nonce | uint64_t | 8 bytes | Little Endian | A nonce for use in short transaction ID calculations |
shortids_length | CompactSize | 1 or 3 bytes | As used to encode array lengths elsewhere | The number of short transaction IDs in shortids (ie block tx count - prefilledtxn_length) |
shortids | List of 6-byte integers | 6*shortids_length bytes | Little Endian | The short transaction IDs calculated from the transactions which were not provided explicitly in prefilledtxn |
prefilledtxn_length | CompactSize | 1 or 3 bytes | As used to encode array lengths elsewhere | The number of prefilled transactions in prefilledtxn (ie block tx count - shortids_length) |
prefilledtxn | List of PrefilledTransactions | variable size*prefilledtxn_length | As defined by PrefilledTransaction definition, above | Used to provide the coinbase transaction and a select few which we expect a peer may be missing |
See BIP 152 for more information.
A BlockTransactionsRequest structure is used to list transaction indexes in a block being requested.
Field Name | Type | Size | Encoding | Purpose |
---|---|---|---|---|
blockhash | Binary blob | 32 bytes | The output from a double-SHA256 of the block header, as used elsewhere | The blockhash of the block which the transactions being requested are in |
indexes_length | CompactSize | 1 or 3 bytes | As used to encode array lengths elsewhere | The number of transactions being requested |
indexes | List of CompactSizes | 1 or 3 bytes*indexes_length | Differentially encoded | The indexes of the transactions being requested in the block |
See BIP 152 for more information.
A BlockTransactions structure is used to provide some of the transactions in a block, as requested.
Field Name | Type | Size | Encoding | Purpose |
---|---|---|---|---|
blockhash | Binary blob | 32 bytes | The output from a double-SHA256 of the block header, as used elsewhere | The blockhash of the block which the transactions being provided are in |
transactions_length | CompactSize | 1 or 3 bytes | As used to encode array lengths elsewhere | The number of transactions provided |
transactions | List of Transactions | variable | As encoded in tx messages | The transactions provided |
See BIP 152 for more information.
Short transaction IDs are used to represent a transaction without sending a full 256-bit hash. They are calculated by:
- single-SHA256 hashing the block header with the nonce appended (in little-endian)
- Running SipHash-2-4 with the input being the transaction ID and the keys (k0/k1) set to the first two little-endian 64-bit integers from the above hash, respectively.
- Dropping the 2 most significant bytes from the SipHash output to make it 6 bytes.
See BIP 152 for more information.
When a node creates an outgoing connection, it will immediately advertise its version. The remote node will respond with its version. No further communication is possible until both peers have exchanged their version.
Payload 4:
Field Size | Description | Data type | Comments |
---|---|---|---|
4 | version | int32_t | Identifies protocol version being used by the node |
32 | nonce | string | 256 random bytes encoded as hex string |
16 | pw1 | string | md5(nonce+","+sboinchashargs) |
16 | mycpid | string | The CPID of the node sending this message |
16 | mycpid | string | The CPID of the node sending this message |
TODO | acid | string | Command nonce |
8 | nLocalServices | uint64_t | (1 << 0) |
8 | nTime | uint64_t | UNIX Timestamp of current time |
TODO | addrYou | TODO | TODO |
TODO | addrMe | TODO | TODO |
8 | nLocalHostNonce | uint64_t | 8 random bytes |
? | FormatSubVersion | string | Clientversion 5 |
4 | nBestHeight | int | Current blockheight |
34 | sGRCAddress | string | Your Gridcoin address |
A "verack" packet shall be sent if the version packet was accepted.