Pages:
Author

Topic: Regarding Auroracoin TW exploit (Fix included) (Read 27362 times)

sr. member
Activity: 477
Merit: 500

I think what everyone should take away from this thread is that the only way to actively secure a PoW blockchain in a decentralized manner is to support the chain with hashes.

True. If you want to continue this subject, please open a new thread or use some older and copy your comments to it . Sorry for inconvenience
legendary
Activity: 924
Merit: 1132

The point about trying to track the expected block height for the timestamp is to try to control the coin supply. 

We've seen the exploits; we know that burst mining tactics can often result in blockchains running consistently faster than they are supposed to, and supplies of coins that were supposed to become available over the course of years being instamined in a few weeks instead - with difficulty ratcheting up and down wildly as burst miners jump on and off.

These coins then get dumped on the markets and the whole thing collapses (I know, that usually happens anyway, but sometimes the coin developer didn't mean for it to happen and might not even be the one doing it....)

From the POV of someone who is mining, or holding coins, it would be nice to know that there isn't an easy exploit that can make the blockchain run consistently fast, bringing more coins into existence faster than intended.  Having the blockchain detect when it's created more blocks than it's supposed to have, and slow down, or conversely detect that it hasn't been creating enough blocks, and speed up, is a way of committing to the 'nominal' coin creation rate that often gets left by the wayside in the interaction between adjustment algorithms and exploiters (or, indeed, between adjustment algorithms and random chance).



legendary
Activity: 1064
Merit: 1000
sr. member
Activity: 477
Merit: 500
Actually, after all this hassle, I'v ended up thinking 1 block retarget is faulty by design. It is meant to retarget fast, but retargetting fast *is* the vulnerability.

I think that KGW fix might have fixed something, but likely it has not fixed everything, and it might even have opened new ones.

The same vulnerability is, in theory, also on usual bitcoin protocol. But as the retarget time is 2 weeks, it is practically impossible to use.

Whatever is the algorithm, if it is fast, the attacker can quickly get a low difficulty to generate a lot of blocks. Getting back to realtime might be a small problem, but not really.

But we must remember, since block height is based on work done, it means the attacker still needs that 51% of the hashing power, so coins with much hashing power (or PoS) should be safe.

I think the simplest is the best, ie digishield. It is actually the bitcoin retarget, shortened from 2 weeks to 1 block. However, some attenuation makes it 'not so maniac'.

Automatic decentarilzed checkpointing would be good. I had some suggestion somewhere here, but got not much discussion. The princible is that if the latest block is generated with more than 50% of the 'to-be-checkpointed' block in the past (for example height-32), it can be safely checkpointed. And it should be, since the protocol practically means mined coins are fully agreed to exist, so they must not be abandoned in any circumstances. Not even if some hidden higher blockchain appears from nowhere.
legendary
Activity: 924
Merit: 1132

It looks at the last 18 timestamps to get the last 17 intervals.  At the last 10 timestamps to get the last 9 intervals.  Etc. 

6,8,10,18 would actually not be as good, because 6 evenly divides 18, making it possible to find a repeating cycle that might trigger in both intervals.

But you count the first interval with blockoffset=0, so you really are counting one too much. If you end the loop with " <1", you get one interval, so with <18, you will get 18.


Oh, my god.  You're right.  That was boneheaded.  Thanks for pointing that one out.

Well, this is why we have code review.  Code that seems to work "well enough" may still not be doing exactly what we suppose it's doing, in a way that will become obvious only if we examine its behavior on a statistical basis. 

A correction then: Here's how that first function should have gone... 

Code:
void avgRecentTimestamps(const CBlockIndex* pindexLast, int64_t *avgOf5, int64_t *avgOf7, int64_t *avgOf9, int64_t *avgOf17)
{
  int blockoffset = 0;
  int64_t oldblocktime;
  int64_t blocktime;

  *avgOf5 = *avgOf7 = *avgOf9 = *avgOf17 = 0;
  if (pindexLast)
    blocktime = pindexLast->GetBlockTime();
  else blocktime = 0;

   //fixed boundaries in for loop
  for (blockoffset = 0; blockoffset < 17; blockoffset++)
  {
    oldblocktime = blocktime;
    if (pindexLast)
    {
      pindexLast = pindexLast->pprev;
      blocktime = pindexLast->GetBlockTime();
    }
    else
    { // genesis block or previous
      blocktime -= nTargetSpacing;
    }
    // for each block, add interval.
     //compare using < rather than <=
    if (blockoffset < 5) *avgOf5 += (oldblocktime - blocktime);
    if (blockoffset < 7) *avgOf7 += (oldblocktime - blocktime);
    if (blockoffset < 9) *avgOf9 += (oldblocktime - blocktime);
    *avgOf17 += (oldblocktime - blocktime);   
  }
  // now we have the sums of the block intervals. Division gets us the averages.
  *avgOf5 /= 5;
  *avgOf7 /= 7;
  *avgOf9 /= 9;
  *avgOf17 /= 17;
}
[code]
[/code]
sr. member
Activity: 477
Merit: 500

It looks at the last 18 timestamps to get the last 17 intervals.  At the last 10 timestamps to get the last 9 intervals.  Etc. 

6,8,10,18 would actually not be as good, because 6 evenly divides 18, making it possible to find a repeating cycle that might trigger in both intervals.

But you count the first interval with blockoffset=0, so you really are counting one too much. If you end the loop with " <1", you get one interval, so with <18, you will get 18.
legendary
Activity: 924
Merit: 1132
And an experimental feature, adjusts the block interval to keep the blockchain height consistent (in the long run, and approximately...) with the wall clock.


About this; I think it might open a vulnerability, but not sure, please confirm or bust. Scenario:

Attacker can generate a block chain in isolated environment which is constantly 'in the future', so targettime will be shorter than official. When that is the situation, attacker can generate more blocks/timespan with the same hahsing power than the official blockchain.

On the one hand, that's a good point and I haven't yet given it the amount of thought it deserves.  Good thinking!

On the other, that's a special case of the fact that generating a chain in an isolated environment using long block times is going to give you very low difficulty anyway.  You can generate more blocks than the regular blockchain, while going *much* further into the future per block.  

But in order for that to become an attack on the main chain, you have to bring your attack  chain's last timestamp into line with the main chain's last timestamp, and I don't think that you can.  

If you do nothing, then by the time the main chain catches up to the last timestamp of the attack chain, the main chain has more blocks (AND higher difficulty through those blocks).  

If you try to add blocks while not adding time to your attack chain, you need some form of the Time Warp exploit (which allows you to add short-time blocks without triggering difficulty adjustments, or allows you to trigger opposite-direction difficulty adjustments to compensate for them), or the difficulty will rapidly go so high that you cannot continue.  

And I had thought that I had designed this against the time warp exploit, but now I'm thinking of the implications of burst mining and the fact that you can get five rapid blocks without triggering emergency adjustments...  and repeat at intervals of 25 blocks ... and I believe the regular difficulty adjustments compensate, but I haven't proven it rigorously.  If the regular difficulty adjustments don't compensate, you could build a chain about 17% (1/6) longer in the same timestamped time, while keeping the same difficulty setting.   Meaning you'd need about 42% of hash power to build a chain equally long.  

So the question is now whether there's enough wiggle room to play the emergency adjustments against the regular adjustments.  Aww, crap, now I'm going to have to do real math.

legendary
Activity: 1064
Merit: 1000
Look at Dark Gravity Wave which came as a result of KGW's timewarp exploit and post what you think about it. You can find it in the DarkCoin source.

It is still vulnerable to a time warp attack in much the same manner the Kimoto Gravity Well is vulnerable. As is the Digishield and most other one block re-targeting algorithms.

DWG is not vulnerable to Time Warp, and KGW has been patched so is no longer vulnerable either. If you have some technical proof that this is not the case, please explain.
legendary
Activity: 924
Merit: 1132
Code:
 for (blockoffset = 0; blockoffset < 18; blockoffset++)
  {
    oldblocktime = blocktime;
    if (pindexLast)
    {
      pindexLast = pindexLast->pprev;
      blocktime = pindexLast->GetBlockTime();
    }
    else
    { // genesis block or previous
      blocktime -= nTargetSpacing;
    }
    // for each block, add interval.
    if (blockoffset <= 5) *avgOf5 += (oldblocktime - blocktime);
    if (blockoffset <= 7) *avgOf7 += (oldblocktime - blocktime);
    if (blockoffset <= 9) *avgOf9 += (oldblocktime - blocktime);
    *avgOf17 += (oldblocktime - blocktime);    
  }


You are actually counting 6,8,10 and 18 averages (imagine <=1; you would count with 0 and 1, guess it's a typo), but otherwise very interesting algo.


It looks at the last 18 timestamps to get the last 17 intervals.  At the last 10 timestamps to get the last 9 intervals.  Etc. 

6,8,10,18 would actually not be as good, because 6 evenly divides 18, making it possible to find a repeating cycle that might trigger in both intervals.
legendary
Activity: 924
Merit: 1132
Hey, you're welcome.  But it isn't really a miraculous direct and immediate response to you; you just happened to arrive in the thread a few moments before I would have posted it anyway.  

If you read back in the thread you'll see that this is essentially what I said at the top of the last page, except I restated it in C++ because people were ignoring it when I said in English.  

Also, if you keep reading back, you'll see BCX's observation a few posts earlier than that, when he observed that we needed to implement something with a fundamentally different idea rather than trying to fix the fatal flaw in KGW.  He was absolutely right, so I did.

Honestly, KGW (and DGW) are slightly broken.  Aside from the Time Warp exploit, they work okay, and they have the virtue of reacting to rapid hash rate changes rapidly, but they can't tell the difference between a genuine increase in hash rate and the natural randomness of a Poisson process.  Mining is a Poisson process; when hash rate is constant, every second has an equal chance of somebody finding a block.  Just plain randomness gives you a huge variation in individual block intervals.  

And KGW & DGW react in a nonlinear way to that inescapable randomness.  One or two too-short or too-long block times is enough to make them "panic" and make a nonlinear adjustment that leaves everybody looking at WTF difficulty factors.  So, we already knew we needed a replacement, and I'd already done the design work.  

This will react slower than KGW/DGW.  That's unavoidable, I think.   So yes, multipools can cheat it a little bit by "burst mining" to some extent.  They get five rapid blocks or so before emergency difficulty adjustments kick in and maybe several more before difficulty reaches correct levels, depending on how much hash power they're jumping on with.  

In fact, thinking about how a systematic burst miner with large hash power could affect its ability to track the wall clock, I probably need nSlowInterval to be larger, and adjust the IntervalDesired based on how much of a week out of date it is instead of how much of a day out of date.  

On the plus side, at least it doesn't allow them to maximize the cheat by moving in right after a difficulty adjustment boundary when the next adjustment is still far away and then grab cheap blocks right up to that boundary, nor leave the other miners sucking air until another faraway difficulty adjustment boundary arrives after they leave.  And time warps can't trigger adjustments opposite the long-term trend by "loading" a short five-block interval with a fiddled timestamp, because when moving against the direction of the longer-term trend they can't simultaneously load the intervals of different lengths.  

Hmm.  It needs a name.

Multi Interval Difficulty Adjustment System (MIDAS)?  

"Using MIDAS for difficulty adjustment..."  

Sure, that works.
sr. member
Activity: 477
Merit: 500
And an experimental feature, adjusts the block interval to keep the blockchain height consistent (in the long run, and approximately...) with the wall clock.


About this; I think it might open a vulnerability, but not sure, please confirm or bust. Scenario:

Attacker can generate a block chain in isolated environment which is constantly 'in the future', so targettime will be shorter than official. When that is the situation, attacker can generate more blocks/timespan with the same hahsing power than the official blockchain.
sr. member
Activity: 477
Merit: 500
Code:
 for (blockoffset = 0; blockoffset < 18; blockoffset++)
  {
    oldblocktime = blocktime;
    if (pindexLast)
    {
      pindexLast = pindexLast->pprev;
      blocktime = pindexLast->GetBlockTime();
    }
    else
    { // genesis block or previous
      blocktime -= nTargetSpacing;
    }
    // for each block, add interval.
    if (blockoffset <= 5) *avgOf5 += (oldblocktime - blocktime);
    if (blockoffset <= 7) *avgOf7 += (oldblocktime - blocktime);
    if (blockoffset <= 9) *avgOf9 += (oldblocktime - blocktime);
    *avgOf17 += (oldblocktime - blocktime);    
  }


You are actually counting 6,8,10 and 18 averages (imagine <=1; you would count with 0 and 1, guess it's a typo), but otherwise very interesting algo.
member
Activity: 73
Merit: 10
legendary
Activity: 924
Merit: 1132
Here.  

No timewarp.  Rapid adjustments when a burst miner jumps on or off.  And an experimental feature, adjusts the block interval to keep the blockchain height consistent (in the long run, and approximately...) with the wall clock.

Adjusts difficulty potentially every block, based on average block intervals observed within the last 17 blocks.  

Have fun with it.

Code:

// Bitcoin used 10-minute blocks; this uses six minute blocks.
static const int64_t nTargetSpacing = 6 * 60;  // seconds per block, nominal.
static const int64_t nFastInterval = nTargetSpacing * 0.95; // seconds per block desired when behind schedule
static const int64_t nSlowInterval = nTargetSpacing * 1.05; // seconds per block desired when ahead of schedule
static const int64_t nTimeZero = 1400000000; // nominal date at which this blockchain starts, since unix epoch


void avgRecentTimestamps(const CBlockIndex* pindexLast, int64_t *avgOf5, int64_t *avgOf7, int64_t *avgOf9, int64_t *avgOf17)
{
  int blockoffset = 0;
  int64_t oldblocktime;
  int64_t blocktime;

  *avgOf5 = *avgOf7 = *avgOf9 = *avgOf17 = 0;
  if (pindexLast)
    blocktime = pindexLast->GetBlockTime();
  else blocktime = 0;

  for (blockoffset = 0; blockoffset < 18; blockoffset++)
  {
    oldblocktime = blocktime;
    if (pindexLast)
    {
      pindexLast = pindexLast->pprev;
      blocktime = pindexLast->GetBlockTime();
    }
    else
    { // genesis block or previous
      blocktime -= nTargetSpacing;
    }
    // for each block, add interval.
    if (blockoffset <= 5) *avgOf5 += (oldblocktime - blocktime);
    if (blockoffset <= 7) *avgOf7 += (oldblocktime - blocktime);
    if (blockoffset <= 9) *avgOf9 += (oldblocktime - blocktime);
    *avgOf17 += (oldblocktime - blocktime);    
  }
  // now we have the sums of the block intervals. Division gets us the averages.
  *avgOf5 /= 5;
  *avgOf7 /= 7;
  *avgOf9 /= 9;
  *avgOf17 /= 17;
}



// This is a novel getnextwork algorithm.  It responds quickly to huge changes in hashing power, is immune to time warp
// attacks, and regulates the block rate to keep the block height close to the block height expected given the nominal
// block interval and the elapsed time.  How close the correspondence between block height and wall clock time is
// depends on how stable the hashing power has been.

unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
    int64_t avgOf5;
    int64_t avgOf9;
    int64_t avgOf7;
    int64_t avgOf17;
    int64_t toofast;
    int64_t tooslow;
    int64_t difficultyfactor = 10000;
    int64_t now;
    int64_t BlockHeightTime;
    int64_t nIntervalDesired;

    unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact();

    if (pindexLast == NULL)
        // Genesis Block
        return nProofOfWorkLimit;

    
    if (TestNet())
    {
        // Special difficulty rule for testnet: If the new block's timestamp is more than 2* 10 minutes then allow
        // mining of a min-difficulty block.
        if (pblock->nTime > pindexLast->nTime + nTargetSpacing*2)
           return nProofOfWorkLimit;
        else
        {
            // Return the last non-special-min-difficulty-rules-block
           const CBlockIndex* pindex = pindexLast;
           while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit)
               pindex = pindex->pprev;
           return pindex->nBits;
        }
    }

    // Regulate block times so as to remain synchronized in the long run with the actual time.  The first step is to
    // calculate what interval we want to use as our regulatory goal.  It depends on how far ahead of (or behind)
    // schedule we are.  If we're more than a day ahead or behind, we use the maximum (nSlowInterval) or minimum
    // (nFastInterval) values; otherwise we calculate a weighted average somewhere in between them.  The closer we are
    // to being exactly on schedule the closer our selected interval will be to our nominal interval (nTargetSpacing).

    now = pindexLast->GetBlockTime();
    BlockHeightTime = nTimeZero + pindexLast->nHeight * nTargetSpacing;
    
    if (now < BlockHeightTime + 86400 && now > BlockHeightTime )  // ahead of schedule by less than a day.
      nIntervalDesired = ((86400 - (now - BlockHeightTime)) * nTargetSpacing +  
(now - BlockHeightTime) * nFastInterval) / 86400;
    else if (now + 86400 > BlockHeightTime && now < BlockHeightTime)  // behind schedule by less than a day.
      nIntervalDesired = ((86400 - (BlockHeightTime - now)) * nTargetSpacing +
(BlockHeightTime - now) * nSlowInterval) / 86400;
    else if (now < BlockHeightTime) nIntervalDesired = nSlowInterval; // ahead by more than a day.
    else  nIntervalDesired = nFastInterval; // behind by more than a day.
    
    // find out what average intervals over last 5, 7, 9, and 17 blocks have been.
    avgRecentTimestamps(pindexLast, &avgOf5, &avgOf7, &avgOf9, &avgOf17);    



    // check for emergency adjustments. These are to bring the diff up or down FAST when a burst miner or multipool
    // jumps on or off.  Once they kick in they can adjust difficulty by a factor of nine or ten every ten blocks, and
    // they can kick in very rapidly after massive hash power jumps on or off.  The emergency speed-up adjustment uses
    // shorter intervals for quicker reaction times measured in blocks - which when it's needed will be longer in
    // minutes.

    toofast = (nIntervalDesired * 3) / 4;
    tooslow = (nIntervalDesired * 4) / 3;    

    if (avgOf7 < toofast && avgOf9 < toofast && avgOf17 < toofast)
    {  //emergency adjustment, slow down
      difficultyfactor *= 5;
      difficultyfactor /= 4;
    }
    else if (avgOf5 > tooslow && avgOf7 > tooslow && avgOf9 > tooslow)
    {  //emergency adjustment, speed up
      difficultyfactor *= 4;
      difficultyfactor /= 5;
    }

    // If no emergency adjustment, check for normal adjustment.
    else if ((avgOf7 > nIntervalDesired && avgOf9 > nIntervalDesired && avgOf17 > nIntervalDesired) ||
    (avgOf7 < nIntervalDesired && avgOf9 < nIntervalDesired && avgOf17 < nIntervalDesired))
    { // 3 averages too high or 3 too low.  Doesn't matter which. This will be executed occasionally on the basis of
      // random variation, even if the settings are perfect. It regulates one-fifth of the way to the calculated point.
      difficultyfactor *= (5 * nIntervalDesired);
      difficultyfactor /= (avgOf17 + (4 * nIntervalDesired));
    }

    // limit to doubling or halving.... though I'm pretty sure there are no realistic conditions where this will make a
    // difference.
    if (difficultyfactor > 20000) difficultyfactor = 20000;
    if (difficultyfactor < 5000) difficultyfactor = 5000;

    uint256 bnNew;
    uint256 bnOld;

    bnOld.SetCompact(pindexLast->nBits);

    if (difficultyfactor == 10000) // no adjustment
      return(bnOld.GetCompact());

    bnNew = bnOld * 10000;
    bnNew /= difficultyfactor;

    if (bnNew > Params().ProofOfWorkLimit())
      bnNew = Params().ProofOfWorkLimit();

    LogPrintf("GetNextWorkRequired RETARGET\n");
    LogPrintf("Actual time %d, Scheduled time for this block height = %d\n", now, BlockHeightTime );
    LogPrintf("Nominal block interval = %d, regulating on interval %d to get back to schedule.\n",
     nTargetSpacing, nIntervalDesired );
    LogPrintf("Avg intervals of last 5/9/17 blocks = %d / %d / %d.\n", nTargetSpacing, avgOf5, avgOf9, avgOf17);
    LogPrintf("Difficulty Before Adjustment: %08x  %s\n", pindexLast->nBits, bnOld.ToString());
    LogPrintf("Difficulty After Adjustment:  %08x  %s\n", bnNew.GetCompact(), bnNew.ToString());

    return bnNew.GetCompact();
}


This tends to overshoot a little when making emergency adjustments, but it self-corrects within a dozen blocks or so when it does.
sr. member
Activity: 477
Merit: 500
Also, I wanted to post on this thread because of the quality of these comments, but I do agree that this shouldn't really have anything to do with auroracoin specifically - so are there any legitimate threads that attempt to delve into this from a mathematical perspective elsewhere on this forum or should one be created?

https://bitcointalksearch.org/topic/kimoto-gravity-well-simplier-alternative-505243


Edit: Actually I think that digishield is better for diff retarget than my suggestion here.. but I think one should bring ideas to common knowledge, even if they are not as good as the pervious ones.
legendary
Activity: 1064
Merit: 1000
hey so I just stumbled on this thread - I've been researching an alternative form of a "KGW" type of difficulty readjustment (for simplicity). So I'm glad to start finally seeing comments like those from Cryddit and astor - I think we really need to do more research and work on developing a much better designed difficulty adjustment algo rather than simply trying to 'tune' an already flawed one. I'm not too sure about "bob's wormhole", but I'll definitely look into it as this is the first I've heard of it. That being said though, I think that in general there seems to be a huge fundamental misunderstanding on what this algorithm does and how it functions so before trying to create something new, I think a little better analysis needs to be done.

I think this excerpt from astor's post is probably the most accurate thing I've seen written on moving forward to date:

"In order to create a kalman filter, you need to create a model of how the dynamics of the system should behave.  If the goal of the control system is to keep the block output at a fixed rate, then the distance from that rate is the error you want to correct."

Also, I wanted to post on this thread because of the quality of these comments, but I do agree that this shouldn't really have anything to do with auroracoin specifically - so are there any legitimate threads that attempt to delve into this from a mathematical perspective elsewhere on this forum or should one be created?

Look at Dark Gravity Wave which came as a result of KGW's timewarp exploit and post what you think about it. You can find it in the DarkCoin source.
member
Activity: 73
Merit: 10
hey so I just stumbled on this thread - I've been researching an alternative form of a "KGW" type of difficulty readjustment (for simplicity). So I'm glad to start finally seeing comments like those from Cryddit and astor - I think we really need to do more research and work on developing a much better designed difficulty adjustment algo rather than simply trying to 'tune' an already flawed one. I'm not too sure about "bob's wormhole", but I'll definitely look into it as this is the first I've heard of it. That being said though, I think that in general there seems to be a huge fundamental misunderstanding on what this algorithm does and how it functions so before trying to create something new, I think a little better analysis needs to be done.

I think this excerpt from astor's post is probably the most accurate thing I've seen written on moving forward to date:

"In order to create a kalman filter, you need to create a model of how the dynamics of the system should behave.  If the goal of the control system is to keep the block output at a fixed rate, then the distance from that rate is the error you want to correct."

Also, I wanted to post on this thread because of the quality of these comments, but I do agree that this shouldn't really have anything to do with auroracoin specifically - so are there any legitimate threads that attempt to delve into this from a mathematical perspective elsewhere on this forum or should one be created?
newbie
Activity: 17
Merit: 0
Those running KGW might want to take a look and my commit for BOB's Wormhole, and possibly adapt it to their own coin, if they still plan to keep it KGW.  That is if no one finds its flaws are worse than stock.
BOB's Wormh0le - Kimoto Gravity Well Customization

This glorious patch has changed 2 lines of the actual code to make it fit your very slow coin and 1 more line to narrow event horizons. Now, it's surely the greatest thing since tinned beer. Or not? It's still KGW and it's still broken, time warping not fixed, but you don't get it anyway because you haven't cared to read this thread from the start before posting your advertising spam.  Roll Eyes


Nice, you confirm some of my previous statements, but you obviously are guilty of what you assume I've done.  Which is not read this thread.  It's time to stop talking and backup your claims.  TimeWarp BOB.  I DARE YEW!!!   Shocked
legendary
Activity: 1242
Merit: 1020
No surrender, no retreat, no regret.
Those running KGW might want to take a look and my commit for BOB's Wormhole, and possibly adapt it to their own coin, if they still plan to keep it KGW.  That is if no one finds its flaws are worse than stock.
BOB's Wormh0le - Kimoto Gravity Well Customization

This glorious patch has changed 2 lines of the actual code to make it fit your very slow coin and 1 more line to narrow event horizons. Now, it's surely the greatest thing since tinned beer. Or not? It's still KGW and it's still broken, time warping not fixed, but you don't get it anyway because you haven't cared to read this thread from the start before posting your advertising spam.  Roll Eyes
legendary
Activity: 996
Merit: 1013
So, lets have a gander at Auroracoin Block Explorer to prove a point I made in my post right above this, about how default KGW sucks and is a coin fountain.


That was refreshingly hands-on approach, thank you.
Indeed, making charts like these serves as a great introduction to this sometimes abtruse subject.
Pages:
Jump to: