Bitcoin Forum
May 21, 2024, 08:31:31 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: « 1 [2]  All
  Print  
Author Topic: What's the largest number of transactions that have been in a block so far?  (Read 2101 times)
dserrano5
Legendary
*
Offline Offline

Activity: 1974
Merit: 1029



View Profile
June 07, 2013, 07:53:21 AM
 #21

Where's your tip address?!!?

Oh nice Smiley

<--- Firstbits 12345, ie 12345Vypv2QSmuRXcciT5oEB27mPbWGeva
kjj
Legendary
*
Offline Offline

Activity: 1302
Merit: 1025



View Profile
June 07, 2013, 12:13:09 PM
 #22

Script written and running.

bitcoind seems to respond to a getblock request pretty slowly, so it will take a while to scan the entire blockchain...

Reading the block files directly would be much faster.

17Np17BSrpnHCZ2pgtiMNnhjnsWJ2TMqq8
I routinely ignore posters with paid advertising in their sigs.  You should too.
DannyHamilton
Legendary
*
Offline Offline

Activity: 3388
Merit: 4653



View Profile
June 07, 2013, 03:34:11 PM
 #23

Script written and running.
bitcoind seems to respond to a getblock request pretty slowly, so it will take a while to scan the entire blockchain...
Reading the block files directly would be much faster.

Absolutely, but I haven't figured out a good way to deal with variable length integers in perl yet.  I was able to write this script in 10 minutes and get an answer within a few hours.  That's much sooner than I would have gotten a full blockchain parser written.

The script I used was pretty simple and quick to put together, it isn't pretty, but it gets the job done:

Code:
#! /usr/bin/perl

use strict;
use warnings;
use mylibs::json;

sub get_credentials {
        my $envUserName = $ENV{'USER'};
        my $confFile = "/Users/".$envUserName."/Library/Application Support/Bitcoin/bitcoin.conf";
        my ($user, $password);
        my $server = 0;

        chomp $confFile;

        if (open(MYCONFFILE, "< " . $confFile)) {
                my(@lines) = <MYCONFFILE>;
                close(MYCONFFILE);

                foreach (@lines)
                {
                        chomp;
                        if ( /^rpcuser=(.*)$/i ) { $user = $1 }
                        elsif ( /^rpcpassword=(.*)$/i ) { $password = $1 }
                        elsif ( /server=1/i ) { $server = 1 }
                }
        }
        else {
                print "Error opening bitcoin.conf file $!\n";
                exit;
        }

        return $user, $password, $server;
}

################################################
#
#  BEGIN Main
#
################################################


###########
# Authentication
###########
my ($user, $password, $server) = get_credentials();


if ($server != 1) {
        print "ERROR: client is not running in server mode\n";
        exit;
}

###########
# Current Block Height
###########
my $currBlockCommand = "curl --silent --user " .
        $user                       .
        ":"                         .
        $password                   .
        " --data-binary '{\"method\": \"getblockcount\"}' http://127.0.0.1:8332/";

my $currIndexLine = `$currBlockCommand`;

my %currIndex = parse_json($currIndexLine);

###########
# Current Block Hash
###########
my $currHashCommand = "curl --silent --user " .
        $user                       .
        ":"                         .
        $password                   .
        " --data-binary '{\"method\": \"getblockhash\", \"params\": [" .
        ${$currIndex{"result"}} .
        "] }' http://127.0.0.1:8332/";

my $currHashLine = `$currHashCommand`;

my %currHash = parse_json($currHashLine);

###########
# Current Block Details
###########
my $blockDetailsCommand = "curl --silent --user " .
        $user                       .
        ":"                         .
        $password                   .
        " --data-binary '{\"method\": \"getblock\", \"params\": [\"" .
        ${$currHash{"result"}} .
        "\"] }' http://127.0.0.1:8332/";

my $blockDetailsLine = `$blockDetailsCommand`;

my %blockDetails = parse_json($blockDetailsLine);

###########
# Loop through blocks
###########
my $maxTxQty = @{$blockDetails{"result"}{"tx"}};
my $biggestBlock = ${$blockDetails{"result"}{"hash"}};
my $blockTxQty;
my $progress = 0;

while (exists $blockDetails{"result"}{"previousblockhash"}) {
  if ( $progress++ % 100 == 0) {
    print $progress . " , " . $biggestBlock . " , " . $maxTxQty . "\n";
  }
  $blockDetailsCommand = "curl --silent --user " .
          $user                       .
          ":"                         .
          $password                   .
          " --data-binary '{\"method\": \"getblock\", \"params\": [\"" .
          ${$blockDetails{"result"}{"previousblockhash"}} .
          "\"] }' http://127.0.0.1:8332/";

  $blockDetailsLine = `$blockDetailsCommand`;

  %blockDetails = parse_json($blockDetailsLine);

  $blockTxQty = @{$blockDetails{"result"}{"tx"}};
  if ($maxTxQty < $blockTxQty) {
    $maxTxQty = $blockTxQty;
    $biggestBlock = ${$blockDetails{"result"}{"hash"}}
  }
}

print "Block:" . $biggestBlock . ", TxQty:" . $maxTxQty . "\n";
sgravina
Sr. Member
****
Offline Offline

Activity: 451
Merit: 250



View Profile
June 07, 2013, 04:41:22 PM
 #24

Mine is a very general argument.

And therefor not mathematically accurate.

Regardless, having searched through the entire blockchain, the block with the lowest value hash so far is:
000000000000000006582fa9652895fda92c757ae6beee9dfbc3932125b5ab8e

What difficulty does this correspond to.  Looks like it wins my contest.
chriswilmer (OP)
Legendary
*
Offline Offline

Activity: 1008
Merit: 1000


View Profile WWW
June 08, 2013, 07:32:25 AM
 #25

Where's your tip address?!!?

Oh nice Smiley

<--- Firstbits 12345, ie 12345Vypv2QSmuRXcciT5oEB27mPbWGeva

Sent!
dserrano5
Legendary
*
Offline Offline

Activity: 1974
Merit: 1029



View Profile
June 08, 2013, 01:47:00 PM
 #26

Absolutely, but I haven't figured out a good way to deal with variable length integers in perl yet.  I was able to write this script in 10 minutes and get an answer within a few hours.  That's much sooner than I would have gotten a full blockchain parser written.

Look at sub read_var_int in my quick n dirty parser:

Code:
#!/usr/bin/perl

use warnings;
use strict;
use List::MoreUtils qw/natatime/;
use Data::Dumper;

my $MAGIC = 3652501241;
my $BLOCKS_DIR = '/home/btc/.bitcoin/blocks';

## xxd-like output
sub print_dump {
    my ($data) = @_;

    my $offset = 0;
    open my $fd, '<', \$data or die "open: $!";
    while (1) {
        my $read = read $fd, my $bytes, 16;
        last unless $read;
        my @bytes = split '', $bytes;
        my $rawchars = $bytes; $rawchars =~ s/[^ -~]/./g;
        my @hexpairs;
        my $iter = natatime 2, @bytes;
        while (my @vals = $iter->()) {
            push @hexpairs, join '', map { sprintf '%02x', ord } @vals;
        }
        printf "%08x: %-39s  %s\n", $offset, (join ' ', @hexpairs), $rawchars;
        $offset += $read;
    }
    close $fd;
}

sub read_var_int {
    my ($fd, $rem) = @_;
    my $val;

    my $read = read $fd, $val, 1; $$rem -= 1;
    if (!$read) { return undef; }
    $val = unpack 'C', $val;
    if ($val == 0xfd) {
        $read = read $fd, $val, 2; $$rem -= 2;
        $val = unpack 'S', $val;
    } elsif ($val == 0xfe) {
        $read = read $fd, $val, 4; $$rem -= 4;
        $val = unpack 'L', $val;
    } elsif ($val == 0xff) {
        $read = read $fd, $val, 8; $$rem -= 8;
        $val = unpack 'Q', $val;
    }

    return $val;
}

sub read_inputs {
    my ($fd, $count, $rem) = @_;
    my $read;  ## should be used to check ret vals from read/sysread
    my $inputs;

    for my $input (1 .. $count) {
        my ($prev_txid, $prev_idx, $sig_script, $seq);

        $read = read $fd, $prev_txid, 32; $$rem -= 32;
        $prev_txid = unpack 'H64', $prev_txid;
        #print "    prev_txid ($prev_txid)\n";

        $read = read $fd, $prev_idx, 4; $$rem -= 4;
        $prev_idx = unpack 'L', $prev_idx;
        #print "    prev_idx ($prev_idx)\n";

        my $sig_script_len = read_var_int $fd, $rem;
        if (!defined $sig_script_len) { print 'sig_script_len undef'; die; }

        $read = read $fd, $sig_script, $sig_script_len; $$rem -= $sig_script_len;
        #printf "    sig_script: %d bytes\n", length $sig_script;

        $read = read $fd, $seq, 4; $$rem -= 4;
        $seq = unpack 'L', $seq;
        #print "    seq ($seq)\n";

        push @$inputs, {
            prev_txid  => $prev_txid,
            prev_idx   => $prev_idx,
            sig_script => $sig_script,
            seq        => $seq,
        }
    }

    return $inputs;
}

sub read_outputs {
    my ($fd, $count, $rem) = @_;
    my $read;  ## should be used to check ret vals from read/sysread
    my $outputs;

    for my $output (1 .. $count) {
        my ($val, $pubkey_script_len, $pubkey_script);

        $read = read $fd, $val, 8; $$rem -= 8;
        $val = unpack 'Q', $val;

        $pubkey_script_len = read_var_int $fd, $rem;
        if (!defined $pubkey_script_len) { print 'pubkey_script_len undef'; die; }

        $read = read $fd, $pubkey_script, $pubkey_script_len; $$rem -= $pubkey_script_len;
        #printf "    pubkey_script: %d bytes\n", length $pubkey_script;

        push @$outputs, {
            val           => $val,
            pubkey_script => $pubkey_script,
        };
    }

    return $outputs;
}

sub parse_txs {
    my ($txn_data, $len) = @_;
    my $read;  ## should be used to check ret vals from read/sysread
    my $txs;

    my $remaining = $len;
    open my $txn_fd, '<', \$txn_data or die "open: $!";

    my $txn_count = read_var_int $txn_fd, \$remaining;
    if (!defined $txn_count) { print 'txn_count undef'; die; }
    #print "  txn_count ($txn_count)\n";

    #print_dump $txn_data;

    my ($tx_ver, $input_count, $inputs, $output_count, $outputs, $lock_time);
    for my $tx_idx (1 .. $txn_count) {
        $read = read $txn_fd, $tx_ver, 4; $remaining -= 4;
        $tx_ver = unpack 'L', $tx_ver;
        #print "    tx_ver ($tx_ver)\n";

        $input_count = read_var_int $txn_fd, \$remaining;
        if (!defined $input_count) { print 'input_count undef'; die; }
        #print "    input_count ($input_count)\n";

        $inputs = read_inputs $txn_fd, $input_count, \$remaining;
        #print Data::Dumper->Dump ([$inputs],['inputs']);

        $output_count = read_var_int $txn_fd, \$remaining;
        if (!defined $output_count) { print 'output_count undef'; die; }
        #print "    output_count ($output_count)\n";

        $outputs = read_outputs $txn_fd, $output_count, \$remaining;
        #print Data::Dumper->Dump ([$outputs],['outputs']);

        $read = read $txn_fd, $lock_time, 4; $remaining -= 4;
        $lock_time = unpack 'L', $lock_time;
        #print "    lock_time ($lock_time)\n";

        push @$txs, {
            version   => $tx_ver,
            inputs    => $inputs,
            outputs   => $outputs,
            lock_time => $lock_time,
        };
    }

    return $txs;
}

sub parse_block {
    my ($height, $block_data, $len) = @_;
    my $read;  ## should be used to check ret vals from read/sysread

    my $remaining = $len;
    open my $block_fd, '<', \$block_data or die "open: $!";

    my $block_header;
    $read = read $block_fd, $block_header, 80; $remaining -= 80;

    my ($ver, $prev_block, $mrkl, $ts, $bits, $nonce) = unpack 'L H64 H64 L H8 L', $block_header;
    $prev_block = reverse $prev_block=~/../g;
    $mrkl = reverse $mrkl=~/../g;

    my $txn_data;
    $read = read $block_fd, $txn_data, $remaining;

    close $block_fd;

    #my $tx = parse_txs $txn_data, $remaining;  ## commented out for faster parsing

    return {
        version     => $ver,
        height      => $height,
        prev_block  => $prev_block,
        merkle_tree => $mrkl,
        timestamp   => $ts,
        bits        => $bits,
        nonce       => $nonce,
        #tx          => $tx,
    };
}

my $blk_file_num = -1;
my $fd;
sub open_next_blk_file {
    close $fd if defined $fd;
    $blk_file_num++;
    my $blkfile = sprintf "$BLOCKS_DIR/blk%05d.dat", $blk_file_num;
    sysopen $fd, $blkfile, 0 or die "sysopen: $!";
    binmode $fd;
}

#################################################################################################

open_next_blk_file;

my $height = 0;
my %prev_blocks_seen;
while (1) {
    my $read;  ## should be used to check ret vals from read/sysread
    my $data;
    my ($magic, $len, $remaining);

    $read = sysread $fd, $data, 8;
    if (!defined $read) { die "sysread: $!"; }
    if (!$read) {
        warn "sysread: null, going to next file";
        open_next_blk_file;
        redo;
    }
    if ($read < 8) {
        warn "sysread: short read, going to next file";
        open_next_blk_file;
        redo;
    }
    ($magic, $len) = unpack 'L L', $data;
    $remaining = $len;
    next unless $magic;    ## magic == 0, probably near end of file
    if ($MAGIC != $magic) { die "got magic ($magic) instead of ($MAGIC) at block $height\n"; }
    ## read whole block
    $read = sysread $fd, $data, $len;
    if ($len != $read) { $read or last; die "sysread: $!"; }

    #print_dump $block_data;
    my $block = parse_block $height, $data, $len;
    ## orphan detection, untested on orphan chains larger than one single block
    if ($height and exists $prev_blocks_seen{ $block->{'prev_block'} }) {
        my $to_downgrade = ($height-1) - $prev_blocks_seen{ $block->{'prev_block'} };
        warn "orphan, height ($block->{'height'}) pb ($block->{'prev_block'}) ts ($block->{'timestamp'}) to_downgrade ($to_downgrade)\n";
        $height -= ($height-1) - $prev_blocks_seen{ $block->{'prev_block'} };
        next;
    }
    print "$height,$len\n";
#    if (128352 == $block->{'height'}) {
#        use bignum;
#        my $bits = join '', reverse $block->{'bits'} =~ /../g;
#        my ($b1, $b2) = map { hex $_ } $bits =~ /^(..)(.*)$/;
#        my $diff = (0xffff << 208) / ($b2 * 2 ** (8 * ($b1-3)));
#        $block->{'difficulty'} = "$diff";
#
#        print Data::Dumper->Dump ([$block],['block']);
#    }

    $prev_blocks_seen{ $block->{'prev_block'} } = $height;
    $height++;
}
close $fd;


Sent!

Thank you!
Pages: « 1 [2]  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!