/** * Find upstream accepted share that should be valid for a specific block * Assumptions: * * Shares are matching blocks in ASC order * * We can skip all upstream shares of previously found ones used in a block * @param last int Skips all shares up to last to find new share * @return bool **/ public function findUpstreamShare($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)); // Stratum supported blockhash solution entry $stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id FROM {$this->table} WHERE solution = ? LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param('s', $aBlock['hash']) && $stmt->execute() && ($result = $stmt->get_result())) { $this->oUpstream = $result->fetch_object(); $this->share_type = 'stratum_blockhash'; if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id)) { return true; } } // Stratum scrypt hash check $scrypt_hash = swapEndian(bin2hex(Scrypt::calc($header_bin, $header_bin, 1024, 1, 1, 32))); $stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id FROM {$this->table} WHERE solution = ? LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param('s', $scrypt_hash) && $stmt->execute() && ($result = $stmt->get_result())) { $this->oUpstream = $result->fetch_object(); $this->share_type = 'stratum_solution'; if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id)) { return true; } } // Failed to fetch via startum solution, try pushpoold // 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']); $stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, 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(); $this->share_type = 'pp_solution'; if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id)) { return true; } } // Still no match, try upstream result with timerange $stmt = $this->mysqli->prepare("\n SELECT\n SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id\n FROM {$this->table}\n WHERE upstream_result = 'Y'\n AND id > ?\n AND UNIX_TIMESTAMP(time) >= ?\n AND UNIX_TIMESTAMP(time) <= ( ? + 60 )\n ORDER BY id ASC LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param('iii', $last, $aBlock['time'], $aBlock['time']) && $stmt->execute() && ($result = $stmt->get_result())) { $this->oUpstream = $result->fetch_object(); $this->share_type = 'upstream_share'; if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id)) { return true; } } // We failed again, now we take ANY result matching the timestamp $stmt = $this->mysqli->prepare("\n SELECT\n SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id\n FROM {$this->table}\n WHERE our_result = 'Y'\n AND id > ?\n AND UNIX_TIMESTAMP(time) >= ?\n ORDER BY id ASC LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $last, $aBlock['time']) && $stmt->execute() && ($result = $stmt->get_result())) { $this->oUpstream = $result->fetch_object(); $this->share_type = 'any_share'; if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id)) { return true; } } $this->setErrorMessage($this->getErrorMsg('E0052', $aBlock['height'])); return false; }
public function findUpstreamShareStrict($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)); // Stratum supported blockhash solution entry $stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id FROM {$this->table} WHERE solution = ? LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param('s', $aBlock['hash']) && $stmt->execute() && ($result = $stmt->get_result())) { $this->oUpstream = $result->fetch_object(); $this->share_type = 'stratum_blockhash'; if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id)) { return true; } } // Stratum scrypt hash check $scrypt_hash = swapEndian(bin2hex(Scrypt::calc($header_bin, $header_bin, 1024, 1, 1, 32))); $stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id FROM {$this->table} WHERE solution = ? LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param('s', $scrypt_hash) && $stmt->execute() && ($result = $stmt->get_result())) { $this->oUpstream = $result->fetch_object(); $this->share_type = 'stratum_solution'; if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id)) { return true; } } return false; }