Не верю, что такое в принципе существует.
Если "в этом ничего сложного нет"
Ну WhitePapper почитать очень рекомендую. Вот он
http://www.spreadcoin.info/downloads/SpreadCoin-WhitePaper.pdfА обьяснить попытаюсь сразу на примере.
Вот заголовок блока
https://github.com/spreadcoin/spreadcoin/blob/master/src/main.h#L1347class CBlockHeader
В заголовке блока присутствуют 2 важных поля - hashWholeBlock и MinerSignature
MinerSignature - это цифровая подпись заголовка блока. Заголовок блока должен быть подписан тем же приватным ключом, что и coinbase-транзакция, то есть та транзакция, в которая дает вознаграждение за блок.
То есть майнер, найдя блок сможет потратить вознаграждение раньше, чем это сделает пул, по скольку майнер первым находит блок.
Майнер, каждый раз подставляя новый nonce тем самым пытаясь найти блок должен так же пересчитывать подпись заголовка блока.
hashWholeBlock - это хеш всего блока(вместе со всеми транзакциями). Нужен для того, чтобы заставлять майнеров знать весь блок. Тоже пересчитывается каждый раз, когда майнер инкрементирует nonce, пытаясь найти блок.
Вот эти поля
https://github.com/spreadcoin/spreadcoin/blob/master/src/main.cpp#L1497CBlock::GetPoKData
PowHash - то есть блок-id, который должен быть меньше цели - это то, что должен найти майнер.
Этот хеш зависит от всего заголовка блока, в том числе и hashWholeBlock и MinerSignature.
Вот код
https://github.com/spreadcoin/spreadcoin/blob/master/src/main.cpp#L1453CBlockHeader::SerializeHeaderForHash2()
CBlockHeader::GetHash()
Привожу упрощенный код одной итерации майнинга здесь
Signer.SignFast(pblock->GetHashForSignature(), pblock->MinerSignature.begin()); // подписываем блок своим приватным ключом
pblock->hashWholeBlock = CBlock::HashPoKData(PoKData); // вычисляем хеш всего блока
bool Good = pblock->GetPoWHash() <= hashTarget; // вычисляем блок-ID и сравниваем его с целью, это и есть Proof Of Work
if (Good){ // ура, блок найден!
....
break;
}
pblock->nNonce += 1; // блок не найден, инкрементируем nonce и повторяем все с начала.
Получается, чтобы найти блок, майнеру нужно знать:
1. приватный ключ первой(coinbase) транзакции
2. весь блок
Если пул тоже будет иметь эти данные, то майнер, который нашел блок будет знать его первым и сможет отправить его в сеть мимо пула, а зная приватный ключ - отправить в сеть транзакцию, которая тратит награду за блок, то есть переводит ее на другой адрес, ключ от которого есть только у майнера. Пулу он этот блок может и вовсе не отправлять, тк он уже наебал пул.
При чем просто найдя шару, он отправляет пулу эту шару и получает свою долю, а найдя блок - майнер забирает награду целиком, тем самым имея двойной профит
Потом пул, когда узнает, что его майнер наебал может майнера заблочить по IP, но майнер сменит IP и продолжит дальше майнить шары и получать с этого свою долю.
У этого решения есть один недостаток - hashMerkleRoot становится бессмысленным, потому, что для того, чтобы проверить блок на валидность нужно скачать весь блок, в отличии от Bitcoin, где достаточно только заголовка блока. Это создает серьезные трудности при создании SPV-клиентов.