Bitcoin Forum
May 08, 2024, 01:54:54 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Finding unspent transaction outputs  (Read 4309 times)
salfter (OP)
Hero Member
*****
Offline Offline

Activity: 651
Merit: 501


My PGP Key: 92C7689C


View Profile WWW
October 11, 2012, 03:21:49 PM
 #1

I have a project in mind that would involve creating transactions on a webserver that would need to be handed off to a user for signing before they could be sent.  As I understand it, the inputs to any transaction are made up of unspent outputs from previous transactions.  Most wallet programs track the unspent outputs associated with your addresses, but they won't work with someone else's addresses.  You can find this information from blockexplorer.com or blockchain.info for any address, but they probably wouldn't appreciate hitting their servers every time someone needs a transaction generated.  Besides, if you have the Satoshi client running, all of the information is in your copy of the blockchain...the API just doesn't provide an easy way to get at it.

Yesterday, I knocked together some PHP that goes through the blockchain and builds up a table in a MySQL database with all unspent outputs.  It got through testnet pretty quickly.  It's still grinding away at the mainnet blockchain, but once you have it built, updates as new blocks are generated don't take long.  The database should be fairly small (currently at block 118650, and the database is ~27MB with ~144k entries), and finding unused outputs, totals at an address, or whatever is a SQL query away.  You need PHP built with Mysqli support, and you also need the client component from JSON-RPC PHP.

Code:
<?php
  
require_once "jsonRPCClient.php";

  
$mysqli=new mysqli("<mysql_host>""<mysql_user>""<mysql_passwd>""<mysql_schema>");
  if (
$mysqli->connect_errno)
    throw new 
Exception("database connection error");

  
$r=$mysqli->query("select max(block_num) from outputs"MYSQLI_USE_RESULT);
  
$w=$r->fetch_assoc();
  
$last_block_in_db=$w["max(block_num)"]+0;
  
$r->close();

  
$btc=new jsonRPCClient("http://<rpcuser>:<rpcpasswd>@localhost:8332");
  
$blocknum=$btc->getblockcount();

  if (
$last_block_in_db<$blocknum)
  {
    for (
$i=$last_block_in_db+1$i<=$blocknum$i++)
    {
      echo 
"block ".$i."\n";
      
$block=$btc->getblock($btc->getblockhash($i));
      foreach (
$block["tx"] as $txid)
      {
        
$tx=$btc->decoderawtransaction($btc->getrawtransaction($txid));
        foreach (
$tx["vin"] as $tx_in)
        {
          if (!
array_key_exists("coinbase"$tx_in))
            
$mysqli->query("delete from outputs where transaction_hash='".$tx_in["txid"]."' and sequence=".$tx_in["vout"].";");
        }
        foreach (
$tx["vout"] as $tx_out)
        {
          
$scripttype=$tx_out["scriptPubKey"]["type"];
          switch (
$scripttype)
          {
          case 
"pubkeyhash":
          case 
"pubkey":
          case 
"scripthash":
            
$mysqli->query("insert into outputs (block_num, block_hash, transaction_hash, sequence, address, balance) values (".$i.", '".$block["hash"]."', '".$txid."', ".$tx_out["n"].", '".$tx_out["scriptPubKey"]["addresses"][0]."', ".$tx_out["value"].")");
            break;
          case 
"nonstandard":
          case 
"multisig":
            
$mysqli->query("insert into outputs (block_num, block_hash, transaction_hash, sequence, address, balance) values (".$i.", '".$block["hash"]."', '".$txid."', ".$tx_out["n"].", '** ".$scripttype." **', ".$tx_out["value"].")");
            break;
          default:
            throw new 
Exception("don't know how to handle ".$scripttype." scripts in transaction ".$txid);
            break;
          }
        }
      }
    }
  }
  else
    echo 
"database is current\n";
?>


Substitute appropriate values for <mysql_host>, <mysql_user>, <mysql_passwd>, <mysql_schema>, <rpcuser>, and <rpcpasswd>. <mysql_schema> has one table named outputs, defined as follows:

Code:
CREATE TABLE `outputs` (
  `block_num` int(11) NOT NULL,
  `block_hash` char(64) NOT NULL,
  `transaction_hash` char(64) NOT NULL,
  `sequence` int(11) NOT NULL,
  `address` varchar(34) NOT NULL,
  `balance` decimal(16,8) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1

With this, a user to your website can provide one or more addresses for payment.  You can generate a transaction (possibly with extra information embedded in the script) and hand it off to the user for signing.  Once signed, either the user or the website can send it to the blockchain.

Tipjars: BTC 1TipsGocnz2N5qgAm9f7JLrsMqkb3oXe2 LTC LTipsVC7XaFy9M6Zaf1aGGe8w8xVUeWFvR | My Bitcoin Note Generator | Pool Auto-Switchers: zpool MiningPoolHub NiceHash
Bitgem Resources: Pool Explorer Paper Wallet
1715176494
Hero Member
*
Offline Offline

Posts: 1715176494

View Profile Personal Message (Offline)

Ignore
1715176494
Reply with quote  #2

1715176494
Report to moderator
"Your bitcoin is secured in a way that is physically impossible for others to access, no matter for what reason, no matter how good the excuse, no matter a majority of miners, no matter what." -- Greg Maxwell
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
Stephen Gornick
Legendary
*
Offline Offline

Activity: 2506
Merit: 1010


View Profile
October 11, 2012, 04:52:21 PM
 #2

the API just doesn't provide an easy way to get at it.

Nice.  This is an example of using raw transactions.

and won't tell me anything about transactions I'm not involved in.
Run bitcoin from get.  Use getrawtransaction with the decode flag.

Incidentally, raw transactions was just added with version 0.7 of the Bitcoin.org client, so that is a dependency.
 - http://en.bitcoin.it/wiki/Raw_Transactions

Unichange.me

            █
            █
            █
            █
            █
            █
            █
            █
            █
            █
            █
            █
            █
            █
            █
            █


vertoe
Hero Member
*****
Offline Offline

Activity: 518
Merit: 505


View Profile
February 12, 2014, 02:32:56 AM
 #3

thanks for sharing. this script is both - unique and helpful.

i refined this for my needs, you might want to have a look at it.
https://github.com/vertoe/pts-unspent
fbueller
Sr. Member
****
Offline Offline

Activity: 412
Merit: 275


View Profile
February 19, 2014, 11:39:28 PM
 #4

Good job on the code! Should help people looking to play with transactions to p2sh addresses.

Bitwasp Developer.
barwizi
Legendary
*
Offline Offline

Activity: 882
Merit: 1000



View Profile
September 01, 2014, 11:31:07 AM
 #5

thanks for sharing. this script is both - unique and helpful.

i refined this for my needs, you might want to have a look at it.
https://github.com/vertoe/pts-unspent

 i copied vertoe's implementation however it seems to be choking on PoS blocks. Help!!!
barwizi
Legendary
*
Offline Offline

Activity: 882
Merit: 1000



View Profile
September 01, 2014, 11:59:52 AM
 #6

Code:
foreach ($tx["vout"] as $tx_out)

        {

          $scripttype=$tx_out["scriptPubKey"]["type"];

          switch ($scripttype)

          {

          case "pubkeyhash":

          case "pubkey":

          case "scripthash":

            $mysqli->query("insert into outputs (block_num, block_hash, transaction_hash, sequence, address, balance) values (".$i.", '".$block["hash"]."', '".$txid."', ".$tx_out["n"].", '".$tx_out["scriptPubKey"]["addresses"][0]."', ".$tx_out["value"].")");

            break;

          case "scriptPubKey":

          case "multisig":

            $mysqli->query("insert into outputs (block_num, block_hash, transaction_hash, sequence, address, balance) values (".$i.", '".$block["hash"]."', '".$txid."', ".$tx_out["n"].", '** ".$scripttype." **', ".$tx_out["value"].")");

            break;

          case "nonstandard":

            $mysqli->query("insert into outputs (block_num, block_hash, transaction_hash, sequence, address, balance) values (".$i.", '".$block["hash"]."', '".$txid."', ".$tx_out["n"].", '** ".$scripttype." **', ".$tx_out["value"].")");

          default:

            throw new Exception("don't know how to handle ".$scripttype." scripts in transaction ".$txid);

            continue;

It gives me this error

Code:
PHP Fatal error:  Uncaught exception 'Exception' with message 'don't know how to handle nonstandard scripts in transaction 521fdd0f3bd589de759af578cf6bfc595854ba578eb709fe7f7f42d43b2c7960' in /home/build/nrsbala/update-database.php:91
Stack trace:
#0 {main}
  thrown in /home/build/nrsbala/update-database.php on line 91


for this block :-

Code:
Array
(
    [hex] => 010000008b636053010000000000000000000000000000000000000000000000000000000000000000ffffffff0c02a25a0105062f503253482fffffffff010000000000000000000000000000
    [txid] => 521fdd0f3bd589de759af578cf6bfc595854ba578eb709fe7f7f42d43b2c7960
    [version] => 1
    [time] => 1398825867
    [locktime] => 0
    [vin] => Array
        (
            [0] => Array
                (
                    [coinbase] => 02a25a0105062f503253482f
                    [sequence] => 4294967295
                )

        )

    [vout] => Array
        (
            [0] => Array
                (
                    [value] => 0
                    [n] => 0
                    [scriptPubKey] => Array
                        (
                            [asm] =>
                            [hex] =>
                            [type] => nonstandard
                        )

                )

        )

    [blockhash] => 0fcc89dcc850cbf7d7149b8f1534b2464a7902991d19a9367dae0751b3a25be0
    [confirmations] => 46496
    [blocktime] => 1398825867
)

I need help figuring a way for these txs to be handled.
vertoe
Hero Member
*****
Offline Offline

Activity: 518
Merit: 505


View Profile
September 03, 2014, 09:40:00 PM
 #7

@barwizi you are missing a break; behind the mysqli line in non-standard type.
Pages: [1]
  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!