diff --git a/README.md b/README.md
index a8f2b13f50e8ebce7a054ea1bb29769d5445de8b..e3d1ab9955ee2d8836e0f9791ce76841a0f9838e 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,8 @@
 ## Sitio web: https://www.bfa.ar/
 ## Repositorio: https://gitlab.bfa.ar/blockchain/nucleo.git
 
+Este repositorio contiene lo nececario para instalar un "nodo BFA" (nodo sellador, nodo gateway, nodo transaccional "etc", son casi iguales).
+
 Esta guía debería funcionar en Debian o sus derivados. Testeado en *Debian* y *Ubuntu server* sin la GUI instalada en ninguno de ellos.
 
 ([Capturas de pantallas instalando un Ubuntu 18.04](https://gitlab.bfa.ar/blockchain/nucleo/wikis/Instalando-Ubuntu-Server-18.04))  
@@ -17,15 +19,16 @@ Esta guía debería funcionar en Debian o sus derivados. Testeado en *Debian* y
    Van a aparecer varios **warnings** mientras se instala web3. Esto parece ser "normal". Ignorarlo no parece causar problemas.
 4. Cambiá al usuario `bfa`
    - como root: `su - bfa`
-5. Crea una cuenta
+5. Crea una cuenta (solamente nodos selladores y nodos transaccionales necesitan una cuenta)
    - como bfa: `admin.sh account`
 6. Comenzá la sincronización. **Esto puede llevar un rato largo** (este script se ejecuta automáticamente cuando se reinicia el sistema).
    - como bfa: `start.sh`
-7. Monitoreá los logs con `bfalog.sh`. Apretá CTRL-C en cualquier momento para detener el `tail -f`.
-8. Cambiá la configuración de tu nodo usando `admin.sh syncmode`
+7. `localstate.pl` muestra el estado actual del nodo.
+8. Monitoreá los logs con `bfalog.sh`. Apretá CTRL-C en cualquier momento para detener el `tail -f`.
+9. Cambiá la configuración de tu nodo usando `admin.sh syncmode`
    - Hacé esto antes de haber sincronizado mucho en el paso anterior, ya que esto podría remover todos los datos de la cadena que hayas bajado y reiniciar la sincronización de la cadena.
-9. Esperá a aque termine de sincronizar
-10. Herramientas simples super básicas (más bien pruebas de concepto, para inspirar a los programadores):
+10. Esperá a aque termine de sincronizar
+11. Herramientas simples super básicas (más bien pruebas de concepto, para inspirar a los programadores):
     - `explorer.sh` : Sigue el bloque más nuevo "*lastest*" por default, pero podés especificar un número de bloque cualquiera como argumento, por ejemplo `explorer.sh 0` permite ver el génesis (bloque 0).
     - `walker.pl` : También toma un número de bloque para iniciar. Sigue esperando nuevos bloques.
     - `sealerwatch.pl` : Mira cuando los selladores firman.
@@ -100,3 +103,6 @@ Argumento 1 es el nombre de archivo del *smart contract* a compilar.
 
 Ejemplo: `compile.and.deploy.contract src/TimestampAuthority.sol`
 
+## localstate.pl
+
+Muestra varias detalles del entorno local.
\ No newline at end of file
diff --git a/bin/bfaupdate.sh b/bin/bfaupdate.sh
index f6109cc0f79cc5b3572b8a89bbd1dd559285c4dd..bbc8ec83125f2972078088e8dfcb024199a60fcb 100755
--- a/bin/bfaupdate.sh
+++ b/bin/bfaupdate.sh
@@ -6,5 +6,6 @@ source ${BFAHOME}/bin/libbfa.sh || exit 1
 
 set -x
 cd ${BFAHOME}
+sudo apt -y install libclass-accessor-perl
 git pull
 npm rebuild
diff --git a/bin/installbfa.sh b/bin/installbfa.sh
index 8387c8522bcef4297f20cdbefe262f0564067f86..1ff8ec3ed1388d9e870890d6c89adfa22799847b 100755
--- a/bin/installbfa.sh
+++ b/bin/installbfa.sh
@@ -191,7 +191,7 @@ grep -q Ubuntu /etc/issue && apt-add-repository multiverse
 apt update
 # development tools
 aptinstall dirmngr apt-transport-https curl git curl build-essential sudo
-aptinstall jq libjson-perl libwww-perl
+aptinstall jq libjson-perl libwww-perl libclass-accessor-perl
 usersetup
 nodejsinstall
 web3install
diff --git a/bin/sealerwatch.pl b/bin/sealerwatch.pl
index c3c77eafaa17d768a223eb5d29b0fa8b7e5670ab..12d11ebccfb97e010cab2ed4769183964d52ac44 100755
--- a/bin/sealerwatch.pl
+++ b/bin/sealerwatch.pl
@@ -329,13 +329,18 @@ chdir "$ENV{BFAHOME}" or die $!;
 my      $number                 =   shift || 'latest';
 my      $tools                  =   tools->new;
 my      %cache;
-my      $lastblock;
+my      $latestvalidblock;
 my      %signers;
+# If we started with 'latest' then subtract 100,
+# so we get an updated list of recent signers faster.
+my      $subtract               =   $number eq 'latest' ? 100 : 0;
 
 $libbfa                         =   libbfa->new();
 my      $block                  =   block->new( $libbfa )->get( $number );
 die if not defined $block;
 $number                         =   $block->number;
+my      $run_to                 =   $number;
+$number                         -=  $subtract;
 print ansi::CUP().ansi::ED();
 
 sub     determine_colour
@@ -409,14 +414,12 @@ sub     presentation_top
 while ( defined $block || sleep 1 )
 {
     my      $parent             =   undef;
-    $block                      =   block->new( $libbfa )->get( $number );
-    if ( not defined $block )
-    {
-        presentation_top( $lastblock );
-        next;
-    }
+    my      $prospect           =   block->new( $libbfa )->get( $number );
+    $block                      =   $prospect
+        if defined $prospect;
     presentation_top( $block );
-    $lastblock                  =   $block;
+    next
+        if not defined $prospect;
     $cache{$number}{'block'}    =   $block;
     $number                     =   $block->number;
     if ( exists $cache{ $number - 1 }{'block'} )
@@ -488,5 +491,6 @@ while ( defined $block || sleep 1 )
     print ansi::ED(0), ansi::CUP($maxy, 1);
     #
     $number                     =   $block->number + 1;
-    select( undef, undef,undef, 0.2 );
+    select( undef, undef,undef, 0.1 )
+        if $number >= $run_to;
 }
diff --git a/network/aliases b/network/aliases
index 0bbc16c03e6aeff2e6f292fceec66951483e6911..277e0fb51005b45344368a233ac8d522dafda90f 100644
--- a/network/aliases
+++ b/network/aliases
@@ -21,3 +21,4 @@
 0xe191ac3108cb2c5d70d0e978876c048d4ba41b03 ANSV / Agencia Nacional de Seguridad Vial
 0x52f8a89484947cd29903b6f52ec6beda69965e38 CABASE PSS / CABASE Posadas
 0xb43b53af0db2c3fac788195f4b4dcf2b3d72aa44 IPLAN
+0x354779914a94ad428d2b53ae96cce3010bb0ce1e Red Link
diff --git a/src/Sealers.sol b/src/Majority.sol
similarity index 59%
rename from src/Sealers.sol
rename to src/Majority.sol
index bfdecdd62114bce247d237d357baeaceb9db7f3f..71a5515b03f57807ff9c24e03485377e880accab 100644
--- a/src/Sealers.sol
+++ b/src/Majority.sol
@@ -1,13 +1,17 @@
+// Robert Martin-Legene <robert@nic.ar>
 // vim:syntax:filetype=javascript:ai:sm
 
 pragma solidity ^0.4.24;
 
-// This contract is supposed to maintain the list of authorized sealers.
-// For this to work, a sealer must deploy the contract and then all sealers
-// must, say, every 5 minutes, run the related SealerSync.js
-
-contract Sealers {
+// This contract is supposed to maintain a list of accounts authorized
+// to control members of "the club" using a majority (n/1+1).
+// For instance, could be useful for
+// - a list of sealers
+// - a board of directors
+// - a local chess club
+// - even outsourcing this kind of management from another smart contract.
 
+contract Majority {
     // This struct contains a list of votes and who has voted for each victim/beneficiary.
     // Votes taking longer than 30K blocks, will have to restart.
     struct Proposal {
@@ -16,41 +20,41 @@ contract Sealers {
         bool		promotion;  // true=promotion, false=demotion
         address[]	voters;     // List of voters.
     }
-    address[]           private sealers;
-    Proposal[]          private sealerproposals;
+    address[]           public  voters;
+    Proposal[]          public  voterproposals;
 
     event               voteCast( address voter, address victim, bool promotionOrDemotion );
     event               adminChange( address admin, bool promotionOrDemotion );
 
     constructor() public
     {
-        sealers.push( msg.sender );
+        voters.push( msg.sender );
     }
 
-    // This function is used to know how many sealers are in the sealers list.
-    function    sealerLength() public view returns (uint)
+    // This function is used to know how many voters exist.
+    function    votersLength() public view returns (uint)
     {
-        return sealers.length;
+        return voters.length;
     }
 
-    // This function is to be used to get the address from a specific position in the sealers list.
+    // This function is to be used to get the address from a specific position in the list.
     // Remember first position is 0.
-    // Last position is sealers.length-1.
-    function    sealerPosition( uint idx ) public view returns (address)
+    // Last position is voters.length-1.
+    function    voterPosition( uint idx ) public view returns (address)
     {
-        require( idx < sealers.length, "There are not that many sealers registered in the list." );
-        return sealers[idx];
+        require( idx < voters.length, "There are not that many entries in the list." );
+        return voters[idx];
     }
 
-    function    isSealer( address subject ) public view returns (bool)
+    function    isVoter( address subject ) public view returns (bool)
     {
-        return ( _findAddressInList( sealers, subject ) > 0 );
+        return ( _findAddressInList( voters, subject ) > 0 );
     }
 
     // Returns an index to the position of the needle inside haystack.
     // Beware that:
     // 0 = not found.
-    // 1 = first position.
+    // 1 = first position in a list (so this is actually the real list position + 1).
     function    _findAddressInList( address[] haystack, address needle ) private pure returns (uint)
     {
         uint    i   =   haystack.length;
@@ -64,34 +68,34 @@ contract Sealers {
     {
         // Move all items in the list (after idx) one step closer to the
         // front of the list.
-        uint    max     =   sealerproposals.length;
+        uint    max     =   voterproposals.length;
         while ( ++idx < max )
-            sealerproposals[idx-1] = sealerproposals[idx];
+            voterproposals[idx-1] = voterproposals[idx];
         // "pop" the end of the list, making the list shorter.
-        sealerproposals.length--;
+        voterproposals.length--;
     }
 
-    function _del_votes( address victim ) private
+    function    _del_votes( address victim ) private
     {
-        uint    i_max   =   sealerproposals.length;
+        uint    i_max   =   voterproposals.length;
         uint    i       =   i_max;
         // check all proposals
         while ( i-- > 0 )
         {
             // check all voters for every proposal
-            uint    j_max   =   sealerproposals[i].voters.length;
+            uint    j_max   =   voterproposals[i].voters.length;
             uint    j       =   j_max;
             while ( j-- > 0 )
-                if ( sealerproposals[i].voters[j] == victim )
+                if ( voterproposals[i].voters[j] == victim )
                 {
                     // Found the victim as voter, but since he is about
                     // to be deleted, we will remove him from the list.
                     uint    k   =   j;
                     while ( ++k < j_max )
-                        sealerproposals[i].voters[k-1] = sealerproposals[i].voters[k];
-                    sealerproposals[i].voters.length--;
+                        voterproposals[i].voters[k-1] = voterproposals[i].voters[k];
+                    voterproposals[i].voters.length--;
                     j_max--;
-                    if ( sealerproposals[i].voters.length == 0 )
+                    if ( voterproposals[i].voters.length == 0 )
                     {
                         _remove_proposal( i );
                         i_max--;
@@ -100,69 +104,70 @@ contract Sealers {
         }
     }
 
-    function    _remove_sealer( address victim ) private
+    function    _remove_voter( address victim ) private
     {
         // Remove votes that the victim has already cast.
         _del_votes( victim );
         // Move all items in the list (after match) one step closer to the
         // front of the list.
-        uint    max         =   sealers.length;
+        uint    max         =   voters.length;
         uint    i           =   max;
         while ( i-- > 0 )
-            if ( sealers[i] == victim )
+            if ( voters[i] == victim )
             {
                 // We could have recycled 'i' here, but for clarity, we don't.
                 uint    j   =   i;
                 while ( ++j < max )
-                    sealers[j-1] = sealers[j];
+                    voters[j-1] = voters[j];
                 // "pop" the end of the list, making the list shorter.
-                sealers.length--;
+                voters.length--;
                 return;
             }
     }
 
     // This function sees if any proposals have overstayed their welcome and thus
-    // needs to be removed.
+    // needs to be removed. This is a bit like spring cleaning. We remove proposals
+    // that are over 30k blocks old.
     function _trimProposals() private
     {
-        uint    i           =   sealerproposals.length;
+        uint    i           =   voterproposals.length;
         while ( i-- > 0 )
         {
             // If a proposal is more than 30K blocks old, then remove it from the list.
-            if ( sealerproposals[i].votestart + 30000 <= block.number )
+            if ( voterproposals[i].votestart + 30000 <= block.number )
                 _remove_proposal( i );
         }
     }
 
     // We run through the entire list of proposals, checking if they fulfill the
-    // requirements. Why the whole list? Because if a sealer is removed, whom has
+    // requirements. Why the whole list? Because if a voter has been removed, whom has
     // not yet voted for a proposal, that proposal may now have achieved majority.
     function _promotedemote() private
     {
         uint    prevlength  =   0;
         // Keep looping over the list until the number of proposals stops changing.
-        while ( prevlength != sealerproposals.length )
+        while ( prevlength != voterproposals.length )
         {
-            uint    i           =   sealerproposals.length;
+            uint    i           =   voterproposals.length;
             prevlength          =   i;
-            uint    majority    =   sealers.length / 2 + 1;
+            uint    majority    =   voters.length / 2 + 1;
             // Loop over all proposals
             while ( i-- > 0 )
             {
                 // If we have enough votes to perform the actual promotion/demotion
-                if ( sealerproposals[i].voters.length >= majority )
+                if ( voterproposals[i].voters.length >= majority )
                 {
                     // Is it a promotion or a demotion?
-                    if (                sealerproposals[i].promotion )
-                        // Add victim to sealer list
-                        sealers.push(   sealerproposals[i].victim );
+                    if (                voterproposals[i].promotion )
+                        // Add victim to member list
+                        voters.push(   voterproposals[i].victim );
                     else
-                        // Remove victim from sealer list
-                        _remove_sealer( sealerproposals[i].victim );
+                        // Remove victim from member list
+                        _remove_voter( voterproposals[i].victim );
     
                     // Send notification
-                    emit adminChange(   sealerproposals[i].victim,
-                                        sealerproposals[i].promotion );
+                    emit adminChange(   voterproposals[i].victim,
+                                        voterproposals[i].promotion );
                     // Remove the proposal because the voting is complete.
                     _remove_proposal( i );
                 }
@@ -175,9 +180,9 @@ contract Sealers {
     // 1 = first position.
     function    promotionIdx( address victim, bool promotion ) public view returns (uint)
     {
-	uint   	i       =   sealerproposals.length;
+	uint   	i       =   voterproposals.length;
 	while ( i-- > 0)
-            if ( sealerproposals[i].victim == victim && sealerproposals[i].promotion == promotion )
+            if ( voterproposals[i].victim == victim && voterproposals[i].promotion == promotion )
                 return i+1;
         return 0;
     }
@@ -186,24 +191,22 @@ contract Sealers {
     // will get accepted. Save the network, call this first.
     function mayVote( address voter, address victim, bool promotion ) public view returns (bool)
     {
-        // Is caller a sealer?
-        if ( !isSealer(voter) )
+        // Is caller a voter?
+        if ( !isVoter(voter) )
             return false;
 
-        // Is already Sealer and want to promote him?
-        // Can't promote someone who is already a sealer.
-        bool victimSealer   =   isSealer( victim );
-        if ( victimSealer && promotion )
+        // Can't promote someone who is already a voter.
+        bool victimVoter    =   isVoter( victim );
+        if ( victimVoter && promotion )
             return false;
 
-        // Is not Sealer and want to demote him?
-        // Can't demote someone who is not a sealer.
-        if ( !victimSealer && !promotion )
+        // Can't demote someone who is not a member.
+        if ( !victimVoter && !promotion )
             return false;
 
         // See if the voter is already in the list of voters for this [victim,promotion] tuple
         uint    proppos     =   promotionIdx( victim, promotion );
-        if ( proppos > 0 && _findAddressInList( sealerproposals[proppos-1].voters, voter ) > 0 )
+        if ( proppos > 0 && _findAddressInList( voterproposals[proppos-1].voters, voter ) > 0 )
             return false;
         return true;
     }
@@ -211,7 +214,7 @@ contract Sealers {
     // Calling this function will vote for adding an additional or
     // removing an existing member of "the inner circle".
     // As per usual, this requires n/2+1 votes.
-    // The boolean must be true if you want to add a sealer
+    // The boolean must be true if you want to add a member
     // and false if you want to remove one.
     function vote( address victim, bool promotion ) public
     {
@@ -227,18 +230,18 @@ contract Sealers {
         {
             // This is a new proposal, so we will add it, so we can vote on it.
             address[] memory emptyAddressList;
-	    proppos = sealerproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
+	    proppos = voterproposals.push( Proposal(victim, block.number, promotion, emptyAddressList ) );
         }
         proppos--;
 
         // Add our vote
-        sealerproposals[proppos].voters.push( msg.sender );
+        voterproposals[proppos].voters.push( msg.sender );
 
         // See if we're ready to promote/demote anyone, based on the proposals.
         _promotedemote();
 
-        // If we have no more sealers, we have no reason to live.
-        if ( sealers.length == 0 )
+        // If we have no more voters, we have no reason to live.
+        if ( voters.length == 0 )
             selfdestruct( msg.sender );
     }
 }