Author

Topic: bitcoind signrawtransaction fails, but bitcoind decoderawtransaction succeeds? (Read 3396 times)

hero member
Activity: 651
Merit: 501
My PGP Key: 92C7689C
I've been trying to figure out a way to add a short comment to a transaction for a project I'm considering taking up.  The rabbit hole I've gone down is to put together raw transactions with scripts of my own design and hand them off to bitcoind for signing and sending.  Here's what I have so far:

Code:
  // usage: php make-tx.php comment txin_qty txin1_id txin1_idx txin2_id txin2_idx ... txout_qty txout1_amt txout1_addr txout2_amt txout2_addr ...

  // convert unsigned 8-bit integer to hex string
  
function hex8($in
  {
    return 
str_pad(dechex($in),2,"0",STR_PAD_LEFT);
  }

  
// convert signed 32-bit integer to little-endian hex string
  
function hex32($in
  {
    return 
hex8($in&0xFF).hex8($in>>8&0xFF).hex8($in>>16&0xFF).hex8($in>>24&0xFF);
  }

  
// convert string representation of an unsigned 64-bit integer to 
  // little-endian hex string
  
function hex64($in
  {
    
$msw=gmp_div(gmp_init($in),gmp_init("4294967296"));
    
$lsw=gmp_sub(gmp_init($in),gmp_mul($msw,gmp_init("4294967296")));
    if (
gmp_cmp($lsw,gmp_init("2147483647"))>0)
      
$lsw=gmp_sub($lsw,gmp_init("4294967296"));
    
$msw_i=intval(gmp_strval($msw));
    
$lsw_i=intval(gmp_strval($lsw));
    return 
hex32($lsw_i).hex32($msw_i);
  }

  
// convert string representation of fixed-point Bitcoin quantity to 
  // string representation of 64-bit integer satoshis
  
function btctosatoshi($n)
  {
  
$np=explode(".",$n);
  if (
count($np)==2)
  {
    
$whole=$np[0];
    
$frac=substr($np[1],0,8);
  }
  else
  {
    if (
strpos(".",$n)>0)
    {
      
$whole="0";
      
$frac=substr($np[0],0,8);
    }
    else
    {
      
$whole=$np[0];
      
$frac="0";
    }
  }
  if (
$whole=="")
    
$whole="0";
  if (
$frac=="")
    
$frac="0";
  return 
ltrim($whole.str_pad($frac,8,"0"),"0");
  }
  
  
// get hash160 of a Bitcoin address
  
function addrtohash($addr
  {
    
$code_string "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    
$num=gmp_init(0);
    for (
$i=0$i<strlen($addr); $i++)
      
$num=gmp_add(gmp_mul($num58), strpos($code_stringsubstr($addr$i1)));
    
$hex=gmp_strval($num16);
    return 
substr($hexstrlen($hex)-4840);
  }

  
// reverse input string in groups of two characters  
  
function reverse($in
  {
    
$out="";
    for (
$i=0$i<strlen($in); $i+=2)
      
$out=substr($in,$i,2).$out;
    return 
$out;
  }

  echo 
hex32(1); // version
  
  
$p=1// argument position
  
  
$comment=$argv[$p++]; // comment to attach to first tx_out
  
  
$txin_qty=$argv[$p++]; // number of inputs
  
  
echo hex8($txin_qty);
  
  for (
$i=0$i<$txin_qty$i++)
  {
    echo 
reverse($argv[$p++]); // input tx hash
    
echo hex32($argv[$p++]); // input tx index
    
echo "00"// sigscript size
    
echo "ffffffff"// filler
  
}  
  
  
$txout_qty=$argv[$p++]; // number of outputs
  
  
echo hex8($txout_qty+((strlen($comment)>0)?1:0));
  
  for (
$i=0$i<$txout_qty+((strlen($comment)>0)?1:0); $i++)
  {
    if (
$i!=$txout_qty)
    {
      echo 
hex64(btctosatoshi($argv[$p++])); // amount, in satoshis
      
echo hex8(25); // script length
      
echo "76"// OP_DUP
      
echo "a9"// OP_HASH160
      
echo "14"// hash length
      
echo addrtohash($argv[$p++]); // hash
      
echo "88"// OP_EQUALVERIFY
      
echo "ac"// OP_CHECKSIG    
    
}
    else
    {
      echo 
hex64(0);
      echo 
hex64(0);
      echo 
hex64(0);
      echo 
hex64(0);
      echo 
hex32(-1);
      echo 
hex8(3+strlen($comment));
      echo 
"4c"// OP_PUSHDATA1
      
echo hex8(strlen($comment)); // comment length
      
for ($j=0$j<strlen($comment); $j++)
        echo 
hex8(ord(substr($comment$j1)));
      echo 
"75"// OP_DROP
    
}
  }
  
  echo 
"00000000\n"// more filler
?>


As input, it takes a comment (use "" for no comment), one or more unused previous-transaction outputs as sources (txid-index pair), and one or more new outputs (value-address pair).  Here's a possible mainnet invocation that combines 8 unused inputs at 1JL83axd56CQp9NA6k8VkZL526NBhUsapN totaling .0007944 BTC, sends .0001 BTC to 177fNKjH6kkZ8nLVcZWDnLC5Vz9hkjJYAp, returns .0001944 BTC to 1JL83axd56CQp9NA6k8VkZL526NBhUsapN, and leaves .0005 BTC as a fee:

Code:
php make-tx-2.php "This is a comment attached to a transaction on mainnet." \
8 \
e450dc7394f8432d89c68d0df6a5506cb81eac60c977bfc7932633aaf835a31f 1201 \
8867f0f84e80588ed00a05e604487442546ef42ab4c93445a09b00a6d487e74b 294  \
be07132738abff8793a7fa53dc47089a78d223267d0f20f635e33292dd1c0ba2 1125 \
1b2fa6c3d6036aead0a0c011738123ec97e0c83e7d1f077ee6db354a6471773a 112  \
df8ec32ad591396e36e4721909d3e747fb1091f3ee9d15b14dc3250e28695d44 236  \
8397db0c620d2fe6a05a63b791eebdda5737bf2a684c2dab4666c47feced58c2 1026 \
881c603656801e599d96006ef7e54450bb39f4bba7db8984e5562bc2883db938 102  \
f79d17445c63371c0b57053fcb324fd5f0c09143f34582fbcf39ce737c1bdada 39   
2 \
.0001944 1JL83axd56CQp9NA6k8VkZL526NBhUsapN \
.0001    177fNKjH6kkZ8nLVcZWDnLC5Vz9hkjJYAp

It produces this output:

Code:
01000000081fa335f8aa332693c7bf77c960ac1eb86c50a5f60d8dc6892d43f89473dc50e4b104000000ffffffff4be787d4a6009ba04534c9b42af46e5442744804e6050ad08e58804ef8f067882601000000ffffffffa20b1cdd9232e335f6200f7d2623d2789a0847dc53faa79387ffab38271307be6504000000ffffffff3a7771644a35dbe67e071f7d3ec8e097ec23817311c0a0d0ea6a03d6c3a62f1b7000000000ffffffff445d69280e25c34db1159deef39110fb47e7d3091972e4366e3991d52ac38edfec00000000ffffffffc258edec7fc46646ab2d4c682abf3757dabdee91b7635aa0e62f0d620cdb97830204000000ffffffff38b93d88c22b56e58489dba7bbf439bb5044e5f76e00969d591e805636601c886600000000ffffffffdada1b7c73ce39cffb8245f34391c0f0d54f32cb3f05570b1c37635c44179df72700000000ffffffff03f04b0000000000001976a914be17ec0fc1f8aa029223dbe5f53109d0faf8c79788ac10270000000000001976a91443134735b72a1e9cf5e4c56d9102953132352ba688ac0000000000000000000000000000000000000000000000000000000000000000ffffffff3a4c3754686973206973206120636f6d6d656e7420617474616368656420746f2061207472616e73616374696f6e206f6e206d61696e6e65742e7500000000

Feed this to bitcoind decoderawtransaction, and you get valid output:

Code:
{
    "txid" : "e657b8db99066bda49955a41257d924f1eded506874c9733e6b532b71a8a591b",
    "version" : 1,
    "locktime" : 0,
    "vin" : [
        {
            "txid" : "e450dc7394f8432d89c68d0df6a5506cb81eac60c977bfc7932633aaf835a31f",
            "vout" : 1201,
            "scriptSig" : {
                "asm" : "",
                "hex" : ""
            },
            "sequence" : 4294967295
        },
        {
            "txid" : "8867f0f84e80588ed00a05e604487442546ef42ab4c93445a09b00a6d487e74b",
            "vout" : 294,
            "scriptSig" : {
                "asm" : "",
                "hex" : ""
            },
            "sequence" : 4294967295
        },
        {
            "txid" : "be07132738abff8793a7fa53dc47089a78d223267d0f20f635e33292dd1c0ba2",
            "vout" : 1125,
            "scriptSig" : {
                "asm" : "",
                "hex" : ""
            },
            "sequence" : 4294967295
        },
        {
            "txid" : "1b2fa6c3d6036aead0a0c011738123ec97e0c83e7d1f077ee6db354a6471773a",
            "vout" : 112,
            "scriptSig" : {
                "asm" : "",
                "hex" : ""
            },
            "sequence" : 4294967295
        },
        {
            "txid" : "df8ec32ad591396e36e4721909d3e747fb1091f3ee9d15b14dc3250e28695d44",
            "vout" : 236,
            "scriptSig" : {
                "asm" : "",
                "hex" : ""
            },
            "sequence" : 4294967295
        },
        {
            "txid" : "8397db0c620d2fe6a05a63b791eebdda5737bf2a684c2dab4666c47feced58c2",
            "vout" : 1026,
            "scriptSig" : {
                "asm" : "",
                "hex" : ""
            },
            "sequence" : 4294967295
        },
        {
            "txid" : "881c603656801e599d96006ef7e54450bb39f4bba7db8984e5562bc2883db938",
            "vout" : 102,
            "scriptSig" : {
                "asm" : "",
                "hex" : ""
            },
            "sequence" : 4294967295
        },
        {
            "txid" : "f79d17445c63371c0b57053fcb324fd5f0c09143f34582fbcf39ce737c1bdada",
            "vout" : 39,
            "scriptSig" : {
                "asm" : "",
                "hex" : ""
            },
            "sequence" : 4294967295
        }
    ],
    "vout" : [
        {
            "value" : 0.00019440,
            "n" : 0,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 be17ec0fc1f8aa029223dbe5f53109d0faf8c797 OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a914be17ec0fc1f8aa029223dbe5f53109d0faf8c79788ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "1JL83axd56CQp9NA6k8VkZL526NBhUsapN"
                ]
            }
        },
        {
            "value" : 0.00010000,
            "n" : 1,
            "scriptPubKey" : {
                "asm" : "OP_DUP OP_HASH160 43134735b72a1e9cf5e4c56d9102953132352ba6 OP_EQUALVERIFY OP_CHECKSIG",
                "hex" : "76a91443134735b72a1e9cf5e4c56d9102953132352ba688ac",
                "reqSigs" : 1,
                "type" : "pubkeyhash",
                "addresses" : [
                    "177fNKjH6kkZ8nLVcZWDnLC5Vz9hkjJYAp"
                ]
            }
        },
        {
            "value" : 0.00000000,
            "n" : 2,
            "scriptPubKey" : {
                "asm" : "",
                "hex" : "",
                "type" : "nonstandard"
            }
        }
    ]
}

The last bit is a zero-value output that pushes the string "This is a comment attached to a transaction on mainnet." onto the stack, and then pulls it off:



Looking at the illustration above, they're an "arbitrary data" block after a couple of standard TxOuts.

Try signing it (yes, the private key for 1JL83axd56CQp9NA6k8VkZL526NBhUsapN is in my wallet), though, and you get this:

Code:
error: {"code":-22,"message":"TX decode failed"}

Leave the comment out, though, and the transaction can be signed and sent.  I had also experimented with including the comment with one of the existing TxOuts...they went through OK on testnet, but bitcoind considered them "strange" and doesn't want to include them in wallet totals.

It seems like one or both of these should work, so why aren't they?  Am I missing something?
Jump to: