Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client cannot switch to longest chain when one output stakes twice on fork #273

Open
dooglus opened this issue Dec 22, 2015 · 0 comments
Open

Comments

@dooglus
Copy link
Collaborator

dooglus commented Dec 22, 2015

I was playing about with CLAM's testnet. It had been idle for a few weeks, so difficulty was very low and wallets were staking every 16 seconds as difficulty adjusted.

I had 2 wallets staking independently. Both were staking every 16 seconds, building 2 separate forks in parallel. I figured that once difficulty had adjusted high enough that one of them failed to stake just once in a 16 second time period the other would "win", and the loser would do a massive reorg to switch to the winning chain. That's how it's meant to work.

What actually happened was the losing wallet kept on working on its shorter chain. Both wallets continued working on different chains, even though they were different lengths.

I tried making a bootstrap.dat on the 'winning' client (which still had the longest chain) and importing it on the 'losing' client. But that didn't help either. The losing client refused to switch to the longer chain even when presented with the full longer chain in order.

It turned out the reason is that the 'winning' fork contained two blocks staked by the same output (N -> N+1 in block x, and N+1 -> N+2 in block y). Blocks x and y aren't in the main chain on the losing client. The losing client accepts block x and a block but doesn't put it on the main chain yet (because it isn't the longest chain yet), but when it sees block y, CheckProofOfStake() in kernel.cpp rejects it because the output being staked isn't in the "main chain":

    // First try finding the previous transaction in database
    CTxDB txdb("r");
    CTransaction txPrev;
    CTxIndex txindex;
    if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
        return tx.DoS(1, error("CheckProofOfStake() : INFO: read txPrev failed"));  // previous transaction not in main chain, may occur during initial download

ie. we can't find the staking transaction in the txdb because it isn't on the main chain yet.

I wasn't able to get the 'losing' client to sync without deleting the blockchain and reimporting the whole thing from a bootstrap.dat file. (Letting it sync from scratch over the p2p network would have presumably worked too).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant