The intended audience for this document are developers who need to build raw transactions or blocks that interact with the offline staking functionality of Qtum. This document assumes the reader is familiar with basic Ethereum and Bitcoin concepts. In order to understand the delegated PoS block related concepts in this document, the reader should have an understanding of the staking in Qtum's "non-delegated" PoS.
Introduction
Offline staking allows a holder of QTUM to delegate their staking weight to a third party Super Staker. They do this by sending a smart contract transaction to address 0x0000000000000000000000000000000000000086. This transaction includes the address which they want to allow being staked by a third party Super Staker (the "delegation"), the Super Staker address that they want to allow to stake on their behalf (the "staker") and a fee percentage that the staker will receive. For Qtum offline staking all addresses must be legacy addresses starting with a "Q" for Qtum mainnet or "q" for Qtum testnet.
Once such a transaction has been confirmed, the staker is able to stake on behalf of the delegator by constructing a special type of delegated PoS block.
Glossary
Proof of Delegation (PoD)
The proof of delegation ("PoD") is a compact 65 byte signature made by the delegation{privkey} with the staker{hexpubkeyhash} as message. This is done in order to prove that the delegator has at some point allowed the staker to stake blocks on behalf of the delegator. More specifically, the message that is signed is:
sha256d(staker{hexpubkeyhash})
i.e., equivalent to a message signed using the signmessage RPC call in Qtum. Note that the staker{pubkeyhash} should be hex-encoded and is therefore 40 bytes.
The message signed is shown in the script below as sha256d("\x15Qtum signed message:\n\x28"+staker{hexpubkeyhash}) where \x15 hexadecimal represents 21 decimal ASCII characters "Qtum signed message:" plus the newline character 0x0A. These characters are concatinated with \28 hexadecimal or 40 decimal characters of the staker hexpubkeyhash.
Offline staking contract address
The offline staking contract is located at address 0x0000000000000000000000000000000000000086.
OP_CALL script
An OP_CALL (i.e., a contract execution) script requires the following scriptpubkey structure: "\ \ \ \ \ OP_CALL". For the purposes of this document VERSION will always equal 4. GASLIMIT should be 2250000 for an addDelegation call and may be set to 100000 for a removeDelegation call. GAS_PRICE will typically be 40. The CONTRACTADDRESS will always equal 0x0000000000000000000000000000000000000086 in this document. The only variable value in an OP_CALL script will be the CALLDATA in this document. CALLDATA is equivalent to the same concept in Ethereum and should be ABI-encoded in the same way as in Ethereum.
Transaction sender
The sender of a transaction is the pubkeyhash responsible for executing a contract transaction ("msg.sender" in solidity). The sender in Qtum is defined as either the address of the first input to a transaction or the address which is defined by an OP_SENDER subscript (beyond the scope of this document). For the purposes of this document we will always assume that the sender is defined by the address of the first input to a transaction. That output being spent must have either a P2PK or P2PKH script.
Delegating an address to a staker ("addDelegation")
To delegate the staking authority of a particular address the process is as follows:
The delegator selects their address they want to delegate to a staker, the "delegation".
The delegator selects a staker to that will be allowed to submit blocks by staking using the delegation's utxos: the "staker".
The delegator creates a PoD by signing the staker{hexpubkeyhash} using the delegation{privkey}.
The delegator creates a transaction that has one OP_CALL txout that executes the addDelegation function of the offline staking contract. The transaction sender must be the delegation address. The sender (e.g., the first vin prevout's address of the transaction) must be from the delegation address. The output that calls the addDelegation function should contain the following contract calldata:
The contract calldata follows the normal rules for Ethereum's ABI encoding, e.g., all values in the calldata should be left padded by zero bytes to the nearest 32 byte multiple except for the function ABI param (4c0e968c). The fee should be an integer value between 0 and 100, determining the fee percentage which is assigned to the staker upon a successful block being found. 0x60 is the position of the PoD byte array (for more details see the Ethereum ABI specification). 0x41 is the length of the PoD bytes (65 bytes). The PoD bytes is the signature produced by signing staker{pubkeyhash} using the delegation{privkey} (see "Proof of Delegation" for more details).
For example, a delegation{pubkeyhash} = 0x4008700e91bba17d858722d7112adf436ca416ed to the staker{pubkeyhash} = 0x7da6be640325a6048cd67f070c314fa405df126b with a fee of 99%, the calldata could be the following:
To remove an active delegation, the delegator makes a contract call to removeDelegation ("bffe3486") with delegation as sender. The calldata would therefore simply be:
3d666e8b
The full output's scriptPubKey would therefore be:
After the transaction that calls addDelegation has been confirmed, the staker is able to stake blocks on behalf of delegation. To find new blocks, the staker iterates over all delegation utxos with an unuseddepth > 2000 (i.e., they must be confirmed more than 2000 blocks as well as unused for staking for the last 2000 blocks), checking whether the following condition is true:
i.e., the exact same process as normal PoS blocks in Qtum, except that the utxos here are the delegation's utxos and not the staker's. Upon finding a valid block, a staker follows the normal procedures for constructing a Qtum PoS block. Once the block has been constructing and the staker wishes to sign the block, they should create a compact signature on the following message using staker{privkey}:
Note that the utxo here refers to the delegated utxo and the PoD is the proof of delegation created previously. These are the fields that differ when signing delegated PoS blocks. Once this signature has been created, the blocksig field of the should be set to this signature + PoD. i.e., the blockSig field should be a 130 bytes long variable length byte string consisting of two signatures. The stakePrevout field of the block should be set to the delegation utxo. See appendix for the structure of all fields of the block header.
The first input to the coinstake transaction must be an output with a value >= 100 QTUM. The first output of the coinstake transaction must, as in "non-delegated" PoS blocks, be empty. The second output must be the reward to the to staker (reward fee / 100). The third output must be to delegation* with the remaining reward.
For example, for a delegated PoS block with a delegation{pubkeyhash} = 0x4008700e91bba17d858722d7112adf436ca416ed and a staker{pubkey} = 0x0225a9966a7184dc0542bf8c24ced4a0fab4080f9331e683773d2df138fce6fee2 with a fee of 99%, the coinstake outputs would be the following assuming the input value from staker is exactly 100 Qtum and the block subsidy is 4 Qtum:
Block creation timestamp, the 4 least significant bits must be set to 0. Must be greater than the previous block's timestamp.
4
bits
uint32_t
The difficulty of this block.
4
nonce
uint32_t
A nonce, unused in PoS blocks and therefore usually set to 0.
32
state_root
char[32]
The root of the state trie
32
utxo_root
char[32]
The root of the contract utxo balances trie.
32
stake_prevout_hash
char[32]
The delegated staking utxo's hash
4
staking_prevout_vout
uint32_t
The delegated staking utxo's vout index
131
blockSig
varlength
The block's signature created by the staker concatenated with the PoD created by the delegator during delegation. Note that the field will be prefixed by a 0x82 byte specifying the length.