You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
4.1 KiB
125 lines
4.1 KiB
#!/usr/bin/perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
use BerkeleyDB;
|
|
|
|
my $DEBUG = $ENV{DEBUG} || 0;
|
|
my %wallet;
|
|
my $filename = shift || 'wallet.dat';
|
|
my $filesize = -s $filename;
|
|
my $db = tie %wallet, 'BerkeleyDB::Btree',
|
|
-Filename => $filename,
|
|
-Subname => "main",
|
|
-Flags => DB_RDONLY,
|
|
or die "Cannot open file $filename: $! $BerkeleyDB::Error\n";
|
|
|
|
my $count = 0;
|
|
my $counts = {};
|
|
my $avg_xtn_size = 0;
|
|
my $meta = {};
|
|
|
|
# guess the coin a wallet.dat came from
|
|
# NOTE: Zcash wallets start out with no shielded addresses
|
|
# and look exactly like BTC wallets, except for address prefixes
|
|
sub is_zec_prefix { $_[0] eq 't1' or $_[0] eq 't3' }
|
|
sub is_kmd_prefix { $_[0] eq 'R' or $_[0] eq 'b' }
|
|
sub detect_coin {
|
|
my ($c,$meta) = @_;
|
|
my $coin = "BTC";
|
|
|
|
print "Address Prefix=" . $meta->{prefix} . "\n";
|
|
my $prefix = $meta->{prefix};
|
|
my $p1 = substr($prefix, 0, 1);
|
|
|
|
if (is_kmd_prefix($p1)) {
|
|
$coin = "KMD or asset chain";
|
|
} elsif (is_zec_prefix($prefix)) {
|
|
$coin = "ZEC/HUSH";
|
|
}
|
|
|
|
# NOTE: Some wallets will have a mix of Sprout
|
|
# and Sapling keys in same wallet
|
|
if ($c->{sapzkey} or $c->{sapzkeymeta}) {
|
|
$coin .= " Sapling";
|
|
# only zcash forks have these
|
|
} elsif ($c->{zkey} or $c->{zkeymeta}) {
|
|
$coin .= " Sprout";
|
|
}
|
|
return $coin;
|
|
}
|
|
|
|
while (my ($k,$v) = each %wallet) {
|
|
my $len = unpack("W", substr($k, 0, 1));
|
|
my $type = substr $k, 1, $len;
|
|
my $key = substr $k, $len+1;
|
|
my $klen = length $key;
|
|
my $vlen = length $v;
|
|
|
|
#printf "%s => %x\n", $k, $v;
|
|
if ($DEBUG) {
|
|
if ($type eq 'key') {
|
|
my $privkey = unpack("H*", $v);
|
|
$key = unpack("H*", $key);
|
|
print "key=$key, privkey=$privkey\n";
|
|
} elsif ($type eq 'cscript') {
|
|
my $cscript = unpack("H*", $v);
|
|
$key = unpack("H*", $key);
|
|
print "key=$key, cscript=$cscript\n";
|
|
} elsif ($type eq 'tx') {
|
|
# TODO: this could depend on the platform rendering the data
|
|
my $tx = reverse(unpack("h*", $key));
|
|
my $vtx = unpack("h*", $v);
|
|
my $l = length($tx);
|
|
my $lvtx= length($vtx);
|
|
print "len=$l tx=$tx ($lvtx bytes)\n";
|
|
$avg_xtn_size += $vlen;
|
|
} elsif ($type eq 'defaultkey') {
|
|
my $dkey = unpack("H*", $v);
|
|
print "defaultkey=$dkey\n";
|
|
} elsif ($type eq 'zkey') {
|
|
my $privkey = unpack("H*", $v);
|
|
$key = unpack("H*", $key);
|
|
print "zkey=$key, privkey=$privkey\n";
|
|
} elsif ($type eq 'name') {
|
|
print "name: $key, $v\n";
|
|
} elsif ($type eq 'bestblock') {
|
|
my $v = unpack("H*", $v);
|
|
print "$type ($klen,$vlen): ($key => $v)\n";
|
|
} elsif ($type eq 'version') {
|
|
my $len = length $v;
|
|
my $version = unpack("I", $v);
|
|
print "version ($len bytes): $version\n";
|
|
} elsif ($type eq 'watchs') {
|
|
my $key = unpack("H*", $key);
|
|
print "$type ($klen,$vlen): ($key => $v)\n";
|
|
} elsif ($type eq 'purpose') {
|
|
#my $key = unpack("H*", $key);
|
|
#TODO: what is this prefix byte?
|
|
my $addr = substr $k, $len+2;
|
|
my $prefix = substr $addr, 0, 2;
|
|
# multiple prefixes should not occur in the same wallet, right?
|
|
$meta->{prefix} = $prefix;
|
|
print "$type ($klen,$vlen): ($prefix $addr => $v)\n";
|
|
}
|
|
#printf "$type %s:\n", $key;
|
|
}
|
|
$counts->{$type}++;
|
|
$count++;
|
|
}
|
|
$avg_xtn_size = $counts->{tx} ? $avg_xtn_size / $counts->{tx} : 0;
|
|
|
|
printf "\n===== Wallet $filename Stats =====\n";
|
|
my @keys = sort { $counts->{$b} <=> $counts->{$a} } keys(%$counts);
|
|
my $numkeys = scalar @keys;
|
|
for my $k (@keys) {
|
|
if ($DEBUG && $k eq 'tx') {
|
|
printf "%-25s %s (%.2f bytes avg)\n", $k, $counts->{$k}, $avg_xtn_size;
|
|
} else {
|
|
printf "%-25s %s\n", $k, $counts->{$k};
|
|
}
|
|
}
|
|
printf "Total: $count keys in $numkeys key types ($filesize bytes on disk)\n";
|
|
my $coin = detect_coin($counts,$meta);
|
|
print "Coin detection: $coin\n";
|
|
|
|
|