Skip to content
Snippets Groups Projects
Commit 12b11101 authored by Robert Martin-Legene's avatar Robert Martin-Legene
Browse files

First step trying to watch sealers in colours

parent 5608b730
No related branches found
No related tags found
No related merge requests found
......@@ -10,7 +10,7 @@ $Carp::Verbose = 1;
sub _cat
{
my $filename = shift;
my ( $self, $filename ) = @_;
my $fh = IO::File->new($filename);
return if not defined $fh;
local $_ = join( '', $fh->getlines );
......@@ -26,8 +26,7 @@ sub _filecontents_or_default
{
my ($self, $filename, $default) = @_;
local $_ = $self->_cat( $filename );
return $default if not defined $_;
return $_;
return defined $_ ? $_ : $default;
}
sub new
......@@ -68,7 +67,8 @@ sub new
}
#
$self->{'netport'} = $self->_filecontents_or_default( $self->{'nodedir'}.'/netport', 30303 );
$self->{'rpcport'} = $self->_filecontents_or_default( $self->{'nodedir'}.'/netport', 8545 );
$self->{'rpcport'} = $self->_filecontents_or_default( $self->{'nodedir'}.'/rpcport', 8545 );
$self->{'rpchost'} = $self->_filecontents_or_default( $self->{'nodedir'}.'/rpchost', 'http://localhost' );
$self->{'ua'} = LWP::UserAgent->new;
return $self;
}
......@@ -92,14 +92,20 @@ sub contract
sub rpcreq
{
my ( $self, $opname, @params ) = @_;
my $req = HTTP::Request->new( POST => "http://127.0.0.1:".$self->{'rpcport'} );
$req->content_type('application/json');
my $extra = scalar @params
my ( $self, $opname, @params )
= @_;
my $ua = $self->{'ua'}->clone;
$ua->ssl_opts( 'verify_hostname' => 0 );
my $endpoint = sprintf '%s:%d', $self->{rpchost}, $self->{'rpcport'};
my $extra = scalar @params
? sprintf(qq(,\"params\":[%s]), join(',', @params))
: '';
$req->content( qq({"jsonrpc":"2.0","method":"${opname}"${extra},"id":1}));
my $res = $self->{'ua'}->request($req);
#
my $res = $ua->post(
$endpoint,
'Content-Type' => 'application/json',
'Content' => qq({"jsonrpc":"2.0","method":"${opname}"${extra},"id":1}),
);
die $res->status_line
unless $res->is_success;
return $res->content;
......
#!/usr/bin/perl -w
use strict;
use warnings;
use Math::BigInt;
use Carp;
$Carp::Verbose = 1;
BEGIN {
die "\$BFAHOME not set. Did you source bfa/bin/env ?\n"
unless exists $ENV{BFAHOME};
}
use lib $ENV{'BFAHOME'}.'/bin';
use libbfa;
my $libbfa;
package ansi;
our $CSI = "\x1b[";
sub CUP { $CSI.(shift||1).';'.(shift||1).'H' }
sub EL { $CSI.(shift||0).'K' }
sub ED { $CSI.(shift||0).'J' }
sub normal { $CSI.'m' }
sub black { $CSI.'30m' }
sub red { $CSI.'41m' }
sub green { $CSI.'42m' }
sub brightwhite { $CSI.'97m' }
sub bgyellow { $CSI.'103m' }
package alias;
use IO::File;
our $initialised = 0;
our %list;
sub translate
{
my $victim = lc shift;
if ( ! $initialised )
{
$initialised = 1;
local $_ = undef;
my $fh = IO::File->new($libbfa->{'networkdir'}.'/aliases');
if ( defined $fh )
{
while ( $_ = $fh->getline )
{
s|^\s+||;
s|\s+$||;
my @e = split /\s+/, $_, 2;
if ( scalar @e == 2 )
{
my $addr = lc $e[0];
$list{$addr}= $e[1];
}
}
$fh->close;
}
}
return $list{$victim} if exists $list{$victim};
return;
}
package tools;
our $CSI = "\x1b[";
our $clearEOS = "${CSI}J";
our $up = "${CSI}A";
our $red = "${CSI}41m";
our $normal = "${CSI}m";
sub new
{
my ($class, $libbfa) = @_;
my $self = bless {}, ref $class || $class;
return $self;
}
sub gmt
{
my $ts = shift;
return unless defined $ts;
my @t = gmtime($ts);
$t[5] += 1900;
$t[4] ++;
return sprintf('%04d%02d%02d-%02d%02d%02d', (@t)[5,4,3,2,1,0]);
}
sub hex2string($)
{
my ($msg) = @_;
my $txt = '';
while ($msg ne '')
{
my $i = hex( substr($msg,0,2) );
$txt .= ( $i >= 32 and $i <= 127 ) ? chr($i) : '.';
$msg = substr $msg, 2;
}
return $txt;
}
sub max(@)
{
my $num = 0;
local $_ = undef;
foreach $_ (@_)
{
$num = $_
if $num < $_;
}
return $num;
}
package error;
use JSON;
sub new
{
my ($class, $json_in) = @_;
my $self = bless {
'_code' => undef,
'_message' => undef,
}, ref $class || $class;
my $json;
eval {
$json = decode_json( $json_in )
};
return unless defined $json;
return unless exists $json->{'error'};
$self->code( $json->{'error'}->{'code'} ) if exists $json->{'error'}->{'code'};
$self->message( $json->{'error'}->{'message'} ) if exists $json->{'error'}->{'message'};
return $self;
}
sub code
{
my ( $self, $val ) = @_;
$self->{'_code'} = $val if scalar @_ > 1;
return $self->{'_code'};
}
sub message
{
my ( $self, $val ) = @_;
$self->{'_message'} = $val if scalar @_ > 1;
return $self->{'_message'};
}
package block;
#use LWP;
use JSON;
sub new
{
my ( $class, $libbfa ) = @_;
my $self = bless {}, ref $class || $class;
$self->{'libbfa'} = $libbfa if defined $libbfa;
return $self;
}
sub parse
{
my ( $self, $json_raw ) = @_;
return unless defined $json_raw;
return if $json_raw eq '';
$self->{'json_raw'} = $json_raw;
eval { $self->{'json'} = decode_json( $json_raw ) };
return if $@;
$self->error( error->new($json_raw) );
return $self;
}
sub error
{
return if not exists $_[0]->{'error'};
return $_[0]->{'error'};
}
sub json
{
return unless exists $_[0]->{'json'};
return $_[0]->{'json'};
}
sub result
{
return unless exists $_[0]->{'json'}->{'result'};
return $_[0]->{'json'}->{'result'};
}
sub number
{
return if not exists $_[0]->result->{'number'};
return hex( $_[0]->result->{'number'} );
}
sub td
{
return if not exists $_[0]->result->{'totalDifficulty'};
return hex( $_[0]->result->{'totalDifficulty'} );
}
sub timestamp
{
return if not exists $_[0]->result->{'timestamp'};
return hex( $_[0]->result->{'timestamp'} );
}
sub gasLimit
{
return if not exists $_[0]->result->{'gasLimit'};
return hex( $_[0]->result->{'gasLimit'} );
}
sub miner
{
return if not exists $_[0]->result->{'miner'};
return $_[0]->result->{'miner'};
}
sub nonce
{
return if not exists $_[0]->result->{'nonce'};
return lc $_[0]->result->{'nonce'};
}
sub hash
{
return if not exists $_[0]->result->{'hash'};
return lc $_[0]->result->{'hash'};
}
sub parentHash
{
return if not exists $_[0]->result->{'parentHash'};
return lc $_[0]->result->{'parentHash'};
}
sub extradata
{
return if not exists $_[0]->result->{'extraData'};
my $t = $_[0]->result->{'extraData'};
return substr($t,2) if substr($t,0,2) eq '0x';
return lc $t;
}
sub sealers
{
my $t = $_[0]->extradata;
return unless defined $t;
$t = substr $t,64;
$t = substr $t,0,-130;
my @a;
while ( length $t >= 40 )
{
push @a, substr($t, 0, 40);
$t = substr $t, 40;
}
return @a;
}
sub get
{
my ($self, $number) = @_;
my $libbfa = $self->{'libbfa'};
my $hexed = $number =~ /^\d+$/ ? sprintf("0x%x",$number) : $number;
my $content = $libbfa->rpcreq( 'eth_getBlockByNumber', qq("$hexed"), "false");
my $block = block->new( $libbfa );
$block->parse( $content );
return if not exists $block->{'json'};
die $block->error->message if $block->error;
return if not $block->result;
return $block;
}
sub print
{
print scalar($_[0]->sprint),"\n";
}
my $nonce_xlate = {
'0x0000000000000000' => 'SEALER_REM',
'0xffffffffffffffff' => 'SEALER_ADD',
};
sub sprint
{
my ( $self ) = @_;
my $txt = '';
my $lines = 1;
my @sealers = $self->sealers;
if ( @sealers )
{
$txt = sprintf "\r${tools::clearEOS}";
$txt = '';
for my $sealer ( @sealers )
{
$txt .= sprintf
"Confirming signer at epoch: 0x%s\n",
$sealer;
$lines++;
}
}
$txt .= sprintf
'%s block:%s %s',
tools::gmt($self->timestamp),
$self->number,
$self->sealer;
if ( $self->miner !~ /^0x0{40}$/o )
{
# we have auth or drop
my $nonce = $self->nonce;
$nonce = $nonce_xlate->{$nonce} if exists $nonce_xlate->{$nonce};
$txt .= sprintf " %s %s", $nonce, $self->miner;
}
return wantarray ? ($txt, $lines) : $txt;
}
package main;
use JSON;
$| = 1;
chdir "$ENV{BFAHOME}" or die $!;
my $number = shift || 'latest';
my $tools = tools->new;
my %cache;
my $lastblock;
my %signers;
$libbfa = libbfa->new();
my $block = block->new( $libbfa )->get( $number );
die if not defined $block;
$number = $block->number;
print ansi::CUP().ansi::ED();
sub determine_colour
{
my $diff = shift;
return ansi::green() . ansi::brightwhite()
if $diff == 0;
return ansi::green()
if $diff < scalar ( keys %signers );
return ansi::bgyellow() . ansi::black
if $diff < 720; # one hour
return ansi::red();
}
sub colour_split
{
my ($name, $diff, $col) = @_;
return $name
if $diff == 0;
my $len = length $name;
return
substr( $name, 0, $len-$diff) .
(( $col eq '' ) ? ansi::green() : $col) .
substr( $name, $len-$diff ) .
ansi::normal()
if $diff <= $len;
# diff > len
return $col . $name . ansi::normal();
}
sub presentation_top
{
my $block = shift;
return if not defined $block;
#
my $warning = '';
$warning = ' ' . ansi::red() . " **NOT RECENT** " . ansi::normal()
if $block->timestamp + 1800 < time();
print
ansi::CUP(),
ansi::normal(),
tools::gmt($block->timestamp),
$warning,
ansi::EL(0),
ansi::CUP(scalar(keys %signers) + 2, 1);
}
while ( defined $block || sleep 1 )
{
my $parent = undef;
$block = block->new( $libbfa )->get( $number );
if ( not defined $block )
{
presentation_top( $lastblock );
next;
}
presentation_top( $block );
$lastblock = $block;
$cache{$number}{'block'} = $block;
$number = $block->number;
if ( exists $cache{ $number - 1 }{'block'} )
{
$parent = $cache{ $number - 1}{'block'};
# If we do have any information about previous blocks,
# see if the hash matches. If we were in a side branch
# we would eventually get wrong hashes, because we
# ask for blocknumbers (block height).
# This is a good way to determine if we're side tracked.
if ( $parent->hash ne $block->parentHash )
{
# If we are side tracked, we'll read backwards
# until we find a match (or nothing cached)
delete $cache{$number};
$number --;
next;
}
}
my $hexed = $number =~ /^\d+$/ ? sprintf("0x%x",$number) : $number;
my $snapjson = $libbfa->rpcreq( 'clique_getSnapshot', qq("$hexed") );
die unless defined $snapjson;
die if $snapjson eq '';
my $snapparsed;
$snapparsed = decode_json( $snapjson );
my $result = $snapparsed->{'result'};
my $thissigner = $result->{'recents'}{$number};
#
# Make sure we only have current signers listed
my %newsigners = ();
for my $this (sort keys %{ $result->{'signers'} } )
{
$newsigners{$this} = $signers{$this}
if exists $signers{$this};
}
%signers = %newsigners;
$signers{$thissigner} = $number;
$cache{$number}{'signer'} = $thissigner;
#
# presentation
my $num_max_width = tools::max( length $number, 3 );
print ansi::CUP(2,1);
foreach my $this ( sort keys %{ $result->{'signers'}} )
{
my $lastnum = exists $signers{$this} ? $signers{$this} : -12345;
my $diff = $number - $lastnum;
my $col = determine_colour( $diff );
my $id = colour_split( $this, $diff, $col );
my $flags = $diff == 0 ? '*' : '';
my $alias = alias::translate( $this );
my $numtxt = (not defined $lastnum or $lastnum < 0) ? 'n/a' : $lastnum;
printf "%s%-1s%s%-${num_max_width}s%s %s%s\n",
$id, $flags, $col, $numtxt, ansi::normal(),
defined $alias ? $alias : '',
ansi::EL(0);
}
print ansi::ED(0);
#
$number = $block->number + 1;
}
0x91c055c6478bd0ad6d19bcb58f5e7ca7b04e67f1 Dirección General de Sistemas de Información
0x46991ada2a2544468eb3673524641bf293f23ccc Universidad Nacional de Córdoba
0x342e1d075d820ed3f9d9a05967ec4055ab23fa1e CABASE CABA
0x02665f10cb7b93b4491ac9594d188ef2973c310a CABASE Mendoza
0x19fe7b9b3a1bebde77c5374c8e13c623e3d1b5b2 Asociación Redes de Interconexión Universitaria
0x2feb6a8876bd9e2116b47834b977506a08ea77bd Prefectura Naval Argentina
0x9b3ac6719b02ec7bb4820ae178d31c0bbda3a4e0 everis
0x609043eBDE4a06bD28a1DE238848E8f82cca9C23 Universidad Nacional de San Juan
0xc0310a7b3b25f49b11b901a667208a3eda8d7ceb Servicios y Telecomunicaciones S.A.
0x998c2651db6f76ca568c0071667d265bcc1b1e98 Agencia de Sistemas de Información, CABA
0x39170a1ce03729d141dfaf8077c08b72c9cfdd0c IXP Bahia Blanca
0x2388d2cdb2cd6e7722b4af39c3bb406dd31f560e Universidad Nacional de Rosario
0x401d7a8432caa1025d5f093276cc6ec957b87c00 Oficina Nacional de Tecnologías de Información
0x97a47d718eab9d660b10de08ef42bd7fd915b783 Universidad Nacional de La Plata
0xa14152753515674ae47453bea5e155a20c4ebabc Universidad de Palermo
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment