<p>After a quick look at the <a href="https://github.com/Python-Cardano/pycardano/blob/ec8722f7bc3a309477bcd106601088b880982d9f/pycardano/plutus.py#L802" rel="nofollow noreferrer">PyCardano implementation of <code>script_hash</code></a></p>
<p>the problem is in the input of the function.</p>
<p>The hash of a Plutus script is calculated using the compiled contract wrapped <strong>only once</strong> in CBOR.</p>
<p><code>cardano-cli</code> wraps the contract bytes twice in CBOR for historical reasons.</p>
<p>for that reason it is a valid input for <code>cardano-cli</code> but a bad input for <code>PyCardano</code></p>
<p>in your case your script looks like this</p>
<pre><code>581a581801000022232632498cd5ce2481064255524e542100120011
</code></pre>
<div class="s-table-container">
<table class="s-table">
<thead>
<tr>
<th>581a</th>
<th>5818</th>
<th>01000022232632498cd5ce2481064255524e542100120011</th>
</tr>
</thead>
<tbody>
<tr>
<td>CBOR #1</td>
<td>CBOR #2</td>
<td>the actual contract</td>
</tr>
</tbody>
</table>
</div>
<p>so ultimately you want to pass <code>CBOR #2 + the actual contract</code></p>
<p>your snippet should then look like this</p>
<pre class="lang-python prettyprint-override"><code>&gt;&gt;&gt; from pycardano import (
...     BlockFrostChainContext,
...     Network,
...     Address,
...     plutus_script_hash,
...     PlutusV2Script
... )
&gt;&gt;&gt; from blockfrost import ApiUrls
&gt;&gt;&gt; network = Network.TESTNET
&gt;&gt;&gt; script_plutus = PlutusV2Script(bytes.fromhex(&quot;581801000022232632498cd5ce2481064255524e542100120011&quot;))                            
&gt;&gt;&gt; script_hash = plutus_script_hash(script_plutus)
&gt;&gt;&gt; scriptB_addr = Address(script_hash, network=network)
&gt;&gt;&gt; scriptB_addr
addr_test1wrmz3pjz4dmfxj0fc0a0eyw69tp6h7mpndzf9g3kttq9cqqqw47ym
</code></pre>

CC BY-SA 4.0
2023-05-14T07:41:04.120Z
2023-05-15T19:12:48.130Z
2023-05-15T19:12:48.130Z
Michele Nuzzi
<p>Given the CBOR representation of a plutus validator, its script address can be easily generated with a variety of tools, e.g. <strong>cardano-cli</strong> and <strong>PyCardano</strong>.  However, both tools generate different script addresses for the same CBOR.  How is this possible?  Am I finding a bug in PyCardano?</p>
<p>In what follows I describe the building of the script address with both tools, using an example.  We are going to work with the following CBOR:</p>
<pre class="lang-shell prettyprint-override"><code>$ cat script.plutus
{
    &quot;type&quot;: &quot;PlutusScriptV2&quot;,
    &quot;description&quot;: &quot;&quot;,
    &quot;cborHex&quot;: &quot;581a581801000022232632498cd5ce2481064255524e542100120011&quot;
}
</code></pre>
<h4>Generate script address with <code>cardano-cli</code>:</h4>
<pre class="lang-shell prettyprint-override"><code>$ cardano-cli address build \
&gt;   --payment-script-file script.plutus \
&gt;   --testnet-magic 2 \
&gt;   --out-file scriptA.addr
</code></pre>
<p>which resulted in</p>
<pre class="lang-shell prettyprint-override"><code>$ cat scriptA.addr ; echo
addr_test1wrmz3pjz4dmfxj0fc0a0eyw69tp6h7mpndzf9g3kttq9cqqqw47ym
</code></pre>
<h4>Generate script address with <code>PyCardano</code>:</h4>
<pre class="lang-python prettyprint-override"><code>&gt;&gt;&gt; from pycardano import (
...     BlockFrostChainContext,
...     Network,
...     Address,
...     plutus_script_hash,
...     PlutusV2Script
... )
&gt;&gt;&gt; from blockfrost import ApiUrls
&gt;&gt;&gt; context = BlockFrostChainContext(&quot;your-preview-project-id&quot;, base_url=ApiUrls.preview.value)
&gt;&gt;&gt; network = Network.TESTNET
&gt;&gt;&gt; script_plutus = PlutusV2Script(bytes.fromhex(&quot;581a581801000022232632498cd5ce2481064255524e542100120011&quot;))                            
&gt;&gt;&gt; script_hash = plutus_script_hash(script_plutus)
&gt;&gt;&gt; scriptB_addr = Address(script_hash, network=network)
&gt;&gt;&gt; scriptB_addr
addr_test1wqql5y0gsa3ul0vcmdzmp9zaxz8ak0d3j8yfd4yd73pfh4c6ew25x
</code></pre>
<p>As claimed, we have obtained two completely different script-addresses, which is very strange.</p>
<h4>Edit: correct procedure with <code>PyCardano</code>:</h4>
<p>Following Michele's solution and insight, an efficient way of using <em>PyCardano</em> to deal with the same file <code>script.plutus</code> that we used with <em>cardano-cli</em> could be as follows:</p>
<pre class="lang-python prettyprint-override"><code>&gt;&gt;&gt; import json
&gt;&gt;&gt; from pycardano import (
...     BlockFrostChainContext,
...     Network,
...     Address,
...     plutus_script_hash,
...     PlutusV2Script
... )
&gt;&gt;&gt; from blockfrost import ApiUrls
&gt;&gt;&gt; context = BlockFrostChainContext(&quot;your-preview-project-id&quot;, base_url=ApiUrls.preview.value)
&gt;&gt;&gt; network = Network.TESTNET
&gt;&gt;&gt; with open(&quot;script.plutus&quot;, &quot;r&quot;) as f:
...     script_cborHex = json.load(f)[&quot;cborHex&quot;][4:]
... 
&gt;&gt;&gt; script_plutus = PlutusV2Script(bytes.fromhex(script_cborHex))
&gt;&gt;&gt; script_hash = plutus_script_hash(script_plutus)
&gt;&gt;&gt; scriptB_addr = Address(script_hash, network=network)
&gt;&gt;&gt; scriptB_addr
addr_test1wrmz3pjz4dmfxj0fc0a0eyw69tp6h7mpndzf9g3kttq9cqqqw47ym
</code></pre>
<p>and, as Michele pointed out, we have recovered the same address produced by <em>cardano-cli</em>.</p>

CC BY-SA 4.0
2023-05-14T07:07:35.140Z
The script address is the hash of a larger binary data struct. Even a single byte being different between the two will cause the hash to be vastly different. My first guess is that `Network.TESTNET` is not the same as `2`. Even if these two are the same there is something else different.
Erik de Castro Lopo
CC BY-SA 4.0
2023-05-14T07:29:30.827Z
network magic is irrelevant; all the address cares about is if it is testnet (any of them) or mainnet
Michele Nuzzi
<cardano-cli><python>
Inconsistent script addresses built with cardano-cli vs. PyCardano
# Inconsistent script addresses built with cardano-cli vs. PyCardano

(Asked by: username_0 on 2023-05-14)

Given the CBOR representation of a plutus validator, its script address can be easily generated with a variety of tools, e.g. cardano-cli and PyCardano.  However, both tools generate different script addresses for the same CBOR.  How is this possible?  Am I finding a bug in PyCardano?
In what follows I describe the building of the script address with both tools, using an example.  We are going to work with the following CBOR:
$ cat script.plutus
{
    "type": "PlutusScriptV2",
    "description": "",
    "cborHex": "581a581801000022232632498cd5ce2481064255524e542100120011"
}

Generate script address with cardano-cli:
$ cardano-cli address build \
>   --payment-script-file script.plutus \
>   --testnet-magic 2 \
>   --out-file scriptA.addr

which resulted in
$ cat scriptA.addr ; echo
addr_test1wrmz3pjz4dmfxj0fc0a0eyw69tp6h7mpndzf9g3kttq9cqqqw47ym

Generate script address with PyCardano:
>>> from pycardano import (
...     BlockFrostChainContext,
...     Network,
...     Address,
...     plutus_script_hash,
...     PlutusV2Script
... )
>>> from blockfrost import ApiUrls
>>> context = BlockFrostChainContext("your-preview-project-id", base_url=ApiUrls.preview.value)
>>> network = Network.TESTNET
>>> script_plutus = PlutusV2Script(bytes.fromhex("581a581801000022232632498cd5ce2481064255524e542100120011"))                            
>>> script_hash = plutus_script_hash(script_plutus)
>>> scriptB_addr = Address(script_hash, network=network)
>>> scriptB_addr
addr_test1wqql5y0gsa3ul0vcmdzmp9zaxz8ak0d3j8yfd4yd73pfh4c6ew25x

As claimed, we have obtained two completely different script-addresses, which is very strange.
Edit: correct procedure with PyCardano:
Following Michele's solution and insight, an efficient way of using PyCardano to deal with the same file script.plutus that we used with cardano-cli could be as follows:
>>> import json
>>> from pycardano import (
...     BlockFrostChainContext,
...     Network,
...     Address,
...     plutus_script_hash,
...     PlutusV2Script
... )
>>> from blockfrost import ApiUrls
>>> context = BlockFrostChainContext("your-preview-project-id", base_url=ApiUrls.preview.value)
>>> network = Network.TESTNET
>>> with open("script.plutus", "r") as f:
...     script_cborHex = json.load(f)["cborHex"][4:]
... 
>>> script_plutus = PlutusV2Script(bytes.fromhex(script_cborHex))
>>> script_hash = plutus_script_hash(script_plutus)
>>> scriptB_addr = Address(script_hash, network=network)
>>> scriptB_addr
addr_test1wrmz3pjz4dmfxj0fc0a0eyw69tp6h7mpndzf9g3kttq9cqqqw47ym

and, as Michele pointed out, we have recovered the same address produced by cardano-cli.

**Tags:** cardano-cli, python
> **Comments:**
> **username_1**: The script address is the hash of a larger binary data struct. Even a single byte being different between the two will cause the hash to be vastly different. My first guess is that `Network.TESTNET` is not the same as `2`. Even if these two are the same there is something else different.  
> **username_2**: network magic is irrelevant; all the address cares about is if it is testnet (any of them) or mainnet  

---

## 1 answers

### Answer by username_2 on 2023-05-14. Score: 3 | Accepted answer

After a quick look at the PyCardano implementation of script_hash
the problem is in the input of the function.
The hash of a Plutus script is calculated using the compiled contract wrapped only once in CBOR.
cardano-cli wraps the contract bytes twice in CBOR for historical reasons.
for that reason it is a valid input for cardano-cli but a bad input for PyCardano
in your case your script looks like this
581a581801000022232632498cd5ce2481064255524e542100120011





581a
5818
01000022232632498cd5ce2481064255524e542100120011




CBOR #1
CBOR #2
the actual contract




so ultimately you want to pass CBOR #2 + the actual contract
your snippet should then look like this
>>> from pycardano import (
...     BlockFrostChainContext,
...     Network,
...     Address,
...     plutus_script_hash,
...     PlutusV2Script
... )
>>> from blockfrost import ApiUrls
>>> network = Network.TESTNET
>>> script_plutus = PlutusV2Script(bytes.fromhex("581801000022232632498cd5ce2481064255524e542100120011"))                            
>>> script_hash = plutus_script_hash(script_plutus)
>>> scriptB_addr = Address(script_hash, network=network)
>>> scriptB_addr
addr_test1wrmz3pjz4dmfxj0fc0a0eyw69tp6h7mpndzf9g3kttq9cqqqw47ym


---

