From 16315b7048134a7bde3d4c060a0d05a560cb0ff5 Mon Sep 17 00:00:00 2001
From: Robert Martin-Legene <robert@nic.ar>
Date: Tue, 11 Sep 2018 17:11:12 -0300
Subject: [PATCH] transactors traverses the blockchain\'s transactions and
 finds out who has ever received ether

---
 bin/transactors.pl | 262 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 262 insertions(+)
 create mode 100755 bin/transactors.pl

diff --git a/bin/transactors.pl b/bin/transactors.pl
new file mode 100755
index 0000000..d5018b0
--- /dev/null
+++ b/bin/transactors.pl
@@ -0,0 +1,262 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+use IO::File;
+use Math::BigInt;
+use Carp;
+$Carp::Verbose  =   1;
+
+die "\$BFAHOME not set. Did you source bfa/bin/env ?\n"
+  unless exists $ENV{BFAHOME};
+chdir "$ENV{BFAHOME}" or die $!;
+
+package tools;
+my  $rpcport;
+my  $ua		=   LWP::UserAgent->new;
+
+sub new
+{
+    my $class = shift;
+    return bless {@_}, ref $class || $class;
+}
+
+sub wait
+{
+    my $i = ++$_[0]->{'wait'};
+    printf "%s%c[D", substr('|/-\\', $i%4, 1), 27;
+    sleep 1;
+}
+
+sub cat($)
+{
+  my ($filename) = @_;
+  my $fh = IO::File->new($filename) or return;
+  return join('', $fh->getlines);
+}
+
+sub hex2string($)
+{
+  my ($msg)=@_;
+  my $txt = '';
+  while ($msg ne '')
+  {
+    my $i=hex( substr($msg,0,2) );
+    my $c='.';
+    $c=chr($i) if $i >= 32 and $i <= 127;
+    $txt .= $c;
+    $msg=substr $msg, 2;
+  }
+  return $txt;
+}
+
+sub rpcreq
+{
+    my  ( $opname, @params ) = @_;
+    if  ( not defined $rpcport )
+    {
+        $rpcport    =   tools::cat "$ENV{BFAHOME}/network5445/node1/rpcport" or die;
+    }
+    my  $req        =   HTTP::Request->new( POST => "http://127.0.0.1:$rpcport" );
+    $req->content_type('application/json');
+    my $extra      =   scalar @params
+        ? sprintf(qq(,\"params\":[%s]), join(',', @params))
+        : '';
+    $req->content( qq({"jsonrpc":"2.0","method":"${opname}"${extra},"id":1}));
+    my  $res        =   $ua->request($req);
+    die $res->status_line
+        unless $res->is_success;
+    return $res->content;
+}
+
+package balance;
+use JSON;
+
+sub new
+{
+    my  ($class, $acct, $at) = @_;
+    my  $self = bless {}, ref $class || $class;
+    $self->get( $acct, $at ) if defined $acct;
+    return $self;
+}
+
+sub acct
+{
+    my  ($self, $acct) = @_;
+    if ( defined $acct )
+    {
+        $acct   =   '0x'.$acct if $acct !~ /^0x/;
+        $self->{'_acct'} = $acct;
+    }
+    return unless exists $self->{'_acct'};
+    return $self->{'_acct'};
+}
+
+sub at
+{
+    my  ($self, $at) = @_;
+    $self->{'_at'} = $at if defined $at;
+    return sprintf('0x%x', $self->{'_at'}) if exists $self->{'_at'};
+    return 'latest';
+}
+
+sub get
+{
+    my      ($self, $acct, $at) = @_;
+    $self->acct($acct)  if defined $acct;
+    $self->at($at)      if defined $at;
+    my      @params         =   ( sprintf(qq("%s","%s"),$self->acct,$self->at) );
+    my      $content        =   tools::rpcreq( 'eth_getBalance', @params );
+    my      $json;
+    eval { $json = decode_json( $content ) };
+    my      $error          =   error->new( $content );
+    if ( $error )
+    {
+        my $msg = '';
+        return 'NOTFOUND' if $error->message =~ /^missing trie node /;
+        die join(' * ', @params, $content);
+        return;
+    }
+    die if not exists  $json->{'result'};
+    die if not defined $json->{'result'};
+    return Math::BigInt->from_hex( $json->{'result'} );
+}
+
+
+package error;
+use JSON;
+
+sub new
+{
+    my      ($class, $json_in)  =   @_;
+    my      $json;
+    eval { $json = decode_json( $json_in ) };
+    return unless defined $json;
+    return unless exists $json->{'error'};
+    my      $self = bless {
+        '_code'     =>  undef,
+        '_message'  =>  undef,
+    }, ref $class || $class;
+    $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, $json_raw ) = @_;
+    return unless defined $json_raw;
+    return if $json_raw eq '';
+    my  $self   = bless {}, ref $class || $class;
+    $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 timestamp
+{
+    return if not exists $_[0]->result->{'timestamp'};
+    return hex( $_[0]->result->{'timestamp'} );
+}
+
+sub miner
+{
+  return if not exists $_[0]->result->{'miner'};
+  return $_[0]->result->{'miner'};
+}
+
+sub get($;$)
+{
+    my  ($number)   =   @_;
+    $number         =   sprintf('0x%x', $number) if $number ne 'earliest';
+    my  $cachefile  =   "cache/block.$number";
+    my  $content    =   tools::rpcreq( 'eth_getBlockByNumber', qq("$number"), "true");
+    my  $block      =   block->new( $content );
+    return if not defined $block;
+    return if not exists $block->{'json'};
+    die $block->error->message
+        if $block->error;
+    return if not $block->result;
+    return $block;
+}
+
+sub tx {
+    my      ($self)         =   @_;
+    return  $self->result->{'transactions'};
+}
+
+package main;
+
+my $number  =   shift || 'earliest';
+my $_rcpts;
+
+sub rcpt
+{
+    return 0 if exists $_rcpts->{$_[0]};
+    $_rcpts->{$_[0]} =   1;
+    return 1;
+}
+
+while ( 1 )
+{
+    my $block   =   block::get($number);
+    exit 0 if not defined $block;
+use Data::Dumper; print Dumper( $block->result );
+die $block->miner;
+    rcpt( $block->miner );
+    my  $txref  =   $block->tx;
+    for my $tx (@$txref)
+    {
+        my  $from   =   $tx->{'from'};
+        my  $to     =   $tx->{'to'};
+        my  $value  =   $tx->{'value'};
+        next if $value eq '0x0';
+        printf "%s\n", $to if rcpt( $to );
+    }
+    $number     =   $block->number + 1;
+}
-- 
GitLab