Informal Discussion -- "How does the minting process work?"

I hope sigmike doesn’t mind that I posted this, but I felt that it’s a useful conversation for the community to see, because he does a great job of simplifying the concepts of what happens when the CPUMinter process is running. I, of course, come off as a total n00b, and deserve any ridicule that comes out of this :slight_smile: As you’ll notice, in addition to being a great developer and teacher, sigmike, has the patience of a saint.


[13:23] Mike, am I recalling a conversation we had a couple weeks (maybe months, now) ago correctly? “When CPUMinter is running, the process is looking to solve for the next block, and if it finds a prospective match, only then does it actually check to see if the user’s wallet contains mature coins that can be used for proof-of-stake”?

[13:26] It goes the other way around: each second it takes all the available wallet coins (the ones you can spend) minus the reserve, and for each one it checks whether it matches the target difficulty

[13:28] So, let me make sure I’m clear on that. Here’s a hypothetical scenario:

[13:29] Over the past 3 months, I’ve received 4 transactions for 100 PPC each

[13:29] One 90 days ago, one 60 days ago, one 31 days ago, and the last was today

[13:30] When CPUMinter is running, once per second it’s checking to see if any of the first three values matches the current target difficulty?

[13:30] (assuming I have no reserve set)

[13:32] ben: it will try to find a kernel on all coins, but for the coins not old enough it will stop early, before the actual difficulty check

[13:32] Ok, so it would be attempting four validations per second, in that case

[13:33] depends on what you call validation, but yes

[13:34] it will stop here exactly: https://github.com/Peershares/Peershares/blob/master/src/wallet.cpp#L1261-L1262

[13:37] Knowing that the process is able to do that (differentiate between immature and mature coins), is it reasonable to expect that a new method could be added that would output a list of transactions that are currently being used in those attempts, with details like “amount,” “current coin age,” “from tx_id,” etc.?

[13:39] you mean keeping a record of the outputs that were used during the last minting and make these data available through an rpc command or in the GUI?

[13:41] or adding a new method that does the same thing as the mint thread but would not actually mint and only report these data?

[13:42] Through the GUI or CLI, yes, but the intent would be for me to be able to see what coins in my wallet are potentially going to solve a block. So if that means a report, after the last second’s mint attempt, then yes, that’s what I mean :slight_smile:

[13:43] If it was in Peercoin first, I was thinking something like:

[13:43] $ ./ppcoind listmintablecoins

[13:44] or listmintingcoins

[13:45] From what I’m hearing from people, and from my own experiences, it’s very difficult to understand what’s going on behind the scenes while minting is occuring

[13:45] I’d rather keep a record, it involves less code duplication

[13:46] A record would be fine, if the end result was the same

[13:46] and you could also add how far it was from the difficulty

[13:47] it shouldn’t be hard to implement. The difficult part may be to make Sunny merge it :slight_smile:

[13:47] Other than as a “nice to know,” what would that tell me? Is it predictive of how long before that input could likely match the difficulty (meaning, if difficulty was 10.8 and you saw ‘5.5’, does that mean anything from this second to the next?)

[13:50] ben: no it would not be predictive of anything

[13:54] I think it would help if I had a better understand of the mechanics. If I have 1000 PPC and have held them for 60 days (coinage= 60000) and I have 100 PPC for the same 60 days (coinage=6000), does my 1000 PPC input tx have a better chance of solving a block with minting because the search space it’s provided is much closer to the current target difficulty?

[13:55] (Completely fake numbers) – TargetDiff = 10.8M, 1000 PPC tx searches hashes that would fall into a range near that, vs. the 100 PPC tx, that has to search the whole space?

[13:56] And thank you for putting up with these questions, and having the patience to answer them :slight_smile:

[13:57] you have more chances with the 60000 coinage tx because the difficulty target is lower than for the 6000 coinage tx

[13:58] the target is actually a TargetPerCoinDay

[13:59] I’ll have to think about that one. I’m not quite grasping how it all works together

[14:00] Thanks

[14:00] the hash you produce is random, and it must be below TargetPerCoinDay * CoinDay

[14:00] so your 60000 coinage has 10 times more chances than the 6000 to match this condition

[14:01] and “more chances” isn’t a measure of actual attempts, but a reduction in the number of potential matches?

[14:02] So, in a very simplistic scenario, not using minting – I ask you and PB to pick a number between 1 and 1000

[14:02] For PB, his guess is within the scope of 1 - 1000, but for your guess, I give you a hint and say, ‘it’s between 1 and 100’?

[14:05] 99! I cheated

[14:05] :slight_smile:

[14:05] yes ben

[14:05] your 60000 tx has to find a random number between 0 and 60000target, and your 6000 between 0 and 6000target

[14:06] and both can do 1 attempt per second

[14:10] and the random number you pick is between 0 and 2^256

[14:11] An that’s the part that mixes me up a bit

[14:13] How does the target get calculated?

[14:13] from the time between the last 2 blocks

[14:14] I don’t fully understand the calcuation. Must be a standard math formula though

[14:14] Ok, so that’s like PoW, trying to maintain the distribution of ~ 1 per 10 minutes

[14:14] s/like/same as

[14:14] yes

[14:16] So the total search set is between 0 and 2^256 – the target multiplier “helps” both tx’s above, but it helps the 60000 one more

[14:16] So the 6000 tx always has a chance, it’s just that the chance isn’t nearly as good

[14:18] (which, now, I can see why Sunny capped maturity at 90 days; otherwise, a long-held, small stake could eventually reach a point where the chance to solve the next block would be very high)

[14:19] yes

[14:20] This has definitely been an “AH HA!” moment

[14:20] nice :slight_smile:


Thanx for sharing… It clarifies things a bit :wink:

Thanks for sharing that Ben, that’s good information!

And thank you Sigmike for helping Ben help us all :slight_smile:

When I ran a test with this with BCX / Battlecoin

and for each one it checks whether it matches the target difficulty

…that part was untrue. But BCX’s code appeared to be based on ppcoin 0.2.0 with a stake bug in it. Not sure. Either way, it keep trying to mint the oldest transaction. It didn’t try the 3 oldest transactions even though they were all transactions that were able to be used as stake.

My oldest transaction was something small like 2 BCX and my next one was huge, like 1500 BCX, yet it would never try to mint the 1500 BCX until the 2 BCX transaction stake was used.

I found this to be a problem, and when I saw that BCX didn’t have devs to properly fix the coin at that time for other issues, I dumped mine and gave up.

I don’t know if any of this is inherent in ppcoin still, but it is my experience with battlecoin’s minter.

Is the search space [0, 2^256) or [0, 2^32) ?

I’m wondering whether we can understand it as following: PoS minting is just like a PoW merge mining nonce search for different chains/output txs. So each second a nonce is picked in the search space, and this nonce is used to get something similar to the hash for each output transaction in your wallet ( say, 600 PPC * 31days, 6000PPC * 60 days, …), and then compare those hashes with current “target”/“difficulty” to decide whether it hits and generates a PoS block.

That’s my logic understanding. More details should be studied from the source code.

[quote=“ppcman, post:4, topic:2189”]When I ran a test with this with BCX / Battlecoin

and for each one it checks whether it matches the target difficulty

…that part was untrue.[/quote]

Peercoin does select all your balance (minus reserve): https://github.com/ppcoin/ppcoin/blob/master/src/wallet.cpp#L1240
And tries each output: https://github.com/ppcoin/ppcoin/blob/master/src/wallet.cpp#L1246
And only aborts if it finds a matching kernel.

Each second you get a new 256 bits hash so the maximum value is 2^256-1.

There’s no nonce. Or you can say the nonce is the timestamp which changes every second. This timestamp is added to other data from your transaction and you produce a 256 bits hash with that. And you compare this big number with (current target * coin age). If your hash is below this adjusted target, your kernel is valid to make a PoS block.

It is great to see Sigmike explaining this. I’ve been trying to understand this from an analytical and logical point of view for months. Having a coder explaining makes it all a bit more concrete. Thanks Sigmike and thanks Ben for asking the ‘smart’ questions.

I’m glad to hear that the lottery analogy in the “Long PoS thread” still stands (more coins/ tickets, more chances to mint / win the lottery). Each block we have a new draw 8)

Since the network has a tolerance of two hours of time stamp error, does it mean one can try 14400 different time stamps per second?

Since the network has a tolerance of two hours of time stamp error, does it mean one can try 14400 different time stamps per second?[/quote]

Yes. There are other limits involved but you can try more timestamps per second. The client already tries some previous timestamps if you missed them.

But if you try the next 14400 timestamps at time t, then at time t+1 you’ll try 14399 timestamps you’ve already tried, and only try 1 new. So you still try only 1 new timestamp per second.

If you do that it may still be a little easier to find a block if the difficulty changes a lot (because you’ll try more timestamps when the difficulty is low). But it’s probably not significant. And you wouldn’t get more reward, you’d only a part of it earlier.

Since the network has a tolerance of two hours of time stamp error, does it mean one can try 14400 different time stamps per second?[/quote]

Yes. There are other limits involved but you can try more timestamps per second. The client already tries some previous timestamps if you missed them.

But if you try the next 14400 timestamps at time t, then at time t+1 you’ll try 14399 timestamps you’ve already tried, and only try 1 new. So you still try only 1 new timestamp per second.[/quote]

Is it right? In the (N+1)th second the difficulty and the hash for the previous block have all changed so you won’t get the same hash with timesptamp=N as you did in the Nth second (when timesptamp was N). All 14400 hashes would be new compared with the last second.

And you wouldn't get more reward, you'd only a part of it earlier.
That is true. But the minters with small stakes have incentive to get a block earlier or they don't get any POS for a long time (years). Or for those who want to spend the coins that have generated coin-ages but haven't gotten POS.

Difficulty and hash of previous block only change when there is a new block, which happens about every 10 minutes, not every second.

Difficulty and hash of previous block only change when there is a new block, which happens about every 10 minutes, not every second.[/quote]

You are right. So when there is a new block this can work once. On average there is a 14400/60/10=24 times advantage. (14400 is the number of seconds in +/-2hr). Every stake that finds a POS block will be off for 30 days. So actually it will take 30246=4320 stakes to be able to have one exploit for every block. Nodes doing this will push up POS difficulty, reducing other stakes’ access to POS blocks by 24 times, hence weakening network security. Unless I get it wrong somewhere it seems a serious problem.

That calculation was not totally correct. It assumed anyone who does this will finish looking for a block within a second, and will repeat the same the next second. Actually he has a 14400 times advantage as long as a valid stake (unspent input). If it takes 10 minutes to try all of them, he will have a solid 14400 times advantage.

Is it right? In the (N+1)th second the difficulty and the hash for the previous block have all changed so you won’t get the same hash with timesptamp=N as you did in the Nth second (when timesptamp was N). All 14400 hashes would be new compared with the last second.[/quote]

Actually the previous block hash in not part of the hash you compute in PoS. So the 14400 hashes stay the same even if there’s a new block.
The only thing that may change is the difficulty.

[quote=“sigmike, post:15, topic:2189”]Actually the previous block hash in not part of the hash you compute in PoS. So the 14400 hashes stay the same even if there’s a new block.
The only thing that may change is the difficulty.[/quote]

Since the new kernel is found by hash(nStakeModifier + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime) < bnTarget * nCoinDayWeight can’t you try 7200+600 nTimes for every prev block? Other people can only try 600 times before the next block is found, in average 600 sec. The 7200 is the number of seconds in the 2hr clock error that the network allows you to have. Maybe it is 14400. I am not sure. But anyway in this exploit basically you pretend to have a wrong system clock.

btw I don’t really understand stakeModifier.

You can try, but since the prev block is not used in the hash, you’ll find the same hash for every prev block. So you don’t get any more chances when the prev block changes.

Note that txPrev.block is the block where your coins were confirmed, not the last block in the blockchain.

It is generated a few blocks after your coins are confirmed. It exists to prevent you from precalculating when you’ll be able to find a block before the transaction is confirmed. It doesn’t change over time either.

Aha that is what I didn’t get. Thanks. So the exploit only get an extra two hours. That is no big deal.

But if nothing in the expression changes except nTime, bnTarget, and nCoinDayWeight which is a known function of nTime , this means that I can calculate when in the future I likely will be getting a kernel. ???

Yes, if you can guess the difficulty.

Yes, if you can guess the difficulty.[/quote]

The difficulty fluctuates around a relatively slow changing average hence can be estimated at some certainly. For a particular stake, anyone who wants take advantage of knowing roughly when the stake will find a kernel might skip minting before time is about up. This stake still contributes to supporting the network. This in itself is harmless. However if a person has many stakes of similar coin age, he could use this knowledge to spend those stakes that will find stakes far in the future, hence improve the average block finding rate for all his stakes; Or he could immediately send the stake that needs more than average time to find a kernel to himself again, if the odd to get a better time, and the compound interest outweighs the tx fee.
I am glad that in any case the impact to network security is limited.