Adding solution detections for blocks

This will finally fix all block finding issues with a 4 way detection.
The find upstream method will continue to try other ways to find a
proper share until they are all exhausted or a match was found.

* Use stratum solution, create scrypt hash from block header
* Use pushpoold solution, create solution string from block header
* Use first available upstream share in timerange of block time
* Use *any* first available valid share older than time of block

This will fix #405 - no more unknown blocks. Ever.
This commit is contained in:
Sebastian Grewe 2013-07-09 11:27:20 +02:00
parent 0f69032fd3
commit f6b350370d
3 changed files with 52 additions and 5 deletions

View File

@ -72,7 +72,8 @@ if (empty($aAllBlocks)) {
foreach ($aAllBlocks as $iIndex => $aBlock) {
if (empty($aBlock['share_id'])) {
// Fetch this blocks upstream ID
if ($share->setUpstream($block->getLastUpstreamId(), $aBlock['time'])) {
$aBlockInfo = $bitcoin->query('getblock', $aBlock['blockhash']);
if ($share->setUpstream($aBlockInfo, $block->getLastUpstreamId())) {
$iCurrentUpstreamId = $share->getUpstreamId();
$iAccountId = $user->getUserId($share->getUpstreamFinder());
} else {

View File

@ -177,7 +177,41 @@ class Share {
* @param last int Skips all shares up to last to find new share
* @return bool
**/
public function setUpstream($last=0, $time=0) {
public function setUpstream($aBlock, $last=0) {
// Many use stratum, so we create our stratum check first
$version = pack("I*", sprintf('%08d', $aBlock['version']));
$previousblockhash = pack("H*", swapEndian($aBlock['previousblockhash']));
$merkleroot = pack("H*", swapEndian($aBlock['merkleroot']) );
$time = pack("I*", $aBlock['time']);
$bits = pack("H*", swapEndian($aBlock['bits']));
$nonce = pack("I*", $aBlock['nonce']);
$header_bin = $version . $previousblockhash . $merkleroot . $time . $bits . $nonce;
$header_hex = implode(unpack("H*", $header_bin));
$scrypt_hash = swapEndian(bin2hex(Scrypt::calc($header_bin, $header_bin, 1024, 1, 1, 32)));
// Fallback to pushpoold solution type
$ppheader = sprintf('%08d', $aBlock['version']) . word_reverse($aBlock['previousblockhash']) . word_reverse($aBlock['merkleroot']) . dechex($aBlock['time']) . $aBlock['bits'] . dechex($aBlock['nonce']);
echo "ppheader : $ppheader \n";
echo "header : $header_hex \n";
echo "Scrypt hash : $scrypt_hash \n";
$stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id FROM $this->table WHERE solution = ? LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('s', $scrypt_hash) && $stmt->execute() && $result = $stmt->get_result()->num_rows > 0) {
$this->oUpstream = $result->fetch_object();
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
return true;
}
// Failed to fetch via startum solution, try pushpoold
$stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id FROM $this->table WHERE solution LIKE CONCAT(?, '%') LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('s', $ppheader) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
return true;
}
// Still no match, try upstream result with timerange
$stmt = $this->mysqli->prepare("
SELECT
SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id
@ -185,13 +219,15 @@ class Share {
WHERE upstream_result = 'Y'
AND id > ?
AND UNIX_TIMESTAMP(time) >= ?
AND UNIX_TIMESTAMP(time) <= ? + 60
ORDER BY id ASC LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $last, $time) && $stmt->execute() && $result = $stmt->get_result()) {
if ($this->checkStmt($stmt) && $stmt->bind_param('iii', $last, $aBlock['time'], $Block['time']) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
return true;
}
// First attempt failed, we do a fallback with any share available for now
// We failed again, now we take ANY result matching the timestamp
$stmt = $this->mysqli->prepare("
SELECT
SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id
@ -200,7 +236,7 @@ class Share {
AND id > ?
AND UNIX_TIMESTAMP(time) >= ?
ORDER BY id ASC LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $last, $time) && $stmt->execute() && $result = $stmt->get_result()) {
if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $last, $aBlock['time']) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
return true;

View File

@ -523,4 +523,14 @@ $value = Scrypt::calc($i, $i, 1024, 1, 1, 32);
*/
// Function used for pushpoold solution checks
function word_reverse($str) {
$ret = '';
while (strlen($str) > 0) {
$ret .= substr($str, -8, 8);
$str = substr($str, 0, -8);
}
return $ret;
}
?>