Python-Cardano / pycardano

A lightweight Cardano library in Python
https://pycardano.readthedocs.io
MIT License
215 stars 67 forks source link

Minting error at end of example #43

Closed 34r7h closed 2 years ago

34r7h commented 2 years ago

Heya, I'm getting an error at the chain_context.submit_tx(signed_tx.to_cbor()) function, seemingly around deserialization. Maybe something with keys but I can't understand from the following log where to fix. Thanks for any help!

File "/Users/347h/a/cardano-python-js/python/mint.py", line 227, in <module>
    chain_context.submit_tx(signed_tx.to_cbor())
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pycardano/backend/blockfrost.py", line 161, in submit_tx
    self.api.transaction_submit(f.name)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/blockfrost/utils.py", line 63, in error_wrapper
    raise ApiError(request_response)
blockfrost.utils.ApiError: {'error': 'Bad Request', 'message': '"transaction read error RawCborDecodeError [DecoderErrorDeserialiseFailure \\"Byron Tx\\" (DeserialiseFailure 1 \\"Size mismatch when decoding TxAux.\\\\nExpected 2, but found 4.\\"),DecoderErrorDeserialiseFailure \\"Shelley Tx\\" (DeserialiseFailure 1 \\"Size mismatch when decoding \\\\nRecord RecD.\\\\nExpected 4, but found 3.\\"),DecoderErrorDeserialiseFailure \\"Shelley Tx\\" (DeserialiseFailure 1 \\"Size mismatch when decoding \\\\nRecord RecD.\\\\nExpected 4, but found 3.\\"),DecoderErrorDeserialiseFailure \\"Shelley Tx\\" (DeserialiseFailure 1 \\"Size mismatch when decoding \\\\nRecord RecD.\\\\nExpected 4, but found 3.\\"),DecoderErrorDeserialiseFailure \\"Shelley Tx\\" (DeserialiseFailure 79 \\"expected string\\")]"', 'status_code': 400}

Here's the script i'm running, slightly modified for local testing and to take existing payment, stake, and signing keys,


import pathlib
import sys
import json
from pycardano import *

if len(sys.argv) > 1:
    ### args = [address, data, blockfrostid]
    args = list(sys.argv[1:])
    sendaddress = args[0]
    tokenmetadata = json.loads(args[1])
    bf = args[2]

else:
    args = [
      "addr1qxvqw3xawj76533sf8dl4rkm9sn5t4vfzwgtc0mvmcjpmgee8dlsen8n464ucw69acfgdxgguscgfl5we3rwts4s57assqu5h5",
{}, "mainnetXXXXXXRdtWqh2SNVLNqfQbhlNmTbza",]
    # print("no args", sys.argv)
    sendaddress = args[0]
    tokenmetadata = args[1]
    bf = args[2]

# Copy your BlockFrost project ID below. Go to https://blockfrost.io/ for more information.
BLOCK_FROST_PROJECT_ID = bf
NETWORK = Network.MAINNET

chain_context = BlockFrostChainContext(
    project_id=BLOCK_FROST_PROJECT_ID, network=NETWORK
)

PROJECT_ROOT = "nft"
root = pathlib.Path(PROJECT_ROOT)
root.mkdir(parents=True, exist_ok=True)
key_dir = root / "keys"
key_dir.mkdir(exist_ok=True)

def load_or_create_key_pair(base_dir, base_name):
    skey_path = base_dir / f"{base_name}.skey"
    vkey_path = base_dir / f"{base_name}.vkey"

    if skey_path.exists():
        skey = PaymentSigningKey.load(str(skey_path))
        vkey = PaymentVerificationKey.from_signing_key(skey)
    else:
        key_pair = PaymentKeyPair.generate()
        key_pair.signing_key.save(str(skey_path))
        key_pair.verification_key.save(str(vkey_path))
        skey = key_pair.signing_key
        vkey = key_pair.verification_key
    return skey, vkey

pkey = PaymentVerificationKey.load("testpayment.vkey")
skey = PaymentSigningKey.load("testpayment.skey")
spkey = PaymentVerificationKey.load("teststake.vkey")

address = Address(
    payment_part=pkey.hash(), staking_part=spkey.hash(), network=Network.MAINNET
)

policy_skey, policy_vkey = load_or_create_key_pair(key_dir, "policy")
pub_key_policy = ScriptPubkey(policy_vkey.hash())
must_before_slot = InvalidHereAfter(chain_context.last_block_slot + 10000)
policy = ScriptAll([pub_key_policy, must_before_slot])
policy_id = policy.hash()
with open(root / "policy.id", "a+") as f:
    f.truncate(0)
    f.write(str(policy_id))

my_asset = Asset()
nft1 = AssetName(b"MY_NFT_1")
nft2 = AssetName(b"MY_NFT_2")
my_asset[nft1] = 1
my_asset[nft2] = 1
my_nft = MultiAsset()
my_nft[policy_id] = my_asset
native_scripts = [policy]

my_nft_alternative = MultiAsset.from_primitive(
    {
        policy_id.payload: { 
            b"MY_NFT_1": 1,  b"MY_NFT_2": 1, 
        }
    }
)

assert my_nft == my_nft_alternative

metadata = {
    721: {
        policy_id.payload.hex(): {
            "MY_NFT_1": {
                "description": "This is my first NFT thanks to PyCardano",
                "name": "PyCardano NFT example token 1",
                "id": 1,
                "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw",
            },
            "MY_NFT_2": {
                "description": "This is my second NFT thanks to PyCardano",
                "name": "PyCardano NFT example token 2",
                "id": 2,
                "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw",
            },
        }
    }
}
auxiliary_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(metadata)))

builder = TransactionBuilder(chain_context)
builder.add_input_address(address)
builder.ttl = must_before_slot.after
builder.mint = my_nft
builder.native_scripts = native_scripts
builder.auxiliary_data = auxiliary_data
min_val = min_lovelace(Value(0, my_nft), chain_context)
builder.add_output(TransactionOutput(sendaddress, Value(min_val, my_nft)))
signed_tx = builder.build_and_sign([skey, policy_skey], change_address=address)

print("############### Submitting transaction ###############")
chain_context.submit_tx(signed_tx.to_cbor())

The decoded CBOR

[{0: [[h'9322A59F6217108AC921633F273574CDE9CA216A5C4677396B643B37E41E1767', 0], [h'D316D93709E4333D971F948A4D8E6EEAA68343E6CB65A25A18D31B6975EDAF11', 0]], 1: [["addr1qxvqw3xawj76533sf8dl4rkm9sn5t4vfzwgtc0mvmcjpmgee8dlsen8n464ucw69acfgdxgguscgfl5we3rwts4s57assqu5h5", [1448244, {h'371EF437DEE7FFB7F3E9114D99C69EA6E32995D9AC1AB2A4A9B3DB41': {h'4D595F4E46545F31': 1, h'4D595F4E46545F32': 1}}]], [h'01D6B2022CA04D892444CAA9C5C650E29D15272B43083B8449394DD78F9BBABB874FFAE9114744EF5A90485EC955DA03145A58FD3ED2FBB2D5', 4912157]], 2: 201889, 3: 61914215, 7: h'F520A8A8AD15203B8834AE126CAF1D94EBB6B6BADF101DACC60B59BF7D016713', 9: {h'371EF437DEE7FFB7F3E9114D99C69EA6E32995D9AC1AB2A4A9B3DB41': {h'4D595F4E46545F31': 1, h'4D595F4E46545F32': 1}}}, {0: [[h'7823A205BD851586A623644C620010BFAAD6A9C4ADBEA06F1385012778EA36F0', h'B34D4200A0A1E99D246A34BAB8C87699381F1A3F3B64AA890F8CE1284E9400FC062B2BF56A34058662501AB0D6B18AB7F0B2FD2A4B0B4E5131148ACDC390CF0A'], [h'99ED574592B366C8BA57D149415B0A1BC98C6031D696921C4F23B2AE4359D616', h'3249FD069D1BF76198ECAE653246C14412CB6DE2467F7E502872656F6C6AD961DF183DF26029FC85274AE17465D499EC765874C6826BEE24B4FD3A6F792E5100']], 1: [[1, [[0, h'DA3C74EE098DEE1A8E7E3043315742CC7A484D8F8A299FEA4BD35716'], [5, 61914215]]]]}, true, 259({0: {721: {"371ef437dee7ffb7f3e9114d99c69ea6e32995d9ac1ab2a4a9b3db41": {"MY_NFT_1": {"description": "This is my first NFT thanks to PyCardano", "name": "PyCardano NFT example token 1", "id": 1, "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw"}, "MY_NFT_2": {"description": "This is my second NFT thanks to PyCardano", "name": "PyCardano NFT example token 2", "id": 2, "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw"}}}}})]
34r7h commented 2 years ago

I found my mistake. Forgot to use Address.from_primitive(sendaddress) for the add_output() address. No problem here!