diff --git a/collector/Dockerfile b/collector/Dockerfile
index 2c114b4e59c4f1598b2d6dd0ae9dac237f23ccb4..013a123c35437b3d82a836c8c48b5fc369377c69 100644
--- a/collector/Dockerfile
+++ b/collector/Dockerfile
@@ -1,9 +1,10 @@
-FROM debian
-RUN useradd --create-home --shell /bin/bash bfa && mkdir /home/bfa/collector
-RUN apt-get update && apt-get upgrade -y
-RUN apt-get install -y libjson-perl libnet-dns-perl libdbd-pg-perl libwww-perl vim
-COPY collector.pl /home/bfa/collector
-RUN chown -R bfa /home/bfa
-USER bfa
-#CMD /home/bfa/collector/collector.sh
-CMD sleep 14d
+FROM    debian
+RUN     useradd --create-home --shell /bin/bash bfa && mkdir /home/bfa/collector
+RUN     apt-get update && apt-get upgrade -y
+RUN     apt-get install -y libjson-perl libnet-dns-perl libdbd-pg-perl libwww-perl vim
+COPY    collector.pl /home/bfa/collector
+RUN     chown -R bfa /home/bfa
+USER    bfa
+ENV     BFANODE public.47525974938.bfa.martin-legene.dk.
+#CMD    /home/bfa/collector/collector.sh
+CMD     sleep 14d
\ No newline at end of file
diff --git a/collector/collector.pl b/collector/collector.pl
index a14bbe6bc1f4911b8a8913fbe0c14ab9a1cef912..e25a1e62f1302f9a598350dc8fa999929a59571f 100755
--- a/collector/collector.pl
+++ b/collector/collector.pl
@@ -11,8 +11,8 @@ use     LWP;
 use     JSON;
 use	    Net::DNS;
 use     Net::DNS::Resolver;
-use     DBI;
-use     "sql"
+use     lib '.';
+use     sql;
 
 # 47525974938;
 my      $netversion         =   Math::BigInt->new( "0xb10c4d39a" );
@@ -20,12 +20,9 @@ my      $netversion         =   Math::BigInt->new( "0xb10c4d39a" );
 my      $chainid            =   Math::BigInt->new( "0xbfa2018"   );
 my      $idcounter          =   0;
 my      $ua;
-my      @endpoints;
 my      @blockqueue;
 my      %sealers;
-# Set maxruns to 1 if you want to just do a single run to keep
-# your database up-to-date.
-my      $maxruns            =   0;
+my      $sql;
 
 sub     info(@)
 {
@@ -54,8 +51,9 @@ sub     shorthash($)
 
 sub     rpcreq
 {
-    my  ( $endpoint,
-        $opname, @params )  =   @_;
+    my  ( $opname, @params )=   @_;
+    $ua                     =   LWP::UserAgent->new( keep_alive => 10 )
+        if not defined $ua;
     # $ua->ssl_opts( 'verify_hostname' => 0 );
     my      %args           =   (
         jsonrpc             =>  '2.0',
@@ -83,8 +81,12 @@ sub     rpcreq
         push @args, $p;
     }
     my  $args               =   '{' . join(',',@args) . '}';
+    die 'The environment variable $BFANODE must contain a URL for a ' .
+        'server to connect to (e.g. https://10.20.30.40/), but it it ' .
+        'not set. Stopped'
+        unless defined $ENV{'BFANODE'};
     my  $res                =   $ua->post(
-        $endpoint,
+        $ENV{BFANODE},
         'Content-Type'      =>  'application/json',
         'Content'           =>  $args,
     );
@@ -94,88 +96,17 @@ sub     rpcreq
     return $json->{'result'};
 }
 
-sub     endpoint_find
-{
-    my      $networknumber  =   $netversion->bstr;
-    my      $res            =   Net::DNS::Resolver->new();
-    my      $origin         =   'bfa.martin-legene.dk';
-    my      $fqdn           =   sprintf
-        '_rpc._tcp.public.%s.%s.',
-        $networknumber, $origin;
-    my	    $reply          =   $res->query( $fqdn, 'SRV' );
-    die "No SRV RR found for public endpoints. Stopped"
-        if not $reply;
-    my      @answer;
-    @answer                 =   rrsort( 'SRV', 'priority', $reply->answer );
-    die "DNS SRV query returned no SRV records. Stopped"
-        if not @answer;
-    my  %protolookup        =   (
-        '_rpc'              =>  'http',
-        '_rpcs'             =>  'https',
-    );
-    @endpoints              =   ();
-    foreach my $answer ( @answer )
-    {
-        my      $targetname =   $answer->target;
-        info "Publicly open endpoint found at %s.\n", $targetname;
-        my      $r_a        =   $res->query( $targetname, 'A'    );
-        my      $r_aaaa     =   $res->query( $targetname, 'AAAA' );
-        my      @addresses  =   ();
-        push @addresses, rrsort( 'A',    $r_a->answer )
-            if $r_a;
-        push @addresses, rrsort( 'AAAA', $r_aaaa->answer )
-            if $r_aaaa;
-        warn "No address found for $targetname,"
-            if not @addresses;
-        my      $label1     =   (split( /\./, $fqdn, 2 ))[0];
-        foreach my $address_rr ( @addresses )
-        {
-            next
-                if not exists $protolookup{$label1};
-            my $proto       =   $protolookup{$label1};
-            push @endpoints, sprintf(
-                '%s://%s:%s',
-                $proto,
-                $address_rr->address,
-                $answer->port
-            );
-        }
-    }
-    info "Preferring endpoint at %s\n", $endpoints[0];
-}
-
 sub     getblock
 {
-    my      $blockid        =   $_[0];
-    my      $json;
-    $blockid                =   Math::BigInt->new( $blockid )
-        if ref($blockid) eq ''
-        and $blockid =~ /^\d+$/;
-    if ( ref $blockid eq 'Math::BigInt' or $blockid =~ /^(earliest|latest|pending)$/ )
-    {
-        my  $specific       =  ref $blockid eq 'Math::BigInt'
-                            ?  $blockid->as_hex
-                            :  $blockid;
-        $json               =   rpcreq(
-            $endpoints[0],
-            'eth_getBlockByNumber',
-            $specific, 'false' );
-    }
-    else
-    {
-        $sth_selectBlockByHash->execute( $blockid );
-        return if $sth_selectBlockByHash->fetch;
-        $json               =   rpcreq(
-            $endpoints[0],
-            'eth_getBlockByHash',
-            $blockid, 'false'
-        );
-    }
+    my      $block          =   shift;
+    my      $rpccmd         =   $block =~ /^(earliest|latest|pending)$/
+                            ?   'eth_getBlockByNumber'
+                            :   'eth_getBlockByHash';
+    my  $json               =   rpcreq( $rpccmd, $block, 'false' );
     die "We should have received some kind of JSON from our RPC call, " .
         "but apparently not. Stopped "
         if not defined $json;
-    $sth_selectBlockByHash->execute( $json->{'hash'} );
-    return if $sth_selectBlockByHash->fetch;
+    return if $sql->selectBlockByHash( $json->{'hash'} );
     foreach my $key (qw(
         timestamp gasUsed gasLimit difficulty number totalDifficulty size
     )) {
@@ -190,7 +121,7 @@ sub     getblock
         $json->{'size'},
         $json->{'gasUsed'},
         $json->{'gasLimit'};
-    $sth_insertBlock->execute(
+    $sql->sth_insertBlock->execute(
         lc $json->{'hash'},
         lc $json->{'parentHash'},
         $json->{'number'},
@@ -213,11 +144,11 @@ sub     getblock
 
 sub     getTransByHash
 {
-    my  $hash               =   $_[0];
-    $sth_selectTransactionByHash->execute( $hash );
-    return if $sth_selectTransactionByHash->fetch;
+    my  $hash               =   shift;
+    # Don't get it via RPC if we already have it in the database
+    return
+        if $sql->selectTransactionByHash( $hash );
     my  $json               =   rpcreq(
-        $endpoints[0],
         'eth_getTransactionByHash',
         $hash
     );
@@ -225,7 +156,6 @@ sub     getTransByHash
     my  $rcpt                   =   undef;
     do {
         $rcpt                   =   rpcreq(
-            $endpoints[0],
             'eth_getTransactionReceipt',
             $hash
         );
@@ -234,7 +164,7 @@ sub     getTransByHash
             sleep 1;
             warn "Couldn't get the transaction receipt for $hash\n";
         }
-    } while not $rcpt and $max++ < 60;
+    } while not $rcpt and $max++ < 10;
     die "Couldn't get the transaction receipt for $hash\n" if not $rcpt;
     $json->{'status'}       =   $rcpt->{'status'};
     $json->{'gasUsed'}      =   $rcpt->{'gasUsed'};
@@ -251,8 +181,11 @@ sub     getTransByHash
             shorthash $json->{'from'},
             shorthash $json->{'to'};
     my      $input          =   $json->{'input'};
-    $input                  =~  s/^0x//;
-    my      $inputlen       =   length($input) / 2;
+    my      $inputlen       =   0;
+    if ( $input =~  /^0x/ )
+    {
+        $inputlen           =   (length($input)-2) / 2;
+    }
     my      @args           =   (
         lc $json->{'hash'},
         lc $json->{'blockHash'},
@@ -262,31 +195,26 @@ sub     getTransByHash
         $json->{'value'},
         lc $json->{'from'},
         lc $json->{'to'},
-        $inputlen,
-        $json->{'gasUsed'},
         $json->{'status'},
+        $json->{'gasUsed'},
+        $input,
+        $inputlen,
     );
-    my  $function           =   $sth_insertTransaction;
     if ( $json->{'contractAddress'} )
     {
-        push @args, $json->{'contractAddress'};
-        $function           =   $sth_insertTransactionWithContractAddress;
+        $sql->insertTransactionWithContractAddress( @args, lc $json->{'contractAddress'} );
+    }
+    else
+    {
+        $sql->insertTransaction( @args );
     }
-    $function->execute( @args );
-}
-
-sub     getTransRcptByHash
-{
-    my  $hash               =   $_[0];
 }
 
 sub     versioncheck
 {
     my      $n;
     my      $ok             =   1;
-    $n                      =   Math::BigInt->new(
-        rpcreq( $endpoints[0], "net_version" )
-    );
+    $n                      =   Math::BigInt->new( rpcreq( "net_version" ) );
     if ( $n->bcmp( $netversion ) != 0 )
     {
         warn "Network says it has net.version "
@@ -298,9 +226,7 @@ sub     versioncheck
             . ").\n";
         $ok                 =   0;
     }
-    $n                      =   Math::BigInt->new(
-        rpcreq( $endpoints[0], "eth_chainId" )
-    );
+    $n                      =   Math::BigInt->new( rpcreq( "eth_chainId" ) );
     if ( $n->bcmp( $chainid ) != 0 )
     {
         warn sprintf("Network says it has eth.chainId %s (%s). Expected %s (%s).\n", $n->bstr, $n->as_hex, $chainid->bstr, $chainid->as_hex);
@@ -310,76 +236,56 @@ sub     versioncheck
     return $ok;
 }
 
-sub     sealer
-{
-    my      $hash           =   $_[0];
-    my      $row;
-    die unless defined $hash;
-    return $sealers{$hash} if exists $sealers{$hash};
-    $sth_selectsealer->execute( $hash );
-    return $sealers{$hash} = $row->[0] if $row = $sth_selectsealer->fetch;
-    $sth_insertsealer->execute( $hash );
-    $sth_selectsealer->execute( $hash );
-    die     "Apparently we failed to get find/create a new sealer. Stopped"
-        if not $row = $sth_selectsealer->fetch;
-    return $sealers{$hash} = $row->[0];
-}
-
 sub     getsnap
 {
-    my      $number         =   $_[0];
-    my      @blocks;
-    $number                 =   Math::BigInt->new( $number )
-        if ref($number) ne 'Math::BigInt';
+    my      $blockhash      =   $_[0];
     my      $json           =   rpcreq(
-        $endpoints[0],
-        'clique_getSnapshot',
-        $number->as_hex
+        'clique_getSnapshotAtHash',
+        $blockhash
     );
+    # Sanity check 1 - does the lookup return the block?
     return if not defined $json;
     my      $recents        =   $json->{'recents'};
-    return if not defined $recents;
-    my      $hash           =   $json->{'hash'};
-    my      $count          =   0;
-    while ( exists $recents->{$number->bstr} )
+    # Blockhash of the requested block - we must use this for the insert
+    $blockhash              =   $json->{'hash'};
+    my      $blocknumber    =   Math::BigInt->new( $json->{'number'} );
+    my      @infonumbers;
+    while ( not $blocknumber->is_zero )
     {
-        push    @blocks, $number->bstr;
-        $sth_selectBlockByHash->execute( $hash );
-        my  $row            =   $sth_selectBlockByHash->fetchrow_hashref;
-        return if not defined $row;
-        my  $newnumber      =   Math::BigInt->new( $row->{'number'} );
-        return if $newnumber->bcmp($number) != 0;
+        my  $sealerhash     =   $recents->{$blocknumber->bstr};
+        last if not defined $sealerhash;
+        push    @infonumbers, $blocknumber->bstr;
+        my  $ref            =   $sql->selectBlockByHash( $blockhash );
+        # Stop if we get to blocks which we still haven't stored in the db
+        return ( undef, $blocknumber )
+            if not defined $ref;
         # Stop if we got to a block with sealers.
-        return if defined $row->{'sealer'};
-        my  $sealerhash     =   $recents->{$number->bstr};
-        return if not defined $sealerhash;
-        my  $internalid     =   sealer( $sealerhash );
-        return if not defined $internalid;
-        my $rows_affected   =   $sth_updatewhosealed->execute(
-            $internalid,
-            $hash
-        );
+        return ( undef, $blocknumber )
+            if exists $ref->{'sealerAccountId'} and defined $ref->{'sealerAccountId'};
+        $sql->updateWhoSealed( $sealerhash, $blockhash );
+        my  $parentblockid  =   $ref->{'parentBlockhashId'};
         # For next block...
-        $hash               =   $row->{'parentHash'};
-        $number->bsub(1);
+        $blockhash          =   $sql->selectBlockhashById( $parentblockid );
+        $blocknumber->bsub(1);
     }
-    info    "S Snapshot at block # @blocks.\n";
-    return  $number;
+    info    "S Snapshot at block # @infonumbers.\n";
+    return  ($blockhash, $blocknumber);
 }
 
+# Find strands of blocks in the database which have their sealer set to NULL
 sub     allsnaps
 {
-    $sth_selectmaxunknownsigned->execute();
-    my      $unkn           =   $sth_selectmaxunknownsigned->fetchrow_hashref;
-    my      $number         =   Math::BigInt->new( $unkn->{'number'} );
+    my      $blockhash      =   $sql->selectMaxUnknownSigned;
     my      $committer      =   0;
-    while ( defined $number and not $number->is_zero )
+    while ( defined $blockhash )
     {
-        $number             =   getsnap( $number );
-        $dbh->commit
+        my  $blocknumber;
+        ( $blockhash, $blocknumber )
+                            =   getsnap( $blockhash );
+        $sql->commit
             if ( $committer++ % 75 ) == 0;
+        last if $blocknumber->is_zero;
     }
-    $dbh->commit;
 }
 
 sub     main
@@ -387,20 +293,15 @@ sub     main
     $|                      =   1;
     info                        "Connecting to database and setting up "
                             .   "prepared statements.\n";
-    sql::setup;
-    #
-    info                        "Looking for public RPC endpoints of "
-                            .   "the BFA.\n";
-    $ua                     =   LWP::UserAgent->new( keep_alive => 10 );
-    endpoint_find();
+    $sql                    =   sql->new();
     versioncheck();
     info                        "Looking for orphaned blocks in the "
                             .   "database.\n";
-    push @blockqueue, sql::listOrphans();
+    push @blockqueue,           sql->listOrphans();
     
-    while ( --$maxruns != 0 )
+    while ( 1 )
     {
-        unshift @blockqueue, "latest";
+        unshift @blockqueue,    'latest';
         while ( @blockqueue )
         {
             my  $maxinarow      =   2500;
@@ -408,7 +309,7 @@ sub     main
                 while @blockqueue and --$maxinarow;
             # Find out who signed all blocks
             allsnaps();
-            $dbh->commit;
+            $sql->commit;
         }
         sleep 5;
     }
diff --git a/collector/sql.pm b/collector/sql.pm
index 3c84935db94a09b550526b3613681f2e44a1a4de..249f5d7b08e35ed9b97d38facc28668c977f5e5c 100644
--- a/collector/sql.pm
+++ b/collector/sql.pm
@@ -4,105 +4,322 @@
 
 package sql;
 use     DBI;
+use     base qw( Class::Accessor );
 
-my      @blockqueue;
-my      $dbh;
-my      $sth_insertBlock;
-my      $sth_selectBlockByHash;
-my      $sth_selectTransactionByHash;
-my      $sth_insertTransaction;
-my      $sth_insertTransactionWithContractAddress;
-my      $sth_insertsealer;
-my      $sth_selectsealer;
-my      $sth_updatewhosealed;
-my      $sth_selectmaxunknownsigned;
-
-sub     setup
+__PACKAGE__->mk_accessors( 'dbh' );
+sub     new
 {
-    $dbh                    =   DBI->connect(
+    my      ( $class )      =   @_;
+    my      $self           =   bless {}, ref $class || $class;
+    $self->dbh( DBI->connect(
         'dbi:Pg:dbname=postgres;host=postgres','postgres','onlythelonely',
         {AutoCommit=>0,RaiseError=>1}
-    )
-        or die                      DBI::errstr;
-    $sth_insertBlock        =   $dbh->prepare(q(
-        INSERT INTO blocks
-        (   hash,       parentHash, number,     timestamp,
-            difficulty, gasUsed,    gasLimit,   size        )
-        VALUES  (?,?,?,?,?,?,?,?)
-    )) or die $DBI::errstr;
-    $sth_selectBlockByHash  =   $dbh->prepare(q(
-        SELECT  parenthash,number,sealer
-        FROM    blocks
-        WHERE   hash=?
-    )) or die $DBI::errstr;
-    $sth_selectTransactionByHash
-                            =   $dbh->prepare(q(
-        SELECT  "exists"
-        FROM    transactions
-        WHERE   hash=?
-    )) or die $DBI::errstr;
-    $sth_insertTransactionWithContractAddress
-                            =   $dbh->prepare(q(
-        INSERT INTO transactions
-        (   hash,       blockHash,  nonce,  gas,
-            gasPrice,   value,      _from,  _to,
-            inputlen,   gasUsed,    status, contractAddress )
-        VALUES  (?,?,?,?,?,?,?,?,?,?,?,?)
-    )) or die $DBI::errstr;
-    $sth_insertTransaction  =   $dbh->prepare(q(
-        INSERT INTO transactions
-        (   hash,       blockHash,  nonce,  gas,
-            gasPrice,   value,      _from,  _to,
-            inputlen,   gasUsed,    status                  )
-        VALUES  (?,?,?,?,?,?,?,?,?,?,?)
-    )) or die $DBI::errstr;
-    $sth_selectsealer       =   $dbh->prepare(q(
-        SELECT  internalid
-        FROM    sealers
-        WHERE   hash=?
-    )) or die $DBI::errstr;
-    $sth_insertsealer       =   $dbh->prepare(q(
-        INSERT INTO sealers
-        (   hash    )
-        VALUES  (?)
-    )) or die $DBI::errstr;
-    $sth_updatewhosealed    =   $dbh->prepare(q(
-        UPDATE  blocks
-        SET     sealer=?
-        WHERE   hash=?
-        AND     sealer IS NULL
-    )) or die $DBI::errstr;
-    $sth_selectmaxunknownsigned
-                            =   $dbh->prepare(q(
-        SELECT  number
-        FROM    blocks
-        WHERE   number = (
-            SELECT  MAX(number)
-            FROM    blocks
-            WHERE   sealer IS NULL
-        )
-    )) or die $DBI::errstr;
+    ));
+    return  $self;
 }
 
-sub listOrphans
+sub     commit
 {
-    my      @results;
-    my      $sth_selectOrphans
-                            =   $dbh->prepare(q(
-        SELECT  parentHash,number
+    my      ( $self )       =   @_;
+    $self->dbh->commit;
+}
+
+sub     listOrphans
+{
+    my      ( $self )       =   @_;
+    my      $sth            =   $self->dbh->prepare(q(
+        SELECT  parentBlockhashId,id
         FROM    blocks
-        WHERE   parentHash NOT IN (
-            SELECT  hash
+        WHERE   parentBlockhashId NOT IN (
+            SELECT  id
             FROM    blocks
         )
-    )) or die $DBI::errstr;
-    $sth_selectOrphans->execute();
-    while ( my $row         =   $sth_selectOrphans->fetch )
+    ));
+    my      @results;
+    $sth->execute();
+    while ( my $row         =   $sth->fetchrow_arrayref )
     {
         # Block 0 has it's parent listed as 0x0{64}
-        next if $row->[0] =~ /^0x0{64}$/;
-        push @results, $row->[0]
+        next if $row->[0]   =~  /^0x0{64}$/;
+        push @results,          $self->selectBlockhashById( $row->[0] );
+    }
+    $sth->finish;
+    return  @results;
+}
+
+__PACKAGE__->mk_accessors( 'sth_insertTransactionWithContractAddress' );
+sub     insertTransactionWithContractAddress
+{
+    my      $self           =   shift;
+    if ( not defined $self->sth_insertTransactionWithContractAddress )
+    {
+        $self->sth_insertTransactionWithContractAddress(
+            $self->dbh->prepare(q(
+                INSERT INTO transactions
+                (   hash,                       blockId,    nonce,          gas,
+                    gasPrice,                   value,      fromAccountId,  toAccountId,
+                    status,                     gasUsed,    input,          inputlen,
+                    contractaddressAccountId )
+                VALUES  (?,?,?,?,?,?,?,?,?,?,?,?,?)
+            ))
+        );
+    }
+    $_[1]                   =   $self->selectBlockhashByHash( $_[1] );
+    $self->sth_insertTransactionWithContractAddress->execute( @_ );
+}
+
+__PACKAGE__->mk_accessors( 'sth_insertTransaction' );
+sub     insertTransaction
+{
+    my      $self           =   shift;
+    $self->sth_insertTransaction(
+        $self->dbh->prepare(q(
+            INSERT INTO transactions
+            (   hash,       blockId,    nonce,          gas,
+                gasPrice,   value,      fromAccountId,  toAccountId,
+                status,     gasUsed,    input,          inputlen )
+            VALUES  (?,?,?,?,?,?,?,?,?,?,?,?)
+        ))
+    );
+    $_[1]                   =   $self->selectBlockhashByHash( $_[1] );
+    $self->sth_insertTransaction->execute( @_ );
+}
+
+__PACKAGE__->mk_accessors( 'sth_selectBlockhashById' );
+sub     selectBlockhashById
+{
+    my      ( $self, $id )  =   @_;
+    if ( not defined $self->sth_selectBlockhashById )
+    {
+        $self->sth_selectBlockhashById(
+            $self->dbh->prepare(q(
+                SELECT  hash
+                FROM    blockhash
+                WHERE   id=?
+            ))
+        );
+    }
+    $self->sth_selectBlockhashById->execute( $id );
+    my      $ref            =   $self->sth_selectBlockhashById->fetchrow_arrayref;
+    $self->sth_selectBlockhashById->finish;
+    return
+        if not defined $ref;
+    return $ref->[0];
+}
+
+__PACKAGE__->mk_accessors( 'sth_selectBlockhashByHash' );
+sub     selectBlockhashByHash
+{
+    my      ( $self, $hash )=   @_;
+    if ( not defined $self->sth_selectBlockhashByHash )
+    {
+        $self->sth_selectBlockhashByHash(
+            $self->dbh->prepare(q(
+                SELECT  id
+                FROM    blockhash
+                WHERE   hash=?
+            ))
+        );
+    }
+    my      $inserts        =   0;
+    while ( 1 )
+    {
+        # Try to look up the hash
+        $self->sth_selectBlockhashByHash->execute( $hash );
+        my $ref             =   $self->sth_selectBlockhashByHash->fetchrow_arrayref;
+        $self->sth_selectBlockhashByHash->finish;
+        # If found, return it immediately
+        return $ref->[0]        if defined $ref;
+        # Do maximum 1 attempt to insert a hash
+        return                  if $inserts > 0;
+        # Insert a hash, because it is not already in the database.
+        $self->insertBlockhash( $hash );
+        # Avoid loops.
+        $inserts++;
+    }
+}
+
+__PACKAGE__->mk_accessors( 'sth_insertBlockhash' );
+sub     insertBlockhash
+{
+    my      ( $self, $hash )=   @_;
+    if ( not defined $self->sth_insertBlockhash )
+    {
+        $self->sth_insertBlockhash(
+            $self->dbh->prepare(q(
+                INSERT INTO blockhash
+                (   hash    )
+                VALUES  (?)
+            ))
+        )
+    }
+    $self->sth_insertBlockhash->execute( $hash );
+}
+
+__PACKAGE__->mk_accessors( 'sth_selectAccountIdByAddress' );
+my      %account;
+sub     selectAccountIdByAddress
+{
+    my      ( $self, $address )=   @_;
+    if ( not defined $self->sth_selectAccountIdByAddress )
+    {
+        $self->sth_selectAccountIdByAddress(
+            $self->dbh->prepare(q(
+                SELECT  id
+                FROM    account
+                WHERE   address=?
+            ))
+        );
+    }
+    while ( not exists $account{$address} )
+    {
+        # Try to look up the hash
+        $self->sth_selectAccountIdByAddress->execute( $address );
+        my  $ref                    =   $self->sth_selectAccountIdByAddress->fetchrow_arrayref;
+        $self->sth_selectAccountIdByAddress->finish;
+        # If found, return it immediately
+        if ( defined $ref )
+        {
+            $account{$address}      =   $row->[0];
+            last;
+        }
+        # Do maximum 1 attempt to insert a hash
+        # (this is actually a failure and should not happen)
+        return                  if $inserts > 0;
+        # Insert a hash, because it is not already in the database.
+        $self->insertAccount( $hash );
+        # Avoid loops.
+        $inserts++;
+    }
+    return $account{$address};
+}
+
+__PACKAGE__->mk_accessors( 'sth_insertAccount' );
+sub     insertAccount
+{
+    my      ( $self, $address )=   @_;
+    if ( not defined $self->sth_insertAccount )
+    {
+        $self->sth_insertAccount(
+            $self->dbh->prepare(q(
+                INSERT INTO account
+                (   address    )
+                VALUES  (?)
+            ))
+        );
+    }
+    $self->sth_insertAccount->execute( $hash );
+}
+
+__PACKAGE__->mk_accessors( 'sth_insertBlock' );
+sub     insertBlock
+{
+    my      ( $self, $hash, $parentHash, $number, $timestamp, $difficulty, $gasUsed, $gasLimit, $size )
+                            =   @_;
+    if ( not defined $self->sth_insertBlock )
+    {
+        $self->sth_insertBlock(
+            $self->dbh->prepare(q(
+                INSERT INTO blocks
+                (   id, parentBlockhashId, number, timestamp,
+                    difficulty, gasUsed, gasLimit, size )
+                VALUES  (?,?,?,?,?,?,?,?)
+            ))
+        );
+    }
+    my      $id             =   $self->selectBlockhashByHash( $hash );
+    my      $parentid       =   $self->selectBlockhashByHash( $parentHash );
+    $self->sth_insertBlock->execute( $id, $parentid, $number, $timestamp, $difficulty, $gasUsed, $gasLimit, $size );
+}
+
+__PACKAGE__->mk_accessors( 'sth_selectBlockByHash' );
+sub     selectBlockByHash
+{
+    my      ( $self, $hash) =   @_;
+    if ( not defined $self->sth_selectBlockByHash )
+    {
+        $self->sth_selectBlockByHash(
+            $self->dbh->prepare(q(
+                SELECT  parenthash,number,sealer
+                FROM    blocks
+                WHERE   hash=?
+            ))
+        );
+    }
+    $sth->sth_selectBlockByHash( $hash );
+    my      $row            =   $sth->selectBlockByHash->fetchrow_hashref;
+    $sth->selectBlockByHash->finish;
+    return
+        if not defined $row;
+    return  $row;
+}
+
+__PACKAGE__->mk_accessors( 'sth_selectTransactionByHash' );
+sub     selectTransactionByHash
+{
+    my      ( $self, $hash) =   @_;
+    if ( not defined $self->sth_selectTransactionByHash )
+    {
+        $self->sth_selectTransactionByHash(
+            $self->dbh->prepare(q(
+                SELECT  1
+                FROM    transactions
+                WHERE   hash=?
+            ))
+        );
+    }
+    $sth->sth_selectTransactionByHash( $hash );
+    my      $row            =   $sth->selectTransactionByHash->fetchrow_hashref;
+    $sth->selectTransactionByHash->finish;
+    return
+        if not defined $row;
+    return  $row;
+}
+
+__PACKAGE__->mk_accessors( 'sth_selectAccountIdByAddress' );
+sub     updateWhoSealed
+{
+    my  ( $self, $sealerhash, $blockhash  )  =   @_;
+    if ( not defined $self->sth_updatewhosealed )
+    {
+        $self->sth_updatewhosealed(
+            $self->dbh->prepare(q(
+                UPDATE  blocks
+                SET     sealerAccountId=?
+                WHERE   id=?
+                AND     sealerAccountId IS NULL
+            ))
+        );
+    }
+    my  $blockid        =   $self->selectBlockhashByHash( $blockhash  );
+    my  $sealerid       =   $self->selectSealerByHash(    $sealerhash );
+    $self->sth_updatewhosealed->execute( $sealerid, $blockid );
+}
+
+__PACKAGE__->mk_accessors( 'sth_selectmaxunknownsigned' );
+sub     selectMaxUnknownSigned
+{
+    my      ( $self )       =   @_;
+    if ( not defined $self->sth_selectmaxunknownsigned )
+    {
+        $self->sth_selectmaxunknownsigned(
+            $self->dbh->prepare(q(
+                SELECT  id
+                FROM    blocks
+                WHERE   number = (
+                    SELECT  MAX(number)
+                    FROM    blocks
+                    WHERE   sealer IS NULL
+                )
+            ))
+        );
     }
+    $self->sth_selectmaxunknownsigned->execute();
+    my      $ref            =   $self->sth_selectmaxunknownsigned->fetchrow_hashref;
+    $self->sth_selectmaxunknownsigned->finish();
+    my      $blockid        =   $ref->{'number'};
+    my      $blockhash      =   $self->selectBlockhashById( $blockid );
+    return                      $blockhash;
 }
 
-1;
\ No newline at end of file
+1;
diff --git a/docker-compose.yml b/docker-compose.yml
index c5b38b46e6451ee88d8aa34b500b7629ec5981ae..fbfa55ca5eabf0e5a58679b56a3f227ee501bbe8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,8 +2,7 @@
 
 ## POSTGRES SUPERUSER user name is postgres
 ## POSTGRES SUPERUSER password is onlythelonely
-## POSTGRES USER dgsi has password bfa
-# defined in postgres/90-add-db-user.sh
+## POSTGRES USER leer has password bfa defined in postgres/90-add-db-user.sh
 
 version: '3.4'