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">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">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">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="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>
@ -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="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">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">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">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>
</div>

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -6,6 +6,7 @@ The class for creating transaction.
.. autoclass:: pybtc.Transaction
:members:
:members:

View File

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

View File

@ -6,6 +6,7 @@ The class for creating transaction.
.. autoclass:: pybtc.Transaction
:members:
:members:

View File

@ -43,10 +43,11 @@ class PrivateKey():
self.hex = hexlify(self.key).decode()
self.wif = private_key_to_wif(self.key, compressed, testnet)
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.hex = hexlify(self.key).decode()
self.wif = private_key_to_wif(self.key, compressed, testnet)
if key[0] in (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,
TESTNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX):
self.compressed = False
@ -57,6 +58,7 @@ class PrivateKey():
self.testnet = True
else:
self.testnet = False
self.wif = private_key_to_wif(self.key, self.compressed, self.testnet)
def __str__(self):
return self.wif
@ -201,15 +203,18 @@ class Address():
class ScriptAddress():
def __init__(self, script, address_type="P2SH",
testnet=False, witness_version=None):
def __init__(self, script,
testnet=False, witness_version=0):
self.witness_version = witness_version
self.testnet = testnet
if isinstance(script, str):
script = unhexlify(script)
self.script = script
self.script_hex = hexlify(self.script).decode()
self.hash = hash160(self.script)
if witness_version is None:
self.hash = hash160(self.script)
else:
self.hash = sha256(self.script)
self.script_opcodes = decode_script(self.script)
self.script_opcodes_asm = decode_script(self.script, 1)
self.address = hash_to_address(self.hash,
@ -217,3 +222,49 @@ class ScriptAddress():
witness_version=self.witness_version,
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_1NEGATE"] = 0x4f
OPCODE["OP_RESERVED"] = 0x50
OPCODE["OP_1"] = 0x51
OPCODE["OP_TRUE"] = 0x51
OPCODE["OP_1"] = 0x51
OPCODE["OP_2"] = 0x52
OPCODE["OP_3"] = 0x53
OPCODE["OP_4"] = 0x54

View File

@ -438,6 +438,13 @@ def get_witness_version(address):
# 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):
"""
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.
: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.
"""
if isinstance(script, str):
try:
script = unhexlify(script)
@ -573,14 +581,35 @@ def decode_script(script, asm=False):
result.append('[%s]' % script[s])
s += script[s] + 1
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"]:
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"]:
s += 4 + struct.unpack('<L', script[s: s + 4])
result.append(RAW_OPCODE[script[s]])
s += 1
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]])
s += 1
return ' '.join(result)
@ -673,7 +702,44 @@ def script_to_hash(script, witness=False, hex=True):
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):
"""
@ -759,9 +825,51 @@ def sign_message(msg, private_key, hex=True):
if not res:
raise RuntimeError("secp256k1 error")
signature = bytes(ffi.buffer(output, outputlen[0]))
raw_sig = ffi.new('secp256k1_ecdsa_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):
"""
Check is valid signature encoded in DER format

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -6,6 +6,7 @@ if parentPath not in sys.path:
from pybtc import address
from pybtc.transaction import *
from pybtc import OPCODE
from binascii import unhexlify
@ -16,6 +17,25 @@ class AddressClassTests(unittest.TestCase):
print("\nTesting address class:\n")
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")
pub = address.PublicKey(p)
a = address.Address(p)
@ -29,7 +49,30 @@ class AddressClassTests(unittest.TestCase):
self.assertEqual(a.redeem_script_hex, '001434370a8d74e9965d7aade2ba2f30110b321bf236')
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
# private key hex string to compressed pub key
p = address.PrivateKey("7b56e2b7bd189f4491d43a1d209e6268046df1741f61b6397349d7aa54978e76", compressed=False)
pub = address.PublicKey(p)
a = address.Address(p, address_type="P2PKH")
@ -51,13 +94,18 @@ class AddressClassTests(unittest.TestCase):
self.assertEqual(a.public_key.hex, '02a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb4')
# from uncompressed pubkey
p = address.PublicKey('04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb43bbd96a641808e5f34eb568e804fe679de82de419e2512736ea09013a82324a6')
p = address.PublicKey('04a8fb85e98c99b79150df12fde488639d8445c57babef83d53c66c1e5c818eeb43bbd96a641808'
'e5f34eb568e804fe679de82de419e2512736ea09013a82324a6')
a = address.Address(p, address_type="P2PKH")
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
a = address.Address(p, address_type="PUBKEY")
self.assertEqual(a.address, '17suVjHXyWF9KiGkpRRQW4ysiEqdDkRqo1')
redeem = "5221032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6953ae"
redeem = "5221032bfc25cf7cccc278b26473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b2" \
"6473e2967b8fd403b4b544b836e71abdfebb08d8c96d6921032bfc25cf7cccc278b26473e2967b8fd403b4b544b8" \
"36e71abdfebb08d8c96d6953ae"
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:
sys.path.insert(0, parentPath)
from pybtc import *
from binascii import unhexlify
from pybtc import address_to_hash as address2hash160
class SighashTests(unittest.TestCase):
@classmethod
@ -517,86 +516,70 @@ class SighashTests(unittest.TestCase):
]
for k in t:
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):
# """
# ["raw_transaction, script, input_index, hashType, signature_hash (result)"],
# :return:
# """
# print("\nNative P2WPKH")
# raw_tx = "0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000"
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_ALL,
# 1,
# "1976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac",
# 600000000,
# True)),
# "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670")
# print(Script("c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670").type)
# print("P2SH-P2WPKH")
# raw_tx = "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000"
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_ALL,
# 0,
# "1976a91479091972186c449eb1ded22b78e40d009bdf008988ac",
# 1000000000,
# True)),
# "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6")
# print("Native P2WSH")
# raw_tx = "0100000002fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e0000000000ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac00000000"
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_SINGLE,
# 1,
# "23210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac",
# 4900000000,
# True)),
# "fef7bd749cce710c5c052bd796df1af0d935e59cea63736268bcbe2d2134fc47")
#
# print("P2SH-P2WSH SIGHASH_ALL")
# raw_tx = "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000"
# self.assertEqual((Transaction.deserialize(raw_tx).sighash_segwit(SIGHASH_ALL,
# 0,
# "cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
# 987654321,
# 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")
print("P2SH-P2WSH SIGHASH_ALL")
raw_tx = "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000"
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
"cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
SIGHASH_ALL),
"185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c")
print("P2SH-P2WSH SIGHASH_NONE")
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
"cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
SIGHASH_NONE),
"e9733bc60ea13c95c6527066bb975a2ff29a925e80aa14c213f686cbae5d2f36")
print("P2SH-P2WSH SIGHASH_SINGLE")
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
"cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
SIGHASH_SINGLE),
"1e1f1c303dc025bd664acb72e583e933fae4cff9148bf78c157d1e8f78530aea")
print("P2SH-P2WSH SIGHASH_ALL + SIGHASH_ANYONECANPAY")
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
"cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
SIGHASH_ALL + SIGHASH_ANYONECANPAY),
"2a67f03e63a6a422125878b40b82da593be8d4efaafe88ee528af6e5a9955c6e")
print("P2SH-P2WSH SIGHASH_NONE + SIGHASH_ANYONECANPAY")
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
"cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
SIGHASH_NONE + SIGHASH_ANYONECANPAY),
"781ba15f3779d5542ce8ecb5c18716733a5ee42a6f51488ec96154934e2c890a")
print("P2SH-P2WSH SIGHASH_SINGLE + SIGHASH_ANYONECANPAY")
self.assertEqual(Transaction(raw_tx).sig_hash_segwit(0, 987654321,
"cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae",
SIGHASH_SINGLE + SIGHASH_ANYONECANPAY),
"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):
stream = get_stream(block)
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):
@ -137,7 +137,7 @@ class TransactionDeserializeTests(unittest.TestCase):
"c0b7cdf67d16b00f6a20dda7159a49f20aa493a7889b2851b2fea30147522103b09ac1fa65a55fa4" \
"feadea57c4cf417d7490065d8b844ada60c242a441e0e3a42103c0625169b46dbbde3492db7c62f1" \
"be8f582131467620cef17335306bad7ef88a52aebe810700"
print("Deserialize Segwit transaction")
print("Deserialize Segwit transaction 2")
ns = Transaction(non_segwit_view)
s = Transaction(segwit_view)
self.assertEqual(s.serialize(segwit=False,hex = True), non_segwit_view)
@ -188,11 +188,107 @@ class TransactionDeserializeTests(unittest.TestCase):
"20202020202020202020202069202b3d20310a200a2020202020202020206966206f70636f6465203c3d206f7" \
"0636f6465732e4f505f5055534844415441343a0a202020202020202020202020206e53697a65203d206f7063" \
"6f64650a2d2d200a312e372e392e340a0a6800000000"
Transaction(tx)
t= Transaction(tx)
tx = "0100000001c86c4ddc01f59b748e6a55a6d09c5bce7574fbdec721ca468768b5d6d9e3fb00000000006b48304" \
"5022076b5504ad7aff614e32159ac055362a1197c9a5e50de48cf4f05c7547b39c0b5022100ea67efb2585aae" \
"40a53363f48e3e38dfc7387b238f8716fa53a5f0ed51b7c314012102452928340bc618777d217a52f30d8e144" \
"0d98f561c523a31834a1614106f3c15ffffffff025cf5352f0d0000001976a9141855d5890b8aec536ffc3e59" \
"cb586e98b34b5b9288ac0bd32204000000001976a9146f3f6845da01e856a426c31dfeef188c06bf574d88ac0" \
"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)