sighash sewgit

sign P2WPKH, P2WSH, P2SH-P2WPKH, P2WSH-MULTISIG, P2SH-P2WSH-MULTISIG
This commit is contained in:
4tochka 2018-06-29 13:05:53 +04:00
parent 2ff46649d9
commit 3da185c241
22 changed files with 2827 additions and 1350 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -78,10 +78,11 @@
<span class="bp">self</span><span class="o">.</span><span class="n">hex</span> <span class="o">=</span> <span class="n">hexlify</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">hex</span> <span class="o">=</span> <span class="n">hexlify</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">wif</span> <span class="o">=</span> <span class="n">private_key_to_wif</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">compressed</span><span class="p">,</span> <span class="n">testnet</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">wif</span> <span class="o">=</span> <span class="n">private_key_to_wif</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">compressed</span><span class="p">,</span> <span class="n">testnet</span><span class="p">)</span>
<span class="k">return</span> <span class="k">return</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">is_wif_valid</span><span class="p">(</span><span class="n">key</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;private key invalid&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">wif_to_private_key</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">hex</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">wif_to_private_key</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="nb">hex</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">hex</span> <span class="o">=</span> <span class="n">hexlify</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">hex</span> <span class="o">=</span> <span class="n">hexlify</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">wif</span> <span class="o">=</span> <span class="n">private_key_to_wif</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">compressed</span><span class="p">,</span> <span class="n">testnet</span><span class="p">)</span>
<span class="k">if</span> <span class="n">key</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">in</span> <span class="p">(</span><span class="n">MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX</span><span class="p">,</span> <span class="k">if</span> <span class="n">key</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">in</span> <span class="p">(</span><span class="n">MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX</span><span class="p">,</span>
<span class="n">TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX</span><span class="p">):</span> <span class="n">TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">compressed</span> <span class="o">=</span> <span class="kc">False</span> <span class="bp">self</span><span class="o">.</span><span class="n">compressed</span> <span class="o">=</span> <span class="kc">False</span>
@ -92,6 +93,7 @@
<span class="bp">self</span><span class="o">.</span><span class="n">testnet</span> <span class="o">=</span> <span class="kc">True</span> <span class="bp">self</span><span class="o">.</span><span class="n">testnet</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">else</span><span class="p">:</span> <span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">testnet</span> <span class="o">=</span> <span class="kc">False</span> <span class="bp">self</span><span class="o">.</span><span class="n">testnet</span> <span class="o">=</span> <span class="kc">False</span>
<span class="bp">self</span><span class="o">.</span><span class="n">wif</span> <span class="o">=</span> <span class="n">private_key_to_wif</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">compressed</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">testnet</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">wif</span></div> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">wif</span></div>
@ -252,6 +254,51 @@
<span class="n">witness_version</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">witness_version</span><span class="p">,</span> <span class="n">witness_version</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">witness_version</span><span class="p">,</span>
<span class="n">testnet</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">testnet</span><span class="p">)</span> <span class="n">testnet</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">testnet</span><span class="p">)</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">multisig</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">public_key_list</span><span class="p">,</span> <span class="n">testnet</span> <span class="o">=</span> <span class="kc">False</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The class method for creating a multisig address.</span>
<span class="sd"> :param n: count of required signatures (max 15).</span>
<span class="sd"> :param m: count of total addresses of participants (max 15).</span>
<span class="sd"> :param list address_list: addresses list, allowed types:</span>
<span class="sd"> </span>
<span class="sd"> - bytes or HEX encoded private key</span>
<span class="sd"> - private key in WIF format</span>
<span class="sd"> - PrivateKey instance,</span>
<span class="sd"> - bytes or HEX encoded public key</span>
<span class="sd"> - PublicKey instance</span>
<span class="sd"> </span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="mi">15</span> <span class="ow">or</span> <span class="n">m</span> <span class="o">&gt;</span> <span class="mi">15</span> <span class="ow">or</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="n">m</span> <span class="ow">or</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">1</span> <span class="ow">or</span> <span class="n">m</span> <span class="o">&lt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;invalid n of m maximum 15 of 15 multisig allowed&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">public_key_list</span><span class="p">)</span> <span class="o">!=</span> <span class="n">m</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;invalid address list count&quot;</span><span class="p">)</span>
<span class="n">script</span> <span class="o">=</span> <span class="nb">bytes</span><span class="p">([</span><span class="mh">0x50</span> <span class="o">+</span> <span class="n">n</span><span class="p">])</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">public_key_list</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">unhexlify</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">if</span> <span class="n">is_wif_valid</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">private_to_public_key</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="nb">hex</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">pass</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">Address</span><span class="p">):</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">public_key</span><span class="o">.</span><span class="n">key</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">PublicKey</span><span class="p">):</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">key</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">PrivateKey</span><span class="p">):</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">private_to_public_key</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;invalid public key list element&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">==</span> <span class="mi">32</span><span class="p">:</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">private_to_public_key</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">33</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;invalid public key list element size&quot;</span><span class="p">)</span>
<span class="n">script</span> <span class="o">+=</span> <span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">a</span><span class="p">))</span> <span class="o">+</span> <span class="n">a</span>
<span class="n">script</span> <span class="o">+=</span> <span class="nb">bytes</span><span class="p">([</span><span class="mh">0x50</span> <span class="o">+</span> <span class="n">m</span><span class="p">])</span> <span class="o">+</span> <span class="n">OP_CHECKMULTISIG</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">script</span><span class="p">,</span> <span class="n">testnet</span><span class="o">=</span><span class="n">testnet</span><span class="p">)</span>
</pre></div> </pre></div>
</div> </div>

View File

@ -42,8 +42,23 @@
<div class="viewcode-block" id="Transaction"><a class="viewcode-back" href="../../transaction.html#pybtc.Transaction">[docs]</a><span class="k">class</span> <span class="nc">Transaction</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span> <div class="viewcode-block" id="Transaction"><a class="viewcode-back" href="../../transaction.html#pybtc.Transaction">[docs]</a><span class="k">class</span> <span class="nc">Transaction</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_tx</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">tx_format</span><span class="o">=</span><span class="s2">&quot;decoded&quot;</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">lockTime</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">testnet</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span> <span class="sd">&quot;&quot;&quot;</span>
<span class="k">assert</span> <span class="n">tx_format</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;decoded&quot;</span><span class="p">,</span> <span class="s2">&quot;raw&quot;</span><span class="p">)</span> <span class="sd"> The class for Transaction object</span>
<span class="sd"> :param raw_tx: (optional) raw transaction in bytes or HEX encoded string, if no raw transaction provided</span>
<span class="sd"> well be created new empty transaction template.</span>
<span class="sd"> :param tx_format: &quot;raw&quot; or &quot;decoded&quot; format. Raw format is mean that all transaction represented in bytes</span>
<span class="sd"> for best performance.</span>
<span class="sd"> Decoded transaction is represented in human readable format using base68, hex, bech32, </span>
<span class="sd"> asm and opcodes. By default &quot;decoded&quot; format using.</span>
<span class="sd"> :param int version: transaction version for new template, by default 1.</span>
<span class="sd"> :param int lock_time: transaction lock time for new template, by default 0.</span>
<span class="sd"> :param boolean testnet: address type for &quot;decoded&quot; transaction representation.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_tx</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">tx_format</span><span class="o">=</span><span class="s2">&quot;decoded&quot;</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">lock_time</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">testnet</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="k">if</span> <span class="n">tx_format</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;decoded&quot;</span><span class="p">,</span> <span class="s2">&quot;raw&quot;</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;tx_format error, raw or decoded allowed&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">tx_format</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">tx_format</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;testnet&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">testnet</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;testnet&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">testnet</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;segwit&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;segwit&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
@ -53,7 +68,7 @@
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;size&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;size&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vSize&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vSize&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;bSize&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;bSize&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;lockTime&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">lockTime</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;lockTime&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">lock_time</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;rawTx&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;rawTx&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
@ -68,25 +83,31 @@
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;amount&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;amount&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">raw_tx</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="k">if</span> <span class="n">raw_tx</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="k">return</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;amount&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;amount&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">sw</span> <span class="o">=</span> <span class="n">sw_len</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">stream</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_stream</span><span class="p">(</span><span class="n">raw_tx</span><span class="p">)</span> <span class="n">stream</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_stream</span><span class="p">(</span><span class="n">raw_tx</span><span class="p">)</span>
<span class="n">start</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span> <span class="n">start</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span>
<span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">],)</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))</span>
<span class="c1"># start deserialization</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">n</span> <span class="o">=</span> <span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span> <span class="n">n</span> <span class="o">=</span> <span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
<span class="n">sw</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">sw_len</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="sa">b</span><span class="s1">&#39;</span><span class="se">\x00</span><span class="s1">&#39;</span><span class="p">:</span> <span class="k">if</span> <span class="n">n</span> <span class="o">==</span> <span class="sa">b</span><span class="s1">&#39;</span><span class="se">\x00</span><span class="s1">&#39;</span><span class="p">:</span>
<span class="c1"># segwit format</span>
<span class="n">sw</span> <span class="o">=</span> <span class="mi">1</span> <span class="n">sw</span> <span class="o">=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;flag&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;flag&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">n</span> <span class="o">=</span> <span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span> <span class="n">n</span> <span class="o">=</span> <span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span>
<span class="c1"># inputs</span>
<span class="n">ic</span> <span class="o">=</span> <span class="n">var_int_to_int</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="n">ic</span> <span class="o">=</span> <span class="n">var_int_to_int</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">ic</span><span class="p">):</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">ic</span><span class="p">):</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;txId&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;txId&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">32</span><span class="p">)</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;vOut&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;vOut&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">n</span> <span class="o">=</span> <span class="n">var_int_to_int</span><span class="p">(</span><span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">))</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;scriptSig&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">var_int_to_int</span><span class="p">(</span><span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)))</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;scriptSig&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;sequence&quot;</span><span class="p">],)</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))</span> <span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;sequence&quot;</span><span class="p">],)</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))</span>
<span class="c1"># outputs</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">var_int_to_int</span><span class="p">(</span><span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">))):</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">var_int_to_int</span><span class="p">(</span><span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">))):</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;value&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;Q&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">8</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;value&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;Q&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">8</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span>
@ -101,13 +122,17 @@
<span class="k">if</span> <span class="n">s</span><span class="p">[</span><span class="s2">&quot;nType&quot;</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">):</span> <span class="k">if</span> <span class="n">s</span><span class="p">[</span><span class="s2">&quot;nType&quot;</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">7</span><span class="p">):</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;addressHash&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="s2">&quot;addressHash&quot;</span><span class="p">]</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;addressHash&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="s2">&quot;addressHash&quot;</span><span class="p">]</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;reqSigs&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="s2">&quot;reqSigs&quot;</span><span class="p">]</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;reqSigs&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="s2">&quot;reqSigs&quot;</span><span class="p">]</span>
<span class="c1"># witness</span>
<span class="k">if</span> <span class="n">sw</span><span class="p">:</span> <span class="k">if</span> <span class="n">sw</span><span class="p">:</span>
<span class="n">sw</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span> <span class="n">sw</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">ic</span><span class="p">):</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">ic</span><span class="p">):</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;txInWitness&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">var_int_to_int</span><span class="p">(</span><span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)))</span> \ <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">k</span><span class="p">][</span><span class="s2">&quot;txInWitness&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">var_int_to_int</span><span class="p">(</span><span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)))</span> \
<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">var_int_to_int</span><span class="p">(</span><span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)))]</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">var_int_to_int</span><span class="p">(</span><span class="n">read_var_int</span><span class="p">(</span><span class="n">stream</span><span class="p">)))]</span>
<span class="n">sw_len</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span> <span class="o">-</span> <span class="n">sw</span> <span class="o">+</span> <span class="mi">2</span> <span class="n">sw_len</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span> <span class="o">-</span> <span class="n">sw</span> <span class="o">+</span> <span class="mi">2</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;lockTime&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;lockTime&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unpack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">end</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span> <span class="n">end</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span>
<span class="n">stream</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="n">start</span><span class="p">)</span> <span class="n">stream</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="n">start</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span> <span class="n">b</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span>
@ -131,7 +156,13 @@
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">double_sha256</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">double_sha256</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;hash&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">]</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;hash&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">decode</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">testnet</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <div class="viewcode-block" id="Transaction.decode"><a class="viewcode-back" href="../../transaction.html#pybtc.Transaction.decode">[docs]</a> <span class="k">def</span> <span class="nf">decode</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">testnet</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> change Transacion object representation to &quot;decoded&quot; human readable format</span>
<span class="sd"> :param bool testnet: (optional) address type for &quot;decoded&quot; transaction representation, by default None.</span>
<span class="sd"> if None used type from transaction property &quot;format&quot;.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;decoded&quot;</span><span class="p">:</span> <span class="k">if</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;decoded&quot;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;decoded&quot;</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;decoded&quot;</span>
@ -210,9 +241,14 @@
<span class="k">if</span> <span class="s2">&quot;data&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span> <span class="k">if</span> <span class="s2">&quot;data&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span> <span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">hexlify</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">])</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">hexlify</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">])</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="k">return</span> <span class="bp">self</span> <span class="k">return</span> <span class="bp">self</span></div>
<span class="k">def</span> <span class="nf">encode</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <div class="viewcode-block" id="Transaction.encode"><a class="viewcode-back" href="../../transaction.html#pybtc.Transaction.encode">[docs]</a> <span class="k">def</span> <span class="nf">encode</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> change Transaction object representation to &quot;raw&quot; bytes format, </span>
<span class="sd"> all human readable part will be stripped.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span> <span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">s2rh</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">])</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">s2rh</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;txId&quot;</span><span class="p">])</span>
<span class="k">if</span> <span class="s2">&quot;flag&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span> <span class="k">if</span> <span class="s2">&quot;flag&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">:</span>
@ -272,7 +308,7 @@
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span> <span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unhexlify</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">])</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">unhexlify</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">])</span>
<span class="bp">self</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;raw&quot;</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;format&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;raw&quot;</span>
<span class="k">return</span> <span class="bp">self</span> <span class="k">return</span> <span class="bp">self</span></div>
<span class="k">def</span> <span class="nf">get_stream</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">):</span> <span class="k">def</span> <span class="nf">get_stream</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stream</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span> <span class="o">!=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">:</span> <span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">stream</span><span class="p">)</span> <span class="o">!=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">:</span>
@ -284,19 +320,27 @@
<span class="k">raise</span> <span class="ne">TypeError</span> <span class="k">raise</span> <span class="ne">TypeError</span>
<span class="k">return</span> <span class="n">stream</span> <span class="k">return</span> <span class="n">stream</span>
<span class="k">def</span> <span class="nf">serialize</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">segwit</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="nb">hex</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span> <div class="viewcode-block" id="Transaction.serialize"><a class="viewcode-back" href="../../transaction.html#pybtc.Transaction.serialize">[docs]</a> <span class="k">def</span> <span class="nf">serialize</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">segwit</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="nb">hex</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get serialized transaction </span>
<span class="sd"> </span>
<span class="sd"> :param bool segwit: (optional) flag for segwit representation of serialized transaction, by </span>
<span class="sd"> default True.</span>
<span class="sd"> :param bool hex: (optional) if set to True return HEX encoded string, by default True.</span>
<span class="sd"> :return str,bytes: serialized transaction in HEX or bytes.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">chunks</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">chunks</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;version&quot;</span><span class="p">]))</span>
<span class="k">if</span> <span class="n">segwit</span> <span class="ow">and</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;segwit&quot;</span><span class="p">]:</span> <span class="k">if</span> <span class="n">segwit</span> <span class="ow">and</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;segwit&quot;</span><span class="p">]:</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">b</span><span class="s2">&quot;</span><span class="se">\x00\x01</span><span class="s2">&quot;</span><span class="p">)</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">b</span><span class="s2">&quot;</span><span class="se">\x00\x01</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">])))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">])))</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">]:</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">]:</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txId&#39;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txId&#39;</span><span class="p">],</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txId&#39;</span><span class="p">])</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txId&#39;</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span> <span class="k">else</span><span class="p">:</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">s2rh</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txId&#39;</span><span class="p">]))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">s2rh</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txId&#39;</span><span class="p">]))</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;vOut&#39;</span><span class="p">]))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;vOut&#39;</span><span class="p">]))</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptSig&#39;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptSig&#39;</span><span class="p">],</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptSig&#39;</span><span class="p">])))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptSig&#39;</span><span class="p">])))</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptSig&#39;</span><span class="p">])</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptSig&#39;</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span> <span class="k">else</span><span class="p">:</span>
@ -306,7 +350,7 @@
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">])))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">])))</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">]:</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">]:</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&lt;Q&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;value&#39;</span><span class="p">]))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&lt;Q&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;value&#39;</span><span class="p">]))</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptPubKey&#39;</span><span class="p">])</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptPubKey&#39;</span><span class="p">],</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptPubKey&#39;</span><span class="p">])))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptPubKey&#39;</span><span class="p">])))</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptPubKey&#39;</span><span class="p">])</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vOut&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;scriptPubKey&#39;</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span> <span class="k">else</span><span class="p">:</span>
@ -316,7 +360,7 @@
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">]:</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">]:</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txInWitness&#39;</span><span class="p">])))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txInWitness&#39;</span><span class="p">])))</span>
<span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txInWitness&#39;</span><span class="p">]:</span> <span class="k">for</span> <span class="n">w</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">[</span><span class="s2">&quot;vIn&quot;</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="s1">&#39;txInWitness&#39;</span><span class="p">]:</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">w</span><span class="p">)</span> <span class="o">==</span> <span class="nb">bytes</span><span class="p">:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">w</span><span class="p">)))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">int_to_var_int</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">w</span><span class="p">)))</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">w</span><span class="p">)</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">w</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="k">else</span><span class="p">:</span>
@ -324,14 +368,18 @@
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">unhexlify</span><span class="p">(</span><span class="n">w</span><span class="p">))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">unhexlify</span><span class="p">(</span><span class="n">w</span><span class="p">))</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">[</span><span class="s1">&#39;lockTime&#39;</span><span class="p">]))</span> <span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s1">&#39;&lt;L&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="p">[</span><span class="s1">&#39;lockTime&#39;</span><span class="p">]))</span>
<span class="n">tx</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">chunks</span><span class="p">)</span> <span class="n">tx</span> <span class="o">=</span> <span class="sa">b</span><span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">chunks</span><span class="p">)</span>
<span class="k">return</span> <span class="n">tx</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">hex</span> <span class="k">else</span> <span class="n">hexlify</span><span class="p">(</span><span class="n">tx</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span> <span class="k">return</span> <span class="n">tx</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">hex</span> <span class="k">else</span> <span class="n">hexlify</span><span class="p">(</span><span class="n">tx</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span></div>
<span class="k">def</span> <span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <div class="viewcode-block" id="Transaction.json"><a class="viewcode-back" href="../../transaction.html#pybtc.Transaction.json">[docs]</a> <span class="k">def</span> <span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get json transaction representation</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span>
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span> <span class="k">except</span><span class="p">:</span>
<span class="k">pass</span> <span class="k">pass</span>
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span> <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span></div>
<span class="k">def</span> <span class="nf">add_input</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tx_id</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">v_out</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">sequence</span><span class="o">=</span><span class="mh">0xffffffff</span><span class="p">,</span> <span class="k">def</span> <span class="nf">add_input</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tx_id</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">v_out</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">sequence</span><span class="o">=</span><span class="mh">0xffffffff</span><span class="p">,</span>
<span class="n">script_sig</span><span class="o">=</span><span class="sa">b</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">tx_in_witness</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">amount</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">script_sig</span><span class="o">=</span><span class="sa">b</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">tx_in_witness</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">amount</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>

View File

@ -44,7 +44,7 @@ Usage example::
import pybtc import pybtc
a = pybtc.Address() a = pybtc.Address()
print(a.address) print(a.address)
print(a.private_key.wif()) print(a.private_key.wif)

View File

@ -9,3 +9,4 @@ The class for creating transaction.
:members: :members:

View File

@ -41,9 +41,11 @@
| <a href="#B"><strong>B</strong></a> | <a href="#B"><strong>B</strong></a>
| <a href="#C"><strong>C</strong></a> | <a href="#C"><strong>C</strong></a>
| <a href="#D"><strong>D</strong></a> | <a href="#D"><strong>D</strong></a>
| <a href="#E"><strong>E</strong></a>
| <a href="#G"><strong>G</strong></a> | <a href="#G"><strong>G</strong></a>
| <a href="#H"><strong>H</strong></a> | <a href="#H"><strong>H</strong></a>
| <a href="#I"><strong>I</strong></a> | <a href="#I"><strong>I</strong></a>
| <a href="#J"><strong>J</strong></a>
| <a href="#K"><strong>K</strong></a> | <a href="#K"><strong>K</strong></a>
| <a href="#M"><strong>M</strong></a> | <a href="#M"><strong>M</strong></a>
| <a href="#P"><strong>P</strong></a> | <a href="#P"><strong>P</strong></a>
@ -113,6 +115,8 @@
<h2 id="D">D</h2> <h2 id="D">D</h2>
<table style="width: 100%" class="indextable genindextable"><tr> <table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="transaction.html#pybtc.Transaction.decode">decode() (pybtc.Transaction method)</a>
</li>
<li><a href="functional.html#pybtc.decode_script">decode_script() (in module pybtc)</a> <li><a href="functional.html#pybtc.decode_script">decode_script() (in module pybtc)</a>
</li> </li>
</ul></td> </ul></td>
@ -124,6 +128,14 @@
</ul></td> </ul></td>
</tr></table> </tr></table>
<h2 id="E">E</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="transaction.html#pybtc.Transaction.encode">encode() (pybtc.Transaction method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="G">G</h2> <h2 id="G">G</h2>
<table style="width: 100%" class="indextable genindextable"><tr> <table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
@ -174,6 +186,14 @@
</ul></td> </ul></td>
</tr></table> </tr></table>
<h2 id="J">J</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="transaction.html#pybtc.Transaction.json">json() (pybtc.Transaction method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="K">K</h2> <h2 id="K">K</h2>
<table style="width: 100%" class="indextable genindextable"><tr> <table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
@ -254,6 +274,8 @@
</ul></td> </ul></td>
<td style="width: 33%; vertical-align: top;"><ul> <td style="width: 33%; vertical-align: top;"><ul>
<li><a href="functional.html#pybtc.script_to_hash">script_to_hash() (in module pybtc)</a> <li><a href="functional.html#pybtc.script_to_hash">script_to_hash() (in module pybtc)</a>
</li>
<li><a href="transaction.html#pybtc.Transaction.serialize">serialize() (pybtc.Transaction method)</a>
</li> </li>
<li><a href="functional.html#pybtc.sign_message">sign_message() (in module pybtc)</a> <li><a href="functional.html#pybtc.sign_message">sign_message() (in module pybtc)</a>
</li> </li>

View File

@ -59,7 +59,7 @@
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pybtc</span> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">pybtc</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">pybtc</span><span class="o">.</span><span class="n">Address</span><span class="p">()</span> <span class="n">a</span> <span class="o">=</span> <span class="n">pybtc</span><span class="o">.</span><span class="n">Address</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">address</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">address</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">private_key</span><span class="o">.</span><span class="n">wif</span><span class="p">())</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">private_key</span><span class="o">.</span><span class="n">wif</span><span class="p">)</span>
</pre></div> </pre></div>
</div> </div>
</div> </div>

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -39,8 +39,79 @@
<p>The class for creating transaction.</p> <p>The class for creating transaction.</p>
<dl class="class"> <dl class="class">
<dt id="pybtc.Transaction"> <dt id="pybtc.Transaction">
<em class="property">class </em><code class="descclassname">pybtc.</code><code class="descname">Transaction</code><span class="sig-paren">(</span><em>raw_tx=None</em>, <em>tx_format='decoded'</em>, <em>version=1</em>, <em>lockTime=0</em>, <em>testnet=False</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/pybtc/transaction.html#Transaction"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pybtc.Transaction" title="Permalink to this definition"></a></dt> <em class="property">class </em><code class="descclassname">pybtc.</code><code class="descname">Transaction</code><span class="sig-paren">(</span><em>raw_tx=None</em>, <em>tx_format='decoded'</em>, <em>version=1</em>, <em>lock_time=0</em>, <em>testnet=False</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/pybtc/transaction.html#Transaction"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pybtc.Transaction" title="Permalink to this definition"></a></dt>
<dd></dd></dl> <dd><p>The class for Transaction object</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
<li><strong>raw_tx</strong> (optional) raw transaction in bytes or HEX encoded string, if no raw transaction provided
well be created new empty transaction template.</li>
<li><strong>tx_format</strong> “raw” or “decoded” format. Raw format is mean that all transaction represented in bytes
for best performance.
Decoded transaction is represented in human readable format using base68, hex, bech32,
asm and opcodes. By default “decoded” format using.</li>
<li><strong>version</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.6)"><em>int</em></a>) transaction version for new template, by default 1.</li>
<li><strong>lock_time</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.6)"><em>int</em></a>) transaction lock time for new template, by default 0.</li>
<li><strong>testnet</strong> (<em>boolean</em>) address type for “decoded” transaction representation.</li>
</ul>
</td>
</tr>
</tbody>
</table>
<dl class="method">
<dt id="pybtc.Transaction.decode">
<code class="descname">decode</code><span class="sig-paren">(</span><em>testnet=None</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/pybtc/transaction.html#Transaction.decode"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pybtc.Transaction.decode" title="Permalink to this definition"></a></dt>
<dd><p>change Transacion object representation to “decoded” human readable format</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>testnet</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#bool" title="(in Python v3.6)"><em>bool</em></a>) (optional) address type for “decoded” transaction representation, by default None.
if None used type from transaction property “format”.</td>
</tr>
</tbody>
</table>
</dd></dl>
<dl class="method">
<dt id="pybtc.Transaction.encode">
<code class="descname">encode</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/pybtc/transaction.html#Transaction.encode"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pybtc.Transaction.encode" title="Permalink to this definition"></a></dt>
<dd><p>change Transaction object representation to “raw” bytes format,
all human readable part will be stripped.</p>
</dd></dl>
<dl class="method">
<dt id="pybtc.Transaction.json">
<code class="descname">json</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="_modules/pybtc/transaction.html#Transaction.json"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pybtc.Transaction.json" title="Permalink to this definition"></a></dt>
<dd><p>Get json transaction representation</p>
</dd></dl>
<dl class="method">
<dt id="pybtc.Transaction.serialize">
<code class="descname">serialize</code><span class="sig-paren">(</span><em>segwit=True</em>, <em>hex=True</em><span class="sig-paren">)</span><a class="reference internal" href="_modules/pybtc/transaction.html#Transaction.serialize"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#pybtc.Transaction.serialize" title="Permalink to this definition"></a></dt>
<dd><p>Get serialized transaction</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first simple">
<li><strong>segwit</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#bool" title="(in Python v3.6)"><em>bool</em></a>) (optional) flag for segwit representation of serialized transaction, by
default True.</li>
<li><strong>hex</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#bool" title="(in Python v3.6)"><em>bool</em></a>) (optional) if set to True return HEX encoded string, by default True.</li>
</ul>
</td>
</tr>
<tr class="field-even field"><th class="field-name" colspan="2">Return str,bytes:</th></tr>
<tr class="field-even field"><td>&#160;</td><td class="field-body"><p class="first last">serialized transaction in HEX or bytes.</p>
</td>
</tr>
</tbody>
</table>
</dd></dl>
</dd></dl>
</div> </div>

View File

@ -9,3 +9,4 @@ The class for creating transaction.
:members: :members:

View File

@ -43,10 +43,11 @@ class PrivateKey():
self.hex = hexlify(self.key).decode() self.hex = hexlify(self.key).decode()
self.wif = private_key_to_wif(self.key, compressed, testnet) self.wif = private_key_to_wif(self.key, compressed, testnet)
return return
assert isinstance(key, str) if not isinstance(key, str) or not is_wif_valid(key):
raise TypeError("private key invalid")
self.key = wif_to_private_key(key, hex=False) self.key = wif_to_private_key(key, hex=False)
self.hex = hexlify(self.key).decode() self.hex = hexlify(self.key).decode()
self.wif = private_key_to_wif(self.key, compressed, testnet)
if key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX, if key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX): TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
self.compressed = False self.compressed = False
@ -57,6 +58,7 @@ class PrivateKey():
self.testnet = True self.testnet = True
else: else:
self.testnet = False self.testnet = False
self.wif = private_key_to_wif(self.key, self.compressed, self.testnet)
def __str__(self): def __str__(self):
return self.wif return self.wif
@ -201,15 +203,18 @@ class Address():
class ScriptAddress(): class ScriptAddress():
def __init__(self, script, address_type="P2SH", def __init__(self, script,
testnet=False, witness_version=None): testnet=False, witness_version=0):
self.witness_version = witness_version self.witness_version = witness_version
self.testnet = testnet self.testnet = testnet
if isinstance(script, str): if isinstance(script, str):
script = unhexlify(script) script = unhexlify(script)
self.script = script self.script = script
self.script_hex = hexlify(self.script).decode() self.script_hex = hexlify(self.script).decode()
if witness_version is None:
self.hash = hash160(self.script) self.hash = hash160(self.script)
else:
self.hash = sha256(self.script)
self.script_opcodes = decode_script(self.script) self.script_opcodes = decode_script(self.script)
self.script_opcodes_asm = decode_script(self.script, 1) self.script_opcodes_asm = decode_script(self.script, 1)
self.address = hash_to_address(self.hash, self.address = hash_to_address(self.hash,
@ -217,3 +222,49 @@ class ScriptAddress():
witness_version=self.witness_version, witness_version=self.witness_version,
testnet=self.testnet) testnet=self.testnet)
@classmethod
def multisig(cls, n, m, public_key_list,
testnet=False, witness_version=0):
"""
The class method for creating a multisig address.
:param n: count of required signatures (max 15).
:param m: count of total addresses of participants (max 15).
:param list address_list: addresses list, allowed types:
- bytes or HEX encoded private key
- private key in WIF format
- PrivateKey instance,
- bytes or HEX encoded public key
- PublicKey instance
"""
if n > 15 or m > 15 or n > m or n < 1 or m < 1:
raise TypeError("invalid n of m maximum 15 of 15 multisig allowed")
if len(public_key_list) != m:
raise TypeError("invalid address list count")
script = bytes([0x50 + n])
for a in list(public_key_list):
if isinstance(a, str):
try:
a = unhexlify(a)
except:
if is_wif_valid(a):
a = private_to_public_key(a, hex=False)
pass
if isinstance(a, Address):
a = a.public_key.key
elif isinstance(a, PublicKey):
a = a.key
elif isinstance(a, PrivateKey):
a = private_to_public_key(a.key)
if not isinstance(a, bytes):
raise TypeError("invalid public key list element")
if len(a) == 32:
a = private_to_public_key(a)
if len(a) != 33:
raise TypeError("invalid public key list element size")
script += int_to_var_int(len(a)) + a
script += bytes([0x50 + m]) + OP_CHECKMULTISIG
return cls(script, testnet=testnet, witness_version=witness_version)

View File

@ -11,8 +11,8 @@ OPCODE["OP_PUSHDATA2"] = 0x4d
OPCODE["OP_PUSHDATA4"] = 0x4e OPCODE["OP_PUSHDATA4"] = 0x4e
OPCODE["OP_1NEGATE"] = 0x4f OPCODE["OP_1NEGATE"] = 0x4f
OPCODE["OP_RESERVED"] = 0x50 OPCODE["OP_RESERVED"] = 0x50
OPCODE["OP_1"] = 0x51
OPCODE["OP_TRUE"] = 0x51 OPCODE["OP_TRUE"] = 0x51
OPCODE["OP_1"] = 0x51
OPCODE["OP_2"] = 0x52 OPCODE["OP_2"] = 0x52
OPCODE["OP_3"] = 0x53 OPCODE["OP_3"] = 0x53
OPCODE["OP_4"] = 0x54 OPCODE["OP_4"] = 0x54

View File

@ -438,6 +438,13 @@ def get_witness_version(address):
# Script # Script
def public_key_to_pubkey_script(key, hex=True):
if isinstance(key, str):
key = unhexlify(key)
s = bytes([len(key)]) + key + OP_CHECKSIG
return hexlify(s).decode() if hex else s
def parse_script(script, segwit=True): def parse_script(script, segwit=True):
""" """
Parse script and return script type, script address and required signatures count. Parse script and return script type, script address and required signatures count.
@ -552,9 +559,10 @@ def decode_script(script, asm=False):
Decode script to ASM format or to human readable OPCODES string. Decode script to ASM format or to human readable OPCODES string.
:param script: script in bytes string or HEX encoded string format. :param script: script in bytes string or HEX encoded string format.
:param asm: (optional) If set to True decode to ASM fromat, by default set to False. :param asm: (optional) If set to True decode to ASM format, by default set to False.
:return: script in ASM format string or OPCODES string. :return: script in ASM format string or OPCODES string.
""" """
if isinstance(script, str): if isinstance(script, str):
try: try:
script = unhexlify(script) script = unhexlify(script)
@ -573,12 +581,33 @@ def decode_script(script, asm=False):
result.append('[%s]' % script[s]) result.append('[%s]' % script[s])
s += script[s] + 1 s += script[s] + 1
continue continue
elif script[s] == OPCODE["OP_PUSHDATA1"]:
s += 1 + script[s + 1] if script[s] == OPCODE["OP_PUSHDATA1"]:
ld = script[s + 1]
if asm:
result.append(hexlify(script[s + 1:s + 1 + ld]).decode())
else:
result.append(RAW_OPCODE[script[s]])
result.append('[%s]' % ld)
s += 1 + script[s + 1] + 1
elif script[s] == OPCODE["OP_PUSHDATA2"]: elif script[s] == OPCODE["OP_PUSHDATA2"]:
s += 2 + struct.unpack('<H', script[s: s + 2])
ld = struct.unpack('<H', script[s+1: s + 3])[0]
if asm:
result.append(hexlify(script[s + 1:s + 1 + ld]).decode())
else:
result.append(RAW_OPCODE[script[s]])
result.append('[%s]' % ld)
s += 2 + 1 + ld
elif script[s] == OPCODE["OP_PUSHDATA4"]: elif script[s] == OPCODE["OP_PUSHDATA4"]:
s += 4 + struct.unpack('<L', script[s: s + 4]) ld = struct.unpack('<L', script[s + 1: s + 5])[0]
if asm:
result.append(hexlify(script[s + 1:s + 1 + ld]).decode())
else:
result.append(RAW_OPCODE[script[s]])
result.append('[%s]' % ld)
s += 5 + 1 + ld
else:
result.append(RAW_OPCODE[script[s]]) result.append(RAW_OPCODE[script[s]])
s += 1 s += 1
return ' '.join(result) return ' '.join(result)
@ -673,7 +702,44 @@ def script_to_hash(script, witness=False, hex=True):
return hash160(script, hex) return hash160(script, hex)
# Signatures def op_push_data(data):
if len(data) <= 0x4b:
return b''.join([bytes([len(data)]),data])
elif len(data) <= 0xff:
return b''.join([OP_PUSHDATA1, bytes([len(data)]), data])
elif len(data) <= 0xffff:
return b''.join([OP_PUSHDATA2, int_to_bytes(len(data), byteorder="little"), data])
else:
return b''.join([OP_PUSHDATA4, int_to_bytes(len(data), byteorder="little"), data])
def get_multisig_public_keys(script):
pub_keys = []
s = get_stream(script)
o, d = read_opcode(s)
while o:
o, d = read_opcode(s)
if d:
pub_keys.append(d)
return pub_keys
def read_opcode(stream):
b = stream.read(1)
if not b:
return None, None
if b[0] <= 0x4b:
return b, stream.read(b[0])
elif b[0] == OP_PUSHDATA1:
return b, stream.read(stream.read(1)[0])
elif b[0] == OP_PUSHDATA2:
return b, stream.read(struct.unpack("<H", stream.read(2)[0]))
elif b[0] == OP_PUSHDATA4:
return b, stream.read(struct.unpack("<L", stream.read(4)[0]))
else:
return b, None
def verify_signature(sig, pub_key, msg): def verify_signature(sig, pub_key, msg):
""" """
@ -759,9 +825,51 @@ def sign_message(msg, private_key, hex=True):
if not res: if not res:
raise RuntimeError("secp256k1 error") raise RuntimeError("secp256k1 error")
signature = bytes(ffi.buffer(output, outputlen[0])) signature = bytes(ffi.buffer(output, outputlen[0]))
raw_sig = ffi.new('secp256k1_ecdsa_signature *')
return hexlify(signature).decode() if hex else signature return hexlify(signature).decode() if hex else signature
def public_key_recovery(signature, messsage, rec_id, compressed=True, hex=True):
if isinstance(signature, str):
signature = unhexlify(signature)
if isinstance(messsage, str):
messsage = unhexlify(messsage)
raw_sig = ffi.new('secp256k1_ecdsa_signature *')
r = secp256k1.secp256k1_ecdsa_signature_parse_der(ECDSA_CONTEXT_SIGN,
raw_sig,
signature,
len(signature))
if not r:
raise RuntimeError("secp256k1 error")
compact_sig = ffi.new('unsigned char[%d]' % 64)
r = secp256k1.secp256k1_ecdsa_signature_serialize_compact(ECDSA_CONTEXT_VERIFY,
compact_sig,
raw_sig)
if not r:
raise RuntimeError("secp256k1 error")
recover_sig = ffi.new('secp256k1_ecdsa_recoverable_signature *')
t = secp256k1.secp256k1_ecdsa_recoverable_signature_parse_compact(
ECDSA_CONTEXT_ALL, recover_sig, compact_sig, rec_id)
if not r:
raise RuntimeError("secp256k1 error")
pubkey_ptr = ffi.new('secp256k1_pubkey *')
t = secp256k1.secp256k1_ecdsa_recover(
ECDSA_CONTEXT_ALL, pubkey_ptr, recover_sig, messsage)
len_key = 33 if compressed else 65
pubkey = ffi.new('char [%d]' % len_key)
outlen = ffi.new('size_t *', len_key)
compflag = EC_COMPRESSED if compressed else EC_UNCOMPRESSED
if bytes(ffi.buffer(pubkey_ptr.data, 64)) == b"\x00" * 64:
return None
r = secp256k1.secp256k1_ec_pubkey_serialize(ECDSA_CONTEXT_VERIFY, pubkey, outlen, pubkey_ptr, compflag)
if not r:
raise RuntimeError("secp256k1 error")
pub = bytes(ffi.buffer(pubkey, len_key))
return hexlify(pub).decode() if hex else pub
def is_valid_signature_encoding(sig): def is_valid_signature_encoding(sig):
""" """
Check is valid signature encoded in DER format Check is valid signature encoded in DER format

View File

@ -7,8 +7,23 @@ from binascii import hexlify, unhexlify
class Transaction(dict): class Transaction(dict):
def __init__(self, raw_tx=None, tx_format="decoded", version=1, lockTime=0, testnet=False): """
assert tx_format in ("decoded", "raw") The class for Transaction object
:param raw_tx: (optional) raw transaction in bytes or HEX encoded string, if no raw transaction provided
well be created new empty transaction template.
:param tx_format: "raw" or "decoded" format. Raw format is mean that all transaction represented in bytes
for best performance.
Decoded transaction is represented in human readable format using base68, hex, bech32,
asm and opcodes. By default "decoded" format using.
:param int version: transaction version for new template, by default 1.
:param int lock_time: transaction lock time for new template, by default 0.
:param boolean testnet: address type for "decoded" transaction representation.
"""
def __init__(self, raw_tx=None, tx_format="decoded", version=1, lock_time=0, testnet=False):
if tx_format not in ("decoded", "raw"):
raise TypeError("tx_format error, raw or decoded allowed")
self["format"] = tx_format self["format"] = tx_format
self["testnet"] = testnet self["testnet"] = testnet
self["segwit"] = False self["segwit"] = False
@ -18,7 +33,7 @@ class Transaction(dict):
self["size"] = 0 self["size"] = 0
self["vSize"] = 0 self["vSize"] = 0
self["bSize"] = 0 self["bSize"] = 0
self["lockTime"] = lockTime self["lockTime"] = lock_time
self["vIn"] = dict() self["vIn"] = dict()
self["vOut"] = dict() self["vOut"] = dict()
self["rawTx"] = None self["rawTx"] = None
@ -33,25 +48,31 @@ class Transaction(dict):
self["amount"] = None self["amount"] = None
if raw_tx is None: if raw_tx is None:
return return
self["amount"] = 0 self["amount"] = 0
sw = sw_len = 0
stream = self.get_stream(raw_tx) stream = self.get_stream(raw_tx)
start = stream.tell() start = stream.tell()
(self["version"],) = unpack('<L', stream.read(4))
# start deserialization
self["version"] = unpack('<L', stream.read(4))[0]
n = read_var_int(stream) n = read_var_int(stream)
sw = 0
sw_len = 0
if n == b'\x00': if n == b'\x00':
# segwit format
sw = 1 sw = 1
self["flag"] = stream.read(1) self["flag"] = stream.read(1)
n = read_var_int(stream) n = read_var_int(stream)
# inputs
ic = var_int_to_int(n) ic = var_int_to_int(n)
for k in range(ic): for k in range(ic):
self["vIn"][k] = dict() self["vIn"][k] = dict()
self["vIn"][k]["txId"] = stream.read(32) self["vIn"][k]["txId"] = stream.read(32)
self["vIn"][k]["vOut"] = unpack('<L', stream.read(4))[0] self["vIn"][k]["vOut"] = unpack('<L', stream.read(4))[0]
n = var_int_to_int(read_var_int(stream)) self["vIn"][k]["scriptSig"] = stream.read(var_int_to_int(read_var_int(stream)))
self["vIn"][k]["scriptSig"] = stream.read(n)
(self["vIn"][k]["sequence"],) = unpack('<L', stream.read(4)) (self["vIn"][k]["sequence"],) = unpack('<L', stream.read(4))
# outputs
for k in range(var_int_to_int(read_var_int(stream))): for k in range(var_int_to_int(read_var_int(stream))):
self["vOut"][k] = dict() self["vOut"][k] = dict()
self["vOut"][k]["value"] = unpack('<Q', stream.read(8))[0] self["vOut"][k]["value"] = unpack('<Q', stream.read(8))[0]
@ -66,13 +87,17 @@ class Transaction(dict):
if s["nType"] not in (3, 4, 7): if s["nType"] not in (3, 4, 7):
self["vOut"][k]["addressHash"] = s["addressHash"] self["vOut"][k]["addressHash"] = s["addressHash"]
self["vOut"][k]["reqSigs"] = s["reqSigs"] self["vOut"][k]["reqSigs"] = s["reqSigs"]
# witness
if sw: if sw:
sw = stream.tell() - start sw = stream.tell() - start
for k in range(ic): for k in range(ic):
self["vIn"][k]["txInWitness"] = [stream.read(var_int_to_int(read_var_int(stream))) \ self["vIn"][k]["txInWitness"] = [stream.read(var_int_to_int(read_var_int(stream))) \
for c in range(var_int_to_int(read_var_int(stream)))] for c in range(var_int_to_int(read_var_int(stream)))]
sw_len = stream.tell() - sw + 2 sw_len = stream.tell() - sw + 2
self["lockTime"] = unpack('<L', stream.read(4))[0] self["lockTime"] = unpack('<L', stream.read(4))[0]
end = stream.tell() end = stream.tell()
stream.seek(start) stream.seek(start)
b = stream.read(end - start) b = stream.read(end - start)
@ -95,8 +120,16 @@ class Transaction(dict):
self["segwit"] = False self["segwit"] = False
self["txId"] = double_sha256(b) self["txId"] = double_sha256(b)
self["hash"] = self["txId"] self["hash"] = self["txId"]
if self["format"] == "decoded":
self.decode()
def decode(self, testnet=None): def decode(self, testnet=None):
"""
change Transacion object representation to "decoded" human readable format
:param bool testnet: (optional) address type for "decoded" transaction representation, by default None.
if None used type from transaction property "format".
"""
if self["format"] == "decoded": if self["format"] == "decoded":
self.encode() self.encode()
self["format"] = "decoded" self["format"] = "decoded"
@ -123,10 +156,7 @@ class Transaction(dict):
w = hexlify(w).decode() w = hexlify(w).decode()
t.append(w) t.append(w)
self["vIn"][i]["txInWitness"] = t self["vIn"][i]["txInWitness"] = t
self["vIn"][i]["txInWitnessAsm"] = [decode_script(ws, 1) for ws in
self["vIn"][i]["txInWitness"]]
self["vIn"][i]["txInWitnessOpcodes"] = [decode_script(ws) for ws in
self["vIn"][i]["txInWitness"]]
except: except:
pass pass
try: try:
@ -178,6 +208,11 @@ class Transaction(dict):
return self return self
def encode(self): def encode(self):
"""
change Transaction object representation to "raw" bytes format,
all human readable part will be stripped.
"""
if type(self["txId"]) == str: if type(self["txId"]) == str:
self["txId"] = s2rh(self["txId"]) self["txId"] = s2rh(self["txId"])
if "flag" in self: if "flag" in self:
@ -200,10 +235,6 @@ class Transaction(dict):
w = unhexlify(w) w = unhexlify(w)
t.append(w) t.append(w)
self["vIn"][i]["txInWitness"] = t self["vIn"][i]["txInWitness"] = t
if "txInWitnessAsm" in self["vIn"][i]:
del self["vIn"][i]["txInWitnessAsm"]
if "txInWitnessOpcodes" in self["vIn"][i]:
del self["vIn"][i]["txInWitnessOpcodes"]
except: except:
pass pass
try: try:
@ -217,6 +248,18 @@ class Transaction(dict):
del self["vIn"][i]["scriptSigAsm"] del self["vIn"][i]["scriptSigAsm"]
if "scriptSigOpcodes" in self["vIn"][i]: if "scriptSigOpcodes" in self["vIn"][i]:
del self["vIn"][i]["scriptSigOpcodes"] del self["vIn"][i]["scriptSigOpcodes"]
if "scriptPubKeyOpcodes" in self["vIn"][i]:
del self["vIn"][i]["scriptPubKeyOpcodes"]
if "scriptPubKeyAsm" in self["vIn"][i]:
del self["vIn"][i]["scriptPubKeyAsm"]
if "scriptPubKey" in self["vIn"][i]:
self["vIn"][i]["scriptPubKey"] = unhexlify(self["vIn"][i]["scriptPubKey"])
if "redeemScriptOpcodes" in self["vIn"][i]:
del self["vIn"][i]["redeemScriptOpcodes"]
if "redeemScriptAsm" in self["vIn"][i]:
del self["vIn"][i]["redeemScriptAsm"]
if "redeemScript" in self["vIn"][i]:
del self["vIn"][i]["redeemScript"]
for i in self["vOut"]: for i in self["vOut"]:
if type(self["vOut"][i]["scriptPubKey"]) == str: if type(self["vOut"][i]["scriptPubKey"]) == str:
@ -250,18 +293,26 @@ class Transaction(dict):
return stream return stream
def serialize(self, segwit=True, hex=True): def serialize(self, segwit=True, hex=True):
"""
Get serialized transaction
:param bool segwit: (optional) flag for segwit representation of serialized transaction, by
default True.
:param bool hex: (optional) if set to True return HEX encoded string, by default True.
:return str,bytes: serialized transaction in HEX or bytes.
"""
chunks = [] chunks = []
chunks.append(struct.pack('<L', self["version"])) chunks.append(struct.pack('<L', self["version"]))
if segwit and self["segwit"]: if segwit and self["segwit"]:
chunks.append(b"\x00\x01") chunks.append(b"\x00\x01")
chunks.append(int_to_var_int(len(self["vIn"]))) chunks.append(int_to_var_int(len(self["vIn"])))
for i in self["vIn"]: for i in self["vIn"]:
if type(self["vIn"][i]['txId']) == bytes: if isinstance(self["vIn"][i]['txId'], bytes):
chunks.append(self["vIn"][i]['txId']) chunks.append(self["vIn"][i]['txId'])
else: else:
chunks.append(s2rh(self["vIn"][i]['txId'])) chunks.append(s2rh(self["vIn"][i]['txId']))
chunks.append(struct.pack('<L', self["vIn"][i]['vOut'])) chunks.append(struct.pack('<L', self["vIn"][i]['vOut']))
if type(self["vIn"][i]['scriptSig']) == bytes: if isinstance(self["vIn"][i]['scriptSig'], bytes):
chunks.append(int_to_var_int(len(self["vIn"][i]['scriptSig']))) chunks.append(int_to_var_int(len(self["vIn"][i]['scriptSig'])))
chunks.append(self["vIn"][i]['scriptSig']) chunks.append(self["vIn"][i]['scriptSig'])
else: else:
@ -271,7 +322,7 @@ class Transaction(dict):
chunks.append(int_to_var_int(len(self["vOut"]))) chunks.append(int_to_var_int(len(self["vOut"])))
for i in self["vOut"]: for i in self["vOut"]:
chunks.append(struct.pack('<Q', self["vOut"][i]['value'])) chunks.append(struct.pack('<Q', self["vOut"][i]['value']))
if type(self["vOut"][i]['scriptPubKey']) == bytes: if isinstance(self["vOut"][i]['scriptPubKey'], bytes):
chunks.append(int_to_var_int(len(self["vOut"][i]['scriptPubKey']))) chunks.append(int_to_var_int(len(self["vOut"][i]['scriptPubKey'])))
chunks.append(self["vOut"][i]['scriptPubKey']) chunks.append(self["vOut"][i]['scriptPubKey'])
else: else:
@ -281,7 +332,7 @@ class Transaction(dict):
for i in self["vIn"]: for i in self["vIn"]:
chunks.append(int_to_var_int(len(self["vIn"][i]['txInWitness']))) chunks.append(int_to_var_int(len(self["vIn"][i]['txInWitness'])))
for w in self["vIn"][i]['txInWitness']: for w in self["vIn"][i]['txInWitness']:
if type(w) == bytes: if isinstance(w, bytes):
chunks.append(int_to_var_int(len(w))) chunks.append(int_to_var_int(len(w)))
chunks.append(w) chunks.append(w)
else: else:
@ -292,6 +343,10 @@ class Transaction(dict):
return tx if not hex else hexlify(tx).decode() return tx if not hex else hexlify(tx).decode()
def json(self): def json(self):
"""
Get json transaction representation
"""
try: try:
return json.dumps(self) return json.dumps(self)
except: except:
@ -300,36 +355,42 @@ class Transaction(dict):
def add_input(self, tx_id=None, v_out=0, sequence=0xffffffff, def add_input(self, tx_id=None, v_out=0, sequence=0xffffffff,
script_sig=b"", tx_in_witness=None, amount=None, script_sig=b"", tx_in_witness=None, amount=None,
script_pub_key=None, address=None, private_key=None): script_pub_key=None, address=None, private_key=None, redeem_script=None):
if tx_id is None: if tx_id is None:
tx_id = b"\x00" * 32 tx_id = b"\x00" * 32
v_out = 0xffffffff v_out = 0xffffffff
assert v_out == 0xffffffff and sequence == 0xffffffff if sequence != 0xffffffff or self["vIn"]:
assert not self["vIn"] raise RuntimeError("invalid coinbase transaction")
if type(tx_id) == str:
if isinstance(tx_id, str):
tx_id = s2rh(tx_id) tx_id = s2rh(tx_id)
if type(script_sig) == str: if not isinstance(tx_id, bytes) or len(tx_id) != 32:
raise TypeError("tx_id invalid")
if isinstance(script_sig, str):
script_sig = unhexlify(script_sig) script_sig = unhexlify(script_sig)
assert type(tx_id) == bytes if not isinstance(script_sig, bytes) or not len(script_sig) <= 520:
assert len(tx_id) == 32 raise TypeError("script_sig invalid")
assert type(v_out) == int
assert v_out <= 0xffffffff and v_out >= 0 if not isinstance(v_out, int) or not (v_out <= 0xffffffff and v_out >= 0):
assert type(sequence) == int raise TypeError("v_out invalid")
assert sequence <= 0xffffffff and sequence >= 0 if not isinstance(sequence, int) or not (sequence <= 0xffffffff and sequence >= 0):
assert type(script_sig) == bytes raise TypeError("sequence invalid")
assert len(script_sig) <= 520
if private_key: if private_key:
if type(private_key) != PrivateKey: if not isinstance(private_key, PrivateKey):
private_key = PrivateKey(private_key) private_key = PrivateKey(private_key)
if amount: if amount:
assert type(amount) == int if not isinstance(amount, int) or not amount >= 0 and amount <= MAX_AMOUNT:
assert amount >= 0 and amount <= MAX_AMOUNT raise TypeError("amount invalid")
if tx_in_witness: if tx_in_witness:
assert type(tx_in_witness) == list if not isinstance(tx_in_witness, list):
raise TypeError("tx_in_witness invalid")
l = 0 l = 0
witness = [] witness = []
for w in tx_in_witness: for w in tx_in_witness:
if type(w) == str: if isinstance(w, str):
witness.append(unhexlify(w) if self["format"] == "raw" else w) witness.append(unhexlify(w) if self["format"] == "raw" else w)
else: else:
witness.append(w if self["format"] == "raw" else unhexlify(w)) witness.append(w if self["format"] == "raw" else unhexlify(w))
@ -339,23 +400,34 @@ class Transaction(dict):
if len(w) > 0xff: if len(w) > 0xff:
l += 1 l += 1
# witness script limit # witness script limit
assert l <= 10000 if not l <= 10000:
raise TypeError("tx_in_witness invalid")
if tx_id == b"\x00" * 32: if tx_id == b"\x00" * 32:
assert v_out == 0xffffffff and sequence == 0xffffffff and len(script_sig) <= 100 if not (v_out == 0xffffffff and sequence == 0xffffffff and len(script_sig) <= 100):
raise TypeError("coinbase tx invalid")
self["coinbase"] = True self["coinbase"] = True
# script_pub_key # script_pub_key
if script_pub_key: if script_pub_key:
if type(script_pub_key) == str: if isinstance(script_pub_key, str):
script_pub_key = unhexlify(script_pub_key) script_pub_key = unhexlify(script_pub_key)
type(script_pub_key) == bytes if not isinstance(script_pub_key, bytes):
raise TypeError("script_pub_key tx invalid")
if redeem_script:
if isinstance(redeem_script, str):
redeem_script = unhexlify(redeem_script)
if not isinstance(redeem_script, bytes):
raise TypeError("redeem_script tx invalid")
if address is not None: if address is not None:
if type(address) == str: if isinstance(address, str):
net = True if address_net_type(address) == 'mainnet' else False net = True if address_net_type(address) == 'mainnet' else False
assert not net == self["testnet"] if not net != self["testnet"]:
raise TypeError("address invalid")
script = address_to_script(address) script = address_to_script(address)
elif type(address) in (Address, ScriptAddress): elif type(address) in (Address, ScriptAddress):
assert type(address) == Address
script = address_to_script(address.address) script = address_to_script(address.address)
if script_pub_key: if script_pub_key:
assert script_pub_key == script assert script_pub_key == script
@ -371,6 +443,8 @@ class Transaction(dict):
self["vIn"][k]["scriptSig"] = script_sig self["vIn"][k]["scriptSig"] = script_sig
if script_pub_key: if script_pub_key:
self["vIn"][k]["scriptPubKey"] = script_pub_key self["vIn"][k]["scriptPubKey"] = script_pub_key
if redeem_script:
self["vIn"][k]["redeemScript"] = redeem_script
else: else:
self["vIn"][k]["txId"] = rh2s(tx_id) self["vIn"][k]["txId"] = rh2s(tx_id)
self["vIn"][k]["scriptSig"] = hexlify(script_sig).decode() self["vIn"][k]["scriptSig"] = hexlify(script_sig).decode()
@ -378,6 +452,12 @@ class Transaction(dict):
self["vIn"][k]["scriptSigAsm"] = decode_script(script_sig, 1) self["vIn"][k]["scriptSigAsm"] = decode_script(script_sig, 1)
if script_pub_key: if script_pub_key:
self["vIn"][k]["scriptPubKey"] = hexlify(script_pub_key).decode() self["vIn"][k]["scriptPubKey"] = hexlify(script_pub_key).decode()
self["vIn"][k]["scriptPubKeyOpcodes"] = decode_script(script_pub_key)
self["vIn"][k]["scriptPubKeyAsm"] = decode_script(script_pub_key, 1)
if redeem_script:
self["vIn"][k]["redeemScript"] = hexlify(redeem_script).decode()
self["vIn"][k]["redeemScriptOpcodes"] = decode_script(redeem_script)
self["vIn"][k]["redeemScriptAsm"] = decode_script(script_pub_key, 1)
if tx_in_witness: if tx_in_witness:
self["segwit"] = True self["segwit"] = True
self["vIn"][k]["txInWitness"] = witness self["vIn"][k]["txInWitness"] = witness
@ -468,62 +548,294 @@ class Transaction(dict):
self.__refresh__() self.__refresh__()
return self return self
def sign_input(self, n, private_key=None, script_pub_key=None, redeem_script=None, sighash_type=SIGHASH_ALL): def sign_input(self, n, private_key=None, script_pub_key=None,
if private_key is not None: redeem_script=None,
if private_key: sighash_type=SIGHASH_ALL,
if type(private_key) != PrivateKey: address=None, amount=None, witness_version=0,
private_key_obj = PrivateKey(private_key) p2sh_p2wsh=False):
public_key = PublicKey(private_key_obj).key # private key
private_key = private_key_obj.key if not private_key:
else: try:
if "privateKey" not in self["vIn"][n]:
return self
private_key = self["vIn"][n].private_key.key private_key = self["vIn"][n].private_key.key
public_key = PublicKey(self["vIn"][n].private_key).key except:
raise RuntimeError("no private key")
if isinstance(private_key, list):
public_key = [PublicKey(p).key for p in private_key]
private_key = [p.key if isinstance(p, PrivateKey) else PrivateKey(p).key for p in private_key]
else:
if not isinstance(private_key, PrivateKey):
private_key = PrivateKey(private_key)
public_key = [PublicKey(private_key).key]
private_key = [private_key.key]
if redeem_script: if address is not None:
if type(redeem_script) == str: if isinstance(address, str):
redeem_script = unhexlify(redeem_script).decode() net = True if address_net_type(address) == 'mainnet' else False
assert type(redeem_script) == bytes if not net != self["testnet"]:
script = redeem_script raise TypeError("address invalid")
else: script_pub_key = address_to_script(address)
script = script_pub_key elif type(address) in (Address, ScriptAddress):
script_pub_key = address_to_script(address.address)
# script pub key
if script_pub_key is None:
sighash = self.sig_hash_input(n, script_pub_key=script, sighash_type=sighash_type) if "scriptPubKey" in self["vIn"][n]:
if type(sighash) == str: script_pub_key = self["vIn"][n]["scriptPubKey"]
sighash = s2rh(sighash) st = parse_script(script_pub_key)
signature = sign_message(sighash, private_key, 0) + bytes([sighash_type]) elif redeem_script or "redeemScript" in self["vIn"][n]:
if redeem_script: if witness_version is None or p2sh_p2wsh:
if self["vIn"][n]["scriptSig"]: st = {"type": "P2SH"}
sig_script = self["vIn"][n]["scriptSig"] elif witness_version == 0:
if type(sig_script) == str: st = {"type": "P2WSH"}
sig_script = unhexlify(sig_script).decode()
sig_script = bytes([len(public_key)]) + public_key + sig_script
sig_script = bytes([len(signature)]) + signature + sig_script
else: else:
sig_script = bytes([len(signature)]) + signature raise RuntimeError("not implemented")
sig_script += bytes([len(public_key)]) + public_key
if len(redeem_script) <= 0x4b:
sig_script += bytes([len(redeem_script)]) + redeem_script
elif len(redeem_script) <= 0xff:
sig_script = BYTE_OPCODE["OP_PUSHDATA1"] + bytes([len(redeem_script)]) + redeem_script
elif len(redeem_script) <= 0xffff:
sig_script = BYTE_OPCODE["OP_PUSHDATA2"] + bytes([len(redeem_script)]) + redeem_script
else: else:
sig_script = BYTE_OPCODE["OP_PUSHDATA4"] + bytes([len(redeem_script)]) + redeem_script raise RuntimeError("no scriptPubKey key")
else: else:
sig_script = bytes([len(signature)]) + signature st = parse_script(script_pub_key)
sig_script += bytes([len(public_key)]) + public_key if isinstance(script_pub_key, str):
script_pub_key = unhexlify(script_pub_key)
# sign input
if st["type"] == "PUBKEY":
script_sig = self.__sign_pubkey__(n, private_key, script_pub_key, sighash_type)
elif st["type"] == "P2PKH":
script_sig = self.__sign_p2pkh__(n, private_key, public_key, script_pub_key, sighash_type)
elif st["type"] == "P2SH":
script_sig = self.__sign_p2sh(n, private_key, public_key, redeem_script, sighash_type, amount, p2sh_p2wsh)
elif st["type"] == "P2WPKH":
script_sig = self.__sign_p2wpkh(n, private_key, public_key, script_pub_key, sighash_type, amount)
elif st["type"] == "P2WSH":
script_sig = self.__sign_p2wsh(n, private_key, public_key, script_pub_key,
redeem_script, sighash_type, amount)
else:
raise RuntimeError("not implemented")
if self["format"] == "raw": if self["format"] == "raw":
self["vIn"][n]["scriptSig"] = sig_script self["vIn"][n]["scriptSig"] = script_sig
else: else:
self["vIn"][n]["scriptSig"] = hexlify(sig_script).decode() self["vIn"][n]["scriptSig"] = hexlify(script_sig).decode()
self["vIn"][n]["scriptSigOpcodes"] = decode_script(sig_script) self["vIn"][n]["scriptSigOpcodes"] = decode_script(script_sig)
self["vIn"][n]["scriptSigAsm"] = decode_script(sig_script, 1) self["vIn"][n]["scriptSigAsm"] = decode_script(script_sig, 1)
self.__refresh__() self.__refresh__()
return self return self
def sig_hash_input(self, n, script_pub_key=None, sighash_type=SIGHASH_ALL): def __sign_pubkey__(self, n, private_key, script_pub_key, sighash_type):
sighash = self.sig_hash(n, script_pub_key=script_pub_key, sighash_type=sighash_type)
sighash = s2rh(sighash) if isinstance(sighash, str) else sighash
signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type])
return b''.join([bytes([len(signature)]), signature])
def __sign_p2pkh__(self, n, private_key, public_key, script_pub_key, sighash_type):
sighash = self.sig_hash(n, script_pub_key=script_pub_key, sighash_type=sighash_type)
sighash = s2rh(sighash) if isinstance(sighash, str) else sighash
signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type])
script_sig = b''.join([bytes([len(signature)]),
signature,
bytes([len(public_key[0])]),
public_key[0]])
return script_sig
def __sign_p2sh(self, n, private_key, public_key, redeem_script, sighash_type, amount, p2sh_p2wsh):
if not redeem_script:
if "redeemScript" in self["vIn"][n]:
redeem_script = self["vIn"][n]["redeemScript"]
else:
raise RuntimeError("no redeem script")
if isinstance(redeem_script, str):
redeem_script = unhexlify(redeem_script)
rst = parse_script(redeem_script)
if p2sh_p2wsh:
return self.__sign_p2sh_p2wsh(n, private_key,
public_key, redeem_script, sighash_type, amount)
if rst["type"] == "MULTISIG":
return self.__sign_p2sh_multisig(n, private_key, public_key, redeem_script, sighash_type)
elif rst["type"] == "P2WPKH":
return self.__sign_p2sh_p2wpkh(n, private_key, public_key, redeem_script, sighash_type, amount)
else:
return self.__sign_p2sh_custom(n, private_key, public_key, redeem_script, sighash_type, amount)
def __sign_p2sh_multisig(self, n, private_key, public_key, redeem_script, sighash_type):
sighash = self.sig_hash(n, script_pub_key=redeem_script, sighash_type=sighash_type)
sighash = s2rh(sighash) if isinstance(sighash, str) else sighash
sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key]
return b''.join(self.__get_multisig_script_sig__(self["vIn"][n]["scriptSig"],
public_key, sig,
redeem_script,
redeem_script,
n))
def __sign_p2sh_p2wpkh(self, n, private_key, public_key, redeem_script, sighash_type, amount):
s = [b'\x19', OP_DUP, OP_HASH160,
op_push_data(hash160(public_key[0], 0)),
OP_EQUALVERIFY, OP_CHECKSIG]
if amount is None:
try:
amount = self["vIn"][n]["value"]
except:
raise RuntimeError("no input amount")
sighash = self.sig_hash_segwit(n, amount, script_pub_key=b"".join(s), sighash_type=sighash_type)
sighash = unhexlify(sighash) if isinstance(sighash, str) else sighash
signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type])
self["segwit"] = True
if self["format"] == "raw":
self["vIn"][n]['txInWitness'] = [signature, public_key[0]]
else:
self["vIn"][n]['txInWitness'] = [hexlify(signature).decode(), hexlify(public_key[0]).decode()]
return op_push_data(redeem_script)
def __sign_p2sh_p2wsh(self, n, private_key, public_key,
redeem_script, sighash_type, amount):
rst = parse_script(redeem_script)
if rst["type"] == "MULTISIG":
return self.__sign_p2sh_p2wsh_multisig(n, private_key, public_key,
redeem_script, sighash_type, amount)
else:
raise RuntimeError("not implemented")
def __sign_p2sh_custom(self, n, private_key, public_key, redeem_script, sighash_type, amount):
raise RuntimeError("not implemented")
return b""
def __sign_p2wpkh(self, n, private_key, public_key, script_pub_key, sighash_type, amount):
s = [b'\x19', OP_DUP, OP_HASH160, script_pub_key[1:], OP_EQUALVERIFY, OP_CHECKSIG]
if amount is None:
try:
amount = self["vIn"][n]["value"]
except:
raise RuntimeError("no input amount")
sighash = self.sig_hash_segwit(n, amount, script_pub_key=b"".join(s), sighash_type=sighash_type)
sighash = unhexlify(sighash) if isinstance(sighash, str) else sighash
signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type])
self["segwit"] = True
if self["format"] == "raw":
self["vIn"][n]['txInWitness'] = [signature,
public_key[0]]
else:
self["vIn"][n]['txInWitness'] = [hexlify(signature).decode(),
hexlify(public_key[0]).decode()]
return b""
def __sign_p2wsh(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
self["segwit"] = True
if not redeem_script:
if "redeemScript" in self["vIn"][n]:
redeem_script = self["vIn"][n]["redeemScript"]
else:
raise RuntimeError("no redeem script")
if isinstance(redeem_script, str):
redeem_script = unhexlify(redeem_script)
rst = parse_script(redeem_script)
if amount is None:
try:
amount = self["vIn"][n]["value"]
except:
raise RuntimeError("no input amount")
if rst["type"] == "MULTISIG":
return self.__sign_p2wsh_multisig(n, private_key, public_key,
script_pub_key, redeem_script, sighash_type, amount)
else:
return self.__sign_p2wsh_custom(n, private_key, public_key,
script_pub_key, redeem_script, sighash_type, amount)
def __sign_p2wsh_multisig(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
script_code = int_to_var_int(len(redeem_script)) + redeem_script
sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=sighash_type)
sighash = unhexlify(sighash) if isinstance(sighash, str) else sighash
sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key]
if "txInWitness" not in self["vIn"][n]:
self["vIn"][n]["txInWitness"] = []
witness = self.__get_multisig_script_sig__(self["vIn"][n]["txInWitness"],
public_key, sig, script_code, redeem_script, n, amount)
if self["format"] == "raw":
self["vIn"][n]['txInWitness'] = list(witness)
else:
self["vIn"][n]["txInWitness"] = list([hexlify(w).decode() for w in witness])
return b""
def __sign_p2wsh_custom(self, n, private_key, public_key, script_pub_key, redeem_script, sighash_type, amount):
raise RuntimeError("not implemented __sign_p2wsh_custom")
def __sign_p2sh_p2wsh_multisig(self, n, private_key, public_key,
redeem_script, sighash_type, amount):
self["segwit"] = True
script_code = int_to_var_int(len(redeem_script)) + redeem_script
sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=sighash_type)
sighash = unhexlify(sighash) if isinstance(sighash, str) else sighash
sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key]
if "txInWitness" not in self["vIn"][n]:
self["vIn"][n]["txInWitness"] = []
witness = self.__get_multisig_script_sig__(self["vIn"][n]["txInWitness"],
public_key,
sig,
script_code,
redeem_script,
n,
amount)
if self["format"] == "raw":
self["vIn"][n]['txInWitness'] = list(witness)
else:
self["vIn"][n]["txInWitness"] = list([hexlify(w).decode() for w in witness])
# calculate P2SH redeem script from P2WSH redeem script
return op_push_data(b"\x00" + op_push_data(sha256(redeem_script)))
def __get_multisig_script_sig__(self, script_sig,
keys, signatures,
script_code,
redeem_script,
n, amount=None):
sig_map = {keys[i]:signatures[i] for i in range(len(keys))}
pub_keys = get_multisig_public_keys(redeem_script)
p2wsh = True if isinstance(script_sig, list) else False
if not p2wsh:
s = get_stream(script_sig)
o, d = read_opcode(s)
while o:
o, d = read_opcode(s)
if d and is_valid_signature_encoding(d):
for i in range(4):
sighash = self.sig_hash(n, script_pub_key=script_code, sighash_type=d[-1])
sighash = s2rh(sighash) if isinstance(sighash, str) else sighash
pk = public_key_recovery(d[:-1], sighash, i, hex=0)
if pk in pub_keys:
sig_map[pk] = d
break
# recreate script sig
r = [OP_0]
for k in pub_keys:
try:
r.append(op_push_data(sig_map[k]))
except:
pass
r += [op_push_data(redeem_script)]
else:
for w in script_sig:
if isinstance(w, str):
w = unhexlify(w)
if w and is_valid_signature_encoding(w):
d = w[:-1]
for i in range(4):
sighash = self.sig_hash_segwit(n, amount,
script_pub_key=script_code,
sighash_type=w[-1])
pk = public_key_recovery(d, sighash, i, hex=0)
if pk is not None:
l = hexlify(pk)
if pk in pub_keys:
sig_map[pk] = w
break
r = [b""]
for k in pub_keys:
try:
r.append(sig_map[k])
except:
pass
r += [redeem_script]
return r
def sig_hash(self, n, script_pub_key=None, sighash_type=SIGHASH_ALL):
# check n # check n
assert n >= 0 assert n >= 0
tx_in_count = len(self["vIn"]) tx_in_count = len(self["vIn"])
@ -602,9 +914,84 @@ class Transaction(dict):
preimage += struct.pack(b"<i", sighash_type) preimage += struct.pack(b"<i", sighash_type)
return double_sha256(preimage) if self["format"] == "raw" else rh2s(double_sha256(preimage)) return double_sha256(preimage) if self["format"] == "raw" else rh2s(double_sha256(preimage))
def sig_hash_segwit(self, n, amount, script_pub_key=None, sighash_type=SIGHASH_ALL):
# check n
assert n >= 0
tx_in_count = len(self["vIn"])
if n >= tx_in_count:
if self["format"] == "raw":
return b'\x01' + b'\x00' * 31
else:
return rh2s(b'\x01' + b'\x00' * 31)
# check script_pub_key for input
if script_pub_key is not None:
script_code = script_pub_key
else:
assert "scriptPubKey" in self["vIn"][n]
script_code = self["vIn"][n]["scriptPubKey"]
if type(script_code) == str:
script_code = unhexlify(script_code)
assert type(script_code) == bytes
# remove opcode separators
preimage = bytearray()
# 1. nVersion of the transaction (4-byte little endian)
preimage += struct.pack('<L', self["version"])
# 2. hashPrevouts (32-byte hash)
# 3. hashSequence (32-byte hash)
# 4. outpoint (32-byte hash + 4-byte little endian)
# 5. scriptCode of the input (serialized as scripts inside CTxOuts)
# 6. value of the output spent by this input (8-byte little endian)
# 7. nSequence of the input (4-byte little endian)
hp = bytearray() # hash of out points
hs = bytearray() # hash of sequences
for i in self["vIn"]:
tx_id = self["vIn"][i]["txId"]
if type(tx_id) == str:
tx_id = s2rh(tx_id)
if not (sighash_type & SIGHASH_ANYONECANPAY):
hp += tx_id + struct.pack('<L', self["vIn"][i]["vOut"])
if (sighash_type & 31) != SIGHASH_SINGLE and (sighash_type & 31) != SIGHASH_NONE:
hs += struct.pack('<L', self["vIn"][i]["sequence"])
if i == n:
outpoint = tx_id + struct.pack('<L', self["vIn"][i]["vOut"])
n_sequence = struct.pack('<L', self["vIn"][i]["sequence"])
hash_prevouts = double_sha256(hp) if hp else b'\x00' * 32
hash_sequence = double_sha256(hs) if hs else b'\x00' * 32
value = amount.to_bytes(8, 'little')
# 8. hashOutputs (32-byte hash)
ho = bytearray()
for o in self["vOut"]:
script_pub_key = self["vOut"][o]["scriptPubKey"]
if type(self["vOut"][o]["scriptPubKey"]) == str:
script_pub_key = unhexlify(script_pub_key)
if (sighash_type & 31) != SIGHASH_SINGLE and (sighash_type & 31) != SIGHASH_NONE:
ho += self["vOut"][o]["value"].to_bytes(8, 'little')
ho += int_to_var_int(len(script_pub_key)) + script_pub_key
elif (sighash_type & 31) == SIGHASH_SINGLE and n < len(self["vOut"]):
if o == n:
ho += self["vOut"][o]["value"].to_bytes(8, 'little')
ho += int_to_var_int(len(script_pub_key)) + script_pub_key
hash_outputs = double_sha256(ho) if ho else b'\x00' * 32
preimage += hash_prevouts + hash_sequence + outpoint
preimage += script_code + value + n_sequence + hash_outputs
preimage += struct.pack('<L', self["lockTime"])
preimage += struct.pack('<L', sighash_type)
sig_hash = double_sha256(preimage)
return sig_hash if self["format"] == "raw" else hexlify(sig_hash).decode()
def __refresh__(self): def __refresh__(self):
if not self["vOut"] or not self["vIn"]: if not self["vOut"] or not self["vIn"]:
return return
if self["segwit"]:
for i in self["vIn"]:
if "txInWitness" not in self["vIn"][i]:
if self["format"] == "raw":
self["vIn"][i]["txInWitness"] = []
else:
self["vIn"][i]["txInWitness"] = []
no_segwit_view = self.serialize(segwit=False, hex=False) no_segwit_view = self.serialize(segwit=False, hex=False)
self["txId"] = double_sha256(no_segwit_view) self["txId"] = double_sha256(no_segwit_view)
self["rawTx"] = self.serialize(segwit=True, hex=False) self["rawTx"] = self.serialize(segwit=True, hex=False)

View File

@ -1,9 +1,9 @@
from .hash_functions import * # from .hash_functions import *
from .integer import * # from .integer import *
from .address_functions import * # from .address_functions import *
from .address_class import * # from .address_class import *
from .ecdsa import * # from .ecdsa import *
from .transaction_deserialize import * # from .transaction_deserialize import *
from .transaction_constructor import * from .transaction_constructor import *

View File

@ -6,6 +6,7 @@ if parentPath not in sys.path:
from pybtc import address from pybtc import address
from pybtc.transaction import *
from pybtc import OPCODE from pybtc import OPCODE
from binascii import unhexlify from binascii import unhexlify
@ -16,6 +17,25 @@ class AddressClassTests(unittest.TestCase):
print("\nTesting address class:\n") print("\nTesting address class:\n")
def test_is_WIF_valid(self): def test_is_WIF_valid(self):
# mainnet
self.assertEqual(address.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
compressed=True, testnet=False).wif,
'L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4')
self.assertEqual(address.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
compressed=False, testnet=False).wif,
'5Jkc7xqsrqA5pGQdwDHSQXRV3pUBLTXVjBjqJUSVz3pUmyuAFwP')
# testnet
self.assertEqual(address.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
compressed=True, testnet=True).wif,
'cRiTUeUav1FMR4UbQh2gW9n8RfpNHLBHsEYXJYa4Rv6ZrCdTPGqv')
self.assertEqual(address.PrivateKey("7B56E2B7BD189F4491D43A1D209E6268046DF1741F61B6397349D7AA54978E76",
compressed=False, testnet=True).wif,
'92XEhhfRT4EDnKuvZZBMH7yShUptVd4h58bnP6o1KnZXYzkVa55')
self.assertEqual(address.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4",
compressed=False, testnet=True).wif,
'L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4')
p = address.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4") p = address.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4")
pub = address.PublicKey(p) pub = address.PublicKey(p)
a = address.Address(p) a = address.Address(p)
@ -29,7 +49,30 @@ class AddressClassTests(unittest.TestCase):
self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236') self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236')
self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4') self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
cpk = "02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4"
ucpk = "04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb" \
"43bbd96a641808e5f34eb568e804fe679de82de419e2512736ea09013a82324a6"
# public key uncompressed from HEX private
self.assertEqual(address.PublicKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76",
compressed=False).hex, ucpk)
# public key compressed from HEX private
self.assertEqual(address.PublicKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76",
compressed=True).hex, cpk)
# public key compressed from WIF private
self.assertEqual(address.PublicKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4",
compressed=False).hex, cpk)
# public key compressed from PrivateKey instance (flags have no effect)
p = address.PrivateKey("L1MU1jUjUwZ6Fd1L2HDZ8qH4oSWxct5boCQ4C87YvoSZbTW41hg4")
self.assertEqual(address.PublicKey(p, compressed=False).hex, cpk)
# public key compressed from public
self.assertEqual(address.PublicKey(cpk, compressed=False).hex, cpk)
# public key compressed from public
self.assertEqual(address.PublicKey(unhexlify(cpk), compressed=False).hex, cpk)
# compressed public key # compressed public key
# private key hex string to compressed pub key
p = address.PrivateKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76", compressed=False) p = address.PrivateKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76", compressed=False)
pub = address.PublicKey(p) pub = address.PublicKey(p)
a = address.Address(p, address_type="P2PKH") a = address.Address(p, address_type="P2PKH")
@ -51,13 +94,18 @@ class AddressClassTests(unittest.TestCase):
self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4') self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
# from uncompressed pubkey # from uncompressed pubkey
p = address.PublicKey('04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb43bbd96a641808e5f34eb568e804fe679de82de419e2512736ea09013a82324a6') p = address.PublicKey('04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb43bbd96a641808'
'e5f34eb568e804fe679de82de419e2512736ea09013a82324a6')
a = address.Address(p, address_type="P2PKH") a = address.Address(p, address_type="P2PKH")
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1') self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
a = address.Address(p, address_type="PUBKEY") a = address.Address(p, address_type="PUBKEY")
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1') self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
redeem = "5221032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6953ae" redeem = "5221032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b2" \
"6473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b8" \
"36e71abdfebb08d8c96d6953ae"
a = address.ScriptAddress(redeem) a = address.ScriptAddress(redeem)
print(a.script_opcodes_asm)
self.assertEqual(a.address, '3KCqqS6eznp3ucVPxtNkiYcVg6kQKNX9sg') self.assertEqual(a.address, '3KCqqS6eznp3ucVPxtNkiYcVg6kQKNX9sg')

View File

@ -4,8 +4,7 @@ parentPath = os.path.abspath("..")
if parentPath not in sys.path: if parentPath not in sys.path:
sys.path.insert(0, parentPath) sys.path.insert(0, parentPath)
from pybtc import * from pybtc import *
from binascii import unhexlify
from pybtc import address_to_hash as address2hash160
class SighashTests(unittest.TestCase): class SighashTests(unittest.TestCase):
@classmethod @classmethod
@ -517,86 +516,70 @@ class SighashTests(unittest.TestCase):
] ]
for k in t: for k in t:
tx = Transaction(k[0]) tx = Transaction(k[0])
self.assertEqual(tx.sig_hash_input(k[2], k[1], k[3]), k[4]) self.assertEqual(tx.sig_hash(k[2], k[1], k[3]), k[4])
def test_sighash_segwit(self):
"""
["raw_transaction, script, input_index, hashType, signature_hash (result)"],
:return:
"""
print("\nNative P2WPKH")
raw_tx = "0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000"
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(1, 600000000, "1976a9141d0f172a0ecb48aee1be1f2687"
"d2963ae33f71a188ac",
SIGHASH_ALL),
"c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670")
print("P2SH-P2WPKH")
raw_tx = "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000"
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 1000000000,
"1976a91479091972186c449eb1ded22b78e40d009bdf008988ac",
SIGHASH_ALL),
"64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6")
print("Native P2WSH")
raw_tx = "0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000"
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(1, 4900000000,
"23210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac",
SIGHASH_SINGLE),
"fef7bd749cce710c5c052bd796df1af0d935e59cea63736268bcbe2d2134fc47")
# def test_sighash_segwit(self): print("P2SH-P2WSH SIGHASH_ALL")
# """ raw_tx = "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000"
# ["raw_transaction, script, input_index, hashType, signature_hash (result)"], self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
# :return: "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# """ SIGHASH_ALL),
# print("\nNative P2WPKH") "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
# raw_tx = "0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000"
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_ALL, print("P2SH-P2WSH SIGHASH_NONE")
# 1, self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
# "1976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac", "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# 600000000, SIGHASH_NONE),
# True)), "e9733bc60ea13c95c6527066bb975a2ff29a925e80aa14c213f686cbae5d2f36")
# "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670")
# print(Script("c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670").type) print("P2SH-P2WSH SIGHASH_SINGLE")
# print("P2SH-P2WPKH") self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
# raw_tx = "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000" "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_ALL, SIGHASH_SINGLE),
# 0, "1e1f1c303dc025bd664acb72e583e933fae4cff9148bf78c157d1e8f78530aea")
# "1976a91479091972186c449eb1ded22b78e40d009bdf008988ac",
# 1000000000, print("P2SH-P2WSH SIGHASH_ALL + SIGHASH_ANYONECANPAY")
# True)), self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
# "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6") "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# print("Native P2WSH") SIGHASH_ALL + SIGHASH_ANYONECANPAY),
# raw_tx = "0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000" "2a67f03e63a6a422125878b40b82da593be8d4efaafe88ee528af6e5a9955c6e")
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_SINGLE,
# 1, print("P2SH-P2WSH SIGHASH_NONE + SIGHASH_ANYONECANPAY")
# "23210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac",
# 4900000000, self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
# True)), "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# "fef7bd749cce710c5c052bd796df1af0d935e59cea63736268bcbe2d2134fc47") SIGHASH_NONE + SIGHASH_ANYONECANPAY),
# "781ba15f3779d5542ce8ecb5c18716733a5ee42a6f51488ec96154934e2c890a")
# print("P2SH-P2WSH SIGHASH_ALL")
# raw_tx = "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000" print("P2SH-P2WSH SIGHASH_SINGLE + SIGHASH_ANYONECANPAY")
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_ALL, self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
# 0, "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae", SIGHASH_SINGLE + SIGHASH_ANYONECANPAY),
# 987654321, "511e8e52ed574121fc1b654970395502128263f62662e076dc6baf05c2e6a99b")
# True)),
# "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
# print("P2SH-P2WSH SIGHASH_NONE")
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_NONE,
# 0,
# "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# 987654321,
# True)),
# "e9733bc60ea13c95c6527066bb975a2ff29a925e80aa14c213f686cbae5d2f36")
# print("P2SH-P2WSH SIGHASH_SINGLE")
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_SINGLE,
# 0,
# "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# 987654321,
# True)),
# "1e1f1c303dc025bd664acb72e583e933fae4cff9148bf78c157d1e8f78530aea")
#
# print("P2SH-P2WSH SIGHASH_ALL + SIGHASH_ANYONECANPAY")
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_ALL + SIGHASH_ANYONECANPAY,
# 0,
# "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# 987654321,
# True)),
# "2a67f03e63a6a422125878b40b82da593be8d4efaafe88ee528af6e5a9955c6e")
# print("P2SH-P2WSH SIGHASH_NONE + SIGHASH_ANYONECANPAY")
#
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_NONE + SIGHASH_ANYONECANPAY,
# 0,
# "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# 987654321,
# True)),
# "781ba15f3779d5542ce8ecb5c18716733a5ee42a6f51488ec96154934e2c890a")
# print("P2SH-P2WSH SIGHASH_SINGLE + SIGHASH_ANYONECANPAY")
#
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_SINGLE + SIGHASH_ANYONECANPAY,
# 0,
# "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# 987654321,
# True)),
# "511e8e52ed574121fc1b654970395502128263f62662e076dc6baf05c2e6a99b")

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,7 @@ from pybtc import address_to_hash as address2hash160
def decode_block_tx(block): def decode_block_tx(block):
stream = get_stream(block) stream = get_stream(block)
stream.seek(80) stream.seek(80)
return {i: Transaction(stream) for i in range(var_int_to_int(read_var_int(stream)))} return {i: Transaction(stream, tx_format="raw") for i in range(var_int_to_int(read_var_int(stream)))}
class TransactionDeserializeTests(unittest.TestCase): class TransactionDeserializeTests(unittest.TestCase):
@ -137,7 +137,7 @@ class TransactionDeserializeTests(unittest.TestCase):
"c0b7cdf67d16b00f6a20dda7159a49f20aa493a7889b2851b2fea30147522103b09ac1fa65a55fa4" \ "c0b7cdf67d16b00f6a20dda7159a49f20aa493a7889b2851b2fea30147522103b09ac1fa65a55fa4" \
"feadea57c4cf417d7490065d8b844ada60c242a441e0e3a42103c0625169b46dbbde3492db7c62f1" \ "feadea57c4cf417d7490065d8b844ada60c242a441e0e3a42103c0625169b46dbbde3492db7c62f1" \
"be8f582131467620cef17335306bad7ef88a52aebe810700" "be8f582131467620cef17335306bad7ef88a52aebe810700"
print("Deserialize Segwit transaction") print("Deserialize Segwit transaction 2")
ns = Transaction(non_segwit_view) ns = Transaction(non_segwit_view)
s = Transaction(segwit_view) s = Transaction(segwit_view)
self.assertEqual(s.serialize(segwit=False,hex = True), non_segwit_view) self.assertEqual(s.serialize(segwit=False,hex = True), non_segwit_view)
@ -188,11 +188,107 @@ class TransactionDeserializeTests(unittest.TestCase):
"20202020202020202020202069202b3d20310a200a2020202020202020206966206f70636f6465203c3d206f7" \ "20202020202020202020202069202b3d20310a200a2020202020202020206966206f70636f6465203c3d206f7" \
"0636f6465732e4f505f5055534844415441343a0a202020202020202020202020206e53697a65203d206f7063" \ "0636f6465732e4f505f5055534844415441343a0a202020202020202020202020206e53697a65203d206f7063" \
"6f64650a2d2d200a312e372e392e340a0a6800000000" "6f64650a2d2d200a312e372e392e340a0a6800000000"
Transaction(tx) t= Transaction(tx)
tx = "0100000001c86c4ddc01f59b748e6a55a6d09c5bce7574fbdec721ca468768b5d6d9e3fb00000000006b48304" \ tx = "0100000001c86c4ddc01f59b748e6a55a6d09c5bce7574fbdec721ca468768b5d6d9e3fb00000000006b48304" \
"5022076b5504ad7aff614e32159ac055362a1197c9a5e50de48cf4f05c7547b39c0b5022100ea67efb2585aae" \ "5022076b5504ad7aff614e32159ac055362a1197c9a5e50de48cf4f05c7547b39c0b5022100ea67efb2585aae" \
"40a53363f48e3e38dfc7387b238f8716fa53a5f0ed51b7c314012102452928340bc618777d217a52f30d8e144" \ "40a53363f48e3e38dfc7387b238f8716fa53a5f0ed51b7c314012102452928340bc618777d217a52f30d8e144" \
"0d98f561c523a31834a1614106f3c15ffffffff025cf5352f0d0000001976a9141855d5890b8aec536ffc3e59" \ "0d98f561c523a31834a1614106f3c15ffffffff025cf5352f0d0000001976a9141855d5890b8aec536ffc3e59" \
"cb586e98b34b5b9288ac0bd32204000000001976a9146f3f6845da01e856a426c31dfeef188c06bf574d88ac0" \ "cb586e98b34b5b9288ac0bd32204000000001976a9146f3f6845da01e856a426c31dfeef188c06bf574d88ac0" \
"0000000" "0000000"
Transaction(tx) # Transaction(tx)
tx = "02000000000117096abdf1191fc4e1aa92e66b0dcc04241cd3949d7cb8f6e3f8b7d2867f9cf80900000000171" \
"600146ec7cb98e540f2d0b39bed94511d44a24be7f2f0feffffff146e022c0a8b94bb0b38ae93a3cda7265db7" \
"3d4f658d10634acb4816c4131fcb01000000171600141d48006f03cdc922da829c479feecf3d6bc7d4d8fefff" \
"fff290d1b0ff9d2eb2c3e09c23f05eb1edce4493d0722b9c6d677692f749ab1b6a50000000017160014acb529" \
"ba2f57150b6c52781bbd82d224fcda9a33feffffff3b1ad0e2198759c7157c837af79351161630e7b389f43bc" \
"2db501781a1562a850000000017160014116ba1a4ffec3012cd009de84db9a10a88169ecdfeffffff3b7d62e6" \
"750593892af6f2cd789db8db3b8d5ec40d3a604aa50ef17010a05e7200000000171600140a2ecd45ea98ff976" \
"641f11cfd65b489c2931e2efeffffff52f17014e779d564173ecb38e5911e5b43f2d593529729a62cb4768f3d" \
"4acc39eb0000001716001410c090b35e7d62334c0aab64fd9459e58d2aace1feffffff52f17014e779d564173" \
"ecb38e5911e5b43f2d593529729a62cb4768f3d4acc396501000017160014eba3843f4d612cd5f73b44d2d2b2" \
"0a14bc402afffeffffff52f17014e779d564173ecb38e5911e5b43f2d593529729a62cb4768f3d4acc397c010" \
"00017160014436e3e8e328425e04929c7624534405a1a8ec87efeffffff7987375451a860c131f5661ecfd6ac" \
"f2206b9eeba90f6d7e2e2bf828fc74000701000000171600149bc9b2c23b4d3aaee5c206de8eb88f64e37d8f8" \
"cfeffffff867a8c3c48e7995d70b7d39c25cd7b21749b2756f0aa5b0140a32e545baa1f100100000017160014" \
"8698b478bcd14c7f12d5f43f9f566ba6cfe44172feffffff9790a339ebd0a0caa802cb9168635d738e075032c" \
"1619f556b7634b2985ee4ce0000000017160014770cc4796bab516455a6e1f3b75343888050f1b2feffffff9c" \
"bc483b0e911190880e48cb0fad167a33c8e73ecdded9f63e5001a54e0d9c460300000017160014d02d35e9276" \
"4caf590cb0b309f40bf6ee0673de5feffffffa219e1f09e7c168ed469a9948d88248d7d2561514f22d6e47661" \
"9fce90876c4b01000000171600144c9d756273fa839887413d8e57429a09263f7757feffffffbb99d3c6a586e" \
"40ed80e782a0584febb15daf1622e2717daaed4c71e224a5745000000001716001429a23327092f771825a0d4" \
"3c7c2187865df4d01ffeffffffbf4932f21c4bee27918fa0e400e4fa5e53dbc7893b334980ea5dd9044c6baf6" \
"d01000000171600144b7063ed9a8f3d7fd14f18a399269256c5e6cbc1feffffffcba7ccd697116c1a259f1292" \
"0334ec62c54e42fab865ebc1cbcbbabe42d20ab2010000001716001432d881b6893d2360a6cb65732829cfe45" \
"292d642feffffffddcd78811d2b73feca247c787105c362a23f32da01472fd504579cb0e64c70a70100000017" \
"160014e4e03eba879ef2f13abb38647767b4e8cbc94356feffffffe9a166d7e4b8372886160893f376084b9f0" \
"c5b289d06774315cf7a15a0b95cc80000000017160014f3f1e21efa1acc3c6ca1786fe6a38462a38b5855feff" \
"fffff0707a5ad2c3e052badcc40236b12fb866d203b73b6b7df1e8d5a5a60eece8f9030000001716001416b40" \
"0b1168b387284c2925c3789700027a83932fefffffff0ff68934c0cd40d10ba612346f26c72fa4a67ea0b0b84" \
"578729dca540a285e731000000171600140afb8e8d46deabffaeffe3402fd57537a445fa57fefffffff0ff689" \
"34c0cd40d10ba612346f26c72fa4a67ea0b0b84578729dca540a285e70302000017160014d29b4da896e24b81" \
"980f3dc5319302a3dec6a6f4fefffffffb6e1c56c1243d038bfdcab451a701e8766baf787aa8d74e6aeb87713" \
"f67c0120100000017160014725752b632549054dbf0bedaaa091e12dabcc8f0feffffffffaf40d3cfbeefdecf" \
"14db8bd5ec7ae6f8d1e69c222f951600d6b514ebf3e9420100000017160014330624c35e0e371c15acdcc6325" \
"7dae5b1930088feffffff021cb81c00000000001976a914ce5cd304c7ba6f89e96aa6c4e92b7455b5359e4e88" \
"ac51420f00000000001976a9142c997b4e8951e7b3e863bbb439b1050bf0fcdd1d88ac0247304402201f4c1c9" \
"0d25365fa146106edf11416459b02d4d6d5f4537b37fe5cc523f3a63002206748a144f4012e838705edb505a5" \
"ef556ecc91df615cab12786369c3d8ab6d3c012102b4323697c2fa1ff13e696f6bc5fe5f67c989cb91b8755e1" \
"1a7c37213c94e957902483045022100dfe620ca3167e75fac002448069fbface366ee7c57f7f86e9a77113127" \
"7c91b20220108a436df211fc21909c450e270c765c2c20814643f3804173be88d6863d51260121032522bbee5" \
"1b2ccad81c4255e2d4eb516ea7943aa8656eaa8ad7b7cd6abcc97370247304402206a4a1836d79004b3430bd6" \
"1d73e938f0bcc1a56c655b52444d4e047464db0592022067bd8d4965d55e261d1e4e38462f20a8a2610f5ac78" \
"d551fc95a522b7144589a0121026baf81f20d6a50e6262f433875651e7b192c304105c6911276541e45a67f96" \
"9402473044022057741ff3470fa4b70b204d621ed737097d3f6cec4a2e43d39c5d6c650117b28d02205b6c3b2" \
"c92ec047c1c4d3fd7b785474345a038f9842d6a30048737cd471117ea012102fbf1d98a34bd3f1283c9f258f8" \
"7a6baff2b65710d4f3b77d5589dacc155b6f8d02483045022100bc07cccf6ac51626147ccb0c1ffd91d0bbedb" \
"6e5df3c798fd8035112bc92070c022034eb7a9658d9ed7b56256155151f8280e871e00e3aefa9b6ea8ae35a27" \
"0c3b8d0121032004240c860bd92ebcf6c834cdc1d9d28fefe757245d61fe86a02c04994697cd0248304502210" \
"0c62ecdebd1728f18a746cf1575cdf29cdf6b03dd86d9b7ead96c9a7341c8ad1702205cd92ace00bf53254e1d" \
"bed3d10f675540dc3a1b1b3dc353ffe3901508bbbb0101210242ff69abeaea31b6fc6e1ea1625179003b9d0d8" \
"2c729ec78df8ef5fb378e6bc002473044022026217dec2bbc97afbfeba833cf9fa323206c26037a5dce5221cb" \
"323af142cb1e02206e2ef15be6da7b99e50339a8924de232693494154f792018b6cca4f9f307192e012103ea5" \
"0f77697dd3467f4876382a447372cd03e5ec567385152e4e91c573c54cf49024730440220256d9ab9ce4c8efb" \
"7628f7f56e0a59b81c0f973d6c9b89b3ac5c018c54d61a58022064f7c7084c3fb30f118187956e624ce4d4eef" \
"7acee81a52be1ccd5683e661f6c0121024d812e6254577bdf98d2b52b36d548dfcf03c994b159309839d30c38" \
"73ec15d5024830450221009618e1427a53dc66e26178416afe6465feb6882d6c4b4a0a3f6b6ce70965a40f022" \
"03d1b0bdee921bb733674d5b373244c4676982eec20c0f7069917b0e2c1d20f6c012103f8c70a3b0a1bdd9ab4" \
"0770a1532a2d0f2eb046e4eb56434ba1a9b214e19ed47a0247304402205e8d08cdae61f6c8ba2d17a18b6575e" \
"4d5e2511f491621d4fa1bebbe89b7794e02200c565ab9379b57b731821e0c9172c65e3339e5a83dbc24d3ecff" \
"79dc8879edc0012102d4c245cb72bc520be55959df9faea82c470a51942907ad83339ae70c5e2a8efa0247304" \
"402207bc8e60dbf3ed02d9b08df09572716cf486e1f49927467131b05487f376eede4022040fd95d42a11456a" \
"2a49eda376edcb0b71baa21cdd562236162806ad9e5d4a4701210287cd827827140bbd304b5feaa9a8c9e36d4" \
"f5a1da292e16e207039b1fadc488402473044022052e177e94353f03a2bb8aed3a3cbc14cb1095b36d972b356" \
"dd2e9ef12a38cb95022055624ef65618144c4ffc9125bedfd625594f2926d5c14f5805cf26d278e802f101210" \
"25493a9da73c46838c6bad1414d1497a8216fbc8e0f46d981167d004b2cc4a6b802483045022100c09f346d36" \
"af2ab4915e96f1088f431cea41854e6a605dfb86b0f87764269203022000fb0354e7d3d6b42ca8b2c59736a0c" \
"a9c3f2cc5263c056abc84c7be62bd6184012103f86036ceb2bd6a57b9f39f5aa986e7fc6a0dd1f379e9549396" \
"2aaf88b228b0b70247304402205be7111758fa4670778571af558ad85c802b9292503df389cd47cd063936185" \
"f0220481965e1ba34cbf6e7b548af01a34c6185921a6120f07cfe437f33071c83c625012102414eb9f4393b9a" \
"5f30f9d4ab2612a9782b062ec0a6b13dbbc5037b185ad8f72002483045022100db73b46fd12fbb17663750417" \
"8f0aa784749b9cd20e7cbfc23586ad7e06fe7fc022038512998ce23ed4b1aff7d07e1654344bc11720976ac0a" \
"3aeece7018999a35ee01210292e1e3b2079ce6ef363f633cffa07f9a0d316e67c0c8d50eea2da026d3cfc6070" \
"2473044022000cd297f5b9aaa94e40210bfc47d10d9156be8ba3db665741d7c77c29118f355022033aa9c328e" \
"90a12bf701167659db4cddbb091af7bb8ae4dc83fd0833667123a4012103c45c84d80cd594a9d014935248622" \
"a33b8ee1c597334586273aab9a9ef1784d502483045022100a152152ee871ac06bd0f0e385b0e281188504ae9" \
"40f54c86760ca0bc1bde6e8902207578d03e42670d5172fb589974853402e00136d2e07c9285171ad79435a94" \
"17e012102cbd3cfc675393c20d9acc51086d8faff48621a216531446ac7c388dcd88decc40247304402200e64" \
"ece9d74242f638db43fa600af34df9289ce93d1756bc5c3be77973b28d7a02205608d5a304efd41c8024a60bc" \
"0f1ed44413941fa80239d01a1e95f15499c2bca0121028447cfc8b84edc759eace6dfbbd6138ebeb470da7819" \
"5a96caf192750487c0c30247304402207244b3a176cf0a7203fbcab9e0f3be5eea21b9ce701a07140b7d591ec" \
"19234f302205e5c6cc861576a871d55609a52f0895710812cb6a2aaa1279a5e01f2d1874779012102bd77789c" \
"af99127c39f22ff5432be6c285c9c5bbbebc86cb35d4f1d5f6fa652302483045022100dbad3f4038a81323d97" \
"f6f6347e31739b7f8d6331ca1fce17ee46f1c9d0b97da022005678968ff1946e1e368a04e87e8954ff5606c42" \
"57c9a114940d32f39f6fbd1f01210322f53e7d73d997c1875db26464875ad797c6cffe80ba548ff524c360495" \
"78fae02473044022075aec794771d9d133e9de71bf89e24227c08bf58dec8cdfff0cd781fa3bf9bed02200d26" \
"e2b9535b9ea8e6aed0ba41aff6dd9f0181418679305c67b5bb888e526df40121020eb887a39d202928ba2abf1" \
"d16df73aaa17daf9922fd3a3bf6554e730f9c88eb02483045022100dd2d2187fd37e5bf333c1bf0b4dae9f42d" \
"ef626458bc9283fe6bdf991e9abcab02207e1954eaadbeed240e577aa0f7d329d53b5934edd1da0320964aace" \
"da09af35f012102ff5bdd1e69f2363d95d80eeeced34bc0de8fc5df9f819cce6ed1d6805beff8ec0247304402" \
"205ec43c7d919216ad16ed85d75f9d98d1695dddc5810ad0c5635d96b47588eeda02201d71c85602169a109e9" \
"0e558125033075237d9177553bac1d1d24d8610cb9d0a012103f50abc70096bb6f6f8742e73c5bf0f1bd4d475" \
"9c1dd2e4486b6fec52b3c8eda6daf10700"
tx = Transaction(tx)