Source code for cometa.transaction_builder.balancing.input_to_redeemer_map
"""
Copyright 2025 Biglup Labs.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from __future__ import annotations
from collections.abc import Mapping
from typing import Optional, Iterator, Tuple, TYPE_CHECKING
from ..._ffi import ffi, lib
from ...errors import CardanoError
if TYPE_CHECKING:
from ...transaction_body import TransactionInput
from ...witness_set import Redeemer
[docs]
class InputToRedeemerMap(Mapping["TransactionInput", "Redeemer"]):
"""
A map of transaction inputs to redeemers.
This map associates specific references of inputs to redeemers in the witness set.
Balancing the transaction can add additional inputs and this can make inputs change
positions in the input set. Redeemers must be updated to point to the correct input.
If you provide redeemers for any pre-selected input, you must specify this
association in this map.
Example:
>>> from cometa.transaction_builder.balancing import InputToRedeemerMap
>>> from cometa.transaction_body import TransactionInput
>>> from cometa.witness_set import Redeemer
>>>
>>> input_map = InputToRedeemerMap.new()
>>> input_map.insert(tx_input, redeemer)
>>> print(f"Map contains {len(input_map)} entries")
"""
[docs]
def __init__(self, ptr=None) -> None:
if ptr is None:
out = ffi.new("cardano_input_to_redeemer_map_t**")
err = lib.cardano_input_to_redeemer_map_new(out)
if err != 0:
raise CardanoError(
f"Failed to create InputToRedeemerMap (error code: {err})"
)
self._ptr = out[0]
else:
if ptr == ffi.NULL:
raise CardanoError("InputToRedeemerMap: invalid handle")
self._ptr = ptr
def __del__(self) -> None:
if getattr(self, "_ptr", ffi.NULL) not in (None, ffi.NULL):
ptr_ptr = ffi.new("cardano_input_to_redeemer_map_t**", self._ptr)
lib.cardano_input_to_redeemer_map_unref(ptr_ptr)
self._ptr = ffi.NULL
[docs]
def __len__(self) -> int:
return int(lib.cardano_input_to_redeemer_map_get_length(self._ptr))
[docs]
def __iter__(self) -> Iterator["TransactionInput"]:
"""Iterate over keys (TransactionInputs)."""
for i in range(len(self)):
yield self.get_key_at(i)
[docs]
@classmethod
def new(cls) -> InputToRedeemerMap:
"""
Create a new empty InputToRedeemerMap.
Returns:
A new InputToRedeemerMap instance.
Raises:
CardanoError: If creation fails.
"""
return cls()
[docs]
def insert(self, key: "TransactionInput", value: "Redeemer") -> None:
"""
Insert a key-value pair into the map.
Args:
key: The transaction input to use as key.
value: The redeemer to associate with the input.
Raises:
CardanoError: If insertion fails.
"""
err = lib.cardano_input_to_redeemer_map_insert(
self._ptr, key._ptr, value._ptr
)
if err != 0:
raise CardanoError(
f"Failed to insert into InputToRedeemerMap (error code: {err})"
)
[docs]
def __getitem__(self, key: "TransactionInput") -> "Redeemer":
"""
Get the redeemer associated with a transaction input.
Args:
key: The transaction input to look up.
Returns:
The associated redeemer.
Raises:
KeyError: If key is not found.
CardanoError: If lookup fails.
"""
from ...witness_set import Redeemer
redeemer_out = ffi.new("cardano_redeemer_t**")
err = lib.cardano_input_to_redeemer_map_get(self._ptr, key._ptr, redeemer_out)
if err != 0:
raise KeyError(key)
if redeemer_out[0] == ffi.NULL:
raise KeyError(key)
return Redeemer(redeemer_out[0])
[docs]
def get(self, key: "TransactionInput", default: Optional["Redeemer"] = None) -> Optional["Redeemer"]:
"""
Get the redeemer associated with a transaction input.
Args:
key: The transaction input to look up.
default: Value to return if key is not found.
Returns:
The associated redeemer, or default if not found.
"""
try:
return self[key]
except KeyError:
return default
[docs]
def get_key_at(self, index: int) -> "TransactionInput":
"""
Get the transaction input at the specified index.
Args:
index: The index of the key to retrieve.
Returns:
The TransactionInput at the specified index.
Raises:
CardanoError: If retrieval fails.
"""
from ...transaction_body import TransactionInput
input_out = ffi.new("cardano_transaction_input_t**")
err = lib.cardano_input_to_redeemer_map_get_key_at(
self._ptr, index, input_out
)
if err != 0:
raise CardanoError(
f"Failed to get key at index {index} (error code: {err})"
)
return TransactionInput(input_out[0])
[docs]
def get_value_at(self, index: int) -> "Redeemer":
"""
Get the redeemer at the specified index.
Args:
index: The index of the value to retrieve.
Returns:
The Redeemer at the specified index.
Raises:
CardanoError: If retrieval fails.
"""
from ...witness_set import Redeemer
redeemer_out = ffi.new("cardano_redeemer_t**")
err = lib.cardano_input_to_redeemer_map_get_value_at(
self._ptr, index, redeemer_out
)
if err != 0:
raise CardanoError(
f"Failed to get value at index {index} (error code: {err})"
)
return Redeemer(redeemer_out[0])
[docs]
def get_key_value_at(
self, index: int
) -> Tuple["TransactionInput", "Redeemer"]:
"""
Get both the key and value at the specified index.
Args:
index: The index of the key-value pair to retrieve.
Returns:
A tuple of (TransactionInput, Redeemer) at the specified index.
Raises:
CardanoError: If retrieval fails.
"""
from ...transaction_body import TransactionInput
from ...witness_set import Redeemer
input_out = ffi.new("cardano_transaction_input_t**")
redeemer_out = ffi.new("cardano_redeemer_t**")
err = lib.cardano_input_to_redeemer_map_get_key_value_at(
self._ptr, index, input_out, redeemer_out
)
if err != 0:
raise CardanoError(
f"Failed to get key-value at index {index} (error code: {err})"
)
return TransactionInput(input_out[0]), Redeemer(redeemer_out[0])
[docs]
def update_redeemer_index(
self, tx_input: "TransactionInput", new_index: int
) -> None:
"""
Update the index of a redeemer that matches the given input.
If a matching redeemer is found, its index is updated. Otherwise,
nothing happens.
Args:
tx_input: The input key to search for.
new_index: The new index to assign to the redeemer.
Raises:
CardanoError: If update fails.
"""
err = lib.cardano_input_to_redeemer_map_update_redeemer_index(
self._ptr, tx_input._ptr, new_index
)
if err != 0:
raise CardanoError(
f"Failed to update redeemer index (error code: {err})"
)
[docs]
def get_last_error(self) -> str:
"""
Get the last error message recorded for this map.
Returns:
The last error message, or empty string if none.
"""
result = lib.cardano_input_to_redeemer_map_get_last_error(self._ptr)
if result == ffi.NULL:
return ""
return ffi.string(result).decode("utf-8")