Adding support for orphan blocks

* Adjusted blockupdate cronjob
 * Fetch block information via `gettransaction`
* Adjusted block class
 * Only getAllUnconfirmed where confirmations > -1
* Adjusted transaction class
 * added setOrphan method to mark orphaned transactions
* If block is orphaned
 * Mark all related transactions as Orphan_*type*
 * Set confirmations of block to -1 so it is ignored and marked as orphan
* Change transaction template, added listing for orphan transactions
* Add orphan status to block listings template
This commit is contained in:
Sebastian Grewe 2013-05-27 14:44:40 +02:00
parent 436aed65f1
commit d44c236f2b
5 changed files with 98 additions and 3 deletions

View File

@ -33,7 +33,18 @@ $aAllBlocks = $block->getAllUnconfirmed($config['confirmations']);
verbose("ID\tBlockhash\tConfirmations\t\n");
foreach ($aAllBlocks as $iIndex => $aBlock) {
$aBlockInfo = $bitcoin->query('getblock', $aBlock['blockhash']);
// Fetch this blocks transaction details to find orphan blocks
$aTxDetails = $bitcoin->query('gettransaction', $aBlockInfo['merkleroot']);
verbose($aBlock['id'] . "\t" . $aBlock['blockhash'] . "\t" . $aBlock['confirmations'] . " -> " . $aBlockInfo['confirmations'] . "\t");
if ($aTxDetails['details'][0]['category'] == 'orphan') {
// We have an orphaned block, we need to invalidate all transactions for this one
if ($transaction->setOrphan($aBlock['id']) && $block->setConfirmations($aBlock['id'], -1)) {
verbose("ORPHAN\n");
} else {
verbose("ORPHAN_ERR");
}
continue;
}
if ($aBlock['confirmations'] == $aBlockInfo['confirmations']) {
verbose("SKIPPED\n");
} else if ($block->setConfirmations($aBlock['id'], $aBlockInfo['confirmations'])) {

View File

@ -50,7 +50,7 @@ class Block {
}
public function getAllUnconfirmed($confirmations='120') {
$stmt = $this->mysqli->prepare("SELECT id, blockhash, confirmations FROM $this->table WHERE confirmations < ?");
$stmt = $this->mysqli->prepare("SELECT id, blockhash, confirmations FROM $this->table WHERE confirmations < ? AND confirmations > -1");
if ($this->checkStmt($stmt)) {
$stmt->bind_param("i", $confirmations);
$stmt->execute();

View File

@ -38,6 +38,41 @@ class Transaction {
return false;
}
public function setOrphan($block_id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
UPDATE $this->table
SET type = 'Orphan_Credit'
WHERE type = 'Credit'
AND block_id = ?
");
if (!($this->checkStmt($stmt) && $stmt->bind_param('i', $block_id) && $stmt->execute())) {
$this->debug->append("Failed to set orphan credit transactions for $block_id");
return false;
}
$stmt = $this->mysqli->prepare("
UPDATE $this->table
SET type = 'Orphan_Fee'
WHERE type = 'Fee'
AND block_id = ?
");
if (!($this->checkStmt($stmt) && $stmt->bind_param('i', $block_id) && $stmt->execute())) {
$this->debug->append("Failed to set orphan fee transactions for $block_id");
return false;
}
$stmt = $this->mysqli->prepare("
UPDATE $this->table
SET type = 'Orphan_Donation'
WHERE type = 'Donation'
AND block_id = ?
");
if (!($this->checkStmt($stmt) && $stmt->bind_param('i', $block_id) && $stmt->execute())) {
$this->debug->append("Failed to set orphan donation transactions for $block_id");
return false;
}
return true;
}
public function getTransactions($account_id, $start=0) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("

View File

@ -1,4 +1,4 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Transaction Log" BUTTONS=array(Confirmed,Unconfirmed)}
{include file="global/block_header.tpl" BLOCK_HEADER="Transaction Log" BUTTONS=array(Confirmed,Unconfirmed,Orphan)}
<div class="block_content tab_content" id="Confirmed" style="clear:;">
<center>
<table cellpadding="1" cellspacing="1" width="98%" class="sortable">
@ -84,4 +84,48 @@
<p><font color="" sizeze="1">Listed are your estimated rewards and donations/fees for all blocks awaiting {$GLOBAL.confirmations} confirmations.</font></p>
</center>
</div>
<div class="block_content tab_content" id="Orphan" style="">
<center>
<table cellpadding="1" cellspacing="1" width="98%" class="sortable">
<thead style="font-size:13px;">
<tr>
<th class="header" style="cursor: pointer;">TX #</th>
<th class="header" style="cursor: pointer;">Date</th>
<th class="header" style="cursor: pointer;">TX Type</th>
<th class="header" style="cursor: pointer;">Payment Address</th>
<th class="header" style="cursor: pointer;">Block #</th>
<th class="header" style="cursor: pointer;">Amount</th>
</tr>
</thead>
<tbody style="font-size:12px;">
{section transaction $TRANSACTIONS}
{if (
$TRANSACTIONS[transaction].type == 'Orphan_Credit'
or $TRANSACTIONS[transaction].type == 'Orphan_Donation'
or $TRANSACTIONS[transaction].type == 'Orphan_Fee'
)}
<tr class="{cycle values="odd,even"}">
<td>{$TRANSACTIONS[transaction].id}</td>
<td>{$TRANSACTIONS[transaction].timestamp}</td>
<td>{$TRANSACTIONS[transaction].type}</td>
<td>{$TRANSACTIONS[transaction].coin_address}</td>
<td>{if $TRANSACTIONS[transaction].height == 0}n/a{else}{$TRANSACTIONS[transaction].height}{/if}</td>
<td><font color="{if $TRANSACTIONS[transaction].type == Orphan_Credit}green{else}red{/if}">{$TRANSACTIONS[transaction].amount}</td>
</tr>
{if $TRANSACTIONS[transaction].type == Orphan_Credit}
{assign var="orphan_credits" value="`$orphan_credits+$TRANSACTIONS[transaction].amount`"}
{else}
{assign var="orphan_debits" value="`$orphan_debits+$TRANSACTIONS[transaction].amount`"}
{/if}
{/if}
{/section}
<tr>
<td colspan="5"><b>Orphaned Totals:</b></td>
<td><b>{$orphan_credits - $orphan_debits}</b></td>
</tr>
</tbody>
</table>
<p><font color="" sizeze="1">Listed are your orphaned transactions for blocks not part of the main blockchain.</font></p>
</center>
</div>
{include file="global/block_footer.tpl"}

View File

@ -16,7 +16,12 @@
{section block $BLOCKSFOUND}
<tr class="{cycle values="odd,even"}">
<td><a href="{$GLOBAL.blockexplorer}{$BLOCKSFOUND[block].height}" target="_blank">{$BLOCKSFOUND[block].height}</a></td>
<td>{if $BLOCKSFOUND[block].confirmations >= $GLOBAL.confirmations}<font color="green">Confirmed</font>{else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if}</td>
<td>
{if $BLOCKSFOUND[block].confirmations >= $GLOBAL.confirmations}
<font color="green">Confirmed</font>
{else if $BLOCKSFOUND[block].confirmations == -1}
<font color="red">Orphan</font>
{else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if}</td>
<td>{$BLOCKSFOUND[block].finder|default:"unknown"}</td>
<td>{$BLOCKSFOUND[block].time|date_format:"%d/%m/%Y %H:%M:%S"}</td>
<td class="right">{$BLOCKSFOUND[block].difficulty|number_format:"8"}</td>