Commit a8bfa0a3 authored by Gampe Sebastian's avatar Gampe Sebastian

initial upload

parent a4bfc518
335072
\ No newline at end of file
This diff is collapsed.
{}
\ No newline at end of file
{ "0000" :
{
"startblock" : 218720,
"blockupdate" : 0,
"expired" : 0,
"tag" : "TestTag",
"url" : "",
"addresses" : [],
"verified" : 0,
"blocks" : [],
"txs": {}
}
}
{ "fT1my55yFHcKXQyr8EpS9vA2wBv5EVHCbv" : "0000" }
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
@font-face { font-family: 'MonospaceTypewriter';
src: url('MonospaceTypewriter.ttf') format('truetype'); }
body {
font-family: 'MonospaceTypewriter';
background: rgb(33,33,33);
color:ghostwhite;
}
.btn {
margin:0.1rem;
padding-top:0px;
padding-bottom:0px;
}
.no-cursor {
cursor: default !important;
}
#transactions {
position:relative;
z-index:1;
top:4.5rem;
padding-bottom:4.5rem;
}
#transactions > .row > .col {
text-align: right;
border-bottom:1px solid rgb(33,33,33);
}
.fade-in {
transition: opacity 2s;
}
.fade-in.new-block {
opacity:0;
transition: opacity 0s !important;
}
.fair-amount {
width: 10rem;
text-align: right;
}
.container-fluid > .row:first-child {
position: fixed;
top:0px;
left:0px;
height:4.5rem;
width:100%;
padding-left:0.1rem;
z-index:100;
background:rgba(33,33,33,0.9);
}
.container-fluid > .row:last-child {
position: fixed;
bottom:0px;
left:0px;
height:4.5rem;
width:100%;
padding-left:0.1rem;
z-index:100;
background:rgba(33,33,33,0.9);
margin:0;
}
.container-fluid {
height:100vh;
overflow-y: scroll;
}
.tx-count {
position: relative;
width:0px;
height:0px;
z-index:1;
}
.tx-count > p {
width:1.5rem;
text-align: right;
font-weight: bold;
color:darkgreen;
}
.block b {
cursor:pointer;
}
.block.marked {
background:seagreen !important;
}
#singlemode {
position: fixed;
top:0;
right:0;
margin:1rem;
z-index:200;
}
#newsticker {
overflow: hidden;
position: relative;
top:-0.5em;
padding-left:0.2em;
}
#newsticker p {
margin:0;
}
.livestats .col {
border:1px solid grey;
text-align:center;
font-size:2rem;
}
.livestats .col small {
font-size:1rem;
}
.livestats .col sub {
font-size:1rem;
}
.with-label {
position: relative;
top:-0.4rem;
left:0.4rem;
}
label.with-label {
color:goldenrod;
}
addresses
@media print, screen and (max-width: 1060px) {
.container-fluid .row:first-child h2 {
font-size: 3vw;
}
.txid {
text-align: left !important;
margin-left:-1rem;
}
#newsticker {
font-size: 2.5vw;
}
.addresses {
margin-left:0;
}
}
This diff is collapsed.
function content_load( url, datatype ){
var json = null;
if( datatype == undefined ){
datatype=url.match(/\..*$/g)[0].slice(1);
}
console.log( url, datatype );
$.ajax({
'async': false,
'global': false,
'cache': false,
'url': url,
'dataType': ((datatype == 'csv') ? 'text' : datatype),
'success': function (data) {
result = data;
}
});
if(datatype == 'csv'){
result=result.split(/\n/g);
var AA=[];
result.forEach(
function(v,i){
var A=v.split(/,/g);
if( A.length > 1 && A[0] != '' ){
AA.push(A);
}
}
);
result=AA;
}
return result;
}
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
This diff is collapsed.
<?php
$blockheight=$_GET['blockheight'];
if( empty($blockheight ) ) exit;
$blockfile=intVal($blockheight/1000)*1000;
$f='data/blocks/'.$blockfile.'.json';
$fp=fopen($f,'r');
$Blocks=json_decode(fread($fp,filesize($f)),true);
fclose($fp);
if( !empty($Blocks[(string)$blockheight]) ){
$Tx=Array();
foreach($Blocks[(string)$blockheight]['tx'] as $i=>$txid ){
if($i > 0){
$Tx[$txid]=$Blocks['txs'][$txid];
}
}
echo json_encode( [ $Blocks[(string)$blockheight], $Tx] );
} else {
echo '{}';
}
?>
<?php
$f='data/mempool.json';
$fp=fopen($f,'r');
$Mempool=json_decode(fread($fp,filesize($f)),true);
fclose($fp);
echo json_encode( $Mempool );
?>
<?php
?>
<!DOCTYPE html>
<html lang="de">
<head>
<title>FairCoin Statistics Explorer
</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<meta name="robots" content="noindex, nofollow">
<link href="assets/bootstrap/bootstrap.min.css" rel="stylesheet">
<link href="assets/css/styles.css?<?=filemtime('assets/css/styles.css');?>" rel="stylesheet">
</head>
<body>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<button id="singlemode" class="btn btn-sm">singlemode</button>
<div class='container-fluid'>
<div class='row'>
<div class='col'>
<h2>FairCoin Blockchain Live Monitor</h2>
<div id="newsticker"></div>
</div>
</div>
<div id='transactions'></div>
<div class='row livestats'>
<div id='tx24h' class='col'>
</div>
<div id='am24h' class='col'>
</div>
</div>
</div>
<script src="assets/js/jquery.min.js"></script>
<script src="assets/bootstrap/bootstrap.bundle.min.js"></script>
<script src="assets/js/json.js"></script>
<script src="assets/js/script.js"></script>
<script>
</script>
</body>
</html>
<?php
$BLOCKHEIGHT_REMOTE=0;
function loadBlockheightRemote(){
global $BLOCKHEIGHT_REMOTE;
$fn='data/blockheight';
if(file_exists($fn)){
$fp=fopen($fn,'r');
$BLOCKHEIGHT_REMOTE=fread($fp,filesize($fn));
fclose($fp);
} else {
$BLOCKHEIGHT_REMOTE=0;
}
}
function saveBlockheightRemote(){
global $BLOCKHEIGHT_REMOTE;
$fn='data/blockheight';
$fp=fopen($fn,'w+');
fwrite($fp,$BLOCKHEIGHT_REMOTE);
fclose($fp);
}
function loadBlocks($blockfile){
$fn='data/blocks/'.$blockfile.'.json';
if(file_exists($fn)){
$fp=fopen($fn,'r');
$Blocks=json_decode( fread($fp,filesize($fn)),true);
fclose($fp);
} else {
$Blocks=Array('txs' => Array());
}
return $Blocks;
}
function saveBlocks($blockfile,$Blocks){
$fn='data/blocks/'.$blockfile.'.json';
$fp=fopen($fn,'w+');
fwrite($fp,json_encode($Blocks));
fclose($fp);
}
$Data = json_decode(file_get_contents('php://input'), true);
$action=$Data['action'];
if( $action == 'getblockheight' ){
loadBlockheightRemote();
echo $BLOCKHEIGHT_REMOTE;
exit;
}
if( $action == 'updatemempool'){
$f='data/mempool.json';
$fp=fopen($f,'w+');
fwrite($fp,json_encode($Data['updates']));
fclose($fp);
echo 'OK';
exit;
}
if( $action == 'updateblocks' ){
$Updates=$Data['updates'];
if( !empty($Updates) ){
loadBlockheightRemote();
$lastblockfile='';
$lastblockheight=0;
foreach($Updates as $block){
if( $BLOCKHEIGHT_REMOTE < $block['height'] ){
if( $lastblockfile != $block['blockfile'] ){
if( count($Blocks) > 0 ){
saveBlocks($lastblockfile,$Blocks);
$BLOCKHEIGHT_REMOTE=$lastblockheight;
saveBlockheightRemote();
$Blocks=Array('txs' => Array());
}
$lastblockfile=$block['blockfile'];
$Blocks=loadBlocks($block['blockfile']);
}
$Blocks[(string)$block['height']] = $block['block'];
foreach( $block['tx'] as $txid=>$Tx ){
$Blocks['txs'][$txid]=$Tx;
}
$lastblockheight=$block['height'];
}
}
if($lastblockfile!=''){
saveBlocks($lastblockfile,$Blocks);
$BLOCKHEIGHT_REMOTE=$lastblockheight;
saveBlockheightRemote();
}
}
echo 'OK';
exit;
}
/*
$fp=fopen('data/mempool.txt','w+');
fwrite($fp,json_encode($Updates));
fclose($fp);
$fp=fopen('data/blocks.txt','w+');
fwrite($fp,json_encode($Updates));
fclose($fp);
*/
?>
#!/bin/bash
printf `find ~/ -type f -name "faircoin-cli" -print -quit -user tonyford`
# -*- coding: utf-8 -*-
import subprocess
import json
import sys
import os
import time
import urllib.request
import requests
MEMPOOL={}
REMOTE_URL='http://fairplayground.info/explorer/update.php'
# BLOCKHEIGHT=332624
BLOCKHEIGHT_INIT=333000
BLOCKHEIGHT=0
BLOCKHEIGHT_REMOTE=0
BLOCKS={}
# get link to faircoin blockchain service
fair=subprocess.check_output(['./faircoin-cli.sh']).decode('utf-8')
# get tx(JSON) by txid
def getTx(txid):
result=subprocess.check_output([fair,'getrawtransaction',txid]).decode('utf-8').replace('\n','')
if( len(result) > 2000 ):
Tx={'vout' : [ { 'addresses' : ['tx_to_large'], 'value' : 0 } ] }
return Tx
result=subprocess.check_output([fair,'decoderawtransaction',result])
T=json.loads(result)
Tx={}
Tx['vout']=[]
for Vout in T['vout']:
Tx['vout'].append({'value' : Vout['value'], 'n' : Vout['n'], 'addresses' : Vout['scriptPubKey']['addresses'] })
i=-1
ln=-1
am=0
for j,w in enumerate(Tx['vout']):
x=str(round(w['value'],8)).split('.')
if( len(x) > 0 and len(Tx['vout']) > 1 ):
if( ( ( len(x[1]) > 5 or ln < 2 ) and am < w['value']) or am == 0 ):
ln=len(x[1])
i=j
am=w['value']
if(i > -1):
Tx['vout'][i]['is_change']=1
return Tx
def getBlockfile():
global BLOCKHEIGHT
return str(int(BLOCKHEIGHT/1000)*1000)
def getBlockfileRemote():
global BLOCKHEIGHT_REMOTE
return str(int(BLOCKHEIGHT_REMOTE/1000)*1000)
def loadBlocks():
global BLOCKS
fn='data/blocks/'+getBlockfile()+'.json'
if( os.path.isfile(fn) ):
file=open(fn,'r')
BLOCKS=json.loads(file.read())
file.close()
else:
BLOCKS={}
return BLOCKS
def saveBlocks():
global BLOCKS
fn='data/blocks/'+getBlockfile()+'.json'
file=open(fn,'w+')
file.write(json.dumps(BLOCKS))
file.close()
def postBlock(New_blocks):
body={'action' : 'updateblocks', 'updates' : New_blocks }
return postToRemote(body)
def loadBlockheight():
global BLOCKHEIGHT
fn='data/blockheight'
if( os.path.isfile(fn) ):
file=open(fn,'r')
BLOCKHEIGHT=int(file.read())
file.close()
else:
BLOCKHEIGHT=BLOCKHEIGHT_INIT-1
def loadBlockheightRemote():
global BLOCKHEIGHT_REMOTE
result=postToRemote({'action':'getblockheight'})
BLOCKHEIGHT_REMOTE=int(result)
if(BLOCKHEIGHT_REMOTE < BLOCKHEIGHT_INIT):
BLOCKHEIGHT_REMOTE=BLOCKHEIGHT_INIT-1
def saveBlockheight():
global BLOCKHEIGHT
fn='data/blockheight'
file=open(fn,'w+')
file.write(str(BLOCKHEIGHT))
file.close()
def postNewBlocks(New_blocks, New_blocks_h, force=True):
# post blocks update to remote
if( len(New_blocks)>=1000 or( force and len(New_blocks)>0 ) ):
print('post new blocks: '+json.dumps(New_blocks_h))
result=postBlock( New_blocks )
New_blocks=[]
New_blocks_h=[]
if( result == 'OK' ):
loadBlockheightRemote()
else:
print('Error: bad response from remote [blocks update] : '+result)
sys.exit(0)
return [New_blocks, New_blocks_h]
def checkBlocks():
global BLOCKHEIGHT
global BLOCKHEIGHT_REMOTE
result=subprocess.check_output([fair,'getblockcount']).decode('utf-8').replace('\n','')
blockheight=int(result)
result=False
New_blocks=[]
New_blocks_h=[]
# update remote blocks
while(BLOCKHEIGHT_REMOTE < BLOCKHEIGHT ):
BLOCKHEIGHT_REMOTE+=1
B=getBlock(BLOCKHEIGHT_REMOTE)
Tx={}
for txid in B['tx'][1:]:
Tx[txid]=getTx(txid)
New_blocks.append({'blockfile' : getBlockfileRemote(), 'height' : B['height'], 'block' : getBlockdata(B), 'tx' : Tx })
New_blocks_h.append(BLOCKHEIGHT)
Result=True
# update local and remote blocks
while(blockheight > BLOCKHEIGHT):
BLOCKHEIGHT+=1
loadBlocks()
B=getBlock(BLOCKHEIGHT)
BLOCKS[str(B['height'])]=getBlockdata(B)
print('add block '+str(B['height']))
saveBlocks()
saveBlockheight()
if BLOCKHEIGHT_REMOTE < BLOCKHEIGHT:
Tx={}
for txid in B['tx'][1:]:
Tx[txid]=getTx(txid)
New_blocks.append({'blockfile' : getBlockfile(), 'height' : B['height'], 'block' : getBlockdata(B), 'tx' : Tx })
New_blocks_h.append(BLOCKHEIGHT)
N=postNewBlocks(New_blocks, New_blocks_h, False)
New_blocks=N[0]
New_blocks_h=N[1]
result=True
# post blocks update to remote
postNewBlocks(New_blocks, New_blocks_h)
return result
def getBlock(blockheight):
result=subprocess.check_output([fair,'getblockhash',str(blockheight)]).decode('utf-8').replace('\n','')
result=subprocess.check_output([fair,'getblock',result]).decode('utf-8').replace('\n','')
return json.loads(result)
def getBlockdata(B):
return {'hash' : B['hash'], 'size' : B['size'], 'time' : B['time'], 'tx' : B['tx'] }
def getMempool():
global MEMPOOL
# get latest unconfirmed transactions from mempool
result=subprocess.check_output([fair,'getrawmempool'])
Txid=json.loads(result)
MEMPOOL={}
# check new transactions in mempool
for txid in Txid:
MEMPOOL[txid]=getTx(txid)
MEMPOOL[txid]['time']=int(time.time())
return MEMPOOL
def postToRemote(body):
global REMOTE_URL
req = urllib.request.Request(REMOTE_URL)
req.add_header('Content-Type', 'application/json; charset=utf-8')
jsondata = json.dumps(body)
jsondataasbytes = jsondata.encode('utf-8') # needs to be bytes
req.add_header('Content-Length', len(jsondataasbytes))
response = urllib.request.urlopen(req, jsondataasbytes)
return response.read().decode('utf-8')
# get local blockheight
loadBlockheight()
# get remote blockheight
loadBlockheightRemote()
print('Blockheight Local:')
print(BLOCKHEIGHT)
print()
print('Blockheight Remote:')
print(BLOCKHEIGHT_REMOTE)
blkcountdown=180
while(True):
print('~' + str(blkcountdown) + ' seconds to next block!')
# write new transaction
print('post mempool updates')
body = {'action' : 'updatemempool', 'updates': getMempool() }
result=postToRemote(body)
if(result != 'OK'):
print('Error : bad response from remote [mempool update] :' +result)
sys.exit(0)
# subprocess.call(['curl','--request','POST','-H', 'Content-Type: application/json', '--data','{"unconfirmed_tx":'+json.dumps(UNCONFIRMED_TX)+'}', REMOTE_URL])
file=open('data/mempool.json','w+')
file.write(json.dumps(MEMPOOL))
file.close()
if(checkBlocks()):
blkcountdown=180
time.sleep(10)
blkcountdown-=10
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment