forked from onryo/siona
onryo
2 years ago
39 changed files with 3180 additions and 0 deletions
@ -0,0 +1,9 @@ |
|||
# Balances |
|||
|
|||
Showing address balances is currently manual run once in a while, not via cron. It uses a lot of resources. |
|||
|
|||
balances.pl generates addresses/index.html |
|||
|
|||
# Makefile |
|||
|
|||
run `make` to syntax check important files |
@ -0,0 +1,2 @@ |
|||
check: |
|||
perl -wc update.pl && perl -wc update_blocks_redis.pl |
@ -0,0 +1,377 @@ |
|||
#!/usr/bin/env perl |
|||
use strict; |
|||
use warnings; |
|||
use JSON::Any; |
|||
use Data::Dumper; |
|||
use Redis; |
|||
use 5.014; |
|||
my $STATS = {}; |
|||
$|=1; |
|||
|
|||
my $TX = {}; |
|||
my $r = Redis->new; |
|||
my $j = JSON::Any->new; |
|||
|
|||
#sleep 10; |
|||
|
|||
# While Siona swims, we pave with bricks on the road she will run on... |
|||
my $dir = shift || '/var/www/explorer.hush.land/var/www/explorer.hush.land/api'; |
|||
my $cli = "/home/hush/git/hush3/src/hush-cli"; |
|||
my $getinfo = readfile("$dir/getinfo.json"); |
|||
my $mining = readfile("$dir/getmininginfo.json"); |
|||
my $template = readfile("/var/www/explorer.hush.land/var/www/explorer.hush.land/blocks/template.html"); |
|||
my $blocksdir = "/var/www/explorer.hush.land/var/www/explorer.hush.land/blocks/"; |
|||
if($getinfo =~ m/"blocks": (\d+)/){ $STATS->{BLOCKS} ||= $1; } |
|||
if($getinfo =~ m/"tls_connections": (\d+)/){ $STATS->{TLS_CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"connections": (\d+)/){ $STATS->{CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"protocolversion": (\d+)/){ $STATS->{PROTOCOLVERSION} ||= $1; } |
|||
|
|||
my @symbols = qw/ |
|||
TX_TABLE BLOCKS_TABLE TLS_CONNECTIONS CONNECTIONS PROTOCOLVERSION |
|||
/; |
|||
my @blocks = (); |
|||
my $height = $STATS->{BLOCKS} || 0; |
|||
$STATS->{BLOCKS_TABLE} = ""; |
|||
$STATS->{TX_TABLE} = ""; |
|||
|
|||
my $mineraddress = ""; |
|||
for my $h ($height-50 .. $height) { |
|||
#last if($h < 0); |
|||
my $thisminer = ""; |
|||
# TODO: fix this garbage |
|||
my $reward = $h > 340000 ? "3.125 HUSH" : "12.5 HUSH"; |
|||
my $block = get_block($h); |
|||
#die Dumper $block; |
|||
my $time = $block->{time}; |
|||
die Dumper [ $block ] unless $block->{time} and $block->{tx}; |
|||
my @txs = @{ $block->{tx} }; |
|||
my $numtx = @txs; |
|||
# TODO: look on filesystem first? redis cache? |
|||
my $hash = qx!$cli getblockhash $h!; |
|||
chomp $hash; |
|||
|
|||
my $root = "/var/www/explorer.hush.land"; |
|||
my $blockdir = "$root/var/www/explorer.hush.land/block/$hash"; |
|||
if (!-e "$root/block/$h") { |
|||
# make /block/HEIGHT work |
|||
my $cmd = "ln -s $blockdir $root/var/www/explorer.hush.land/block/$h"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
} |
|||
if (!-d $blockdir) { |
|||
# so explorer.hush.is/block/HASH works |
|||
my $cmd = "mkdir -p $blockdir"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
my $block_template_file = "/var/www/explorer.hush.land/var/www/explorer.hush.land/block/template.html"; |
|||
my $new_block_file = "/var/www/explorer.hush.land/var/www/explorer.hush.land/block/$hash/index.html"; |
|||
# TODO: process template with block details |
|||
my $block_template = readfile($block_template_file); |
|||
$block_template =~ s/#BLOCKS#/$h/g; |
|||
$block_template =~ s/#BLOCKHASH#/$hash/g; |
|||
$block_template =~ s/#PREVIOUSBLOCKHASH#/$block->{previousblockhash}/ge; |
|||
$block_template =~ s/#BLOCKTIME#/$time/g; |
|||
$block_template =~ s/#ANCHOR#/$block->{anchor}/ge; |
|||
$block_template =~ s/#VERSION#/$block->{version}/ge; |
|||
$block_template =~ s/#BITS#/$block->{bits}/ge; |
|||
$block_template =~ s/#BLOCKSIZE#/$block->{size}/ge; |
|||
$block_template =~ s/#CHAINWORK#/$block->{chainwork}/ge; |
|||
$block_template =~ s/#MERKLEROOT#/$block->{merkleroot}/ge; |
|||
$block_template =~ s/#FINALSAPLINGROOT#/$block->{finalsaplingroot}/ge; |
|||
# TODO |
|||
$block_template =~ s/#BLOCKREWARD#/3.125 HUSH/g; |
|||
$block_template =~ s/#BLOCKNONCE#/$block->{nonce}/ge; |
|||
$block_template =~ s/#DIFFICULTY#/$block->{difficulty}/ge; |
|||
$block_template =~ s/#NUM_TXS#/$numtx/g; |
|||
|
|||
my $txtype = ""; |
|||
# generate tx list table |
|||
$STATS->{TX_TABLE}=<<HTML; |
|||
|
|||
|
|||
HTML |
|||
|
|||
my $txi = 0; |
|||
for my $tx (@txs) { |
|||
my $json = qx!$cli getrawtransaction $tx 1!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
|
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
|
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
# add tx json to Redis, indexed by txid |
|||
$r->set("tx:$tx", $json); |
|||
|
|||
my $j = JSON::Any->new; |
|||
my $o; |
|||
eval { |
|||
$o = $j->decode($json); |
|||
}; |
|||
next if $@; |
|||
|
|||
$TX->{$tx} = $o; |
|||
my $tx_dir = "$root/var/www/explorer.hush.land/tx/$tx"; |
|||
my $tx_file = "$root/var/www/explorer.hush.land/tx/$tx/index.html"; |
|||
my $tx_template_file = "$root/var/www/explorer.hush.land/tx/template.html"; |
|||
my $tx_template = readfile($tx_template_file); |
|||
my $txtime = localtime($o->{time}); |
|||
#my $txsize = $o->{size} . " bytes"; |
|||
$tx_template =~ s/#TXID#/$tx/ge; |
|||
$tx_template =~ s/#TXTIME#/$txtime/ge; |
|||
#$tx_template =~ s/#TXSIZE#/$txsize/g; |
|||
$tx_template =~ s/#BLOCKHEIGHT#/$h/ge; |
|||
$tx_template =~ s/#BLOCKHASH#/$hash/ge; |
|||
my ($vin,$vout,$zin,$zout) = ($o->{vin},$o->{vout},$o->{vShieldedSpend},$o->{vShieldedOutput}); |
|||
my $expiryheight = $o->{expiryheight} == 0 ? "Default" : $o->{expiryheight}; |
|||
my $locktime = localtime($o->{locktime}); |
|||
my $valueBalance = $o->{valueBalance} || "?"; |
|||
# "vShieldedOutput": [ |
|||
# { |
|||
# "cv": "61e0fed3b97e08e442408c7efc4058a9116695e6e28a22c0fbf0987fdfbcdd27", |
|||
# "cmu": "25245041af3bbc5a03da1cd6d60665f7659cbb3bab1080a6e003f856d45998fc", |
|||
# "ephemeralKey": "bffefb4f55679610bbdbd43bfba64308842348ba70bb999fad00c67356eab998", |
|||
# "encCiphertext": "b685c9d4f6164102999e88e3e30fcca37d9c402fc72533185d495a9d64f1fca277ead03aefe960eeaf102c0c92686a75c792ae8662f40601287ff19635581279d9c9940ba3c29af36166620422c6 |
|||
#49c4a7ca938734ceecb93a3abc8753ff3535950662ef46d8ed3a0608a61c65be5d0bdb1c262bd63fde759040eef74d4d81619ee154bbabe4fc0e27d82b19c6ed0d4cd806d5bc75ebbb13370ff3f19979ab3b74e859d9b88d3802 |
|||
#bc7a2ce7ae4305c6beec2146b374bda7234395d0aa390337e69ef5d04eddef0087244292f358b46eeb3c2a5a6d3bd1c89aaa4ebfd8bab58d2d4771b1d106db1a5dcead3b09cfc9fc38b972ce98c53d3cd658b02e58b087c7c73e |
|||
#0bd7cb093f2b15ab397094be5bc98f5865045d1845e548249fc811545db1645beb2f044366ba9ae584074e6fa5c03d786757c88ed8eff2d81570d15e64f192707d7393ce40b0f2f767cfbeaa5f05a634fe527da982241c92c4c2 |
|||
#9642f633115d34fe6791f00c8867e2242485de5f0bb87a8d4e6b375f557db6968f5ecc4f07b838b2dd85dd54e4e9ae2a28e9305bd1a6ae71adf75335d5f44cc046194fdbc91fb80202f06af9431716dc6627b2aa4723b0b8e4bb |
|||
#504649b6350ba9f020106d71248227ed8d7a10e2fbcbf64824c8923149822970b3c574614a8c32602106132c1209917974566b2990cf106666f985a2fa1f1409efdc457404700da210906b0f19be61c70d70eddc2f1cbffd94bb |
|||
#4c154a332fdd345ad06bd2ac86a339a93eae25db5eb3b4c6090d8483a8e5dd642231d17f3011b2f4b629ef72c08df1eeb6e7d06e", |
|||
# "outCiphertext": "53e3865f52101faf3218b60b7d58b9c426dc7c6cff009a8ceddd58031afe9802cae0f423a1085c2b36c776db29b57db8041e9bac42d6b445a0d69eb5a2f0ef61b4790595a68750c60889ff811dce |
|||
#8fbb", |
|||
# "proof": "82eda0f7de0936f6ca8208e63bda8db9970feb232ae64635e5bea67f16fdbe1b5e5e3a6bb7b7d2f0127c0d17de494834a82e899e8eecdfc71a59de8d1808a53df2989762bd54a855dadc535f2c5107d7b6da |
|||
#a732153c4dda4ac965be79ba2ecc030bd58e4c05d5ac7be283b3dc68af8a39231a31cccb54eae65c676760182bd22965f2e1c3685de44c0b93d84519bf138c7942222795dfdd0f683474b7c75221c9355109258805cc038ca43b |
|||
#26d5770bf25882326f4f508731b36a8632bc0012" |
|||
# } |
|||
# ], |
|||
|
|||
my $vins = @$vin; |
|||
my $vouts = @$vout; |
|||
my $zins = @$zin; |
|||
my $zouts = @$zout; |
|||
my $coinbase = $vin->[0] ? $vin->[0]->{coinbase}." with sequence ".$vin->[0]->{sequence} : "False"; #($vin->[0] && $vin->[0]->{coinbase}) ? $vin->[0]{coinbase} . " with sequence " . $vin->{sequence} : "False"; |
|||
|
|||
# coinbase does not count as a transparent input |
|||
$vins-- if ($vin->[0] && $vin->[0]->{coinbase}); |
|||
|
|||
my $tx_data =<<DATA; |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Coinbase: $coinbase</td> |
|||
<td style="font-size: 14px; width: 50%">Locktime: $locktime</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Transparent Inputs: $vins </td> |
|||
<td style="font-size: 14px; width: 50%">Transparent Outputs: $vouts </td> |
|||
</tr> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Shielded Inputs: $zins </td> |
|||
<td style="font-size: 14px; width: 50%">Shielded Outputs: $zouts </td> |
|||
</tr> |
|||
DATA |
|||
$tx_template =~ s/#TX_DATA#/$tx_data/g; |
|||
|
|||
my $cmd = "mkdir -p $tx_dir"; |
|||
warn $cmd; |
|||
## create tx dir + page |
|||
qx{$cmd}; |
|||
|
|||
open(my $fh, '>', $tx_file) or die "$tx_file: $!"; |
|||
print $fh $tx_template; |
|||
close $fh or die $!; |
|||
|
|||
## create tx view on block page |
|||
my $from = $o->{vin}->[0] ? $o->{vin}->[0]->{address} : "zs1???"; |
|||
#my $to = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : "zs1???"; |
|||
my $to2 = ""; |
|||
# only look at coinbase tx's |
|||
if($txi == 0) { |
|||
# LEXICAL SCOPING BUG, MAN! |
|||
$mineraddress = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : ""; |
|||
$thisminer = $mineraddress; |
|||
} |
|||
# say "<!-- miner for $tx is $mineraddress -->"; |
|||
my $to = $mineraddress ? $mineraddress : "zs1???"; |
|||
if($o->{vout}->[1]) { |
|||
$to2 = $o->{vout}->[1]->{scriptPubKey}->{addresses}->[0]; |
|||
} |
|||
$valueBalance = ($o->{vout}->[0]->{value} || 0) + ($o->{vout}->[1]->{value} || 0); |
|||
$valueBalance ||= "?"; |
|||
$from ||= ""; |
|||
|
|||
$txtype = "Mining"; |
|||
if($zins+$zouts>0) { |
|||
$txtype = "Shielded"; |
|||
if($zins==0 && $zouts>0) { $txtype = "Shielding"; } |
|||
if($vins==0 && $vouts==0){ $txtype = "Fully Shielded" } |
|||
# this is prevented by consensus rule on HUSH mainnet |
|||
# but if we see it, ring the bell, lulz |
|||
if($zins>0 && $zouts==0) { $txtype = "De-Shielding!"; } |
|||
} |
|||
#if($vouts>0) { $txtype = "DPoW"; } |
|||
my $stuff; |
|||
|
|||
if ($txtype eq "Mining") { |
|||
$stuff =<<STUFF; |
|||
=> $to |
|||
<br> |
|||
=> $to2 |
|||
STUFF |
|||
} else { |
|||
#TODO: fix this shite |
|||
$stuff =<<STUFF; |
|||
$from => $to |
|||
<br> |
|||
$from => $to2 |
|||
STUFF |
|||
} |
|||
|
|||
my $tx_table = <<HTML; |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px"><a href="/tx/$tx" class="mainlinkexplorer">$tx</a></td> |
|||
<td style="font-size: 14px">vins: $vins, vouts: $vouts</td> |
|||
<td style="font-size: 14px">zins: $zins, zouts: $zouts</td> |
|||
</tr> |
|||
<tr> |
|||
<td style="font-size: 14px">$stuff</td> |
|||
<td style="font-size: 14px">$txtime</td> |
|||
<td style="font-size: 14px">$valueBalance HUSH</td> |
|||
</tr> |
|||
</table> |
|||
HTML |
|||
$STATS->{TX_TABLE} .= $tx_table; |
|||
$txi++; |
|||
} |
|||
|
|||
# $STATS->{TX_TABLE} .= "</table>"; |
|||
# $STATS->{TX_TABLE} .= "<pre>" . Dumper [ $vin ];'' |
|||
|
|||
$block_template =~ s/#TX_TABLE#/$STATS->{TX_TABLE}/ge; |
|||
|
|||
# > ? |
|||
open(my $fh, '>>', $new_block_file) or die "$new_block_file: $!"; |
|||
print $fh $block_template; |
|||
close $fh or die $!; |
|||
warn "wrote to $new_block_file "; |
|||
} else { |
|||
warn "block exists on disk, looking info up"; |
|||
#TODO: error-checking for corrupt data |
|||
#warn Dumper $block; |
|||
my $lookuptx = $block->{tx}->[0]; |
|||
my $o = get_raw($lookuptx); |
|||
$thisminer = $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0]; |
|||
warn "thisminer=$thisminer"; |
|||
} |
|||
|
|||
my $blockduration = 0; |
|||
if($#blocks >= 0) { |
|||
$blockduration = $time - $blocks[$#blocks]->[3]; |
|||
} |
|||
# give data to blocks after we have processed everything |
|||
my $b = [ $h, $hash, $reward,$time,$numtx,$thisminer, $blockduration ]; |
|||
#warn Dumper $b; |
|||
push @blocks, $b; |
|||
; |
|||
} |
|||
|
|||
sub get_raw { |
|||
my $tx = shift; |
|||
my $cmd = "$cli getrawtransaction $tx 1"; |
|||
warn $cmd; |
|||
my $json = qx!$cmd!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($json); |
|||
return $o; |
|||
} |
|||
|
|||
# render data |
|||
for my $b (reverse @blocks) { |
|||
my ($height,$hash,$reward,$time,$txs,$miner,$duration) = @$b; |
|||
|
|||
$time = localtime($time); |
|||
|
|||
# we can't calc the duration of the first block we look at, yet |
|||
$duration = "--" unless $duration; |
|||
|
|||
$STATS->{BLOCKS_TABLE} .= <<"FUCK"; |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px"><a href="/block/$height/" class="mainlinkexplorer">$height</a></td> |
|||
<td style="font-size: 14px"><a href="/block/$hash/" class="mainlinkexplorer">$hash</a></td> |
|||
<td style="font-size: 14px">$time</td> |
|||
</tr> |
|||
<tr> |
|||
<td style="font-size: 14px">${duration}s</td> |
|||
<td style="font-size: 14px">$miner + $reward</td> |
|||
<td style="font-size: 14px">Transactions: $txs</td> |
|||
</tr> |
|||
</table> |
|||
FUCK |
|||
} |
|||
|
|||
|
|||
|
|||
for my $s (@symbols) { |
|||
if($s && $STATS->{$s}) { $template =~ s/#$s#/$STATS->{$s}/ge } |
|||
} |
|||
|
|||
# derived stat |
|||
#my $zpct = sprintf "%.3f", $STATS->{SUPPLY} > 0 ? 100*($STATS->{ZFUNDS}/$STATS->{SUPPLY}) : "0.000"; |
|||
#$template =~ s/#ZFUNDS_PERCENT#/$zpct/ge; |
|||
|
|||
say $template; |
|||
|
|||
###### functions |
|||
|
|||
# get block at given height |
|||
sub get_block { |
|||
my $height = shift; |
|||
return if $height < 0; |
|||
my $block = $r->get("block:$height") || ''; |
|||
|
|||
# create data if it's not there |
|||
if( $block =~ m/^HASH/ || length($block) == 0 ) { |
|||
my $cmd = "$cli getblock $height"; |
|||
warn $cmd; |
|||
$block = qx/$cmd/; |
|||
} |
|||
my $json = $block; |
|||
if($json) { |
|||
$block = $j->decode($json); |
|||
# cache in Redis |
|||
warn Dumper [ "redis set block:$height =>", $json ]; |
|||
$r->set("block:$height",$json); |
|||
} else { |
|||
warn "empty block $height!!" unless $json; |
|||
warn Dumper [$json]; |
|||
} |
|||
|
|||
return $block; |
|||
} |
|||
|
|||
sub readfile { |
|||
my $file = shift; |
|||
my $data = ""; |
|||
open(my $fh, '<', $file) or die "$file: $!"; |
|||
my $txlist = 0; |
|||
while(<$fh>){ |
|||
$data.=$_ |
|||
} |
|||
close($fh); |
|||
return $data; |
|||
} |
@ -0,0 +1,84 @@ |
|||
#!/usr/bin/env perl |
|||
use strict; |
|||
use warnings; |
|||
use 5.014; |
|||
use JSON::Any; |
|||
$|=1; |
|||
|
|||
# While Siona swims, we pave with bricks on the road she will run on... |
|||
my $STATS = {}; |
|||
my $dir = shift || '/var/www/explorer.hush.land/var/www/explorer.hush.land/api'; |
|||
my $getinfo = readfile("$dir/getinfo.json"); |
|||
my $coinsupply = readfile("$dir/coinsupply.json"); |
|||
my $noprivacy = readfile("$dir/snapshots/snapshot.json"); |
|||
my $template = readfile("/var/www/explorer.hush.land/var/www/explorer.hush.land/addresses/template.html"); |
|||
my @symbols = qw/ BLOCKS CONNECTIONS TLS_CONNECTIONS TXCOUNT |
|||
PROTOCOLVERSION LONGESTCHAIN TIPTIME NOTARIZEDHASH |
|||
ADDRESS_DATA TOTAL_ADDRESSES TOTAL AVG UTXOS |
|||
/; |
|||
|
|||
$STATS->{ADDRESS_DATA} = <<TABLE; |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px">Transparent Address</td> |
|||
<td style="font-size: 14px">Amount</td> |
|||
</tr> |
|||
TABLE |
|||
|
|||
|
|||
if ($noprivacy) { |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($noprivacy); |
|||
|
|||
my $addresses = $o->{addresses}; |
|||
$STATS->{AVG} = $o->{average}; |
|||
$STATS->{TOTAL_ADDRESSES} = $o->{total_addresses}; |
|||
$STATS->{UTXOS} = $o->{utxos}; |
|||
$STATS->{TOTAL} = $o->{total}; |
|||
|
|||
for my $a (@$addresses) { |
|||
my ($addr,$amount) = ($a->{addr}, $a->{amount}); |
|||
$STATS->{ADDRESS_DATA} .= <<ROW; |
|||
<tr> |
|||
<td style="font-size: 14px">$addr</td> |
|||
<td style="font-size: 14px">$amount HUSH</td> |
|||
</tr> |
|||
ROW |
|||
} |
|||
$STATS->{ADDRESS_DATA} .= "</table>"; |
|||
|
|||
for my $s (@symbols) { |
|||
if($s && $STATS->{$s}) { $template =~ s/#$s#/$STATS->{$s}/ge } |
|||
} |
|||
say $template; |
|||
} |
|||
|
|||
sub readfile { |
|||
my $file = shift; |
|||
my $data = ""; |
|||
open(my $fh, '<', $file) or die $!; |
|||
while(<$fh>){ |
|||
$data.=$_; |
|||
# getinfo |
|||
if(m/"tls_connections": (\d+)/){ $STATS->{TLS_CONNECTIONS} ||= $1; } |
|||
if(m/"connections": (\d+)/){ $STATS->{CONNECTIONS} ||= $1; } |
|||
if(m/"blocks": (\d+)/){ $STATS->{BLOCKS} ||= $1; } |
|||
if(m/"notarized": (\d+)/){ $STATS->{NOTARIZED} ||= $1; } |
|||
if(m/"protocolversion": (\d+)/){ $STATS->{PROTOCOLVERSION} ||= $1; } |
|||
if(m/"longestchain": (\d+)/){ $STATS->{LONGESTCHAIN} ||= $1; } |
|||
if(m/"notarizedhash": "([a-z0-9]+)"/){ $STATS->{NOTARIZEDHASH} ||= $1; } |
|||
if(m/"tiptime": (\d+)/){ $STATS->{TIPTIME} ||= localtime($1) . "<!-- $1 -->"; } |
|||
# coinsupply |
|||
if(m/"zfunds": (\d+\.\d+)/){ $STATS->{ZFUNDS} ||= $1; } |
|||
if(m/"total": (\d+\.\d+)/){ $STATS->{SUPPLY} ||= $1; } |
|||
# getmininginfo |
|||
if(m/"difficulty": (\d+)/){ $STATS->{DIFFICULTY} ||= $1; } |
|||
if(m/"networksolps": (\d+)/){ $STATS->{NETWORKSOLPS} ||= sprintf("%.2f", $1 / 1_000_000); } |
|||
# getchaintxstats |
|||
if(m/"txcount": (\d+)/){ $STATS->{TXCOUNT} ||= $1; } |
|||
if(m/"txrate": (\d+\.\d+)/){ $STATS->{TXRATE} ||= sprintf("%.4f",$1*60); } |
|||
if(m/"window_final_block_hash": "([a-z0-9]+)"/){ $STATS->{BLOCKHASH} ||= $1; } |
|||
} |
|||
close($fh); |
|||
return $data; |
|||
} |
@ -0,0 +1,57 @@ |
|||
{ |
|||
"hex": "0400008085202f89010000000000000000000000000000000000000000000000000000000000000000ffffffff050320300500ffffffff02d088c31000000000232102acb24edc1cb97c154773b24c30380ddb6ff3d8f4b9d73dcab18e07ed6b19ab64ac50d6dc01000000001976a9145eb10cf64f2bab1b457f1f25e658526155928fac88ac2f7ec55f000000000000000000000000000000", |
|||
"txid": "d552f6312ef32decc2034ce14aa09020d167c756b8e9ae4f3734275a35010af8", |
|||
"overwintered": true, |
|||
"version": 4, |
|||
"last_notarized_height": 319432, |
|||
"versiongroupid": "892f2085", |
|||
"locktime": 1606778415, |
|||
"expiryheight": 0, |
|||
"vin": [ |
|||
{ |
|||
"coinbase": "0320300500", |
|||
"sequence": 4294967295 |
|||
} |
|||
], |
|||
"vout": [ |
|||
{ |
|||
"value": 2.81250000, |
|||
"valueSat": 281250000, |
|||
"n": 0, |
|||
"scriptPubKey": { |
|||
"asm": "02acb24edc1cb97c154773b24c30380ddb6ff3d8f4b9d73dcab18e07ed6b19ab64 OP_CHECKSIG", |
|||
"hex": "2102acb24edc1cb97c154773b24c30380ddb6ff3d8f4b9d73dcab18e07ed6b19ab64ac", |
|||
"reqSigs": 1, |
|||
"type": "pubkey", |
|||
"addresses": [ |
|||
"RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj" |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
"value": 0.31250000, |
|||
"valueSat": 31250000, |
|||
"n": 1, |
|||
"scriptPubKey": { |
|||
"asm": "OP_DUP OP_HASH160 5eb10cf64f2bab1b457f1f25e658526155928fac OP_EQUALVERIFY OP_CHECKSIG", |
|||
"hex": "76a9145eb10cf64f2bab1b457f1f25e658526155928fac88ac", |
|||
"reqSigs": 1, |
|||
"type": "pubkeyhash", |
|||
"addresses": [ |
|||
"RHushEyeDm7XwtaTWtyCbjGQumYyV8vMjn" |
|||
] |
|||
} |
|||
} |
|||
], |
|||
"valueBalance": 0.00000000, |
|||
"vShieldedSpend": [ |
|||
], |
|||
"vShieldedOutput": [ |
|||
], |
|||
"blockhash": "0000000051649db14dd1557ef4c5cc2bd8ea110e3f0c453f491efe4d21a31356", |
|||
"height": 340000, |
|||
"confirmations": 1, |
|||
"rawconfirmations": 50, |
|||
"time": 1606778445, |
|||
"blocktime": 1606778445 |
|||
} |
@ -0,0 +1,337 @@ |
|||
#!/usr/bin/env perl |
|||
use strict; |
|||
use warnings; |
|||
use JSON::Any; |
|||
use Data::Dumper; |
|||
use 5.014; |
|||
my $STATS = {}; |
|||
$|=1; |
|||
|
|||
my $ADDRS = {}; |
|||
|
|||
# While Siona swims, we pave with bricks on the road she will run on... |
|||
my $dir = shift || $ENV{HOME} . "/data"; |
|||
my $cli = "/home/duke/git/hush3/src/hush-cli"; |
|||
my $getinfo = readfile("$dir/getinfo.json"); |
|||
my $template = readfile("/var/www/explorer.hush.is/address/template.html"); |
|||
my $addrdir = "/var/www/explorer.hush.is/address/"; |
|||
if($getinfo =~ m/"blocks": (\d+)/){ $STATS->{BLOCKS} ||= $1; } |
|||
if($getinfo =~ m/"tls_connections": (\d+)/){ $STATS->{TLS_CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"connections": (\d+)/){ $STATS->{CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"protocolversion": (\d+)/){ $STATS->{PROTOCOLVERSION} ||= $1; } |
|||
|
|||
my @symbols = qw/ |
|||
TX_TABLE ADDRESSES_TABLE TLS_CONNECTIONS CONNECTIONS PROTOCOLVERSION |
|||
/; |
|||
my @addresses; |
|||
my $height = $STATS->{BLOCKS}; |
|||
$STATS->{ADDRESSES_TABLE} = ""; |
|||
$STATS->{TX_TABLE} = ""; |
|||
|
|||
my $mineraddress = ""; |
|||
for my $h ($height-50 .. $height) { |
|||
my $thisminer = ""; |
|||
# TODO: fix this garbage |
|||
my $reward = $h > 340000 ? "3.125 HUSH" : "12.5 HUSH"; |
|||
my $block = get_block($h); |
|||
#die Dumper $block; |
|||
my $time = localtime($block->{time}) . " UTC" || ""; |
|||
my @txs = @{ $block->{tx} }; |
|||
my $numtx = @txs; |
|||
# TODO: look on filesystem first? redis cache? |
|||
my $hash = qx!$cli getblockhash $h!; |
|||
chomp $hash; |
|||
|
|||
my $root = "/var/www/explorer.hush.is"; |
|||
my $blockdir = "$root/block/$hash"; |
|||
if (!-e "$root/block/$h") { |
|||
# make /block/HEIGHT work |
|||
my $cmd = "ln -s $blockdir $root/block/$h"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
} |
|||
if (!-d $blockdir) { |
|||
# so explorer.hush.is/block/HASH works |
|||
my $cmd = "mkdir -p $blockdir"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
my $block_template_file = "$root/block/template.html"; |
|||
my $new_block_file = "$root/block/$hash/index.html"; |
|||
# TODO: process template with block details |
|||
my $block_template = readfile($block_template_file); |
|||
$block_template =~ s/#BLOCKS#/$h/g; |
|||
$block_template =~ s/#BLOCKHASH#/$hash/g; |
|||
$block_template =~ s/#PREVIOUSBLOCKHASH#/$block->{previousblockhash}/ge; |
|||
$block_template =~ s/#BLOCKTIME#/$time/g; |
|||
$block_template =~ s/#ANCHOR#/$block->{anchor}/ge; |
|||
$block_template =~ s/#VERSION#/$block->{version}/ge; |
|||
$block_template =~ s/#BITS#/$block->{bits}/ge; |
|||
$block_template =~ s/#BLOCKSIZE#/$block->{size}/ge; |
|||
$block_template =~ s/#CHAINWORK#/$block->{chainwork}/ge; |
|||
$block_template =~ s/#MERKLEROOT#/$block->{merkleroot}/ge; |
|||
$block_template =~ s/#FINALSAPLINGROOT#/$block->{finalsaplingroot}/ge; |
|||
# TODO |
|||
$block_template =~ s/#BLOCKREWARD#/3.125 HUSH/g; |
|||
$block_template =~ s/#BLOCKNONCE#/$block->{nonce}/ge; |
|||
$block_template =~ s/#DIFFICULTY#/$block->{difficulty}/ge; |
|||
$block_template =~ s/#NUM_TXS#/$numtx/g; |
|||
|
|||
my $txtype = ""; |
|||
# generate tx list table |
|||
$STATS->{TX_TABLE}=<<HTML; |
|||
<table border=1> |
|||
<tr><th>Transaction ID (txid)</th><th>Type</th><th>Inputs</th> |
|||
<th>Outputs</th><th>Shielded Inputs</th><th>Shielded Outputs</th> |
|||
<th>Addresses</th> |
|||
<th>Amount</th> |
|||
<th>Transaction Time</th> |
|||
<!-- |
|||
<th>Expiry Height</th> |
|||
<th>Lock Time</th> |
|||
--> |
|||
</tr> |
|||
HTML |
|||
|
|||
my $txi = 0; |
|||
for my $tx (@txs) { |
|||
my $json = qx!$cli getrawtransaction $tx 1!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
|
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
|
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($json); |
|||
$TX->{$tx} = $o; |
|||
my $tx_dir = "$root/tx/$tx"; |
|||
my $tx_file = "$root/tx/$tx/index.html"; |
|||
my $tx_template_file = "$root/tx/template.html"; |
|||
my $tx_template = readfile($tx_template_file); |
|||
my $txtime = localtime($o->{time}) . " UTC ( " . $o->{time} . " )"; |
|||
#my $txsize = $o->{size} . " bytes"; |
|||
$tx_template =~ s/#TXID#/$tx/ge; |
|||
$tx_template =~ s/#TXTIME#/$txtime/ge; |
|||
#$tx_template =~ s/#TXSIZE#/$txsize/g; |
|||
$tx_template =~ s/#BLOCKHEIGHT#/$h/ge; |
|||
$tx_template =~ s/#BLOCKHASH#/$hash/ge; |
|||
my ($vin,$vout,$zin,$zout) = ($o->{vin},$o->{vout},$o->{vShieldedSpend},$o->{vShieldedOutput}); |
|||
my $expiryheight = $o->{expiryheight} == 0 ? "Default" : $o->{expiryheight}; |
|||
my $locktime = localtime($o->{locktime}) . " UTC ( " . $o->{locktime} . " )"; |
|||
my $valueBalance = $o->{valueBalance} || "?"; |
|||
|
|||
my $vins = @$vin; |
|||
my $vouts = @$vout; |
|||
my $zins = @$zin; |
|||
my $zouts = @$zout; |
|||
my $coinbase = $vin->[0] ? $vin->[0]->{coinbase}." with sequence ".$vin->[0]->{sequence} : "False"; #($vin->[0] && $vin->[0]->{coinbase}) ? $vin->[0]{coinbase} . " with sequence " . $vin->{sequence} : "False"; |
|||
|
|||
# coinbase does not count as a transparent input |
|||
$vins-- if ($vin->[0] && $vin->[0]->{coinbase}); |
|||
|
|||
my $tx_data =<<DATA; |
|||
<table border=1> |
|||
<tr><th>Coinbase</th><td align=center>$coinbase</td></tr> |
|||
<tr><th>Expiry Height</th><td align=center>$expiryheight</td></tr> |
|||
<tr><th>Transparent Inputs</th><td align=center> $vins </td></tr> |
|||
<tr><th>Transparent Outputs</th><td align=center> $vouts </td></tr> |
|||
<tr><th>Shielded Inputs</th><td align=center> $zins </td></tr> |
|||
<tr><th>Shielded Outputs</th><td align=center> $zouts </td></tr> |
|||
<tr><th>Locktime</th><td align=center>$locktime</td></tr> |
|||
</table> |
|||
|
|||
DATA |
|||
$tx_template =~ s/#TX_DATA#/$tx_data/g; |
|||
|
|||
my $cmd = "mkdir -p $tx_dir"; |
|||
warn $cmd; |
|||
## create tx dir + page |
|||
qx{$cmd}; |
|||
|
|||
open(my $fh, '>', $tx_file) or die "$tx_file: $!"; |
|||
print $fh $tx_template; |
|||
close $fh or die $!; |
|||
|
|||
## create tx view on block page |
|||
my $from = $o->{vin}->[0] ? $o->{vin}->[0]->{address} : "zs1???"; |
|||
#my $to = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : "zs1???"; |
|||
my $to2 = ""; |
|||
# only look at coinbase tx's |
|||
if($txi == 0) { |
|||
# LEXICAL SCOPING BUG, MAN! |
|||
$mineraddress = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : ""; |
|||
$thisminer = $mineraddress; |
|||
} |
|||
say "<!-- miner for $tx is $mineraddress -->"; |
|||
my $to = $mineraddress ? $mineraddress : "zs1???"; |
|||
if($o->{vout}->[1]) { |
|||
$to2 = $o->{vout}->[1]->{scriptPubKey}->{addresses}->[0]; |
|||
} |
|||
$valueBalance = ($o->{vout}->[0]->{value} || 0) + ($o->{vout}->[1]->{value} || 0); |
|||
$valueBalance ||= "?"; |
|||
$from ||= ""; |
|||
|
|||
$txtype = "Mining"; |
|||
if($zins+$zouts>0) { |
|||
$txtype = "Shielded"; |
|||
if($zins==0 && $zouts>0) { $txtype = "Shielding"; } |
|||
if($vins==0 && $vouts==0){ $txtype = "Fully Shielded" } |
|||
# this is prevented by consensus rule on HUSH mainnet |
|||
# but if we see it, ring the bell, lulz |
|||
if($zins>0 && $zouts==0) { $txtype = "De-Shielding!"; } |
|||
} |
|||
#if($vouts>0) { $txtype = "DPoW"; } |
|||
my $stuff; |
|||
|
|||
if ($txtype eq "Mining") { |
|||
$stuff =<<STUFF; |
|||
<pre> |
|||
=> $to |
|||
=> $to2 |
|||
</pre> |
|||
<br/> |
|||
STUFF |
|||
} else { |
|||
#TODO: fix this shite |
|||
$stuff =<<STUFF; |
|||
<pre> |
|||
$from => $to |
|||
$from => $to2 |
|||
</pre> |
|||
<br/> |
|||
STUFF |
|||
} |
|||
|
|||
my $tx_table = <<HTML; |
|||
<tr> |
|||
<td><a href="/tx/$tx">$tx</a></td> |
|||
<td>$txtype</td> |
|||
<td align=center>$vins</td> |
|||
<td align=center>$vouts</td> |
|||
<td align=center>$zins</td> |
|||
<td align=center>$zouts</td> |
|||
<td>$stuff</td> |
|||
<td>$valueBalance HUSH</td> |
|||
<td>$txtime</td> |
|||
<!-- |
|||
<td>$expiryheight</td> |
|||
<td>$locktime</td> |
|||
--> |
|||
</tr> |
|||
HTML |
|||
$STATS->{TX_TABLE} .= $tx_table; |
|||
$txi++; |
|||
} |
|||
|
|||
$STATS->{TX_TABLE} .= "</table>"; |
|||
# $STATS->{TX_TABLE} .= "<pre>" . Dumper [ $vin ];'' |
|||
|
|||
$block_template =~ s/#TX_TABLE#/$STATS->{TX_TABLE}/ge; |
|||
|
|||
# > ? |
|||
open(my $fh, '>>', $new_block_file) or die "$new_block_file: $!"; |
|||
print $fh $block_template; |
|||
close $fh or die $!; |
|||
warn "wrote to $new_block_file "; |
|||
} else { |
|||
warn "block exists on disk, looking info up"; |
|||
#TODO: error-checking for corrupt data |
|||
#warn Dumper $block; |
|||
my $lookuptx = $block->{tx}->[0]; |
|||
my $o = get_raw($lookuptx); |
|||
$thisminer = $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0]; |
|||
warn "thisminer=$thisminer"; |
|||
} |
|||
|
|||
# give data to blocks after we have processed everything |
|||
my $b = [ $h, $hash, $reward,$time,$numtx,$thisminer,0 ]; |
|||
#warn Dumper $b; |
|||
push @addresses, $b; |
|||
} |
|||
|
|||
sub get_raw { |
|||
my $tx = shift; |
|||
my $cmd = "$cli getrawtransaction $tx 1"; |
|||
warn $cmd; |
|||
my $json = qx!$cmd!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($json); |
|||
return $o; |
|||
} |
|||
|
|||
# render data |
|||
for my $b (reverse @addresses) { |
|||
|
|||
$STATS->{ADDRESSES_TABLE} .= <<"FUCK"; |
|||
<tr> |
|||
<td align=center><a href="/block/$b->[0]">$b->[0]</a></td> |
|||
<td align=center><a href="/block/$b->[1]">$b->[1]</a></td> |
|||
<td align=center>$b->[2]</td> |
|||
<td align=center>$b->[3]</td> |
|||
<td align=center>$b->[4]</td> |
|||
<td align=center>$b->[5]</td> |
|||
</tr> |
|||
FUCK |
|||
} |
|||
|
|||
|
|||
|
|||
for my $s (@symbols) { |
|||
if($s && $STATS->{$s}) { $template =~ s/#$s#/$STATS->{$s}/ge } |
|||
} |
|||
|
|||
say $template; |
|||
|
|||
###### functions |
|||
|
|||
sub get_block { |
|||
my $height = shift; |
|||
my $dir = "/home/duke/data/blocks/"; |
|||
my $file = "$dir/block-$height.json"; |
|||
my $stats = {}; |
|||
my $block; |
|||
|
|||
# create data if it's not there |
|||
if( (!-e $file) || (-s $file == 0)) { |
|||
# logging? |
|||
my $cmd = "$cli getblock $height > /home/duke/data/blocks/block-$height.json"; |
|||
warn $cmd; |
|||
qx/$cmd/; |
|||
# let the file sync to disk |
|||
sleep 1; |
|||
} |
|||
my $json = readfile($file); |
|||
if($json) { |
|||
my $j = JSON::Any->new; |
|||
$block = $j->decode($json); |
|||
} else { |
|||
warn "empty block $height!!" unless $json; |
|||
warn Dumper [$json]; |
|||
} |
|||
|
|||
return $block; |
|||
} |
|||
|
|||
sub readfile { |
|||
my $file = shift; |
|||
my $data = ""; |
|||
open(my $fh, '<', $file) or die "$file: $!"; |
|||
my $txlist = 0; |
|||
while(<$fh>){ |
|||
$data.=$_ |
|||
} |
|||
close($fh); |
|||
return $data; |
|||
} |
@ -0,0 +1,102 @@ |
|||
While Siona swims, we lack the bricks on the road she will run on... |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>Hush Explorer: Speak And Transact Freely</title> |
|||
<style> |
|||
body { |
|||
width: 66em; |
|||
margin: 0 auto; |
|||
font-family: Tahoma, Verdana, Arial, sans-serif; |
|||
} |
|||
</style> |
|||
<!-- this explorer must be hosted at / or this needs to be changed. |
|||
Not specifying a hostname makes it compatible with Tor/i2p/etc and other mirrors |
|||
- Duke |
|||
--> |
|||
<meta http-equiv="refresh" content="120; URL=/"> |
|||
</head> |
|||
|
|||
<!-- |
|||
"Fuck Blockchain Analysts" |
|||
|
|||
- Duke Leto and The Hush Developers |
|||
--> |
|||
|
|||
<body> |
|||
<h1>HUSH Blockchain Explorer</h1> |
|||
<div id=stats> |
|||
<table width="100%" border=1> |
|||
<tr> |
|||
<td> |
|||
<table> |
|||
<tr><th>Current Height</th><td>339797</td></tr> |
|||
<tr><th>Notarized Height</th><td> 319432</td></tr> |
|||
<tr><th>Total Transactions</th><td> 636565</td></tr> |
|||
<!--<tr><th>Transactions Per Day</th><td> #TXS_PER_DAY#</td></tr> --> |
|||
<tr><th>Difficulty</th><td> 48982331</td></tr> |
|||
<tr><th>Network Solution Rate (Hashrate)</th><td> 5.988313 MegaSols/s</td></tr> |
|||
<tr><th>Circulating Supply</th><td> 10424467.60612515 HUSH</td></tr> |
|||
<tr><th>Shielded Supply</th><td> 3201461.20925607 HUSH (30.711 %)</td></tr> |
|||
</table> |
|||
</td> |
|||
<td valign=top> |
|||
<table> |
|||
<tr><th>Blockhash</th><th>Block height</th><th>Transactions</th><th>Shielded Transactions</th></tr> |
|||
<tr><td><a href="/block/#BLOCK01_HASH#">#BLOCK01_HASH#</a></td><td>#BLOCK01_HEIGHT#</td><td>#BLOCK01_TXS#</td><td>#BLOCK01_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK02_HASH#">#BLOCK02_HASH#</a></td><td>#BLOCK02_HEIGHT#</td><td>#BLOCK02_TXS#</td><td>#BLOCK02_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK03_HASH#">#BLOCK03_HASH#</a></td><td>#BLOCK03_HEIGHT#</td><td>#BLOCK03_TXS#</td><td>#BLOCK03_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK04_HASH#">#BLOCK04_HASH#</a></td><td>#BLOCK04_HEIGHT#</td><td>#BLOCK04_TXS#</td><td>#BLOCK04_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK05_HASH#">#BLOCK05_HASH#</a></td><td>#BLOCK05_HEIGHT#</td><td>#BLOCK05_TXS#</td><td>#BLOCK05_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK06_HASH#">#BLOCK06_HASH#</a></td><td>#BLOCK06_HEIGHT#</td><td>#BLOCK06_TXS#</td><td>#BLOCK06_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK07_HASH#">#BLOCK07_HASH#</a></td><td>#BLOCK07_HEIGHT#</td><td>#BLOCK07_TXS#</td><td>#BLOCK07_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK08_HASH#">#BLOCK08_HASH#</a></td><td>#BLOCK08_HEIGHT#</td><td>#BLOCK08_TXS#</td><td>#BLOCK08_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK09_HASH#">#BLOCK09_HASH#</a></td><td>#BLOCK09_HEIGHT#</td><td>#BLOCK09_TXS#</td><td>#BLOCK09_ZTXS#</tr> |
|||
<tr><td><a href="/block/#BLOCK10_HASH#">#BLOCK10_HASH#</a></td><td>#BLOCK10_HEIGHT#</td><td>#BLOCK10_TXS#</td><td>#BLOCK10_ZTXS#</tr> |
|||
</table> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
<br> |
|||
<h1>About This Extreme Explorer</h1> |
|||
|
|||
This Explorer doesn't snoop on your privacy! There is no Javascript or images for that reason. |
|||
Either could be used to steal your privacy. |
|||
|
|||
<h1>License</h1> |
|||
|
|||
GPLv3 |
|||
|
|||
<br> |
|||
<a href="https://hush.is/twitter">Twitter</a> |
|||
| |
|||
<a href="https://hush.is/tg">Telegram</a> |
|||
| |
|||
<a href="https://hush.is/telegram_support">Telegram Support</a> |
|||
| |
|||
<a href="https://hush.is/telegram_mining">Telegram Mining</a> |
|||
| |
|||
<a href="https://hush.is/reddit">Reddit</a> |
|||
| |
|||
|
|||
<a href="https://hush.is/youtube">YouTube</a> |
|||
| |
|||
|
|||
<a href="https://hush.is/bitcointalk">BitcoinTalk</a> |
|||
| |
|||
|
|||
<a href="https://hush.is/mastodon">Mastodon</a> |
|||
| |
|||
|
|||
<a href="https://hush.is/matrix">Matrix</a> |
|||
|
|||
|
|||
|
|||
<br/> |
|||
<br/> |
|||
<br/> |
|||
|
|||
|
|||
</body> |
|||
</html> |
@ -0,0 +1 @@ |
|||
This is some old version of the code for historical purposes. |
@ -0,0 +1,337 @@ |
|||
#!/usr/bin/env perl |
|||
use strict; |
|||
use warnings; |
|||
use JSON::Any; |
|||
use Data::Dumper; |
|||
use 5.014; |
|||
my $STATS = {}; |
|||
$|=1; |
|||
|
|||
my $ADDRS = {}; |
|||
|
|||
# While Siona swims, we pave with bricks on the road she will run on... |
|||
my $dir = shift || $ENV{HOME} . "/data"; |
|||
my $cli = "/home/duke/git/hush3/src/hush-cli"; |
|||
my $getinfo = readfile("$dir/getinfo.json"); |
|||
my $template = readfile("/var/www/explorer.hush.is/address/template.html"); |
|||
my $addrdir = "/var/www/explorer.hush.is/address/"; |
|||
if($getinfo =~ m/"blocks": (\d+)/){ $STATS->{BLOCKS} ||= $1; } |
|||
if($getinfo =~ m/"tls_connections": (\d+)/){ $STATS->{TLS_CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"connections": (\d+)/){ $STATS->{CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"protocolversion": (\d+)/){ $STATS->{PROTOCOLVERSION} ||= $1; } |
|||
|
|||
my @symbols = qw/ |
|||
TX_TABLE ADDRESSES_TABLE TLS_CONNECTIONS CONNECTIONS PROTOCOLVERSION |
|||
/; |
|||
my @addresses; |
|||
my $height = $STATS->{BLOCKS}; |
|||
$STATS->{ADDRESSES_TABLE} = ""; |
|||
$STATS->{TX_TABLE} = ""; |
|||
|
|||
my $mineraddress = ""; |
|||
for my $h ($height-50 .. $height) { |
|||
my $thisminer = ""; |
|||
# TODO: fix this garbage |
|||
my $reward = $h > 340000 ? "3.125 HUSH" : "12.5 HUSH"; |
|||
my $block = get_block($h); |
|||
#die Dumper $block; |
|||
my $time = localtime($block->{time}) . " UTC" || ""; |
|||
my @txs = @{ $block->{tx} }; |
|||
my $numtx = @txs; |
|||
# TODO: look on filesystem first? redis cache? |
|||
my $hash = qx!$cli getblockhash $h!; |
|||
chomp $hash; |
|||
|
|||
my $root = "/var/www/explorer.hush.is"; |
|||
my $blockdir = "$root/block/$hash"; |
|||
if (!-e "$root/block/$h") { |
|||
# make /block/HEIGHT work |
|||
my $cmd = "ln -s $blockdir $root/block/$h"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
} |
|||
if (!-d $blockdir) { |
|||
# so explorer.hush.is/block/HASH works |
|||
my $cmd = "mkdir -p $blockdir"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
my $block_template_file = "$root/block/template.html"; |
|||
my $new_block_file = "$root/block/$hash/index.html"; |
|||
# TODO: process template with block details |
|||
my $block_template = readfile($block_template_file); |
|||
$block_template =~ s/#BLOCKS#/$h/g; |
|||
$block_template =~ s/#BLOCKHASH#/$hash/g; |
|||
$block_template =~ s/#PREVIOUSBLOCKHASH#/$block->{previousblockhash}/ge; |
|||
$block_template =~ s/#BLOCKTIME#/$time/g; |
|||
$block_template =~ s/#ANCHOR#/$block->{anchor}/ge; |
|||
$block_template =~ s/#VERSION#/$block->{version}/ge; |
|||
$block_template =~ s/#BITS#/$block->{bits}/ge; |
|||
$block_template =~ s/#BLOCKSIZE#/$block->{size}/ge; |
|||
$block_template =~ s/#CHAINWORK#/$block->{chainwork}/ge; |
|||
$block_template =~ s/#MERKLEROOT#/$block->{merkleroot}/ge; |
|||
$block_template =~ s/#FINALSAPLINGROOT#/$block->{finalsaplingroot}/ge; |
|||
# TODO |
|||
$block_template =~ s/#BLOCKREWARD#/3.125 HUSH/g; |
|||
$block_template =~ s/#BLOCKNONCE#/$block->{nonce}/ge; |
|||
$block_template =~ s/#DIFFICULTY#/$block->{difficulty}/ge; |
|||
$block_template =~ s/#NUM_TXS#/$numtx/g; |
|||
|
|||
my $txtype = ""; |
|||
# generate tx list table |
|||
$STATS->{TX_TABLE}=<<HTML; |
|||
<table border=1> |
|||
<tr><th>Transaction ID (txid)</th><th>Type</th><th>Inputs</th> |
|||
<th>Outputs</th><th>Shielded Inputs</th><th>Shielded Outputs</th> |
|||
<th>Addresses</th> |
|||
<th>Amount</th> |
|||
<th>Transaction Time</th> |
|||
<!-- |
|||
<th>Expiry Height</th> |
|||
<th>Lock Time</th> |
|||
--> |
|||
</tr> |
|||
HTML |
|||
|
|||
my $txi = 0; |
|||
for my $tx (@txs) { |
|||
my $json = qx!$cli getrawtransaction $tx 1!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
|
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
|
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($json); |
|||
$TX->{$tx} = $o; |
|||
my $tx_dir = "$root/tx/$tx"; |
|||
my $tx_file = "$root/tx/$tx/index.html"; |
|||
my $tx_template_file = "$root/tx/template.html"; |
|||
my $tx_template = readfile($tx_template_file); |
|||
my $txtime = localtime($o->{time}) . " UTC ( " . $o->{time} . " )"; |
|||
#my $txsize = $o->{size} . " bytes"; |
|||
$tx_template =~ s/#TXID#/$tx/ge; |
|||
$tx_template =~ s/#TXTIME#/$txtime/ge; |
|||
#$tx_template =~ s/#TXSIZE#/$txsize/g; |
|||
$tx_template =~ s/#BLOCKHEIGHT#/$h/ge; |
|||
$tx_template =~ s/#BLOCKHASH#/$hash/ge; |
|||
my ($vin,$vout,$zin,$zout) = ($o->{vin},$o->{vout},$o->{vShieldedSpend},$o->{vShieldedOutput}); |
|||
my $expiryheight = $o->{expiryheight} == 0 ? "Default" : $o->{expiryheight}; |
|||
my $locktime = localtime($o->{locktime}) . " UTC ( " . $o->{locktime} . " )"; |
|||
my $valueBalance = $o->{valueBalance} || "?"; |
|||
|
|||
my $vins = @$vin; |
|||
my $vouts = @$vout; |
|||
my $zins = @$zin; |
|||
my $zouts = @$zout; |
|||
my $coinbase = $vin->[0] ? $vin->[0]->{coinbase}." with sequence ".$vin->[0]->{sequence} : "False"; #($vin->[0] && $vin->[0]->{coinbase}) ? $vin->[0]{coinbase} . " with sequence " . $vin->{sequence} : "False"; |
|||
|
|||
# coinbase does not count as a transparent input |
|||
$vins-- if ($vin->[0] && $vin->[0]->{coinbase}); |
|||
|
|||
my $tx_data =<<DATA; |
|||
<table border=1> |
|||
<tr><th>Coinbase</th><td align=center>$coinbase</td></tr> |
|||
<tr><th>Expiry Height</th><td align=center>$expiryheight</td></tr> |
|||
<tr><th>Transparent Inputs</th><td align=center> $vins </td></tr> |
|||
<tr><th>Transparent Outputs</th><td align=center> $vouts </td></tr> |
|||
<tr><th>Shielded Inputs</th><td align=center> $zins </td></tr> |
|||
<tr><th>Shielded Outputs</th><td align=center> $zouts </td></tr> |
|||
<tr><th>Locktime</th><td align=center>$locktime</td></tr> |
|||
</table> |
|||
|
|||
DATA |
|||
$tx_template =~ s/#TX_DATA#/$tx_data/g; |
|||
|
|||
my $cmd = "mkdir -p $tx_dir"; |
|||
warn $cmd; |
|||
## create tx dir + page |
|||
qx{$cmd}; |
|||
|
|||
open(my $fh, '>', $tx_file) or die "$tx_file: $!"; |
|||
print $fh $tx_template; |
|||
close $fh or die $!; |
|||
|
|||
## create tx view on block page |
|||
my $from = $o->{vin}->[0] ? $o->{vin}->[0]->{address} : "zs1???"; |
|||
#my $to = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : "zs1???"; |
|||
my $to2 = ""; |
|||
# only look at coinbase tx's |
|||
if($txi == 0) { |
|||
# LEXICAL SCOPING BUG, MAN! |
|||
$mineraddress = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : ""; |
|||
$thisminer = $mineraddress; |
|||
} |
|||
say "<!-- miner for $tx is $mineraddress -->"; |
|||
my $to = $mineraddress ? $mineraddress : "zs1???"; |
|||
if($o->{vout}->[1]) { |
|||
$to2 = $o->{vout}->[1]->{scriptPubKey}->{addresses}->[0]; |
|||
} |
|||
$valueBalance = ($o->{vout}->[0]->{value} || 0) + ($o->{vout}->[1]->{value} || 0); |
|||
$valueBalance ||= "?"; |
|||
$from ||= ""; |
|||
|
|||
$txtype = "Mining"; |
|||
if($zins+$zouts>0) { |
|||
$txtype = "Shielded"; |
|||
if($zins==0 && $zouts>0) { $txtype = "Shielding"; } |
|||
if($vins==0 && $vouts==0){ $txtype = "Fully Shielded" } |
|||
# this is prevented by consensus rule on HUSH mainnet |
|||
# but if we see it, ring the bell, lulz |
|||
if($zins>0 && $zouts==0) { $txtype = "De-Shielding!"; } |
|||
} |
|||
#if($vouts>0) { $txtype = "DPoW"; } |
|||
my $stuff; |
|||
|
|||
if ($txtype eq "Mining") { |
|||
$stuff =<<STUFF; |
|||
<pre> |
|||
=> $to |
|||
=> $to2 |
|||
</pre> |
|||
<br/> |
|||
STUFF |
|||
} else { |
|||
#TODO: fix this shite |
|||
$stuff =<<STUFF; |
|||
<pre> |
|||
$from => $to |
|||
$from => $to2 |
|||
</pre> |
|||
<br/> |
|||
STUFF |
|||
} |
|||
|
|||
my $tx_table = <<HTML; |
|||
<tr> |
|||
<td><a href="/tx/$tx">$tx</a></td> |
|||
<td>$txtype</td> |
|||
<td align=center>$vins</td> |
|||
<td align=center>$vouts</td> |
|||
<td align=center>$zins</td> |
|||
<td align=center>$zouts</td> |
|||
<td>$stuff</td> |
|||
<td>$valueBalance HUSH</td> |
|||
<td>$txtime</td> |
|||
<!-- |
|||
<td>$expiryheight</td> |
|||
<td>$locktime</td> |
|||
--> |
|||
</tr> |
|||
HTML |
|||
$STATS->{TX_TABLE} .= $tx_table; |
|||
$txi++; |
|||
} |
|||
|
|||
$STATS->{TX_TABLE} .= "</table>"; |
|||
# $STATS->{TX_TABLE} .= "<pre>" . Dumper [ $vin ];'' |
|||
|
|||
$block_template =~ s/#TX_TABLE#/$STATS->{TX_TABLE}/ge; |
|||
|
|||
# > ? |
|||
open(my $fh, '>>', $new_block_file) or die "$new_block_file: $!"; |
|||
print $fh $block_template; |
|||
close $fh or die $!; |
|||
warn "wrote to $new_block_file "; |
|||
} else { |
|||
warn "block exists on disk, looking info up"; |
|||
#TODO: error-checking for corrupt data |
|||
#warn Dumper $block; |
|||
my $lookuptx = $block->{tx}->[0]; |
|||
my $o = get_raw($lookuptx); |
|||
$thisminer = $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0]; |
|||
warn "thisminer=$thisminer"; |
|||
} |
|||
|
|||
# give data to blocks after we have processed everything |
|||
my $b = [ $h, $hash, $reward,$time,$numtx,$thisminer,0 ]; |
|||
#warn Dumper $b; |
|||
push @addresses, $b; |
|||
} |
|||
|
|||
sub get_raw { |
|||
my $tx = shift; |
|||
my $cmd = "$cli getrawtransaction $tx 1"; |
|||
warn $cmd; |
|||
my $json = qx!$cmd!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($json); |
|||
return $o; |
|||
} |
|||
|
|||
# render data |
|||
for my $b (reverse @addresses) { |
|||
|
|||
$STATS->{ADDRESSES_TABLE} .= <<"FUCK"; |
|||
<tr> |
|||
<td align=center><a href="/block/$b->[0]">$b->[0]</a></td> |
|||
<td align=center><a href="/block/$b->[1]">$b->[1]</a></td> |
|||
<td align=center>$b->[2]</td> |
|||
<td align=center>$b->[3]</td> |
|||
<td align=center>$b->[4]</td> |
|||
<td align=center>$b->[5]</td> |
|||
</tr> |
|||
FUCK |
|||
} |
|||
|
|||
|
|||
|
|||
for my $s (@symbols) { |
|||
if($s && $STATS->{$s}) { $template =~ s/#$s#/$STATS->{$s}/ge } |
|||
} |
|||
|
|||
say $template; |
|||
|
|||
###### functions |
|||
|
|||
sub get_block { |
|||
my $height = shift; |
|||
my $dir = "/home/duke/data/blocks/"; |
|||
my $file = "$dir/block-$height.json"; |
|||
my $stats = {}; |
|||
my $block; |
|||
|
|||
# create data if it's not there |
|||
if( (!-e $file) || (-s $file == 0)) { |
|||
# logging? |
|||
my $cmd = "$cli getblock $height > /home/duke/data/blocks/block-$height.json"; |
|||
warn $cmd; |
|||
qx/$cmd/; |
|||
# let the file sync to disk |
|||
sleep 1; |
|||
} |
|||
my $json = readfile($file); |
|||
if($json) { |
|||
my $j = JSON::Any->new; |
|||
$block = $j->decode($json); |
|||
} else { |
|||
warn "empty block $height!!" unless $json; |
|||
warn Dumper [$json]; |
|||
} |
|||
|
|||
return $block; |
|||
} |
|||
|
|||
sub readfile { |
|||
my $file = shift; |
|||
my $data = ""; |
|||
open(my $fh, '<', $file) or die "$file: $!"; |
|||
my $txlist = 0; |
|||
while(<$fh>){ |
|||
$data.=$_ |
|||
} |
|||
close($fh); |
|||
return $data; |
|||
} |
@ -0,0 +1,7 @@ |
|||
#!/usr/bin/perl |
|||
use strict; |
|||
use warnings; |
|||
use Redis; |
|||
my $r = Redis->new; |
|||
|
|||
$r->set("test:123","fuck"); |
@ -0,0 +1,74 @@ |
|||
#!/usr/bin/env perl |
|||
use strict; |
|||
use warnings; |
|||
use 5.014; |
|||
my $STATS = {}; |
|||
$|=1; |
|||
|
|||
# give rpc's a chance to finish before us in cron |
|||
sleep 30; |
|||
|
|||
# While Siona swims, we pave with bricks on the road she will run on... |
|||
# my $dir = shift || $ENV{HOME} . "/data"; |
|||
my $dir = shift || '/var/www/explorer.hush.land/var/www/explorer.hush.land/api'; |
|||
my $getinfo = readfile("$dir/getinfo.json"); |
|||
my $mining = readfile("$dir/getmininginfo.json"); |
|||
my $txstats = readfile("$dir/getchaintxstats.json"); |
|||
# run the slowest last so the RPC interface isn't juggling |
|||
my $coinsupply = readfile("$dir/coinsupply.json"); |
|||
my $template = readfile("/var/www/explorer.hush.land/var/www/explorer.hush.land/template.html"); |
|||
|
|||
|
|||
#say $template; |
|||
#warn "<!--" . $STATS->{TLS_CONNECTIONS} . "/" . $STATS->{CONNECTIONS} . " peers connected via TLS -->"; |
|||
|
|||
my @symbols = qw/ |
|||
BLOCKS CONNECTIONS TLS_CONNECTIONS TXCOUNT |
|||
NOTARIZED ZFUNDS SUPPLY DIFFICULTY NETWORKSOLPS |
|||
PROTOCOLVERSION LONGESTCHAIN TIPTIME NOTARIZEDHASH |
|||
NOTARIZEDHEIGHT BLOCKHASH TXRATE |
|||
/; |
|||
|
|||
#if ($getinfo && $mining && $txstats && $coinsupply) { |
|||
for my $s (@symbols) { |
|||
if($s && $STATS->{$s}) { $template =~ s/#$s#/$STATS->{$s}/ge } |
|||
} |
|||
# derived stat |
|||
my $zpct = sprintf "%.3f", ($STATS->{SUPPLY} || 0) > 0 ? 100*($STATS->{ZFUNDS}/$STATS->{SUPPLY}) : "0.000"; |
|||
$template =~ s/#ZFUNDS_PERCENT#/$zpct/ge; |
|||
|
|||
say $template; |
|||
|
|||
#} |
|||
|
|||
sub readfile { |
|||
my $file = shift; |
|||
my $data = ""; |
|||
open(my $fh, '<', $file) or die $!; |
|||
while(<$fh>){ |
|||
$data.=$_; |
|||
# getinfo |
|||
if(m/"tls_connections": (\d+)/){ $STATS->{TLS_CONNECTIONS} ||= $1; } |
|||
if(m/"connections": (\d+)/){ $STATS->{CONNECTIONS} ||= $1; } |
|||
if(m/"blocks": (\d+)/){ $STATS->{BLOCKS} ||= $1; } |
|||
if(m/"notarized": (\d+)/){ $STATS->{NOTARIZED} ||= $1; } |
|||
if(m/"protocolversion": (\d+)/){ $STATS->{PROTOCOLVERSION} ||= $1; } |
|||
if(m/"longestchain": (\d+)/){ $STATS->{LONGESTCHAIN} ||= $1; } |
|||
if(m/"notarizedhash": "([a-z0-9]+)"/){ $STATS->{NOTARIZEDHASH} ||= $1; } |
|||
if(m/"tiptime": (\d+)/){ $STATS->{TIPTIME} ||= localtime($1) . "<!-- $1 -->"; } |
|||
# coinsupply |
|||
if(m/"zfunds": (\d+\.\d+)/){ $STATS->{ZFUNDS} ||= sprintf("%8.8f", $1); } |
|||
if(m/"total": (\d+\.\d+)/){ $STATS->{SUPPLY} ||= sprintf("%8.8f", $1); } |
|||
# getmininginfo |
|||
if(m/"difficulty": (\d+)/){ $STATS->{DIFFICULTY} ||= $1; } |
|||
if(m/"networksolps": (\d+)/){ $STATS->{NETWORKSOLPS} ||= sprintf("%.2f", $1 / 1_000_000); } |
|||
# getchaintxstats |
|||
if(m/"txcount": (\d+)/){ $STATS->{TXCOUNT} ||= $1; } |
|||
if(m/"txrate": (\d+\.\d+)/){ $STATS->{TXRATE} ||= sprintf("%.4f",$1*60); } |
|||
if(m/"window_final_block_hash": "([a-z0-9]+)"/){ $STATS->{BLOCKHASH} ||= $1; } |
|||
} |
|||
close($fh); |
|||
return $data; |
|||
} |
|||
# "connections": 48, |
|||
# "tls_connections": 28, |
@ -0,0 +1,375 @@ |
|||
#!/usr/bin/env perl |
|||
use strict; |
|||
use warnings; |
|||
use JSON::Any; |
|||
use Data::Dumper; |
|||
use 5.014; |
|||
my $STATS = {}; |
|||
$|=1; |
|||
|
|||
my $TX = {}; |
|||
|
|||
#sleep 10; |
|||
|
|||
# While Siona swims, we pave with bricks on the road she will run on... |
|||
my $dir = shift || '/var/www/explorer.hush.is/api/'; |
|||
my $cli = "/home/duke/git/hush3/src/hush-cli"; |
|||
my $getinfo = readfile("$dir/getinfo.json"); |
|||
my $mining = readfile("$dir/getmininginfo.json"); |
|||
my $template = readfile("/var/www/explorer.hush.is/blocks/template.html"); |
|||
my $blocksdir = "/var/www/explorer.hush.is/blocks/"; |
|||
if($getinfo =~ m/"blocks": (\d+)/){ $STATS->{BLOCKS} ||= $1; } |
|||
if($getinfo =~ m/"tls_connections": (\d+)/){ $STATS->{TLS_CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"connections": (\d+)/){ $STATS->{CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"protocolversion": (\d+)/){ $STATS->{PROTOCOLVERSION} ||= $1; } |
|||
|
|||
my @symbols = qw/ |
|||
TX_TABLE BLOCKS_TABLE TLS_CONNECTIONS CONNECTIONS PROTOCOLVERSION |
|||
/; |
|||
my @blocks = (); |
|||
my $height = $STATS->{BLOCKS}; |
|||
$STATS->{BLOCKS_TABLE} = ""; |
|||
$STATS->{TX_TABLE} = ""; |
|||
|
|||
my $NUM_BLOCKS = 50; |
|||
my $mineraddress = ""; |
|||
for my $h ($height-$NUM_BLOCKS .. $height) { |
|||
my $thisminer = ""; |
|||
# TODO: fix this garbage |
|||
my $reward = $h > 340000 ? "3.125 HUSH" : "12.5 HUSH"; |
|||
my $block = get_block($h); |
|||
#die Dumper $block; |
|||
my $time = $block->{time}; |
|||
my @txs = @{ $block->{tx} }; |
|||
my $numtx = @txs; |
|||
# TODO: look on filesystem first? redis cache? |
|||
my $hash = qx!$cli getblockhash $h!; |
|||
chomp $hash; |
|||
|
|||
my $root = "/var/www/explorer.hush.is"; |
|||
my $blockdir = "$root/block/$hash"; |
|||
if (!-e "$root/block/$h") { |
|||
# make /block/HEIGHT work |
|||
my $cmd = "ln -s $blockdir $root/block/$h"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
} |
|||
if (!-d $blockdir) { |
|||
# so explorer.hush.is/block/HASH works |
|||
my $cmd = "mkdir -p $blockdir"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
my $block_template_file = "$root/block/template.html"; |
|||
my $new_block_file = "$root/block/$hash/index.html"; |
|||
# TODO: process template with block details |
|||
my $block_template = readfile($block_template_file); |
|||
$block_template =~ s/#BLOCKS#/$h/g; |
|||
$block_template =~ s/#BLOCKHASH#/$hash/g; |
|||
$block_template =~ s/#PREVIOUSBLOCKHASH#/$block->{previousblockhash}/ge; |
|||
$block_template =~ s/#BLOCKTIME#/$time/g; |
|||
$block_template =~ s/#ANCHOR#/$block->{anchor}/ge; |
|||
$block_template =~ s/#VERSION#/$block->{version}/ge; |
|||
$block_template =~ s/#BITS#/$block->{bits}/ge; |
|||
$block_template =~ s/#BLOCKSIZE#/$block->{size}/ge; |
|||
$block_template =~ s/#CHAINWORK#/$block->{chainwork}/ge; |
|||
$block_template =~ s/#MERKLEROOT#/$block->{merkleroot}/ge; |
|||
$block_template =~ s/#FINALSAPLINGROOT#/$block->{finalsaplingroot}/ge; |
|||
# TODO |
|||
$block_template =~ s/#BLOCKREWARD#/3.125 HUSH/g; |
|||
$block_template =~ s/#BLOCKNONCE#/$block->{nonce}/ge; |
|||
$block_template =~ s/#DIFFICULTY#/$block->{difficulty}/ge; |
|||
$block_template =~ s/#NUM_TXS#/$numtx/g; |
|||
|
|||
my $txtype = ""; |
|||
# generate tx list table |
|||
$STATS->{TX_TABLE}=<<HTML; |
|||
<table border=1> |
|||
<tr><th>Transaction ID (txid)</th><th>Type</th><th>Inputs</th> |
|||
<th>Outputs</th><th>Shielded Inputs</th><th>Shielded Outputs</th> |
|||
<th>Addresses</th> |
|||
<th>Amount</th> |
|||
<th>Transaction Time</th> |
|||
<!-- |
|||
<th>Expiry Height</th> |
|||
<th>Lock Time</th> |
|||
--> |
|||
</tr> |
|||
HTML |
|||
|
|||
my $txi = 0; |
|||
for my $tx (@txs) { |
|||
my $json = qx!$cli getrawtransaction $tx 1!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
|
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
|
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($json); |
|||
$TX->{$tx} = $o; |
|||
my $tx_dir = "$root/tx/$tx"; |
|||
my $tx_file = "$root/tx/$tx/index.html"; |
|||
my $tx_template_file = "$root/tx/template.html"; |
|||
my $tx_template = readfile($tx_template_file); |
|||
my $txtime = localtime($o->{time}) . " UTC ( " . $o->{time} . " )"; |
|||
#my $txsize = $o->{size} . " bytes"; |
|||
$tx_template =~ s/#TXID#/$tx/ge; |
|||
$tx_template =~ s/#TXTIME#/$txtime/ge; |
|||
#$tx_template =~ s/#TXSIZE#/$txsize/g; |
|||
$tx_template =~ s/#BLOCKHEIGHT#/$h/ge; |
|||
$tx_template =~ s/#BLOCKHASH#/$hash/ge; |
|||
my ($vin,$vout,$zin,$zout) = ($o->{vin},$o->{vout},$o->{vShieldedSpend},$o->{vShieldedOutput}); |
|||
my $expiryheight = $o->{expiryheight} == 0 ? "Default" : $o->{expiryheight}; |
|||
my $locktime = localtime($o->{locktime}) . " UTC ( " . $o->{locktime} . " )"; |
|||
my $valueBalance = $o->{valueBalance} || "?"; |
|||
# "vShieldedOutput": [ |
|||
# { |
|||
# "cv": "61e0fed3b97e08e442408c7efc4058a9116695e6e28a22c0fbf0987fdfbcdd27", |
|||
# "cmu": "25245041af3bbc5a03da1cd6d60665f7659cbb3bab1080a6e003f856d45998fc", |
|||
# "ephemeralKey": "bffefb4f55679610bbdbd43bfba64308842348ba70bb999fad00c67356eab998", |
|||
# "encCiphertext": "b685c9d4f6164102999e88e3e30fcca37d9c402fc72533185d495a9d64f1fca277ead03aefe960eeaf102c0c92686a75c792ae8662f40601287ff19635581279d9c9940ba3c29af36166620422c6 |
|||
#49c4a7ca938734ceecb93a3abc8753ff3535950662ef46d8ed3a0608a61c65be5d0bdb1c262bd63fde759040eef74d4d81619ee154bbabe4fc0e27d82b19c6ed0d4cd806d5bc75ebbb13370ff3f19979ab3b74e859d9b88d3802 |
|||
#bc7a2ce7ae4305c6beec2146b374bda7234395d0aa390337e69ef5d04eddef0087244292f358b46eeb3c2a5a6d3bd1c89aaa4ebfd8bab58d2d4771b1d106db1a5dcead3b09cfc9fc38b972ce98c53d3cd658b02e58b087c7c73e |
|||
#0bd7cb093f2b15ab397094be5bc98f5865045d1845e548249fc811545db1645beb2f044366ba9ae584074e6fa5c03d786757c88ed8eff2d81570d15e64f192707d7393ce40b0f2f767cfbeaa5f05a634fe527da982241c92c4c2 |
|||
#9642f633115d34fe6791f00c8867e2242485de5f0bb87a8d4e6b375f557db6968f5ecc4f07b838b2dd85dd54e4e9ae2a28e9305bd1a6ae71adf75335d5f44cc046194fdbc91fb80202f06af9431716dc6627b2aa4723b0b8e4bb |
|||
#504649b6350ba9f020106d71248227ed8d7a10e2fbcbf64824c8923149822970b3c574614a8c32602106132c1209917974566b2990cf106666f985a2fa1f1409efdc457404700da210906b0f19be61c70d70eddc2f1cbffd94bb |
|||
#4c154a332fdd345ad06bd2ac86a339a93eae25db5eb3b4c6090d8483a8e5dd642231d17f3011b2f4b629ef72c08df1eeb6e7d06e", |
|||
# "outCiphertext": "53e3865f52101faf3218b60b7d58b9c426dc7c6cff009a8ceddd58031afe9802cae0f423a1085c2b36c776db29b57db8041e9bac42d6b445a0d69eb5a2f0ef61b4790595a68750c60889ff811dce |
|||
#8fbb", |
|||
# "proof": "82eda0f7de0936f6ca8208e63bda8db9970feb232ae64635e5bea67f16fdbe1b5e5e3a6bb7b7d2f0127c0d17de494834a82e899e8eecdfc71a59de8d1808a53df2989762bd54a855dadc535f2c5107d7b6da |
|||
#a732153c4dda4ac965be79ba2ecc030bd58e4c05d5ac7be283b3dc68af8a39231a31cccb54eae65c676760182bd22965f2e1c3685de44c0b93d84519bf138c7942222795dfdd0f683474b7c75221c9355109258805cc038ca43b |
|||
#26d5770bf25882326f4f508731b36a8632bc0012" |
|||
# } |
|||
# ], |
|||
|
|||
my $vins = @$vin; |
|||
my $vouts = @$vout; |
|||
my $zins = @$zin; |
|||
my $zouts = @$zout; |
|||
my $coinbase = $vin->[0] ? $vin->[0]->{coinbase}." with sequence ".$vin->[0]->{sequence} : "False"; #($vin->[0] && $vin->[0]->{coinbase}) ? $vin->[0]{coinbase} . " with sequence " . $vin->{sequence} : "False"; |
|||
|
|||
# coinbase does not count as a transparent input |
|||
$vins-- if ($vin->[0] && $vin->[0]->{coinbase}); |
|||
|
|||
my $tx_data =<<DATA; |
|||
<table border=1> |
|||
<tr><th>Coinbase</th><td align=center>$coinbase</td></tr> |
|||
<tr><th>Expiry Height</th><td align=center>$expiryheight</td></tr> |
|||
<tr><th>Transparent Inputs</th><td align=center> $vins </td></tr> |
|||
<tr><th>Transparent Outputs</th><td align=center> $vouts </td></tr> |
|||
<tr><th>Shielded Inputs</th><td align=center> $zins </td></tr> |
|||
<tr><th>Shielded Outputs</th><td align=center> $zouts </td></tr> |
|||
<tr><th>Locktime</th><td align=center>$locktime</td></tr> |
|||
</table> |
|||
|
|||
DATA |
|||
$tx_template =~ s/#TX_DATA#/$tx_data/g; |
|||
|
|||
my $cmd = "mkdir -p $tx_dir"; |
|||
warn $cmd; |
|||
## create tx dir + page |
|||
qx{$cmd}; |
|||
|
|||
open(my $fh, '>', $tx_file) or die "$tx_file: $!"; |
|||
print $fh $tx_template; |
|||
close $fh or die $!; |
|||
|
|||
## create tx view on block page |
|||
my $from = $o->{vin}->[0] ? $o->{vin}->[0]->{address} : "zs1???"; |
|||
#my $to = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : "zs1???"; |
|||
my $to2 = ""; |
|||
# only look at coinbase tx's |
|||
if($txi == 0) { |
|||
# LEXICAL SCOPING BUG, MAN! |
|||
$mineraddress = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : ""; |
|||
$thisminer = $mineraddress; |
|||
} |
|||
# say "<!-- miner for $tx is $mineraddress -->"; |
|||
my $to = $mineraddress ? $mineraddress : "zs1???"; |
|||
if($o->{vout}->[1]) { |
|||
$to2 = $o->{vout}->[1]->{scriptPubKey}->{addresses}->[0]; |
|||
} |
|||
$valueBalance = ($o->{vout}->[0]->{value} || 0) + ($o->{vout}->[1]->{value} || 0); |
|||
$valueBalance ||= "?"; |
|||
$from ||= ""; |
|||
|
|||
$txtype = "Mining"; |
|||
if($zins+$zouts>0) { |
|||
$txtype = "Shielded"; |
|||
if($zins==0 && $zouts>0) { $txtype = "Shielding"; } |
|||
if($vins==0 && $vouts==0){ $txtype = "Fully Shielded" } |
|||
# this is prevented by consensus rule on HUSH mainnet |
|||
# but if we see it, ring the bell, lulz |
|||
if($zins>0 && $zouts==0) { $txtype = "De-Shielding!"; } |
|||
} |
|||
#if($vouts>0) { $txtype = "DPoW"; } |
|||
my $stuff; |
|||
|
|||
if ($txtype eq "Mining") { |
|||
$stuff =<<STUFF; |
|||
<pre> |
|||
=> $to |
|||
=> $to2 |
|||
</pre> |
|||
<br/> |
|||
STUFF |
|||
} else { |
|||
#TODO: fix this shite |
|||
$stuff =<<STUFF; |
|||
<pre> |
|||
$from => $to |
|||
$from => $to2 |
|||
</pre> |
|||
<br/> |
|||
STUFF |
|||
} |
|||
|
|||
my $tx_table = <<HTML; |
|||
<tr> |
|||
<td><a href="/tx/$tx">$tx</a></td> |
|||
<td>$txtype</td> |
|||
<td align=center>$vins</td> |
|||
<td align=center>$vouts</td> |
|||
<td align=center>$zins</td> |
|||
<td align=center>$zouts</td> |
|||
<td>$stuff</td> |
|||
<td>$valueBalance HUSH</td> |
|||
<td>$txtime</td> |
|||
<!-- |
|||
<td>$expiryheight</td> |
|||
<td>$locktime</td> |
|||
--> |
|||
</tr> |
|||
HTML |
|||
$STATS->{TX_TABLE} .= $tx_table; |
|||
$txi++; |
|||
} |
|||
|
|||
$STATS->{TX_TABLE} .= "</table>"; |
|||
# $STATS->{TX_TABLE} .= "<pre>" . Dumper [ $vin ];'' |
|||
|
|||
$block_template =~ s/#TX_TABLE#/$STATS->{TX_TABLE}/ge; |
|||
|
|||
# > ? |
|||
open(my $fh, '>>', $new_block_file) or die "$new_block_file: $!"; |
|||
print $fh $block_template; |
|||
close $fh or die $!; |
|||
warn "wrote to $new_block_file "; |
|||
} else { |
|||
warn "block exists on disk, looking info up"; |
|||
#TODO: error-checking for corrupt data |
|||
#warn Dumper $block; |
|||
my $lookuptx = $block->{tx}->[0]; |
|||
my $o = get_raw($lookuptx); |
|||
$thisminer = $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0]; |
|||
warn "thisminer=$thisminer"; |
|||
} |
|||
|
|||
my $blockduration = 0; |
|||
if($#blocks >= 0) { |
|||
$blockduration = $time - $blocks[$#blocks]->[3]; |
|||
} |
|||
# give data to blocks after we have processed everything |
|||
my $b = [ $h, $hash, $reward,$time,$numtx,$thisminer, $blockduration ]; |
|||
#warn Dumper $b; |
|||
push @blocks, $b; |
|||
} |
|||
|
|||
sub get_raw { |
|||
my $tx = shift; |
|||
my $cmd = "$cli getrawtransaction $tx 1"; |
|||
warn $cmd; |
|||
my $json = qx!$cmd!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($json); |
|||
return $o; |
|||
} |
|||
|
|||
# render data |
|||
for my $b (reverse @blocks) { |
|||
my ($height,$hash,$reward,$time,$txs,$miner,$duration) = @$b; |
|||
|
|||
$time = localtime($time); |
|||
|
|||
# we can't calc the duration of the first block we look at, yet |
|||
$duration = "--" unless $duration; |
|||
|
|||
$STATS->{BLOCKS_TABLE} .= <<"FUCK"; |
|||
<tr> |
|||
<td align=center><a href="/block/$height">$height</a></td> |
|||
<td align=center><a href="/block/$hash">$hash</a></td> |
|||
<td align=center>$time UTC</td> |
|||
<td align=center>$duration s</td> |
|||
<td align=center>$miner</td> |
|||
<td align=center>$reward</td> |
|||
<td align=center>$txs</td> |
|||
</tr> |
|||
FUCK |
|||
} |
|||
|
|||
|
|||
|
|||
for my $s (@symbols) { |
|||
if($s && $STATS->{$s}) { $template =~ s/#$s#/$STATS->{$s}/ge } |
|||
} |
|||
|
|||
# derived stat |
|||
#my $zpct = sprintf "%.3f", $STATS->{SUPPLY} > 0 ? 100*($STATS->{ZFUNDS}/$STATS->{SUPPLY}) : "0.000"; |
|||
#$template =~ s/#ZFUNDS_PERCENT#/$zpct/ge; |
|||
|
|||
say $template; |
|||
|
|||
###### functions |
|||
|
|||
sub get_block { |
|||
my $height = shift; |
|||
my $dir = "/home/duke/data/blocks/"; |
|||
my $file = "$dir/block-$height.json"; |
|||
my $stats = {}; |
|||
my $block; |
|||
|
|||
# create data if it's not there |
|||
if( (!-e $file) || (-s $file == 0)) { |
|||
# logging? |
|||
my $cmd = "$cli getblock $height > /home/duke/data/blocks/block-$height.json"; |
|||
warn $cmd; |
|||
qx/$cmd/; |
|||
# let the file sync to disk |
|||
sleep 1; |
|||
} |
|||
my $json = readfile($file); |
|||
if($json) { |
|||
my $j = JSON::Any->new; |
|||
$block = $j->decode($json); |
|||
} else { |
|||
warn "empty block $height!!" unless $json; |
|||
warn Dumper [$json]; |
|||
} |
|||
|
|||
return $block; |
|||
} |
|||
|
|||
sub readfile { |
|||
my $file = shift; |
|||
my $data = ""; |
|||
open(my $fh, '<', $file) or die "$file: $!"; |
|||
my $txlist = 0; |
|||
while(<$fh>){ |
|||
$data.=$_ |
|||
} |
|||
close($fh); |
|||
return $data; |
|||
} |
@ -0,0 +1,408 @@ |
|||
#!/usr/bin/env perl |
|||
use strict; |
|||
use warnings; |
|||
use JSON::Any; |
|||
use Data::Dumper; |
|||
use Redis; |
|||
use 5.014; |
|||
my $STATS = {}; |
|||
$|=1; |
|||
|
|||
my $TX = {}; |
|||
my $r = Redis->new; |
|||
my $j = JSON::Any->new; |
|||
|
|||
#sleep 10; |
|||
|
|||
# While Siona swims, we pave with bricks on the road she will run on... |
|||
my $dir = shift || '/var/www/explorer.hush.land/var/www/explorer.hush.land/api'; |
|||
my $cli = "/home/hush/git/hush3/src/hush-cli"; |
|||
my $getinfo = readfile("$dir/getinfo.json"); |
|||
my $mining = readfile("$dir/getmininginfo.json"); |
|||
my $template = readfile("/var/www/explorer.hush.land/var/www/explorer.hush.land/blocks/template.html"); |
|||
my $blocksdir = "/var/www/explorer.hush.land/var/www/explorer.hush.land/blocks/"; |
|||
if($getinfo =~ m/"blocks": (\d+)/){ $STATS->{BLOCKS} ||= $1; } |
|||
if($getinfo =~ m/"tls_connections": (\d+)/){ $STATS->{TLS_CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"connections": (\d+)/){ $STATS->{CONNECTIONS} ||= $1; } |
|||
if($getinfo =~ m/"protocolversion": (\d+)/){ $STATS->{PROTOCOLVERSION} ||= $1; } |
|||
|
|||
my @symbols = qw/ |
|||
TX_TABLE BLOCKS_TABLE TLS_CONNECTIONS CONNECTIONS PROTOCOLVERSION |
|||
/; |
|||
my @blocks = (); |
|||
my $height = $STATS->{BLOCKS} || 0; |
|||
$STATS->{BLOCKS_TABLE} = ""; |
|||
$STATS->{TX_TABLE} = ""; |
|||
|
|||
my $mineraddress = ""; |
|||
for my $h ($height-80 .. $height) { |
|||
#for my $h (910265 .. 910270) { |
|||
#last if($h < 0); |
|||
my $thisminer = ""; |
|||
# TODO: fix this garbage |
|||
my $reward = $h > 340000 ? "3.125 HUSH" : "12.5 HUSH"; |
|||
my $block = get_block($h); |
|||
#die Dumper $block; |
|||
my $time = $block->{time}; |
|||
die Dumper [ $block ] unless $block->{time} and $block->{tx}; |
|||
my @txs = @{ $block->{tx} }; |
|||
my $numtx = @txs; |
|||
# TODO: look on filesystem first? redis cache? |
|||
my $hash = qx!$cli getblockhash $h!; |
|||
chomp $hash; |
|||
|
|||
my $root = "/var/www/explorer.hush.land"; |
|||
my $blockdir = "$root/var/www/explorer.hush.land/block/$hash"; |
|||
if (!-e "$root/block/$h") { |
|||
# make /block/HEIGHT work |
|||
my $cmd = "ln -s $blockdir $root/var/www/explorer.hush.land/block/$h"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
} |
|||
if (!-d $blockdir) { |
|||
# so explorer.hush.is/block/HASH works |
|||
my $cmd = "mkdir -p $blockdir"; |
|||
qx{$cmd}; |
|||
warn $cmd; |
|||
my $block_template_file = "/var/www/explorer.hush.land/var/www/explorer.hush.land/block/template.html"; |
|||
my $new_block_file = "/var/www/explorer.hush.land/var/www/explorer.hush.land/block/$hash/index.html"; |
|||
# TODO: process template with block details |
|||
my $block_template = readfile($block_template_file); |
|||
$block_template =~ s/#BLOCKS#/$h/g; |
|||
$block_template =~ s/#BLOCKHASH#/$hash/g; |
|||
$block_template =~ s/#PREVIOUSBLOCKHASH#/$block->{previousblockhash}/ge; |
|||
$block_template =~ s/#BLOCKTIME#/$time/g; |
|||
$block_template =~ s/#ANCHOR#/$block->{anchor}/ge; |
|||
$block_template =~ s/#VERSION#/$block->{version}/ge; |
|||
$block_template =~ s/#BITS#/$block->{bits}/ge; |
|||
$block_template =~ s/#BLOCKSIZE#/$block->{size}/ge; |
|||
$block_template =~ s/#CHAINWORK#/$block->{chainwork}/ge; |
|||
$block_template =~ s/#MERKLEROOT#/$block->{merkleroot}/ge; |
|||
$block_template =~ s/#FINALSAPLINGROOT#/$block->{finalsaplingroot}/ge; |
|||
# TODO |
|||
$block_template =~ s/#BLOCKREWARD#/3.125 HUSH/g; |
|||
$block_template =~ s/#BLOCKNONCE#/$block->{nonce}/ge; |
|||
$block_template =~ s/#DIFFICULTY#/$block->{difficulty}/ge; |
|||
$block_template =~ s/#NUM_TXS#/$numtx/g; |
|||
|
|||
my $txtype = ""; |
|||
# generate tx list table |
|||
$STATS->{TX_TABLE}=<<HTML; |
|||
|
|||
|
|||
HTML |
|||
|
|||
my $txi = 0; |
|||
for my $tx (@txs) { |
|||
my $json = qx!$cli getrawtransaction $tx 1!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
|
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
|
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
# add tx json to Redis, indexed by txid |
|||
$r->set("tx:$tx", $json); |
|||
|
|||
my $j = JSON::Any->new; |
|||
my $o; |
|||
eval { |
|||
$o = $j->decode($json); |
|||
}; |
|||
next if $@; |
|||
|
|||
$TX->{$tx} = $o; |
|||
my $tx_dir = "$root/var/www/explorer.hush.land/tx/$tx"; |
|||
my $tx_file = "$root/var/www/explorer.hush.land/tx/$tx/index.html"; |
|||
my $tx_template_file = "$root/var/www/explorer.hush.land/tx/template.html"; |
|||
my $tx_template = readfile($tx_template_file); |
|||
my $txtime = localtime($o->{time}); |
|||
#my $txsize = $o->{size} . " bytes"; |
|||
$tx_template =~ s/#TXID#/$tx/ge; |
|||
$tx_template =~ s/#TXTIME#/$txtime/ge; |
|||
#$tx_template =~ s/#TXSIZE#/$txsize/g; |
|||
$tx_template =~ s/#BLOCKHEIGHT#/$h/ge; |
|||
$tx_template =~ s/#BLOCKHASH#/$hash/ge; |
|||
my ($vin,$vout,$zin,$zout) = ($o->{vin},$o->{vout},$o->{vShieldedSpend},$o->{vShieldedOutput}); |
|||
my $expiryheight = $o->{expiryheight} == 0 ? "Default" : $o->{expiryheight}; |
|||
my $locktime = localtime($o->{locktime}); |
|||
my $valueBalance = $o->{valueBalance} || "?"; |
|||
my $valueBalanceSecond = $o->{valueBalance}; |
|||
my $valueBalanceThird = abs($valueBalanceSecond); |
|||
# "vShieldedOutput": [ |
|||
# { |
|||
# "cv": "61e0fed3b97e08e442408c7efc4058a9116695e6e28a22c0fbf0987fdfbcdd27", |
|||
# "cmu": "25245041af3bbc5a03da1cd6d60665f7659cbb3bab1080a6e003f856d45998fc", |
|||
# "ephemeralKey": "bffefb4f55679610bbdbd43bfba64308842348ba70bb999fad00c67356eab998", |
|||
# "encCiphertext": "b685c9d4f6164102999e88e3e30fcca37d9c402fc72533185d495a9d64f1fca277ead03aefe960eeaf102c0c92686a75c792ae8662f40601287ff19635581279d9c9940ba3c29af36166620422c6 |
|||
#49c4a7ca938734ceecb93a3abc8753ff3535950662ef46d8ed3a0608a61c65be5d0bdb1c262bd63fde759040eef74d4d81619ee154bbabe4fc0e27d82b19c6ed0d4cd806d5bc75ebbb13370ff3f19979ab3b74e859d9b88d3802 |
|||
#bc7a2ce7ae4305c6beec2146b374bda7234395d0aa390337e69ef5d04eddef0087244292f358b46eeb3c2a5a6d3bd1c89aaa4ebfd8bab58d2d4771b1d106db1a5dcead3b09cfc9fc38b972ce98c53d3cd658b02e58b087c7c73e |
|||
#0bd7cb093f2b15ab397094be5bc98f5865045d1845e548249fc811545db1645beb2f044366ba9ae584074e6fa5c03d786757c88ed8eff2d81570d15e64f192707d7393ce40b0f2f767cfbeaa5f05a634fe527da982241c92c4c2 |
|||
#9642f633115d34fe6791f00c8867e2242485de5f0bb87a8d4e6b375f557db6968f5ecc4f07b838b2dd85dd54e4e9ae2a28e9305bd1a6ae71adf75335d5f44cc046194fdbc91fb80202f06af9431716dc6627b2aa4723b0b8e4bb |
|||
#504649b6350ba9f020106d71248227ed8d7a10e2fbcbf64824c8923149822970b3c574614a8c32602106132c1209917974566b2990cf106666f985a2fa1f1409efdc457404700da210906b0f19be61c70d70eddc2f1cbffd94bb |
|||
#4c154a332fdd345ad06bd2ac86a339a93eae25db5eb3b4c6090d8483a8e5dd642231d17f3011b2f4b629ef72c08df1eeb6e7d06e", |
|||
# "outCiphertext": "53e3865f52101faf3218b60b7d58b9c426dc7c6cff009a8ceddd58031afe9802cae0f423a1085c2b36c776db29b57db8041e9bac42d6b445a0d69eb5a2f0ef61b4790595a68750c60889ff811dce |
|||
#8fbb", |
|||
# "proof": "82eda0f7de0936f6ca8208e63bda8db9970feb232ae64635e5bea67f16fdbe1b5e5e3a6bb7b7d2f0127c0d17de494834a82e899e8eecdfc71a59de8d1808a53df2989762bd54a855dadc535f2c5107d7b6da |
|||
#a732153c4dda4ac965be79ba2ecc030bd58e4c05d5ac7be283b3dc68af8a39231a31cccb54eae65c676760182bd22965f2e1c3685de44c0b93d84519bf138c7942222795dfdd0f683474b7c75221c9355109258805cc038ca43b |
|||
#26d5770bf25882326f4f508731b36a8632bc0012" |
|||
# } |
|||
# ], |
|||
|
|||
my $vins = @$vin; |
|||
my $vouts = @$vout; |
|||
my $zins = @$zin; |
|||
my $zouts = @$zout; |
|||
my $coinbase = $vin->[0] ? $vin->[0]->{coinbase}." with sequence ".$vin->[0]->{sequence} : "False"; #($vin->[0] && $vin->[0]->{coinbase}) ? $vin->[0]{coinbase} . " with sequence " . $vin->{sequence} : "False"; |
|||
|
|||
# coinbase does not count as a transparent input |
|||
$vins-- if ($vin->[0] && $vin->[0]->{coinbase}); |
|||
|
|||
my $tx_data =<<DATA; |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Coinbase: $coinbase</td> |
|||
<td style="font-size: 14px; width: 50%">Locktime: $locktime</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Transparent Inputs: $vins </td> |
|||
<td style="font-size: 14px; width: 50%">Transparent Outputs: $vouts </td> |
|||
</tr> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Shielded Inputs: $zins </td> |
|||
<td style="font-size: 14px; width: 50%">Shielded Outputs: $zouts </td> |
|||
</tr> |
|||
DATA |
|||
$tx_template =~ s/#TX_DATA#/$tx_data/g; |
|||
|
|||
my $cmd = "mkdir -p $tx_dir"; |
|||
warn $cmd; |
|||
## create tx dir + page |
|||
qx{$cmd}; |
|||
|
|||
open(my $fh, '>', $tx_file) or die "$tx_file: $!"; |
|||
print $fh $tx_template; |
|||
close $fh or die $!; |
|||
|
|||
## create tx view on block page |
|||
my $from = $o->{vin}->[0] ? $o->{vin}->[0]->{address} : "zs1???"; |
|||
#my $to = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : "zs1???"; |
|||
my $to2 = ""; |
|||
my $to3 = ""; |
|||
# only look at coinbase tx's |
|||
if($txi == 0) { |
|||
# LEXICAL SCOPING BUG, MAN! |
|||
$mineraddress = $o->{vout}->[0] ? $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0] : ""; |
|||
$thisminer = $mineraddress; |
|||
} |
|||
# say "<!-- miner for $tx is $mineraddress -->"; |
|||
my $to = $mineraddress ? $mineraddress : "zs1???"; |
|||
if($o->{vout}->[1]) { |
|||
$to2 = $o->{vout}->[1]->{scriptPubKey}->{addresses}->[0]; |
|||
} |
|||
if($o->{vout}->[0]) { |
|||
$to3 = $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0]; |
|||
} |
|||
$valueBalance = ($o->{vout}->[0]->{value} || 0) + ($o->{vout}->[1]->{value} || 0); |
|||
$valueBalance ||= "?"; |
|||
$from ||= ""; |
|||
|
|||
$txtype = "Mining"; |
|||
if($zins+$zouts>0) { |
|||
$txtype = "Shielded"; |
|||
if($zins==0 && $zouts>0) { $txtype = "Shielding"; } |
|||
if($vins==0 && $vouts==1 && $zins==1 && $zouts==8){ $txtype = "Notary" } |
|||
if($vins==1 && $vouts==14 && $zins==0 && $zouts==0){ $txtype = "dPoW" } |
|||
if($vins==0 && $vouts==0){ $txtype = "Fully Shielded" } |
|||
# this is prevented by consensus rule on HUSH mainnet |
|||
# but if we see it, ring the bell, lulz |
|||
if($zins>0 && $zouts==0) { $txtype = "De-Shielding!"; } |
|||
} |
|||
#if($vouts>0) { $txtype = "DPoW"; } |
|||
my $stuff; |
|||
|
|||
if ($txtype eq "Mining") { |
|||
$stuff =<<STUFF; |
|||
|
|||
=> $to (miner) |
|||
<br> |
|||
=> $to2 (FR address) |
|||
STUFF |
|||
} elsif ($txtype eq "Shielding") { |
|||
$stuff =<<STUFF; |
|||
|
|||
$from ($valueBalanceThird HUSH) => zs1??? (shielding) |
|||
|
|||
STUFF |
|||
} elsif ($txtype eq "Notary") { |
|||
$stuff =<<STUFF; |
|||
|
|||
zs1??? => $to3 (notary) |
|||
<br> |
|||
zs1??? => zs1??? (shielded change) |
|||
|
|||
STUFF |
|||
} elsif ($txtype eq "dPoW") { |
|||
$stuff =<<STUFF; |
|||
|
|||
=> $to2 (FR address) |
|||
<br> |
|||
=> $to2 (notary) |
|||
|
|||
STUFF |
|||
} else { |
|||
$stuff =<<STUFF; |
|||
|
|||
$from => zs1??? (fully shielded) |
|||
|
|||
STUFF |
|||
} |
|||
|
|||
my $tx_table = <<HTML; |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px"><a href="/tx/$tx" class="mainlinkexplorer">$tx</a></td> |
|||
<td style="font-size: 14px">vins: $vins, vouts: $vouts</td> |
|||
<td style="font-size: 14px">zins: $zins, zouts: $zouts</td> |
|||
</tr> |
|||
<tr> |
|||
<td style="font-size: 14px">$stuff</td> |
|||
<td style="font-size: 14px">$txtime</td> |
|||
<td style="font-size: 14px">$valueBalance HUSH</td> |
|||
</tr> |
|||
</table> |
|||
HTML |
|||
$STATS->{TX_TABLE} .= $tx_table; |
|||
$txi++; |
|||
} |
|||
|
|||
# $STATS->{TX_TABLE} .= "</table>"; |
|||
# $STATS->{TX_TABLE} .= "<pre>" . Dumper [ $vin ];'' |
|||
|
|||
$block_template =~ s/#TX_TABLE#/$STATS->{TX_TABLE}/ge; |
|||
|
|||
# > ? |
|||
open(my $fh, '>>', $new_block_file) or die "$new_block_file: $!"; |
|||
print $fh $block_template; |
|||
close $fh or die $!; |
|||
warn "wrote to $new_block_file "; |
|||
} else { |
|||
warn "block exists on disk, looking info up"; |
|||
#TODO: error-checking for corrupt data |
|||
#warn Dumper $block; |
|||
my $lookuptx = $block->{tx}->[0]; |
|||
my $o = get_raw($lookuptx); |
|||
$thisminer = $o->{vout}->[0]->{scriptPubKey}->{addresses}->[0]; |
|||
warn "thisminer=$thisminer"; |
|||
} |
|||
|
|||
my $blockduration = 0; |
|||
if($#blocks >= 0) { |
|||
$blockduration = $time - $blocks[$#blocks]->[3]; |
|||
} |
|||
# give data to blocks after we have processed everything |
|||
my $b = [ $h, $hash, $reward,$time,$numtx,$thisminer, $blockduration ]; |
|||
#warn Dumper $b; |
|||
push @blocks, $b; |
|||
; |
|||
} |
|||
|
|||
sub get_raw { |
|||
my $tx = shift; |
|||
my $cmd = "$cli getrawtransaction $tx 1"; |
|||
warn $cmd; |
|||
my $json = qx!$cmd!; |
|||
# "vout": 0, |
|||
# "address": "RBHHGTQoULWb8gPD6Nj4fix6ov46hzzQMj", |
|||
# address is duplicated in the JSON of getrawtransaction !! fuck. |
|||
# KMD or ZEC upstream bug? |
|||
$json =~ s/"vout": 0,\w*"address": "([a-z0-9]+)",/"vout": 0,/mg; |
|||
# Satoshi Forgive Me |
|||
$json =~ s/"address":\w+"([a-z0-9]+)"(.+)"address":\w+"\g1"(.+)/"address": "$1"$2/mg; |
|||
warn "decoding tx=$tx"; # with json=$json"; |
|||
my $j = JSON::Any->new; |
|||
my $o = $j->decode($json); |
|||
return $o; |
|||
} |
|||
|
|||
# render data |
|||
for my $b (reverse @blocks) { |
|||
my ($height,$hash,$reward,$time,$txs,$miner,$duration) = @$b; |
|||
|
|||
$time = localtime($time); |
|||
|
|||
# we can't calc the duration of the first block we look at, yet |
|||
$duration = "--" unless $duration; |
|||
|
|||
$STATS->{BLOCKS_TABLE} .= <<"FUCK"; |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px"><a href="/block/$height/" class="mainlinkexplorer">$height</a></td> |
|||
<td style="font-size: 14px"><a href="/block/$hash/" class="mainlinkexplorer">$hash</a></td> |
|||
<td style="font-size: 14px">$time</td> |
|||
</tr> |
|||
<tr> |
|||
<td style="font-size: 14px">${duration}s</td> |
|||
<td style="font-size: 14px">$miner + $reward</td> |
|||
<td style="font-size: 14px">Transactions: $txs</td> |
|||
</tr> |
|||
</table> |
|||
FUCK |
|||
} |
|||
|
|||
|
|||
|
|||
for my $s (@symbols) { |
|||
if($s && $STATS->{$s}) { $template =~ s/#$s#/$STATS->{$s}/ge } |
|||
} |
|||
|
|||
# derived stat |
|||
#my $zpct = sprintf "%.3f", $STATS->{SUPPLY} > 0 ? 100*($STATS->{ZFUNDS}/$STATS->{SUPPLY}) : "0.000"; |
|||
#$template =~ s/#ZFUNDS_PERCENT#/$zpct/ge; |
|||
|
|||
say $template; |
|||
|
|||
###### functions |
|||
|
|||
# get block at given height |
|||
sub get_block { |
|||
my $height = shift; |
|||
return if $height < 0; |
|||
my $block = $r->get("block:$height") || ''; |
|||
|
|||
# create data if it's not there |
|||
if( $block =~ m/^HASH/ || length($block) == 0 ) { |
|||
my $cmd = "$cli getblock $height"; |
|||
warn $cmd; |
|||
$block = qx/$cmd/; |
|||
} |
|||
my $json = $block; |
|||
if($json) { |
|||
$block = $j->decode($json); |
|||
# cache in Redis |
|||
warn Dumper [ "redis set block:$height =>", $json ]; |
|||
$r->set("block:$height",$json); |
|||
} else { |
|||
warn "empty block $height!!" unless $json; |
|||
warn Dumper [$json]; |
|||
} |
|||
|
|||
return $block; |
|||
} |
|||
|
|||
sub readfile { |
|||
my $file = shift; |
|||
my $data = ""; |
|||
open(my $fh, '<', $file) or die "$file: $!"; |
|||
my $txlist = 0; |
|||
while(<$fh>){ |
|||
$data.=$_ |
|||
} |
|||
close($fh); |
|||
return $data; |
|||
} |
@ -0,0 +1,23 @@ |
|||
# cron jobs to run explorer |
|||
|
|||
``` |
|||
# m h dom mon dow command |
|||
|
|||
*/7 * * * * ./update_explorer_data.sh |
|||
*/5 * * * * ./update_api.sh |
|||
#*/7 * * * * ./hush_cron.sh |
|||
|
|||
|
|||
# restart hushd every 4 hours |
|||
# start it if it's not running |
|||
20 */4 * * * ./restart-hushd.sh |
|||
|
|||
*/10 * * * * /var/www/explorer.hush.land/update.sh |
|||
|
|||
``` |
|||
|
|||
Restarting hushd used to be needed before the LOCK bug fixed in dev (which will be in 3.9.1), so |
|||
that is optional if you are using the latest code. |
|||
|
|||
The times the cronjobs run are specifically chosen to try and run in a specific order, since |
|||
the output of one cron is used in another. |
@ -0,0 +1,13 @@ |
|||
#!/bin/bash |
|||
DIR=/var/www/explorer.hush.land/var/www/explorer.hush.land/api |
|||
|
|||
# TODO: remove IP info from getpeerinfo |
|||
#~/git/hush3/src/hush-cli getpeerinfo > $DIR/getpeerinfo.json |
|||
~/git/hush3/src/hush-cli getinfo &> $DIR/getinfo.json |
|||
~/git/hush3/src/hush-cli getmininginfo &> $DIR/getmininginfo.json |
|||
~/git/hush3/src/hush-cli getblockchaininfo &> $DIR/getblockchain.json |
|||
~/git/hush3/src/hush-cli getchaintxstats &> $DIR/getchaintxstats.json |
|||
~/git/hush3/src/hush-cli gettxoutsetinfo &> $DIR/gettxoutsetinfo.json |
|||
~/git/hush3/src/hush-cli coinsupply &> $DIR/coinsupply.json |
|||
~/git/hush3/src/hush-cli getchaintips &> $DIR/getchaintips.json |
|||
~/git/hush3/src/hush-cli getchaintxstats &> $DIR/getchaintxstats.json |
@ -0,0 +1,18 @@ |
|||
#!/bin/bash |
|||
|
|||
cli=~/git/hush3/src/hush-cli |
|||
|
|||
# only ask for data if we don't have it |
|||
#if [ -s ~/data/blocks/block-$HEIGHT.json ]; then |
|||
# HEIGHT=$($cli getblockcount); $cli getblock $HEIGHT > ~/data/blocks/block-$HEIGHT.json |
|||
#fi |
|||
|
|||
NEWFILE=/var/www/explorer.hush.land/var/www/explorer.hush.land/blocks/index.new.html |
|||
INDEXFILE=/var/www/explorer.hush.land/var/www/explorer.hush.land/blocks/index.html |
|||
|
|||
# reads data from /var/www/explorer.hush.is/api |
|||
#~/git/explorer.hush.is/bin/update_blocks.pl > $NEWFILE |
|||
/var/www/explorer.hush.land/bin/update_blocks_redis.pl > $NEWFILE |
|||
if [ -s $NEWFILE ]; then |
|||
cp $NEWFILE $INDEXFILE |
|||
fi |
@ -0,0 +1,12 @@ |
|||
226212 |
|||
226355 |
|||
226361 |
|||
226664 |
|||
227090 |
|||
227309 |
|||
227738 |
|||
227933 |
|||
228039 |
|||
228062 |
|||
228077 |
|||
228090 |
@ -0,0 +1,84 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>Hush Explorer: Speak And Transact Freely</title> |
|||
<style> |
|||
body { |
|||
width: 95%; |
|||
margin: 5 auto; |
|||
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; |
|||
background: #111111; |
|||
color: #cccccc; |
|||
} |
|||
a:link { color: #888888; } |
|||
a:visited { color: #888888; } |
|||
a:hover { color: #554200; } |
|||
a:active { color: #550000; } |
|||
</style> |
|||
<!-- |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
{ Fuck Blockchain Analysts } |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
\ ^__^ |
|||
\ (@@)\_______ |
|||
(__)\ )\/\ |
|||
||----w | |
|||
|| || |
|||
|
|||
- Duke Leto and The Hush Developers |
|||
--> |
|||
</head> |
|||
<body> |
|||
<center> |
|||
<br/> |
|||
<br/> |
|||
<a href="https://hush.is">Hush</a> | <a href="https://explorer.hush.is">Explorer</a> |
|||
| <a href="https://hush.is/twitter">Twitter</a> | <a href="https://hush.is/tg">Telegram</a> | |
|||
<a href="https://hush.is/telegram_support">Telegram Support</a> | <a href="https://hush.is/telegram_mining">Telegram Mining</a> |
|||
| <a href="https://hush.is/reddit">Reddit</a> | <a href="https://hush.is/youtube">YouTube</a> |
|||
| <a href="https://hush.is/bitcointalk">BitcoinTalk</a> | <a href="https://hush.is/mastodon">Mastodon</a> |
|||
| <a href="https://hush.is/matrix">Matrix</a> |
|||
<br/> |
|||
<h1>HUSH Blockchain Explorer</h1> |
|||
<div id=navbar> |
|||
<a href="/blocks/">Blocks</a> |
|||
</div> |
|||
<div id=stats> |
|||
<table width="100%" border=1> |
|||
<tr> |
|||
<td align=center> |
|||
<table> |
|||
<tr><th>Address</th><td><a href="/address/#ADDRESS#">#ADDRESS#</a></td></tr> |
|||
<tr><th>Transactions</th><td>#TXS#</td></tr> |
|||
</table> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td align=center> |
|||
#ADDRESS_DATA# |
|||
|
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
<br> |
|||
|
|||
</center> |
|||
|
|||
<font color=red> |
|||
<pre> |
|||
|
|||
_____________ |
|||
< Extreme!!!! > |
|||
------------- |
|||
\ ^__^ |
|||
\ (@@)\_______ |
|||
(__)\ )\/\ |
|||
||----w | |
|||
|| || |
|||
|
|||
</pre> |
|||
</font> |
|||
|
|||
</body> |
|||
</html> |
@ -0,0 +1,78 @@ |
|||
<!doctype html> |
|||
<head> |
|||
<title>Home | Hush - Transact and Speak Freely</title> |
|||
<style> |
|||
body { background-color: #101010; max-width: 850px; margin: auto; font-family: 'Ubuntu Mono'; color: #b3b3b3; text-align: center } |
|||
table { width: 100%; border-collapse: collapse; margin-top: 15px } |
|||
td { border: 1px solid #1a1a1a; font-size: 16px; padding: 0.5em } |
|||
td:hover { background-color: #1a1a1a } |
|||
pre { background-color: #0d0d0d; border: 1px solid #1a1a1a; font-size: 6px; padding: 15px; color: #e6e6e6 } |
|||
details { cursor: pointer; background-color: #0d0d0d; text-align: left; margin-top: 15px; padding: 0.5em; border: 1px solid #1a1a1a; font-size: 13px; word-wrap: break-word } |
|||
summary { outline: none; padding: 0.4em } |
|||
.blockt { border: 1px solid #1a1a1a; padding: 0.15em; background-color: #0d0d0d; margin-top: 15px; text-align: left; font-size: 13px; word-wrap: break-word } |
|||
.blockt p { padding-left: 0.7em; padding-right: 0.7em } |
|||
.button:link { float: right; font-size: 11px } |
|||
.mainlinkexplorer:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlinkexplorer:hover { text-decoration: none; color: #595959 } |
|||
.links { margin: 15px; font-size: 13px } |
|||
a:link { color: #b3b3b3; text-decoration: none } |
|||
a:visited { color: #b3b3b3 } |
|||
a:hover { color: #b3b3b3 } |
|||
* { scrollbar-width: thin; scrollbar-color: #333333 #101010 } |
|||
::-webkit-scrollbar { width: 6px } |
|||
::-webkit-scrollbar-thumb { background: #333333 } |
|||
@font-face { font-family: 'Ubuntu Mono'; src: url('../UbuntuMono.ttf') format('truetype') } |
|||
</style> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h2>Hush - Speak and Transact Freely</h2> |
|||
<h3>Private Cryptocurrency and Messenger using Zero Knowledge Mathematics</h3> |
|||
<pre> |
|||
&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&& &&&&&& &&&& &&&&&& &&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& &&&&& |
|||
&&&&& &&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& |
|||
&&&&& &&&& &&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&& &&&&&& && && &&&&&& &&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& |
|||
&&&& <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="button">.onion</a> |
|||
</pre> |
|||
<table> |
|||
<tr> |
|||
<td><a href="https://hush.land">Why Hush</a></td> |
|||
<td><a href="https://hush.land/hushchat.html">HushChat</a></td> |
|||
<td><a href="https://hushpool.is">HushPool</a></td> |
|||
<td><a href="https://git.hush.is/onryo/hush-box">HushBox</a></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://explorer.hush.land">Explorer</a></td> |
|||
<td><a href="https://git.hush.is/hush">Gitea</a></td> |
|||
<td><a href="https://hush.land/faq.html">F.A.Q</a></td> |
|||
<td><a href="https://hush.land/team.html">Team</a></td> |
|||
</tr> |
|||
</table> |
|||
<div class="blockt"><p>These addresses have NO PRIVACY! They really should move funds to a zaddr!</p></div> |
|||
#ADDRESS_DATA# |
|||
<div class="links"> |
|||
<a href="https://hush.is/matrix"><span style="color: #262626">[</span> matrix <span style="color: #262626">]</span></a> |
|||
<a href="https://hush.is/mastodon"><span style="color: #262626">[</span> mastodon <span style="color: #262626">]</span></a> |
|||
<a href="https://videos.hush.is"><span style="color: #262626">[</span> peertube <span style="color: #262626">]</span></a> |
|||
<a href="https://t.me/hush_main"><span style="color: #262626">[</span> telegram <span style="color: #262626">]</span></a> |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1 @@ |
|||
Hush Explorer API |
@ -0,0 +1,101 @@ |
|||
<!doctype html> |
|||
<head> |
|||
<title>Home | Hush - Transact and Speak Freely</title> |
|||
<style> |
|||
body { background-color: #101010; max-width: 850px; margin: auto; font-family: 'Ubuntu Mono'; color: #b3b3b3; text-align: center } |
|||
table { width: 100%; border-collapse: collapse; margin-top: 15px } |
|||
td { border: 1px solid #1a1a1a; font-size: 16px; padding: 0.5em } |
|||
td:hover { background-color: #1a1a1a } |
|||
pre { background-color: #0d0d0d; border: 1px solid #1a1a1a; font-size: 6px; padding: 15px; color: #e6e6e6 } |
|||
details { cursor: pointer; background-color: #0d0d0d; text-align: left; margin-top: 15px; padding: 0.5em; border: 1px solid #1a1a1a; font-size: 13px; word-wrap: break-word } |
|||
summary { outline: none; padding: 0.4em } |
|||
.blockt { border: 1px solid #1a1a1a; padding: 0.15em; background-color: #0d0d0d; margin-top: 15px; text-align: left; font-size: 13px; word-wrap: break-word } |
|||
.blockt p { padding-left: 0.7em; padding-right: 0.7em } |
|||
.button:link { float: right; font-size: 11px } |
|||
.mainlinkexplorer:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlinkexplorer:hover { text-decoration: none; color: #595959 } |
|||
.links { margin: 15px; font-size: 13px } |
|||
a:link { color: #b3b3b3; text-decoration: none } |
|||
a:visited { color: #b3b3b3 } |
|||
a:hover { color: #b3b3b3 } |
|||
* { scrollbar-width: thin; scrollbar-color: #333333 #101010 } |
|||
::-webkit-scrollbar { width: 6px } |
|||
::-webkit-scrollbar-thumb { background: #333333 } |
|||
@font-face { font-family: 'Ubuntu Mono'; src: url('../../UbuntuMono.ttf') format('truetype') } |
|||
</style> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h2>Hush - Speak and Transact Freely</h2> |
|||
<h3>Private Cryptocurrency and Messenger using Zero Knowledge Mathematics</h3> |
|||
<pre> |
|||
&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&& &&&&&& &&&& &&&&&& &&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& &&&&& |
|||
&&&&& &&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& |
|||
&&&&& &&&& &&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&& &&&&&& && && &&&&&& &&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& |
|||
&&&& <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="button">.onion</a> |
|||
</pre> |
|||
<table> |
|||
<tr> |
|||
<td><a href="https://hush.land">Why Hush</a></td> |
|||
<td><a href="https://hush.land/hushchat.html">HushChat</a></td> |
|||
<td><a href="https://hushpool.is">HushPool</a></td> |
|||
<td><a href="https://git.hush.is/onryo/hush-box">HushBox</a></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://explorer.hush.land">Explorer</a></td> |
|||
<td><a href="https://git.hush.is/hush">Gitea</a></td> |
|||
<td><a href="https://hush.land/faq.html">F.A.Q</a></td> |
|||
<td><a href="https://hush.land/team.html">Team</a></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr><td style="font-size: 14px"><a href="/block/#BLOCKS#" class="mainlinkexplorer">Block Height: #BLOCKS#</a></td></tr> |
|||
<tr><td style="font-size: 14px"><a href="/block/#BLOCKHASH#" class="mainlinkexplorer">Block Hash: #BLOCKHASH#</a></td></tr> |
|||
<tr><td style="font-size: 14px"><a href="/block/#PREVIOUSBLOCKHASH#" class="mainlinkexplorer">Previous Block Hash: #PREVIOUSBLOCKHASH#</a></td></tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px">Block Reward: #BLOCKREWARD#</td> |
|||
<td style="font-size: 14px">Block Time: #BLOCKTIME#</td> |
|||
<td style="font-size: 14px">Block Difficulty: #DIFFICULTY#</td> |
|||
</tr> |
|||
<tr> |
|||
<td style="font-size: 14px">Block size: #BLOCKSIZE# bytes</td> |
|||
<td style="font-size: 14px">Block Version: #VERSION#</td> |
|||
<td style="font-size: 14px">Block Bits: #BITS#</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr><td style="font-size: 14px">Block Nonce: #BLOCKNONCE#</td></tr> |
|||
<tr><td style="font-size: 14px">Block Anchor: #ANCHOR#</td></tr> |
|||
<tr><td style="font-size: 14px">Chainwork: #CHAINWORK#</td></tr> |
|||
<tr><td style="font-size: 14px">Merkle Root: #MERKLEROOT#</td></tr> |
|||
<tr><td style="font-size: 14px">Final Sapling Root: #FINALSAPLINGROOT#</td></tr> |
|||
</table> |
|||
#TX_TABLE# |
|||
<div class="links"> |
|||
<a href="https://hush.is/matrix"><span style="color: #262626">[</span> matrix <span style="color: #262626">]</span></a> |
|||
<a href="https://hush.is/mastodon"><span style="color: #262626">[</span> mastodon <span style="color: #262626">]</span></a> |
|||
<a href="https://videos.hush.is"><span style="color: #262626">[</span> peertube <span style="color: #262626">]</span></a> |
|||
<a href="https://t.me/hush_main"><span style="color: #262626">[</span> telegram <span style="color: #262626">]</span></a> |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,77 @@ |
|||
<!doctype html> |
|||
<head> |
|||
<title>Home | Hush - Transact and Speak Freely</title> |
|||
<style> |
|||
body { background-color: #101010; max-width: 850px; margin: auto; font-family: 'Ubuntu Mono'; color: #b3b3b3; text-align: center } |
|||
table { width: 100%; border-collapse: collapse; margin-top: 15px } |
|||
td { border: 1px solid #1a1a1a; font-size: 16px; padding: 0.5em } |
|||
td:hover { background-color: #1a1a1a } |
|||
pre { background-color: #0d0d0d; border: 1px solid #1a1a1a; font-size: 6px; padding: 15px; color: #e6e6e6 } |
|||
details { cursor: pointer; background-color: #0d0d0d; text-align: left; margin-top: 15px; padding: 0.5em; border: 1px solid #1a1a1a; font-size: 13px; word-wrap: break-word } |
|||
summary { outline: none; padding: 0.4em } |
|||
.blockt { border: 1px solid #1a1a1a; padding: 0.15em; background-color: #0d0d0d; margin-top: 15px; text-align: left; font-size: 13px; word-wrap: break-word } |
|||
.blockt p { padding-left: 0.7em; padding-right: 0.7em } |
|||
.button:link { float: right; font-size: 11px } |
|||
.mainlinkexplorer:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlinkexplorer:hover { text-decoration: none; color: #595959 } |
|||
.links { margin: 15px; font-size: 13px } |
|||
a:link { color: #b3b3b3; text-decoration: none } |
|||
a:visited { color: #b3b3b3 } |
|||
a:hover { color: #b3b3b3 } |
|||
* { scrollbar-width: thin; scrollbar-color: #333333 #101010 } |
|||
::-webkit-scrollbar { width: 6px } |
|||
::-webkit-scrollbar-thumb { background: #333333 } |
|||
@font-face { font-family: 'Ubuntu Mono'; src: url('../UbuntuMono.ttf') format('truetype') } |
|||
</style> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h2>Hush - Speak and Transact Freely</h2> |
|||
<h3>Private Cryptocurrency and Messenger using Zero Knowledge Mathematics</h3> |
|||
<pre> |
|||
&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&& &&&&&& &&&& &&&&&& &&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& &&&&& |
|||
&&&&& &&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& |
|||
&&&&& &&&& &&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&& &&&&&& && && &&&&&& &&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& |
|||
&&&& <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="button">.onion</a> |
|||
</pre> |
|||
<table> |
|||
<tr> |
|||
<td><a href="https://hush.land">Why Hush</a></td> |
|||
<td><a href="https://hush.land/hushchat.html">HushChat</a></td> |
|||
<td><a href="https://hushpool.is">HushPool</a></td> |
|||
<td><a href="https://git.hush.is/onryo/hush-box">HushBox</a></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://explorer.hush.land">Explorer</a></td> |
|||
<td><a href="https://git.hush.is/hush">Gitea</a></td> |
|||
<td><a href="https://hush.land/faq.html">F.A.Q</a></td> |
|||
<td><a href="https://hush.land/team.html">Team</a></td> |
|||
</tr> |
|||
</table> |
|||
#BLOCKS_TABLE# |
|||
<div class="links"> |
|||
<a href="https://hush.is/matrix"><span style="color: #262626">[</span> matrix <span style="color: #262626">]</span></a> |
|||
<a href="https://hush.is/mastodon"><span style="color: #262626">[</span> mastodon <span style="color: #262626">]</span></a> |
|||
<a href="https://videos.hush.is"><span style="color: #262626">[</span> peertube <span style="color: #262626">]</span></a> |
|||
<a href="https://t.me/hush_main"><span style="color: #262626">[</span> telegram <span style="color: #262626">]</span></a> |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,125 @@ |
|||
<!doctype html> |
|||
<head> |
|||
<title>Home | Hush - Transact and Speak Freely</title> |
|||
<style> |
|||
body { background-color: #101010; max-width: 850px; margin: auto; font-family: 'Ubuntu Mono'; color: #b3b3b3; text-align: center } |
|||
table { width: 100%; border-collapse: collapse; margin-top: 15px } |
|||
td { border: 1px solid #1a1a1a; font-size: 16px; padding: 0.5em } |
|||
td:hover { background-color: #1a1a1a } |
|||
pre { background-color: #0d0d0d; border: 1px solid #1a1a1a; font-size: 6px; padding: 15px; color: #e6e6e6 } |
|||
details { cursor: pointer; background-color: #0d0d0d; text-align: left; margin-top: 15px; padding: 0.5em; border: 1px solid #1a1a1a; font-size: 13px; word-wrap: break-word } |
|||
summary { outline: none; padding: 0.4em } |
|||
.blockt { border: 1px solid #1a1a1a; padding: 0.15em; background-color: #0d0d0d; margin-top: 15px; text-align: left; font-size: 13px; word-wrap: break-word } |
|||
.blockt p { padding-left: 0.7em; padding-right: 0.7em } |
|||
.button:link { float: right; font-size: 11px } |
|||
.mainlink:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlink:hover { text-decoration: none; color: #595959 } |
|||
.mainlinkexplorer:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlinkexplorer:hover { text-decoration: none; color: #595959 } |
|||
.links { margin: 15px; font-size: 13px } |
|||
a:link { color: #b3b3b3; text-decoration: none } |
|||
a:visited { color: #b3b3b3 } |
|||
a:hover { color: #b3b3b3 } |
|||
* { scrollbar-width: thin; scrollbar-color: #333333 #101010 } |
|||
::-webkit-scrollbar { width: 6px } |
|||
::-webkit-scrollbar-thumb { background: #333333 } |
|||
@font-face { font-family: 'Ubuntu Mono'; src: url('UbuntuMono.ttf') format('truetype') } |
|||
</style> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h2>Hush - Speak and Transact Freely</h2> |
|||
<h3>Private Cryptocurrency and Messenger using Zero Knowledge Mathematics</h3> |
|||
<pre> |
|||
&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&& &&&&&& &&&& &&&&&& &&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& &&&&& |
|||
&&&&& &&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& |
|||
&&&&& &&&& &&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&& &&&&&& && && &&&&&& &&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& |
|||
&&&& <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="button">.onion</a> |
|||
</pre> |
|||
<table> |
|||
<tr> |
|||
<td><a href="https://hush.land">Why Hush</a></td> |
|||
<td><a href="https://hush.land/hushchat.html">HushChat</a></td> |
|||
<td><a href="https://hushpool.is">HushPool</a></td> |
|||
<td><a href="https://git.hush.is/onryo/hush-box">HushBox</a></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://explorer.hush.land">Explorer</a></td> |
|||
<td><a href="https://git.hush.is/hush">Gitea</a></td> |
|||
<td><a href="https://hush.land/faq.html">F.A.Q</a></td> |
|||
<td><a href="https://hush.land/team.html">Team</a></td> |
|||
</tr> |
|||
</table> |
|||
<div class="blockt"><p>This is the most private and secure Blockchain Explorer in Zcash World, inspiration goes to <a href="https://xmrchain.net" class="mainlink">xmrchain.net</a>! There is no Javascript both client or server-side, it has no cookies, web analytics trackers, no images, no external CSS, visited and unvisited links are the same color so screenshots do not leak metadata, likewise it is available as a <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="mainlink">Tor hidden service</a>.</p></div> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Thu Sep 29 17:23:39 2022<!-- 1664472219 --></td> |
|||
<td style="font-size: 14px; width: 50%"><a href="/blocks/" class="mainlinkexplorer">Blocks list</a></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%"><a href="/blocks/" class="mainlinkexplorer">Block Height: 1099008 </a></td> |
|||
<td style="font-size: 14px; width: 50%"><a href="https://git.hush.is/hush/anonsets" class="mainlinkexplorer">Anonymity Set</a>:<span class='anonset'> 2410752 </span></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Total Transactions: 1810407</td> |
|||
<td style="font-size: 14px; width: 50%">Transaction Rate: 2.1093 per minute </td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Hashrate: 11.19 MSol/s</td> |
|||
<td style="font-size: 14px; width: 50%">Difficulty: 49283696</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Circulating Supply: 12798895.34523515 HUSH</td> |
|||
<td style="font-size: 14px; width: 50%">Shielded Supply: 6850551.72538454 HUSH</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<td style="font-size: 14px; width: 50%">Price:<span class='price'> 0.00000273 BTC</span></td> |
|||
<td style="font-size: 14px; width: 50%">Total Volume:<span class='volume'> .0077033708 BTC </span></td> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Percent Shielded: 53.525 </td> |
|||
<td style="font-size: 14px; width: 50%"><a href="/addresses/" class="mainlinkexplorer">T-addresses list</a></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">29 peers connected via TLS 1.3</td> |
|||
<td style="font-size: 14px; width: 50%">Protocol Version: 1987424</td> |
|||
</tr> |
|||
</table> |
|||
<div class="links"> |
|||
<a href="https://hush.is/matrix"><span style="color: #262626">[</span> matrix <span style="color: #262626">]</span></a> |
|||
<a href="https://hush.is/mastodon"><span style="color: #262626">[</span> mastodon <span style="color: #262626">]</span></a> |
|||
<a href="https://videos.hush.is"><span style="color: #262626">[</span> peertube <span style="color: #262626">]</span></a> |
|||
<a href="https://t.me/hush_main"><span style="color: #262626">[</span> telegram <span style="color: #262626">]</span></a> |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1 @@ |
|||
No such file or directory at /var/www/explorer.hush.land/bin/update.pl line 47. |
@ -0,0 +1,142 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>Hush Explorer: Speak And Transact Freely</title> |
|||
<style> |
|||
body { |
|||
width: 87%; |
|||
margin: 5 auto; |
|||
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; |
|||
background: #111111; |
|||
color: #cccccc; |
|||
} |
|||
a:link { color: #888888; } |
|||
a:visited { color: #888888; } |
|||
a:hover { color: #554200; } |
|||
a:active { color: #550000; } |
|||
</style> |
|||
<!-- |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
{ Fuck Blockchain Analysts } |
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|||
\ ^__^ |
|||
\ (@@)\_______ |
|||
(__)\ )\/\ |
|||
||----w | |
|||
|| || |
|||
|
|||
- Duke Leto and The Hush Developers |
|||
--> |
|||
|
|||
<!-- this explorer must be hosted at / or this needs to be changed. |
|||
Not specifying a hostname makes it compatible with Tor/i2p/etc and other mirrors |
|||
- Duke |
|||
--> |
|||
<meta http-equiv="refresh" content="120; URL=/"> |
|||
</head> |
|||
|
|||
<body> |
|||
<center> |
|||
<br/> |
|||
<br/> |
|||
<a href="https://hush.is">Hush</a> |
|||
| |
|||
<a href="https://explorer.hush.is">Explorer</a> |
|||
| |
|||
<a href="https://hush.is/twitter">Twitter</a> |
|||
| |
|||
<a href="https://hush.is/tg">Telegram</a> |
|||
| |
|||
<a href="https://hush.is/telegram_support">Telegram Support</a> |
|||
| |
|||
<a href="https://hush.is/telegram_mining">Telegram Mining</a> |
|||
| |
|||
<a href="https://hush.is/reddit">Reddit</a> |
|||
| |
|||
|
|||
<a href="https://hush.is/youtube">YouTube</a> |
|||
| |
|||
|
|||
<a href="https://hush.is/bitcointalk">BitcoinTalk</a> |
|||
| |
|||
|
|||
<a href="https://hush.is/mastodon">Mastodon</a> |
|||
| |
|||
|
|||
<a href="https://hush.is/matrix">Matrix</a> |
|||
|
|||
<br/> |
|||
<h1>HUSH Blockchain Explorer</h1> |
|||
<div id=navbar> |
|||
<a href="/blocks/">Blocks</a> | |
|||
<a href="/addresses/">Addresses</a> |
|||
</div> |
|||
<div id=stats> |
|||
<table width="100%" border=1> |
|||
<tr> |
|||
<td align=center> |
|||
<table> |
|||
<tr><th>Block Height</th><td><a href="/block/00000007235bcfad2de9c91c13a895263644b362a50efa0e9d91d79ccffcf13b">798463</a></td></tr> |
|||
<tr><th>Block Hash</th><td><a href="/block/00000007235bcfad2de9c91c13a895263644b362a50efa0e9d91d79ccffcf13b">00000007235bcfad2de9c91c13a895263644b362a50efa0e9d91d79ccffcf13b</a></td></tr> |
|||
<!-- <tr><th>Notarized Height</th><td><a href="/block/#NOTARIZED#">#NOTARIZED#</a></td></tr> --> |
|||
<!-- <tr><th>Notarized Hash</th><td><a href="/block/0000000000000000000000000000000000000000000000000000000000000000"> 0000000000000000000000000000000000000000000000000000000000000000</a></td></tr> --> |
|||
<tr><th>Longest Chain</th><td><a href="/block/798463">798463</a></td></tr> |
|||
<tr><th>Chain Tip Time</th><td> <font size=small>Mon Jan 10 14:56:50 2022<!-- 1641826610 --></font></td></tr> |
|||
<tr><th>Total Transactions</th><td> 1237062</td></tr> |
|||
<tr><th>Transaction Rate</th><td> 0.9788 per minute (Monthly Avg)</td></tr> |
|||
<!--<tr><th>Transactions Per Day</th><td> #TXS_PER_DAY#</td></tr> --> |
|||
<tr><th>Difficulty</th><td> 10543947</td></tr> |
|||
<tr><th>Network Solution Rate (Hashrate)</th><td> 2.44 MegaSols/s</td></tr> |
|||
<tr><th>Circulating Supply</th><td> 11859692.58202515 <b>HUSH</b></td></tr> |
|||
<tr><th>Shielded Supply</th><td> 5773652.68191908 <b>HUSH</b></td></tr> |
|||
<tr><th>Percent Shielded</th><td> 48.683 %</td></tr> |
|||
</table> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
<br> |
|||
<h2>About This Extreme Explorer</h2> |
|||
</center> |
|||
|
|||
<p> |
|||
<ul> |
|||
<li>No Cookies</li> |
|||
<li>No Javascript client-side or server-side</li> |
|||
<li>No web analytics trackers</li> |
|||
<li>No images (<a href="https://en.wikipedia.org/wiki/Web_beacon">web bugs</a>)</li> |
|||
<li>No external CSS, only a few lines of inline per page</li> |
|||
<li>Visited/unvisited links are the same color so screenshots do not leak metadata</li> |
|||
<li>Tor Hidden Service Coming Soon</li> |
|||
</ul> |
|||
This Explorer doesn't snoop on your privacy! There is no Javascript or images for that reason. |
|||
Either could be used to steal your privacy. This explorer is natively compatible with Tor, i2p |
|||
and any other technology that improves privacy, because we do not use or rely on Javascript |
|||
IN ANY WAY, on the server-side or the client-side. |
|||
</p> |
|||
<p> |
|||
We beleive this is the most private and secure Blockchain Explorer in Zcash Protocol World. |
|||
Inspiration goes to <a href="https://xmrchain.net">xmrchain.net</a> and their fascinating |
|||
C++ <a href="https://github.com/moneroexamples/onion-monero-blockchain-explorer">codebase</a>. |
|||
Hush continues to "lovingly steal" the best ideas of Monero World and apply them to Zcash World, |
|||
which is why we claim to have the most advanced tech of any privacy coin. |
|||
</p> |
|||
<p> |
|||
The code to this explorer is still under development and will be released in due time. |
|||
</p> |
|||
|
|||
<center> |
|||
|
|||
<h3>Node Stats</h3> |
|||
|
|||
<table border=1> |
|||
<tr><td> |
|||
11 of 11 peers connected via <font color=green>TLS 1.3</font> |
|||
</td></tr> |
|||
<tr><td> |
|||
Protocol Version <font color=orange>1987424</font> |
|||
</td></tr> |
|||
|
|||
</center> |
|||
</body> |
|||
</html> |
@ -0,0 +1,125 @@ |
|||
<!doctype html> |
|||
<head> |
|||
<title>Home | Hush - Transact and Speak Freely</title> |
|||
<style> |
|||
body { background-color: #101010; max-width: 850px; margin: auto; font-family: 'Ubuntu Mono'; color: #b3b3b3; text-align: center } |
|||
table { width: 100%; border-collapse: collapse; margin-top: 15px } |
|||
td { border: 1px solid #1a1a1a; font-size: 16px; padding: 0.5em } |
|||
td:hover { background-color: #1a1a1a } |
|||
pre { background-color: #0d0d0d; border: 1px solid #1a1a1a; font-size: 6px; padding: 15px; color: #e6e6e6 } |
|||
details { cursor: pointer; background-color: #0d0d0d; text-align: left; margin-top: 15px; padding: 0.5em; border: 1px solid #1a1a1a; font-size: 13px; word-wrap: break-word } |
|||
summary { outline: none; padding: 0.4em } |
|||
.blockt { border: 1px solid #1a1a1a; padding: 0.15em; background-color: #0d0d0d; margin-top: 15px; text-align: left; font-size: 13px; word-wrap: break-word } |
|||
.blockt p { padding-left: 0.7em; padding-right: 0.7em } |
|||
.button:link { float: right; font-size: 11px } |
|||
.mainlink:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlink:hover { text-decoration: none; color: #595959 } |
|||
.mainlinkexplorer:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlinkexplorer:hover { text-decoration: none; color: #595959 } |
|||
.links { margin: 15px; font-size: 13px } |
|||
a:link { color: #b3b3b3; text-decoration: none } |
|||
a:visited { color: #b3b3b3 } |
|||
a:hover { color: #b3b3b3 } |
|||
* { scrollbar-width: thin; scrollbar-color: #333333 #101010 } |
|||
::-webkit-scrollbar { width: 6px } |
|||
::-webkit-scrollbar-thumb { background: #333333 } |
|||
@font-face { font-family: 'Ubuntu Mono'; src: url('UbuntuMono.ttf') format('truetype') } |
|||
</style> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h2>Hush - Speak and Transact Freely</h2> |
|||
<h3>Private Cryptocurrency and Messenger using Zero Knowledge Mathematics</h3> |
|||
<pre> |
|||
&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&& &&&&&& &&&& &&&&&& &&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& &&&&& |
|||
&&&&& &&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& |
|||
&&&&& &&&& &&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&& &&&&&& && && &&&&&& &&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& |
|||
&&&& <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="button">.onion</a> |
|||
</pre> |
|||
<table> |
|||
<tr> |
|||
<td><a href="https://hush.land">Why Hush</a></td> |
|||
<td><a href="https://hush.land/hushchat.html">HushChat</a></td> |
|||
<td><a href="https://hushpool.is">HushPool</a></td> |
|||
<td><a href="https://git.hush.is/onryo/hush-box">HushBox</a></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://explorer.hush.land">Explorer</a></td> |
|||
<td><a href="https://git.hush.is/hush">Gitea</a></td> |
|||
<td><a href="https://hush.land/faq.html">F.A.Q</a></td> |
|||
<td><a href="https://hush.land/team.html">Team</a></td> |
|||
</tr> |
|||
</table> |
|||
<div class="blockt"><p>This is the most private and secure Blockchain Explorer in Zcash World, inspiration goes to <a href="https://xmrchain.net" class="mainlink">xmrchain.net</a>! There is no Javascript both client or server-side, it has no cookies, web analytics trackers, no images, no external CSS, visited and unvisited links are the same color so screenshots do not leak metadata, likewise it is available as a <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="mainlink">Tor hidden service</a>.</p></div> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Thu Sep 29 17:23:39 2022<!-- 1664472219 --></td> |
|||
<td style="font-size: 14px; width: 50%"><a href="/blocks/" class="mainlinkexplorer">Blocks list</a></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%"><a href="/blocks/" class="mainlinkexplorer">Block Height: 1099008 </a></td> |
|||
<td style="font-size: 14px; width: 50%"><a href="https://git.hush.is/hush/anonsets" class="mainlinkexplorer">Anonymity Set</a>:<span class='anonset'> 2410752 </span></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Total Transactions: 1810407</td> |
|||
<td style="font-size: 14px; width: 50%">Transaction Rate: 2.1093 per minute </td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Hashrate: 11.19 MSol/s</td> |
|||
<td style="font-size: 14px; width: 50%">Difficulty: 49283696</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Circulating Supply: 12798895.34523515 HUSH</td> |
|||
<td style="font-size: 14px; width: 50%">Shielded Supply: 6850551.72538454 HUSH</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<td style="font-size: 14px; width: 50%">Price:<span class='price'> 0.00000273 BTC</span></td> |
|||
<td style="font-size: 14px; width: 50%">Total Volume:<span class='volume'> .0077033708 BTC </span></td> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Percent Shielded: 53.525 </td> |
|||
<td style="font-size: 14px; width: 50%"><a href="/addresses/" class="mainlinkexplorer">T-addresses list</a></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">29 peers connected via TLS 1.3</td> |
|||
<td style="font-size: 14px; width: 50%">Protocol Version: 1987424</td> |
|||
</tr> |
|||
</table> |
|||
<div class="links"> |
|||
<a href="https://hush.is/matrix"><span style="color: #262626">[</span> matrix <span style="color: #262626">]</span></a> |
|||
<a href="https://hush.is/mastodon"><span style="color: #262626">[</span> mastodon <span style="color: #262626">]</span></a> |
|||
<a href="https://videos.hush.is"><span style="color: #262626">[</span> peertube <span style="color: #262626">]</span></a> |
|||
<a href="https://t.me/hush_main"><span style="color: #262626">[</span> telegram <span style="color: #262626">]</span></a> |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,125 @@ |
|||
<!doctype html> |
|||
<head> |
|||
<title>Home | Hush - Transact and Speak Freely</title> |
|||
<style> |
|||
body { background-color: #101010; max-width: 850px; margin: auto; font-family: 'Ubuntu Mono'; color: #b3b3b3; text-align: center } |
|||
table { width: 100%; border-collapse: collapse; margin-top: 15px } |
|||
td { border: 1px solid #1a1a1a; font-size: 16px; padding: 0.5em } |
|||
td:hover { background-color: #1a1a1a } |
|||
pre { background-color: #0d0d0d; border: 1px solid #1a1a1a; font-size: 6px; padding: 15px; color: #e6e6e6 } |
|||
details { cursor: pointer; background-color: #0d0d0d; text-align: left; margin-top: 15px; padding: 0.5em; border: 1px solid #1a1a1a; font-size: 13px; word-wrap: break-word } |
|||
summary { outline: none; padding: 0.4em } |
|||
.blockt { border: 1px solid #1a1a1a; padding: 0.15em; background-color: #0d0d0d; margin-top: 15px; text-align: left; font-size: 13px; word-wrap: break-word } |
|||
.blockt p { padding-left: 0.7em; padding-right: 0.7em } |
|||
.button:link { float: right; font-size: 11px } |
|||
.mainlink:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlink:hover { text-decoration: none; color: #595959 } |
|||
.mainlinkexplorer:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlinkexplorer:hover { text-decoration: none; color: #595959 } |
|||
.links { margin: 15px; font-size: 13px } |
|||
a:link { color: #b3b3b3; text-decoration: none } |
|||
a:visited { color: #b3b3b3 } |
|||
a:hover { color: #b3b3b3 } |
|||
* { scrollbar-width: thin; scrollbar-color: #333333 #101010 } |
|||
::-webkit-scrollbar { width: 6px } |
|||
::-webkit-scrollbar-thumb { background: #333333 } |
|||
@font-face { font-family: 'Ubuntu Mono'; src: url('UbuntuMono.ttf') format('truetype') } |
|||
</style> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h2>Hush - Speak and Transact Freely</h2> |
|||
<h3>Private Cryptocurrency and Messenger using Zero Knowledge Mathematics</h3> |
|||
<pre> |
|||
&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&& &&&&&& &&&& &&&&&& &&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& &&&&& |
|||
&&&&& &&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& |
|||
&&&&& &&&& &&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&& &&&&&& && && &&&&&& &&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& |
|||
&&&& <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="button">.onion</a> |
|||
</pre> |
|||
<table> |
|||
<tr> |
|||
<td><a href="https://hush.land">Why Hush</a></td> |
|||
<td><a href="https://hush.land/hushchat.html">HushChat</a></td> |
|||
<td><a href="https://hushpool.is">HushPool</a></td> |
|||
<td><a href="https://git.hush.is/onryo/hush-box">HushBox</a></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://explorer.hush.land">Explorer</a></td> |
|||
<td><a href="https://git.hush.is/hush">Gitea</a></td> |
|||
<td><a href="https://hush.land/faq.html">F.A.Q</a></td> |
|||
<td><a href="https://hush.land/team.html">Team</a></td> |
|||
</tr> |
|||
</table> |
|||
<div class="blockt"><p>This is the most private and secure Blockchain Explorer in Zcash World, inspiration goes to <a href="https://xmrchain.net" class="mainlink">xmrchain.net</a>! There is no Javascript both client or server-side, it has no cookies, web analytics trackers, no images, no external CSS, visited and unvisited links are the same color so screenshots do not leak metadata, likewise it is available as a <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="mainlink">Tor hidden service</a>.</p></div> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">#TIPTIME#</td> |
|||
<td style="font-size: 14px; width: 50%"><a href="/blocks/" class="mainlinkexplorer">Blocks list</a></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%"><a href="/blocks/" class="mainlinkexplorer">Block Height: #BLOCKS# </a></td> |
|||
<td style="font-size: 14px; width: 50%"><a href="https://git.hush.is/hush/anonsets" class="mainlinkexplorer">Anonymity Set</a>:<span class='anonset'> 2410752 </span></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Total Transactions: #TXCOUNT#</td> |
|||
<td style="font-size: 14px; width: 50%">Transaction Rate: #TXRATE# per minute </td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Hashrate: #NETWORKSOLPS# MSol/s</td> |
|||
<td style="font-size: 14px; width: 50%">Difficulty: #DIFFICULTY#</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Circulating Supply: #SUPPLY# HUSH</td> |
|||
<td style="font-size: 14px; width: 50%">Shielded Supply: #ZFUNDS# HUSH</td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<td style="font-size: 14px; width: 50%">Price:<span class='price'> 0.00000273 BTC</span></td> |
|||
<td style="font-size: 14px; width: 50%">Total Volume:<span class='volume'> .0077033708 BTC </span></td> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">Percent Shielded: #ZFUNDS_PERCENT# </td> |
|||
<td style="font-size: 14px; width: 50%"><a href="/addresses/" class="mainlinkexplorer">T-addresses list</a></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr> |
|||
<td style="font-size: 14px; width: 50%">#CONNECTIONS# peers connected via TLS 1.3</td> |
|||
<td style="font-size: 14px; width: 50%">Protocol Version: #PROTOCOLVERSION#</td> |
|||
</tr> |
|||
</table> |
|||
<div class="links"> |
|||
<a href="https://hush.is/matrix"><span style="color: #262626">[</span> matrix <span style="color: #262626">]</span></a> |
|||
<a href="https://hush.is/mastodon"><span style="color: #262626">[</span> mastodon <span style="color: #262626">]</span></a> |
|||
<a href="https://videos.hush.is"><span style="color: #262626">[</span> peertube <span style="color: #262626">]</span></a> |
|||
<a href="https://t.me/hush_main"><span style="color: #262626">[</span> telegram <span style="color: #262626">]</span></a> |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,85 @@ |
|||
<!doctype html> |
|||
<head> |
|||
<title>Home | Hush - Transact and Speak Freely</title> |
|||
<style> |
|||
body { background-color: #101010; max-width: 850px; margin: auto; font-family: 'Ubuntu Mono'; color: #b3b3b3; text-align: center } |
|||
table { width: 100%; border-collapse: collapse; margin-top: 15px } |
|||
td { border: 1px solid #1a1a1a; font-size: 16px; padding: 0.5em } |
|||
td:hover { background-color: #1a1a1a } |
|||
pre { background-color: #0d0d0d; border: 1px solid #1a1a1a; font-size: 6px; padding: 15px; color: #e6e6e6 } |
|||
details { cursor: pointer; background-color: #0d0d0d; text-align: left; margin-top: 15px; padding: 0.5em; border: 1px solid #1a1a1a; font-size: 13px; word-wrap: break-word } |
|||
summary { outline: none; padding: 0.4em } |
|||
.blockt { border: 1px solid #1a1a1a; padding: 0.15em; background-color: #0d0d0d; margin-top: 15px; text-align: left; font-size: 13px; word-wrap: break-word } |
|||
.blockt p { padding-left: 0.7em; padding-right: 0.7em } |
|||
.button:link { float: right; font-size: 11px } |
|||
.mainlinkexplorer:link { text-decoration: dotted underline; text-underline-position: under } |
|||
.mainlinkexplorer:hover { text-decoration: none; color: #595959 } |
|||
.links { margin: 15px; font-size: 13px } |
|||
a:link { color: #b3b3b3; text-decoration: none } |
|||
a:visited { color: #b3b3b3 } |
|||
a:hover { color: #b3b3b3 } |
|||
* { scrollbar-width: thin; scrollbar-color: #333333 #101010 } |
|||
::-webkit-scrollbar { width: 6px } |
|||
::-webkit-scrollbar-thumb { background: #333333 } |
|||
@font-face { font-family: 'Ubuntu Mono'; src: url('../../UbuntuMono.ttf') format('truetype') } |
|||
</style> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
</head> |
|||
<body> |
|||
<h2>Hush - Speak and Transact Freely</h2> |
|||
<h3>Private Cryptocurrency and Messenger using Zero Knowledge Mathematics</h3> |
|||
<pre> |
|||
&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&& &&&&&& &&&& &&&&&& &&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& &&&&& |
|||
&&&&& &&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& |
|||
&&&&& &&&& &&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&& &&&&&& && && &&&&&& &&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& |
|||
&&&& <a href="http://jlqhwhak65kokg3pdjp3ufy6almf5spnhsfnugtjsc4z7wtapgozxyad.onion" class="button">.onion</a> |
|||
</pre> |
|||
<table> |
|||
<tr> |
|||
<td><a href="https://hush.land">Why Hush</a></td> |
|||
<td><a href="https://hush.land/hushchat.html">HushChat</a></td> |
|||
<td><a href="https://hushpool.is">HushPool</a></td> |
|||
<td><a href="https://git.hush.is/onryo/hush-box">HushBox</a></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://explorer.hush.land">Explorer</a></td> |
|||
<td><a href="https://git.hush.is/hush">Gitea</a></td> |
|||
<td><a href="https://hush.land/faq.html">F.A.Q</a></td> |
|||
<td><a href="https://hush.land/team.html">Team</a></td> |
|||
</tr> |
|||
</table> |
|||
<table> |
|||
<tr><td style="font-size: 14px"><a href="/block/#BLOCKHEIGHT#" class="mainlinkexplorer">Block Height: #BLOCKHEIGHT#</a></td></tr> |
|||
<tr><td style="font-size: 14px"><a href="/block/#BLOCKHASH#" class="mainlinkexplorer">Block Hash: #BLOCKHASH#</a></td></tr> |
|||
<tr><td style="font-size: 14px"><a href="/tx/#TXID#" class="mainlinkexplorer">Transaction ID: #TXID#</a></td></tr> |
|||
<tr><td style="font-size: 14px">Transaction Time: #TXTIME#</td></tr> |
|||
</table> |
|||
<table> |
|||
#TX_DATA# |
|||
</table> |
|||
<div class="links"> |
|||
<a href="https://hush.is/matrix"><span style="color: #262626">[</span> matrix <span style="color: #262626">]</span></a> |
|||
<a href="https://hush.is/mastodon"><span style="color: #262626">[</span> mastodon <span style="color: #262626">]</span></a> |
|||
<a href="https://videos.hush.is"><span style="color: #262626">[</span> peertube <span style="color: #262626">]</span></a> |
|||
<a href="https://t.me/hush_main"><span style="color: #262626">[</span> telegram <span style="color: #262626">]</span></a> |
|||
</div> |
|||
</body> |
|||
</html> |
Loading…
Reference in new issue