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'