<?php
use BitWasp\Buffertools\Buffer;
include_once "../libraries/vendor/autoload.php";
include_once("html_iframe_header.php");
$result = '';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
try {
$txIds = explode("\n", $_POST['txids']);
$merkleRoot = "";
function createMerkleRoot($txIds) {
$txIds = array_map(function ($v) { $result = Buffer::hex(trim($v));return $result->flip()->getHex(); },$txIds);
function createMerkleBranch($hashes) {
$newHashes = [];
$totalTxIds = @count($hashes);
if ($totalTxIds % 2 > 0) {
$hashes[ $totalTxIds ] = $hashes[ $totalTxIds - 1 ];
}
$groupHashes = array_chunk($hashes, 2);
foreach($groupHashes as $twoHash) {
$newHashes[] = hash('sha256', hex2bin(hash('sha256', hex2bin( implode("", $twoHash) ))));
}
if (@count($newHashes) == 1) {
return $newHashes[0];
} else {
return createMerkleBranch($newHashes);
}
}
if (count($txIds) == 1) {
$merkleRoot = $txIds[0];
} else {
$merkleRoot = createMerkleBranch($txIds);
}
$result = Buffer::hex($merkleRoot);
return $result->flip()->getHex();
}
$merkleRoot = createMerkleRoot($txIds);
} catch (Exception $e) {
$errmsg .= "Problem found. " . $e->getMessage();
}
}
if ($errmsg) {
?>
<div class="alert alert-danger">
<strong>Error!</strong> <?php echo $errmsg?>
</div>
<?php
}
if ($merkleRoot) {
?>
<div class="table-responsive">
<table border=0 class='table'>
<tr><td>Merkle Root</td><td><?php echo $merkleRoot;?></td></tr>
</table>
</div>
<?php
}
?>
<form action='' method='post'>
<div class="form-group">
<label for="txids">Tx Ids (Follow TX order in block):</label>
<textarea rows=10 class="form-control" name='txids' id='txids'><?php echo $_POST['txids']?></textarea>
Press enter key to place new tx id in new line. For example, you can copy all tx ids from <a href="https://api.blockcypher.com/v1/btc/main/blocks/0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af" target="_blank"><img style='width:12px;height:12px;' src='../media/images/external_link.png'/></a> and match the generated merkle root with merkle root in block.
</div>
<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");
<?php
use BitWasp\Buffertools\Buffer;
include_once "../libraries/vendor/autoload.php";
include_once("html_iframe_header.php");
$result = '';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
try {
$txIds = explode("\n", $_POST['txids']);
$merkleRoot = "";
function createMerkleProof($txId, $txIds) {
$proofs = [];
//convert to little endian
$txId = Buffer::hex(trim($txId))->flip()->getHex();
$txIds = array_map(function ($v) { return Buffer::hex(trim($v))->flip()->getHex(); },$txIds);
function createMerkleBranch($targetHash, $hashes, &$proofs) {
$newHashes = [];
$totalTxIds = @count($hashes);
if ($totalTxIds % 2 > 0) {
$hashes[ $totalTxIds ] = $hashes[ $totalTxIds - 1 ];
}
$groupHashes = array_chunk($hashes, 2);
foreach($groupHashes as $twoHash) {
$newHash = hash('sha256', hex2bin(hash('sha256', hex2bin( implode("", $twoHash) ))));
if ($twoHash[0] == $targetHash OR $twoHash[1] == $targetHash) {
if ($twoHash[0] == $targetHash) {
$proofs[] = [$twoHash[1], "right"];
} else {
$proofs[] = [$twoHash[0], "left"];
}
$targetHash = $newHash;
}
$newHashes[] = $newHash;
}
if (@count($newHashes) == 1) {
return $newHashes[0];
} else {
return createMerkleBranch($targetHash, $newHashes,$proofs);
}
}
if (count($txIds) > 1) {
createMerkleBranch($txId,$txIds, $proofs);
}
return $proofs;
}
$merkleProofs = createMerkleProof($_POST['txid'], $txIds);
} catch (Exception $e) {
$errmsg .= "Problem found. " . $e->getMessage();
}
}
if ($errmsg) {
?>
<div class="alert alert-danger">
<strong>Error!</strong> <?php echo $errmsg?>
</div>
<?php
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($merkleProofs) {
?>
<div class="alert alert-success">
<h6 class="mt-3">Merkle Proofs</h6>
<textarea class="form-control" rows="5" id="comment" readonly><?php echo json_encode($merkleProofs)?></textarea>
</div>
<?php
} else {
?>
<div class="alert alert-success">
<h6 class="mt-3">Merkle Proofs</h6>
N/A
</div>
<?php
}
}
?>
<form action='' method='post'>
<div class="form-group">
<label for="txid">Target Tx id:</label>
<input class="form-control" type='text' name='txid' id='txid' value='<?php echo $_POST['txid']?>'>
</div>
<div class="form-group">
<label for="txids">Tx Ids (Follow TX order in block):</label>
<textarea rows=10 class="form-control" name='txids' id='txids'><?php echo $_POST['txids']?></textarea>
Press enter key to place new tx id in new line. For example, you can copy all tx ids from <a href="https://api.blockcypher.com/v1/btc/main/blocks/0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af" target="_blank"><img style='width:12px;height:12px;' src='../media/images/external_link.png'/></a>.
</div>
<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");
<?php
use BitWasp\Buffertools\Buffer;
include_once "../libraries/vendor/autoload.php";
include_once("html_iframe_header.php");
$result = '';
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
try {
$merkleProofs = json_decode($_POST['proofs']);
if (json_last_error() != JSON_ERROR_NONE) {
throw new Exception("Merkle Proofs (JSON) has error.");
}
$txId = Buffer::hex($_POST['txid'])->flip()->getHex();
$toBeConcatHash = $txId;//tx id in litle endian
foreach($merkleProofs as $proof) {
$hash = $proof[0];
$dir = $proof[1];
if ($dir == 'left') {
$toBeConcatHash = hash('sha256', hex2bin(hash('sha256', hex2bin($hash.$toBeConcatHash))));
} else {
$toBeConcatHash = hash('sha256', hex2bin(hash('sha256', hex2bin($toBeConcatHash.$hash ))));
}
}
$merkleRoot = Buffer::hex($toBeConcatHash)->flip()->getHex();//merkle root in big endian
} catch (Exception $e) {
$errmsg .= "Problem found. " . $e->getMessage();
}
}
if ($errmsg) {
?>
<div class="alert alert-danger">
<strong>Error!</strong> <?php echo $errmsg?>
</div>
<?php
}
if ($merkleRoot) {
if ($merkleRoot == $_POST['root']) {
?>
<div class="alert alert-success">
<?php echo $merkleRoot?> <b>Matched!</b>
</div>
<?php
} else {
?>
<div class="alert alert-danger">
<?php echo $merkleRoot?> <b>Not Matched!</b>
</div>
<?php
}
}
?>
<form action='' method='post'>
<div class="form-group">
<label for="root">Merkle Root:</label>
<input class="form-control" type='text' name='root' id='root' value='<?php echo $_POST['root']?>'>
</div>
<div class="form-group">
<label for="txid">Target Tx id:</label>
<input class="form-control" type='text' name='txid' id='txid' value='<?php echo $_POST['txid']?>'>
</div>
<div class="form-group">
<label for="proofs">Merkle Proofs (JSON):</label>
<input class="form-control" name='proofs' id='proofs' value='<?php echo $_POST['proofs']?>'/>
</div>
<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");