-
Notifications
You must be signed in to change notification settings - Fork 46
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
P2pool does not validate that shares make valid blocks #21
Comments
The following are a few comments that I'm moving from #19 in order to keep that issue focused on implementation details for that bounty. |
Quoth @CryptoManiac:
|
Quoth @jtoomim:
|
Quoth @rldleblanc:
|
Quoth @krzr1s:
|
@rldleblanc The issue that @CryptoManiac raised is a misbehaving p2pool node, not misbehaving mining hardware. You are correct that this attack still requires just as much hashpower as mining honestly, and it generates less revenue than mining honestly. Consequently, I consider it to be a medium-severity issue. That said, it is not entirely a hypothetical issue. It is a real issue that we struggled with on the LTC p2pool for a while, as a node with about 3% of p2pool's hashrate was consistently mining invalid LTC blocks due to (apparently) modified p2pool code that miscalculated the fees. You can read about this on the forum at this link and on the following page: My preference for dealing with invalid blocks like this is to have p2pool do delayed propagation of the full block with all transactions, and asynchronously fully validate the block via a bitcoind RPC call that does not yet exist (e.g. verifyblockvalidityexceptpow), and only mine on a share for e.g. 30 seconds unless it has been validated. It will be helpful to have a fast full-block propagation mechanism in place for that, but critically, it will need to be an asynchronous method, which rules out the existing mechanism. Ideally, we would use bitcoind's own fast full-block propagation mechanisms for that, as trying to do any work in Python that's O(transaction_count) is something we want to avoid. |
Fast full-block propagation won't work for shares that do not meet the block difficulty, so those would have to be sent by P2pool, right? With a 32 MB block that could be expensive, especially if there are many shares before a block is found. I guess that is part of the reason for the tx hashes. It would be nice to say that share 2 contains all transactions of share 1 plus these new ones. Basically diff between shares. It seems to make sense to have this at least stubbed out in the new implementation. I just can't think of any way around passing the whole block around to verify. Like you said, taking it out of the main data path makes a lot of sense. And Bitcoind not having a way to validate that a block is valid without meeting the block difficulty puts the burden on us for now (something we can sub out as well). |
Using bitcoind's fast block propagation code for p2pool shares would require modifying bitcoind's code slightly to allow propagation of weak blocks upon request. Doing that modification is probably easier than writing a performant system in python. Slightly changing the functionality of an existing system is usually easier than implementing a completely new system from scratch.
I can: don't fully verify. That's what we've been doing on p2pool since 2012, and it's worked out okay so far. The losses that we've incurred as a result of not verifying have been about 0.1%, which is far less than a traditional pool's fee. Fixing the blocks-aren't-fully-validated issue is a would-be-nice feature, but it's not worth implementing if it will hamstring p2pool's performance, fairness, or reward variance. |
Hmm... Seems that if we require a success from Bitcoind submitblock before propagating it on the share chain, that would prevent bad blocks that meet block difficulty from getting in the share chain. If a P2pool node submits a share with block difficulty, but we never see the hash in the block chain, then we punish that node. The higher % their false block submissions, the lower their payouts. That may get a majority of the issues without all the work. We may have to attach a node id to the share, so that we can punish shares across all miners on a bad node, but if the same miner is on a good node at the same time those shares are counted okay. The only problem I see is that my nodes are so small that they hardly ever find blocks. So I could be mining bad for a long time and never know it. |
@rldleblanc It doesn't matter if share makes block or not. Every one of them must be passed through full set of checkings like if it would be a valid block candidate. Every spent transaction output, signature, output value should be verified to satisfy the protocol conditions. |
@jtoomim submitblock has the parameter which allows you to check the block proposal. This means running full set of protocol checkings except proof of work, i.e. it's exactly what do you need. You need to ensure that block proposal capability is set while doing getblocktemplate requests, as well as to set a mutability flag for prevblock and some other fields. |
@CryptoManiac I'm not seeing the parameter that you are talking about in the bitcoin code: src/rpc/mining.cpp
Looking through the getblocktemplate code, it looks if mode is set to 'proposal', then you can add a 'data' section containing the block and it will be validated for you. This corroborates BIP-0023. It looks like it will only validate shares that are built on the current tip, so for a node coming up to speed it can't check old shares in the chain with this method. They should have been validated by other nodes already, but how can we verify that? I guess download the chain from multiple peers and pick the one that matches the most? That just leaves the handling of transactions. Since each P2pool node should have all the transactions in a block, the share submitter only needs to send a list of txids or something that uniquely identifies them that is common across all nodes. The node can build the block and submit it to getblocktemplate. If any txids are not in the local node cache try again later in case bitcoind is behind, then give up after so much time or the next block arrives on the network and consider it dead/orphan. If this sounds acceptable, then I'll see what I can do. |
@rldleblanc https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki#Block_Proposal Just enable proposals and you should be able to send block candidates via simple submitblock requests. |
To reiterate, this issue is not a high priority, and I'm not offering a bounty for it right now. #19 is more important. |
Understood, but if I can design with the implementation in mind now, it will be less of a kluge to add it in later. |
Currently, p2pool does not perform any full validation of blocks or transactions. A peer can send a share that corresponds to a block that is invalid because it exceeds blocksize or sigop limits, because it includes a transaction with an invalid signature, because it contains a double-spend, because it builds upon an invalid block, because it builds on an extremely old block, or any other issue. This allows a malicious node to collect revenue from p2pool without performing any useful work for p2pool.
Note: In #19 I am advocating for removing fast share/block propagation code from p2pool, which would make it more difficult to add full validation.
The text was updated successfully, but these errors were encountered: