[this is part of a developers guide to be shared as I go along and learn the nitty-gritty of peercoins protocol myself. If I had access to the wiki I would have pasted it there]
In short, a blob of data is double sha256-hashed and compared to a target. A stake is found when the hash is lower than the target.
bytes short descr description
0-7 StakeModifier will decribe later
8-11 Block time unix time of block that contains the tx
12-15 Tx previous offset the position of previous Tx within the Block blob size
16-19 Tx previous time timestamp of Tx’s previous Tx
20-23 Tx previous index index of Tx’s previous Tx
24-27 a future time to be varied like a nounce
The target = Stakeage offsetted by 30 days but capped at 60 * systemTarget as calculated from the last added pos block’s difficulty of the chain.
The blob is sha256 hashed twice, then reversed in order which results in a 32 bytes blob and converted back to a biginteger.
A stake is found when the hash is lower than the target. So this explains why having a large coinage is easier to find a stake.
StakeModifier
Each (pos?)block contains a 8 bytes long modifier property. The StakeModifier to be used for find stakes is not the modifier of the block where the transaction resides, but the first Pos block that is 761920 (+1) seconds older later down the chain. I guess this is a security measure to counter the myths about nothing at stake. (ppc version 3)
UPDATE
stakemodifiers changes not per block but per time intervals, so 40-60 blocks together can have the same modifier. To get the stakemodier, not only 761920 seconds must have passed, but also the modifier must have changed.
A Block blob consist of the following:
4 version uint32_t Block version information
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
4 timestamp uint32_t A Unix timestamp recording when this block was created
4 bits uint32_t The calculated difficulty target being used for this block
4 nonce uint32_t The nonce used to generate this block
1 // TxnCount
? blob of 1 or more tx
A Tx blob consist of the following:
4 version uint32_t Transaction data format version
4 tx timestamp
1 tx_in count, number of transaction inputs
? TxIn blob
1 tx_out count, number of transaction outputs
? TxOut blob
4 lock time
1 Signature length
TxIn consists of the following fields:
32 Previous output hash (OutPoint)
4 Prevous output index (OutPoint)
1 length of signature script
? signature script (coinbase)
4 Sequence
The TxOut structure consists of the following fields:
8 Transaction amount
1 Length of the pk_script
? pk_script Usually contains the public key as a Bitcoin script setting up conditions to claim this output.
here is an example:
var blockOneBytes = byte{
0x01, 0x00, 0x00, 0x00, // Version 1
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72,
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f,
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c,
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, // PrevBlock
0x98, 0x20, 0x51, 0xfd, 0x1e, 0x4b, 0xa7, 0x44,
0xbb, 0xbe, 0x68, 0x0e, 0x1f, 0xee, 0x14, 0x67,
0x7b, 0xa1, 0xa3, 0xc3, 0x54, 0x0b, 0xf7, 0xb1,
0xcd, 0xb6, 0x06, 0xe8, 0x57, 0x23, 0x3e, 0x0e, // MerkleRoot
0x61, 0xbc, 0x66, 0x49, // Timestamp
0xff, 0xff, 0x00, 0x1d, // Bits
0x01, 0xe3, 0x62, 0x99, // Nonce
0x01, // TxnCount
0x01, 0x00, 0x00, 0x00, // Version
0x61, 0xbc, 0x66, 0x49, // Time
0x01, // Varint for number of transaction inputs
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Previous output hash
0xff, 0xff, 0xff, 0xff, // Prevous output index
0x07, // Varint for length of signature script
0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, // Signature script (coinbase)
0xff, 0xff, 0xff, 0xff, // Sequence
0x01, // Varint for number of transaction outputs
0x00, 0xf2, 0x05, 0x2a, 0x01, 0x00, 0x00, 0x00, // Transaction amount
0x43, // Varint for length of pk script
0x41, // OP_DATA_65
0x04, 0x96, 0xb5, 0x38, 0xe8, 0x53, 0x51, 0x9c,
0x72, 0x6a, 0x2c, 0x91, 0xe6, 0x1e, 0xc1, 0x16,
0x00, 0xae, 0x13, 0x90, 0x81, 0x3a, 0x62, 0x7c,
0x66, 0xfb, 0x8b, 0xe7, 0x94, 0x7b, 0xe6, 0x3c,
0x52, 0xda, 0x75, 0x89, 0x37, 0x95, 0x15, 0xd4,
0xe0, 0xa6, 0x04, 0xf8, 0x14, 0x17, 0x81, 0xe6,
0x22, 0x94, 0x72, 0x11, 0x66, 0xbf, 0x62, 0x1e,
0x73, 0xa8, 0x2c, 0xbf, 0x23, 0x42, 0xc8, 0x58,
0xee, // 65-byte uncompressed public key
0xac, // OP_CHECKSIG
0x00, 0x00, 0x00, 0x00, // Lock time
0x00, // Varint for Signature length
}
So to sum up, the Offset used in findstake can be calculated as follows: (4+32+32+4+4+4+1) + (all Tx sizes before the Tx in question)
Sizes, modifier and tx sequences can be obtained via:
- httttttps: bkchain.org/ppc/api/v1/tx/hash/…
- htttttttp: ppc.blockr.io/api/v1/block/raw/…
Variable length integer
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
<= 0xffffffff 5 0xfe followed by the length as uint32_t
- 9 0xff followed by the length as uint64_t
So the tx-Offset is calculated as follows: 80+(1 or 3 or 5 or 9) + the sizes of preceding tx’s
To conclude, I think it is entirely possible to finish thefindstakeJS project! :))
What's in 0.3.0 release:Stake generation protocol upgrade (protocol switch March 20th)
Qt UI support
Fix compatibility with vanitygen (note: private keys dumped in v0.2 is no longer importable into v0.3.0, must dump again from v0.3.0 client)
Miscellaneous bug fixes and improvementsThe protocol upgrade in 0.3.0 includes a new algorithm to derive proof-of-stake hash modifier, the entity that scrambles computation for stake owners, which replaces the current proof-of-stake difficulty used as modifier in 0.2 protocol. The design was started late September last year, when I first began to realize the issues with using difficulty as modifier. Honorary mention also goes to Jutarul, who independently discovered and verified an issue with using difficulty as modifier and published on bitcointalk in December last year, while successfully executed a demo attack on the block chain. Other changes in the protocol include starting hash weight from 0 at the 30-day mininum age, and requirement that coinstake timestamp must equal block timestamp. Overall 0.3 protocol should significantly strengthen the proof-of-stake protection and resolve the current known vulnerabilities.