Author

Topic: How to check any balance and send from any private key? (Read 2046 times)

newbie
Activity: 56
Merit: 0
Your use case might be a fit for the modular server implementation you see in my footer.
Lets discuss what you need, so I create support for.

BTW: Running the bitsofproof server gives you a normalized relational dstabase of the blockchain, sobalances can be queried via SQL. I also consider to add pruned view of unspent output.

This looks promising. I will starts an EC2 instance later and try to get it running.

I am crazy busy at work right now so it may take me to the weekend to try this out.
hero member
Activity: 836
Merit: 1030
bits of proof
I am looking for a tool that can read the blockchain and:

  • Runs on my own server using the blockchain/p2p network for input
  • Quickly return the balance for any address
  • Quickly send a payment from any private key

Your use case might be a fit for the modular server implementation you see in my footer.
Lets discuss what you need, so I create support for.

BTW: Running the bitsofproof server gives you a normalized relational dstabase of the blockchain, sobalances can be queried via SQL. I also consider to add pruned view of unspent output.
full member
Activity: 125
Merit: 100
Here is a (mostly complete) example of creating and signing a raw transaction, it is only part of a larger project that takes requests from elsewhere but it should be enough to see the transaction handling code.  Not exactly commented but hopefully the inputs are named well enough that you can tell what they are supposed to be, if not just ask.

And the usual disclaimer to check any generated transactions very carefully before letting them loose on the main network.  It is also very possible that there are some calls in here that are too long to work with large amounts on a 32 bit system, I know I've replaced some calls in other scripts but not sure this one has ever been run except on 64-bit systems so make sure your test cases include large amounts at some point.

Code:
#!/usr/bin/perl

use Digest::SHA;
require("functions.inc");

$req=shift(@ARGV);
@r=split(/,/,$req);foreach $r(@r){@rr=split(/:/,$r,2);$req{$rr[0]}=$rr[1];}

$total=0;$onum=1;$sout='';undef %out;
@o=split(/-/,$req{'output'});foreach $o(@o){@oo=split(/=/,$o,2);
  ($net,$key)=decode_b58($oo[0]);
  if($oo[1]>0 && $net==0 && $key ne ''){$out{$oo[0]}+=$oo[1];$total+=$oo[1];$onum++;
    $a=sprintf('%x',$oo[1]);while(length($a)<16){$a="0".$a;}
    $a=reverse($a);$sout.=pack('h*',$a);
    $ss=pack('H*','76a914'.$key.'88ac');
    $a=sprintf('%x',length($ss));if(length($a)<2){$a="0".$a;}
    $sout.=pack('H*',$a).$ss;
  }}

$have=0;$inum=0;
@o=split(/-/,$req{'input'});foreach $o(@o){($id,$cc,$amt,$addr)=split(/:/,$o,4);
  $in{"$id:$cc"}=$addr;$have+=$amt;$inum++;
}

$fee=fee($onum,$inum);
if($total+$fee>$have){die("Insufficient Funds");}
$change=$have-$total-$fee;

if($change>0){
  $out{$req{'change'}}=$change;$total+=$change;
  $a=sprintf('%x',$change);while(length($a)<16){$a="0".$a;}
  $a=reverse($a);$sout.=pack('h*',$a);
  ($net,$key)=decode_b58($req{'change'});
  $ss=pack('H*','76a914'.$key.'88ac');
  $a=sprintf('%x',length($ss));if(length($a)<2){$a="0".$a;}
  $sout.=pack('H*',$a).$ss;
}

$send=sprintf('%x',$onum);if($onum<16){$send="0".$send;}
$send=pack('H*',$send).$sout."\x00\x00\x00\x00";
$start=sprintf('%x',1);while(length($start)<8){$start="0".$start;}
$start=reverse($start);$start=pack('h*',$start);
$c=sprintf('%x',$inum);if($inum<16){$c="0".$c;}
$start.=pack('H*',$c);

$xx=0;for my $x(keys %in){$a=$in{$x};$inlist.=$x.",";
  ($ptx,$oid)=split(/:/,$x);$idtx[$xx]=$x;
  $ptx=reverse($ptx);$btx[$xx]=pack('h*',$ptx);
  $c=sprintf('%x',$oid);while(length($c)<8){$c="0".$c;}
  $c=reverse($c);$btx[$xx].=pack('h*',$c);
  $btx[$xx].="\x00\xff\xff\xff\xff";
  $xx++;
}chop($inlist);

$xx=0;while($xx<$inum){$tmp=$btx[$xx];
  ($ptx,$oid)=split(/:/,$idtx[$xx]);$a=$in{$idtx[$xx]};
  $btx[$xx]=substr($btx[$xx],0,-5);
  ($net,$key)=decode_b58($a);$ss=pack('H*','76a914'.$key.'88ac');
  $l=sprintf('%x',length($ss));if(length($l)<2){$l="0".$l;}
  $btx[$xx].=pack('H*',$l).$ss."\xff\xff\xff\xff";
  $pkey=addrprivkey($a);if($pkey eq ''){error("No private key found for $a");}
  $tx=$start.join('',@btx).$send."\x01\x00\x00\x00";
  $tx=Digest::SHA::sha256(Digest::SHA::sha256($tx));
  $tx=unpack('H*',$tx);$ftx[$xx]=substr($tmp,0,-5);
  $sig=signtx($tx,$pkey);
  $l=sprintf('%x',length($sig)+1);if(length($l)<2){$l="0".$l;}
  $sig=pack('H*',$l).$sig."\x01";
  $pk=addrpubkey($a);$pk=pack('H*',$pk);
  $l=sprintf('%x',length($pk));if(length($l)<2){$l="0".$l;}
  $sig.=pack('H*',$l).$pk;
  $l=sprintf('%x',length($sig));if(length($l)<2){$l="0".$l;}
  $ftx[$xx].=pack('H*',$l).$sig."\xff\xff\xff\xff";
  $btx[$xx]=$tmp;$xx++;
}

$dec=$start.join('',@ftx).$send;
$hex=unpack('H*',$dec);

$h=Digest::SHA::sha256(Digest::SHA::sha256($dec));
$hash=reverse(unpack('h*',$h));

print "Raw Transaction: $hex\nTransaction ID: $hash\n";

sub fee{my $o=shift(@_);my $i=shift(@_);my $f=0;
  my $s=size($o,$i);my $pp=int($s/1024)+1;
  if($req{'priority'}>=0){
    $f+=10000*$pp;
  }if($req{'priority'}>=1){
    $f+=40000*$pp;
  }if($req{'priority'}>=2){
    $f+=$s;
  }return $f;
}
sub size{my $o=shift(@_);my $i=shift(@_);
  return 10+(180*$i)+(34*$o);
}
sub addrprivkey{my $a=shift(@_);
  my $u=$db->prepare(qq{select privkey from address where address='$a'});
  $u->execute();my $ep;if($ep=$u->fetchrow_array()){
    return unpack('H*',$cipher->decrypt_hex($ep));
  }
}
sub addrpubkey{my $a=shift(@_);
  my $u=$db->prepare(qq{select pubkey from address where address='$a'});
  $u->execute();my $ep=$u->fetchrow_array();return $ep;
}

And here is the functions.inc that it references:
Code:
use Digest::SHA qw(sha256 sha256_hex);
use Crypt::RIPEMD160;
use Math::BigInt lib => 'GMP';
@bb=(1..9,'A'..'H','J'..'N','P'..'Z','a'..'k','m'..'z');

sub decode_b58{my $x=shift(@_);
  $x=~s/[0O]/o/g;$x=~s/[Il]/1/g;
  my $ox=$x;my $n=Math::BigInt->new(0);
  $i=Math::BigInt->new(0);while($x){my $c=chop($x);
    my $cp=0;while($bb[$cp] ne $c && $cp<=$#bb){$cp++;}
    $n+=$cp*(58**$i);$i++;
  }$i=$n->as_hex();$i=substr($i,2);
  $x=reverse($ox);my $c=chop($x);while($c eq '1'){$c=chop($x);$i="00".$i;}
  if(length($i)%2==1){$i="0".$i;}
  my $ver=substr($i,0,2);my $chk=substr($i,-8);
  $i=substr($i,2,-8);
  $n=pack('H*',$ver.$i);
  my $h=Digest::SHA::sha256(Digest::SHA::sha256($n));
  $c=substr(unpack('H*',$h),0,8);
  $ver=hex($ver);
  if($chk eq $c){return ($ver,$i);}
  return ('','');
}
sub ecadd{my $a=shift(@_);my $b=shift(@_);
  my $p=Math::BigInt->new('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');
  my $ax=Math::BigInt->new('0x'.substr($a,2,64));
  my $ay=Math::BigInt->new('0x'.substr($a,66));
  my $bx=Math::BigInt->new('0x'.substr($b,2,64));
  my $by=Math::BigInt->new('0x'.substr($b,66));
  if($by eq ''){return $a;}
  if($ay eq ''){return $b;}
  if($ax==$bx){
    if(($ay+$by)%$p==0){
      return '';
    }else{
      my ($rx,$ry)=ecdouble($ax,$ay);
      return('04'.substr($rx->as_hex(),2).substr($ry->as_hex(),2));
    }
  }

  my $x=$bx-$ax;$x->bmodinv($p);
  my $xx=(($by-$ay)*$x)%$p;
  my $rx=($xx*$xx-$ax-$bx)%$p;
  my $ry=($xx*($ax-$rx)-$ay)%$p;
  $rx=substr($rx->as_hex(),2);$ry=substr($ry->as_hex(),2);
  while(length($rx)<64){$rx="0".$rx;}while(length($ry)<64){$ry="0".$ry;}
  return "04".$rx.$ry;
}
sub ecaddnum{my $ax=shift(@_);my $ay=shift(@_);my $bx=shift(@_);my $by=shift(@_);
  my $p=Math::BigInt->new('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');
  if($by eq ''){return($ax,$ay);}
  if($ay eq ''){return($bx,$by);}
  if($ax==$bx){
    if(($ay+$by)%$p==0){
      return('','');
    }else{
      return ecdouble($ax,$ay);
    }
  }

  my $x=$bx-$ax;$x->bmodinv($p);
  my $xx=(($by-$ay)*$x)%$p;
  my $rx=($xx*$xx-$ax-$bx)%$p;
  my $ry=($xx*($ax-$rx)-$ay)%$p;
  return($rx,$ry);
}
sub ecmult{my $pb=shift(@_);my $p=shift(@_);
  my $x=Math::BigInt->new('0x'.substr($pb,2,64));
  my $y=Math::BigInt->new('0x'.substr($pb,66));
  my $n=Math::BigInt->new('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');

  if($p==0){return '';}
  if($y eq ''){return '';}
  $p=$p%$n;$pp=$p*3;
  my $i=Math::BigInt->new('1');
  while($i<=$pp){$i=$i*2;}$i=$i/4;
  my $rx=$x->copy();my $ry=$y->copy();
  while($i>1){
    ($rx,$ry)=ecdouble($rx,$ry);
    my $e=$pp->copy();$e->band($i);my $ee=$p->copy();$ee->band($i);
    if($e!=0 && $ee==0){($rx,$ry)=ecaddnum($rx,$ry,$x,$y);}
    if($e==0 && $ee!=0){($rx,$ry)=ecaddnum($rx,$ry,$x,-$y);}
    $i=$i/2;
  }
  $rx=substr($rx->as_hex(),2);$ry=substr($ry->as_hex(),2);
  while(length($rx)<64){$rx="0".$rx;}while(length($ry)<64){$ry="0".$ry;}
  return "04".$rx.$ry;
}
sub ecdouble{my $x=shift(@_);my $y=shift(@_);
  my $p=Math::BigInt->new('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F');
  my $l=2*$y;$l->bmodinv($p);
  $l=($l*3*$x*$x)%$p;
  my $xx=($l*$l-2*$x)%$p;
  my $yy=($l*($x-$xx)-$y)%$p;
  return($xx,$yy);
}
sub signtx{my $m=shift(@_);my $k=shift(@_);
  my $mm=Math::BigInt->new('0x'.$m);
  my $pk=Math::BigInt->new('0x'.$k);
  my $n=Math::BigInt->new('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141');
  my @chars=('a'..'f', 0..9);my $rr=join '',map {$chars[rand @chars]} 1..64;
  my $r=Math::BigInt->new('0x'.$rr);
  my $k=$r%$n;
  my $p=ecmult('0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8',$k);
  $r=Math::BigInt->new('0x'.substr($p,2,64));
  my $s=$k->copy();$s->bmodinv($n);
  $s=$s*($mm+($pk*$r)%$n)%$n;
  $r=substr($r->as_hex(),2);$s=substr($s->as_hex(),2);
  if(length($r)%2==1){$r="0".$r;}if(length($s)%2==1){$s="0".$s;}
  $k=substr($r,0,1);if($k>7 || ($k==0 && $k ne '0')){$r="00".$r;}
  $k=substr($s,0,1);if($k>7 || ($k==0 && $k ne '0')){$s="00".$s;}
  $r=pack('H*',$r);$s=pack('H*',$s);
  my $lr=sprintf('%x',length($r));if(length($lr)<2){$lr="0".$lr;}
  my $ls=sprintf('%x',length($s));if(length($ls)<2){$ls="0".$ls;}
  $rs="\x02".pack('H*',$lr).$r."\x02".pack('H*',$ls).$s;
  my $l=sprintf('%x',length($rs));if(length($l)<2){$l="0".$l;}
  return("\x30".pack('H*',$l).$rs);
}
sub hashtoaddr{my $nb=shift(@_);my $x=shift(@_);
  my $nbh=sprintf('%x',$nb);while(length($nbh)<2){$nbh="0".$nbh;}
  $x=pack('H*',$nbh.$x);
  my $addr=unpack('H*',$x);$x=Digest::SHA::sha256(Digest::SHA::sha256($x));
  $addr.=substr(unpack('H*',$x),0,8);
  my $out='';while(substr($addr,0,2) eq '00'){$out.="1";$addr=substr($addr,2);}
  my $a=Math::BigInt->new('0x'.$addr);my $o='';
  while($a>58){$o=$bb[$a%58].$o;$a=$a/58;}
  $o=$bb[$a].$o;
  return $out.$o;
}
sub pkeytoaddr{my $nb=shift(@_);my $x=shift(@_);
  $x=pack('H*',$x);$x=Digest::SHA::sha256($x);
  my $nbh=sprintf('%x',$nb);while(length($nbh)<2){$nbh="0".$nbh;}
  $x=pack('H*',$nbh).Crypt::RIPEMD160->hash($x);
  my $addr=unpack('H*',$x);$x=Digest::SHA::sha256(Digest::SHA::sha256($x));
  $addr.=substr(unpack('H*',$x),0,8);
  my $out='';while(substr($addr,0,2) eq '00'){$out.="1";$addr=substr($addr,2);}
  my $a=Math::BigInt->new('0x'.$addr);my $o='';
  while($a>58){$o=$bb[$a%58].$o;$a=$a/58;}
  $o=$bb[$a].$o;
  return $out.$o;
}
1;
newbie
Activity: 56
Merit: 0
Yeah, you can even do the signing in perl without bitcoind at all if you have the private key(s), I've been crafting/signing raw transactions that way for a while, can probably come up with some sample code if you want.  The harder part is finding the transaction inputs for the address...

If you have a sample of perl code to sign a bitcoin transaction with a private key that would be really nice. It would prevent me from reinventing the wheel.

I think the database that bitcoin-abe creates can help me find the unspent inputs for a given address. I may have to adjust the indexes it uses though.
full member
Activity: 125
Merit: 100
It looks like you can feed an unsigned raw transaction and a list of private keys into the new bitcoin client and it will sign and send the transaction without storing the keys in your wallet so this seems like a good solution for sending. I can use my perlfoo to create the raw transaction.

Yeah, you can even do the signing in perl without bitcoind at all if you have the private key(s), I've been crafting/signing raw transactions that way for a while, can probably come up with some sample code if you want.  The harder part is finding the transaction inputs for the address...
newbie
Activity: 56
Merit: 0
  • Quickly send a payment from any private key

This isn't what you wanted to do but perhaps if you want a quick and dirty solution, you can use Blockchain.info to sweep the funds from a private key to an address in your local wallet.  That way you don't need to import that private key into the bitcoin.org client.

That can be done using the API:

I have been meaning to add this ability to the blockchain.info API for a while. You can now replace the guid in the send api (https://blockchain.info/api/api_send) with a Hex encoded private key.

https://blockchain.info/merchant/4d6c9dff493fcd2da9508e01c8b13461d37e3d8b6df1732942d3257874051362/payment?to=$address&amount=$amount

$address = destination bitcoin address.
$amount = amount to send in satoshi.


It looks like you can feed an unsigned raw transaction and a list of private keys into the new bitcoin client and it will sign and send the transaction without storing the keys in your wallet so this seems like a good solution for sending. I can use my perlfoo to create the raw transaction.

(By the way I just had to check if 4d6c9dff493fcd2da9508e01c8b13461d37e3d8b6df1732942d3257874051362 had any money in it, damn none!)
legendary
Activity: 2506
Merit: 1010
  • Quickly send a payment from any private key

This isn't what you wanted to do but perhaps if you want a quick and dirty solution, you can use Blockchain.info to sweep the funds from a private key to an address in your local wallet.  That way you don't need to import that private key into the bitcoin.org client.

That can be done using the API:

I have been meaning to add this ability to the blockchain.info API for a while. You can now replace the guid in the send api (https://blockchain.info/api/api_send) with a Hex encoded private key.

https://blockchain.info/merchant/4d6c9dff493fcd2da9508e01c8b13461d37e3d8b6df1732942d3257874051362/payment?to=$address&amount=$amount

$address = destination bitcoin address.
$amount = amount to send in satoshi.
full member
Activity: 125
Merit: 100
Seems to me you should be able to do this pretty easily with the "listunspent" RPC call in version 0.7+ of the standard client, I can confirm on mine that it works for any address whether it is in the wallet or not and gives enough information to check balances on an address and craft transactions that can be passed back in to "sendrawtransaction".

Are you sure about that? I am getting different behavior.

For example when I go:

./bitcoind listunspent

It shows every unspent output in my wallet. If I do:

./bitcoind listunspent

Then it only shows outputs from that address. But if I do:

./bitcoind listunspent

Then it shows every unspent output in my wallet. It does not provide any info about the address I entered.


Hmm, perhaps I didn't look at the output I got quite close enough.  Sorry about that, I've been using the "getrawtransaction" in 0.7+ which was upgraded to provide information whether the transaction in on an address in your wallet or not, when "listunspent" gave me information that looked approximately right I assumed it had been updated as well.  That's too bad, I had been planning on updating another script of mine to use that instead of an external service one of these days, guess I'll have to come up with another way as well.
newbie
Activity: 56
Merit: 0
I am thinking that perhaps the server that the electrum client uses could be used for something like this?

Certainly, electrum servers are easy to use, but unfortunately not (yet) very stable. You would also need to code the actual creation of a transaction (although electrum code is easy to read so that shouldn't be a big problem).

It looks like the electrum server depends on bitcoind and bitcoin-abe. Looking at the database that bitcoin-abe creates I think it is just the thing for what I need to check balances and the sendrawtransaction feature of bitcoind will help me send.

If I figure this out I will post links to the source code.
newbie
Activity: 56
Merit: 0
Seems to me you should be able to do this pretty easily with the "listunspent" RPC call in version 0.7+ of the standard client, I can confirm on mine that it works for any address whether it is in the wallet or not and gives enough information to check balances on an address and craft transactions that can be passed back in to "sendrawtransaction".

Are you sure about that? I am getting different behavior.

For example when I go:

./bitcoind listunspent

It shows every unspent output in my wallet. If I do:

./bitcoind listunspent

Then it only shows outputs from that address. But if I do:

./bitcoind listunspent

Then it shows every unspent output in my wallet. It does not provide any info about the address I entered.
newbie
Activity: 56
Merit: 0
I see, I am running 6.3, going to download and install 7.1 and try this out.
newbie
Activity: 56
Merit: 0
Seems to me you should be able to do this pretty easily with the "listunspent" RPC call in version 0.7+ of the standard client, I can confirm on mine that it works for any address whether it is in the wallet or not and gives enough information to check balances on an address and craft transactions that can be passed back in to "sendrawtransaction".

I am going to try this out and post back. Thanks for the tip.
full member
Activity: 125
Merit: 100
Seems to me you should be able to do this pretty easily with the "listunspent" RPC call in version 0.7+ of the standard client, I can confirm on mine that it works for any address whether it is in the wallet or not and gives enough information to check balances on an address and craft transactions that can be passed back in to "sendrawtransaction".
newbie
Activity: 41
Merit: 0
I am thinking that perhaps the server that the electrum client uses could be used for something like this?

Certainly, electrum servers are easy to use, but unfortunately not (yet) very stable. You would also need to code the actual creation of a transaction (although electrum code is easy to read so that shouldn't be a big problem).
newbie
Activity: 56
Merit: 0
Using the API blockchain.info provides you can check any balance you want, it also allows you to very quickly import a private key and send money from it. This is great but I want to do it on my own servers.

I am looking for a tool that can read the blockchain and:

  • Runs on my own server using the blockchain/p2p network for input
  • Quickly return the balance for any address
  • Quickly send a payment from any private key

It seems to me that the default client cannot do this as it has to rescan the blockchain every time you add another key.

I am thinking that perhaps the server that the electrum client uses could be used for something like this?

I am pretty good with perl and building API clients. Any advise on a good starting point would be appreciated.
Jump to: