Skip to content

Pool certificates #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
20f554e
feat: add cardano-cli chain context
HareemAtWave Oct 7, 2023
d1266d1
fix: allow instances of str to submit_tx_cbor
HareemAtWave Oct 7, 2023
dba6cba
Merge branch 'Python-Cardano:main' into cardano-cli-chain-context
KINGH242 Oct 7, 2023
bcd683b
fix: cast to int for asset amount and check for None in get_min_utxo
HareemAtWave Oct 8, 2023
e1fc6c6
test: add test for cardano-cli chain context
HareemAtWave Oct 8, 2023
eaa4166
Black formatting
nielstron Oct 30, 2023
45fa266
Fix some QA issues
nielstron Oct 30, 2023
20b544f
refactor: use `--out-file /dev/stdout` to get utxo data as json
KINGH242 Nov 2, 2023
efe1698
fix: remove unused offline/online mode code
KINGH242 Nov 2, 2023
6ae4e64
fix: remove unused fraction parser method
KINGH242 Nov 2, 2023
57d4f2e
fix: add docker configuration to use cardano-cli in a Docker containe…
KINGH242 Nov 3, 2023
9a549dd
test: add integration tests for cardano-cli
KINGH242 Nov 3, 2023
3e72507
test: fix cardano-node container name
KINGH242 Nov 6, 2023
e31f9d8
feat: add initial functionality for pool certificates
KINGH242 Nov 11, 2023
5a1b2a4
test: add some tests for pool certificates
KINGH242 Nov 11, 2023
c064bb0
refactor: use built in fractions module
KINGH242 Nov 16, 2023
dad6992
fix: output PoolRegistration as flat list
KINGH242 Nov 16, 2023
af4edbc
fix: clean up some code
KINGH242 Nov 16, 2023
f497d5b
test: add tests for pool params
KINGH242 Nov 16, 2023
ac4a29b
Add more integration tests for cardano cli context
cffls Jan 1, 2024
753e630
Merge branch 'main' into cardano-cli-chain-context
nielstron Feb 6, 2024
7e30628
Merge branch 'cardano-cli-chain-context' into pool-certificates
KINGH242 Feb 8, 2024
8f1df05
feat: add stake pool key pairs
KINGH242 Feb 25, 2024
6d3ce1d
fix: resolve mypy and black linting issues
KINGH242 Feb 25, 2024
daa85c3
feat: add witness count override for fee estimation
KINGH242 Feb 25, 2024
b185559
chore: add integration test temporary folders to ignore
KINGH242 Feb 25, 2024
c72b493
test: add test for pool certificate related code
KINGH242 Feb 25, 2024
789f7cd
Merge branch 'main' into pool-certificates
KINGH242 Feb 25, 2024
abf7182
Simplify Certificate deserialization
cffls Feb 26, 2024
c845908
Fix failing test cases for python<3.10
cffls Feb 26, 2024
e6c1093
Simplify relay parsing
cffls Feb 26, 2024
d79d8cf
Remove unused import
cffls Feb 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Black formatting
  • Loading branch information
nielstron committed Oct 30, 2023
commit eaa41662b110a124b4e77e13566b799d49e20b61
93 changes: 62 additions & 31 deletions pycardano/backend/cardano_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
GenesisParameters,
ProtocolParameters,
)
from pycardano.exception import TransactionFailedException, CardanoCliError, PyCardanoException
from pycardano.exception import (
TransactionFailedException,
CardanoCliError,
PyCardanoException,
)
from pycardano.hash import DatumHash, ScriptHash
from pycardano.transaction import (
Asset,
Expand Down Expand Up @@ -84,14 +88,14 @@ class CardanoCliChainContext(ChainContext):
_datum_cache: Cache

def __init__(
self,
binary: Path,
socket: Path,
config_file: Path,
network: CardanoCliNetwork,
refetch_chain_tip_interval: Optional[float] = None,
utxo_cache_size: int = 10000,
datum_cache_size: int = 10000,
self,
binary: Path,
socket: Path,
config_file: Path,
network: CardanoCliNetwork,
refetch_chain_tip_interval: Optional[float] = None,
utxo_cache_size: int = 10000,
datum_cache_size: int = 10000,
):
if not binary.exists() or not binary.is_file():
raise CardanoCliError(f"cardano-cli binary file not found: {binary}")
Expand Down Expand Up @@ -124,8 +128,8 @@ def __init__(
self._protocol_param = None
if refetch_chain_tip_interval is None:
self._refetch_chain_tip_interval = (
self.genesis_param.slot_length
/ self.genesis_param.active_slots_coefficient
self.genesis_param.slot_length
/ self.genesis_param.active_slots_coefficient
)

self._utxo_cache = TTLCache(
Expand Down Expand Up @@ -153,17 +157,23 @@ def _query_chain_tip(self) -> JsonDict:
return json.loads(result)

def _query_current_protocol_params(self) -> JsonDict:
result = self._run_command(["query", "protocol-parameters"] + self._network.value)
result = self._run_command(
["query", "protocol-parameters"] + self._network.value
)
return json.loads(result)

def _query_genesis_config(self) -> JsonDict:
if not self._config_file.exists() or not self._config_file.is_file():
raise CardanoCliError(f"Cardano config file not found: {self._config_file}")
with open(self._config_file, encoding="utf-8") as config_file:
config_json = json.load(config_file)
shelly_genesis_file = self._config_file.parent / config_json["ShelleyGenesisFile"]
shelly_genesis_file = (
self._config_file.parent / config_json["ShelleyGenesisFile"]
)
if not shelly_genesis_file.exists() or not shelly_genesis_file.is_file():
raise CardanoCliError(f"Shelly Genesis file not found: {shelly_genesis_file}")
raise CardanoCliError(
f"Shelly Genesis file not found: {shelly_genesis_file}"
)
with open(shelly_genesis_file, encoding="utf-8") as genesis_file:
genesis_json = json.load(genesis_file)
return genesis_json
Expand All @@ -172,7 +182,10 @@ def _get_min_utxo(self) -> int:
params = self._query_current_protocol_params()
if "minUTxOValue" in params and params["minUTxOValue"] is not None:
return params["minUTxOValue"]
elif "lovelacePerUTxOWord" in params and params["lovelacePerUTxOWord"] is not None:
elif (
"lovelacePerUTxOWord" in params
and params["lovelacePerUTxOWord"] is not None
):
return params["lovelacePerUTxOWord"]
elif "utxoCostPerWord" in params and params["utxoCostPerWord"] is not None:
return params["utxoCostPerWord"]
Expand Down Expand Up @@ -206,8 +219,12 @@ def _is_chain_tip_updated(self):
def _fetch_protocol_param(self) -> ProtocolParameters:
result = self._query_current_protocol_params()
return ProtocolParameters(
min_fee_constant=result["minFeeConstant"] if "minFeeConstant" in result else result["txFeeFixed"],
min_fee_coefficient=result["minFeeCoefficient"] if "minFeeCoefficient" in result else result["txFeePerByte"],
min_fee_constant=result["minFeeConstant"]
if "minFeeConstant" in result
else result["txFeeFixed"],
min_fee_coefficient=result["minFeeCoefficient"]
if "minFeeCoefficient" in result
else result["txFeePerByte"],
max_block_size=result["maxBlockBodySize"],
max_tx_size=result["maxTxSize"],
max_block_header_size=result["maxBlockHeaderSize"],
Expand All @@ -222,8 +239,12 @@ def _fetch_protocol_param(self) -> ProtocolParameters:
protocol_minor_version=result["protocolVersion"]["minor"],
min_utxo=self._get_min_utxo(),
min_pool_cost=result["minPoolCost"],
price_mem=result["executionUnitPrices"]["priceMemory"] if "executionUnitPrices" in result else result["executionPrices"]["priceMemory"],
price_step=result["executionUnitPrices"]["priceSteps"] if "executionUnitPrices" in result else result["executionPrices"]["priceSteps"],
price_mem=result["executionUnitPrices"]["priceMemory"]
if "executionUnitPrices" in result
else result["executionPrices"]["priceMemory"],
price_step=result["executionUnitPrices"]["priceSteps"]
if "executionUnitPrices" in result
else result["executionPrices"]["priceSteps"],
max_tx_ex_mem=result["maxTxExecutionUnits"]["memory"],
max_tx_ex_steps=result["maxTxExecutionUnits"]["steps"],
max_block_ex_mem=result["maxBlockExecutionUnits"]["memory"],
Expand Down Expand Up @@ -309,7 +330,9 @@ def _utxos(self, address: str) -> List[UTxO]:
if key in self._utxo_cache:
return self._utxo_cache[key]

result = self._run_command(["query", "utxo", "--address", address] + self._network.value)
result = self._run_command(
["query", "utxo", "--address", address] + self._network.value
)
raw_utxos = result.split("\n")[2:]

# Parse the UTXOs into a list of dict objects
Expand All @@ -326,12 +349,13 @@ def _utxos(self, address: str) -> List[UTxO]:
"type": vals[3],
}

tx_in = TransactionInput.from_primitive([utxo_dict["tx_hash"], int(utxo_dict["tx_ix"])])
tx_in = TransactionInput.from_primitive(
[utxo_dict["tx_hash"], int(utxo_dict["tx_ix"])]
)
lovelace_amount = utxo_dict["lovelaces"]

tx_out = TransactionOutput(
Address.from_primitive(address),
amount=Value(coin=int(lovelace_amount))
Address.from_primitive(address), amount=Value(coin=int(lovelace_amount))
)

extra = [i for i, j in enumerate(vals) if j == "+"]
Expand All @@ -351,9 +375,7 @@ def _utxos(self, address: str) -> List[UTxO]:
policy = ScriptHash.from_primitive(policy_id)
asset_name = AssetName.from_primitive(asset_hex_name)

multi_assets.setdefault(policy, Asset())[
asset_name
] = quantity
multi_assets.setdefault(policy, Asset())[asset_name] = quantity

tx_out.amount = Value(lovelace_amount, multi_assets)

Expand Down Expand Up @@ -385,22 +407,31 @@ def submit_tx_cbor(self, cbor: Union[bytes, str]) -> str:
tx_json = {
"type": f"Witnessed Tx {self.era}Era",
"description": "Generated by PyCardano",
"cborHex": cbor
"cborHex": cbor,
}

tmp_tx_file.write(json.dumps(tx_json))

tmp_tx_file.flush()

try:
self._run_command(["transaction", "submit", "--tx-file", tmp_tx_file.name] + self._network.value)
self._run_command(
["transaction", "submit", "--tx-file", tmp_tx_file.name]
+ self._network.value
)
except CardanoCliError as err:
raise TransactionFailedException("Failed to submit transaction") from err
raise TransactionFailedException(
"Failed to submit transaction"
) from err

# Get the transaction ID
try:
txid = self._run_command(["transaction", "txid", "--tx-file", tmp_tx_file.name])
txid = self._run_command(
["transaction", "txid", "--tx-file", tmp_tx_file.name]
)
except CardanoCliError as err:
raise PyCardanoException(f"Unable to get transaction id for {tmp_tx_file.name}") from err
raise PyCardanoException(
f"Unable to get transaction id for {tmp_tx_file.name}"
) from err

return txid
2 changes: 1 addition & 1 deletion pycardano/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ class InputUTxODepletedException(UTxOSelectionException):


class CardanoCliError(PyCardanoException):
pass
pass
77 changes: 25 additions & 52 deletions test/pycardano/backend/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import pytest


@pytest.fixture(scope="session")
def genesis_json():
return {
Expand All @@ -12,48 +13,43 @@ def genesis_json():
"genDelegs": {
"637f2e950b0fd8f8e3e811c5fbeb19e411e7a2bf37272b84b29c1a0b": {
"delegate": "aae9293510344ddd636364c2673e34e03e79e3eefa8dbaa70e326f7d",
"vrf": "227116365af2ed943f1a8b5e6557bfaa34996f1578eec667a5e2b361c51e4ce7"
"vrf": "227116365af2ed943f1a8b5e6557bfaa34996f1578eec667a5e2b361c51e4ce7",
},
"8a4b77c4f534f8b8cc6f269e5ebb7ba77fa63a476e50e05e66d7051c": {
"delegate": "d15422b2e8b60e500a82a8f4ceaa98b04e55a0171d1125f6c58f8758",
"vrf": "0ada6c25d62db5e1e35d3df727635afa943b9e8a123ab83785e2281605b09ce2"
"vrf": "0ada6c25d62db5e1e35d3df727635afa943b9e8a123ab83785e2281605b09ce2",
},
"b00470cd193d67aac47c373602fccd4195aad3002c169b5570de1126": {
"delegate": "b3b539e9e7ed1b32fbf778bf2ebf0a6b9f980eac90ac86623d11881a",
"vrf": "0ff0ce9b820376e51c03b27877cd08f8ba40318f1a9f85a3db0b60dd03f71a7a"
"vrf": "0ff0ce9b820376e51c03b27877cd08f8ba40318f1a9f85a3db0b60dd03f71a7a",
},
"b260ffdb6eba541fcf18601923457307647dce807851b9d19da133ab": {
"delegate": "7c64eb868b4ef566391a321c85323f41d2b95480d7ce56ad2abcb022",
"vrf": "7fb22abd39d550c9a022ec8104648a26240a9ff9c88b8b89a6e20d393c03098e"
"vrf": "7fb22abd39d550c9a022ec8104648a26240a9ff9c88b8b89a6e20d393c03098e",
},
"ced1599fd821a39593e00592e5292bdc1437ae0f7af388ef5257344a": {
"delegate": "de7ca985023cf892f4de7f5f1d0a7181668884752d9ebb9e96c95059",
"vrf": "c301b7fc4d1b57fb60841bcec5e3d2db89602e5285801e522fce3790987b1124"
"vrf": "c301b7fc4d1b57fb60841bcec5e3d2db89602e5285801e522fce3790987b1124",
},
"dd2a7d71a05bed11db61555ba4c658cb1ce06c8024193d064f2a66ae": {
"delegate": "1e113c218899ee7807f4028071d0e108fc790dade9fd1a0d0b0701ee",
"vrf": "faf2702aa4893c877c622ab22dfeaf1d0c8aab98b837fe2bf667314f0d043822"
"vrf": "faf2702aa4893c877c622ab22dfeaf1d0c8aab98b837fe2bf667314f0d043822",
},
"f3b9e74f7d0f24d2314ea5dfbca94b65b2059d1ff94d97436b82d5b4": {
"delegate": "fd637b08cc379ef7b99c83b416458fcda8a01a606041779331008fb9",
"vrf": "37f2ea7c843a688159ddc2c38a2f997ab465150164a9136dca69564714b73268"
}
"vrf": "37f2ea7c843a688159ddc2c38a2f997ab465150164a9136dca69564714b73268",
},
},
"initialFunds": {},
"maxKESEvolutions": 62,
"maxLovelaceSupply": 45000000000000000,
"networkId": "Testnet",
"networkMagic": 1,
"protocolParams": {
"protocolVersion": {
"minor": 0,
"major": 2
},
"protocolVersion": {"minor": 0, "major": 2},
"decentralisationParam": 1,
"eMax": 18,
"extraEntropy": {
"tag": "NeutralNonce"
},
"extraEntropy": {"tag": "NeutralNonce"},
"maxTxSize": 16384,
"maxBlockBodySize": 65536,
"maxBlockHeaderSize": 1100,
Expand All @@ -66,24 +62,21 @@ def genesis_json():
"nOpt": 150,
"rho": 0.003,
"tau": 0.20,
"a0": 0.3
"a0": 0.3,
},
"securityParam": 2160,
"slotLength": 1,
"slotsPerKESPeriod": 129600,
"staking": {
"pools": {},
"stake": {}
},
"staking": {"pools": {}, "stake": {}},
"systemStart": "2022-06-01T00:00:00Z",
"updateQuorum": 5
"updateQuorum": 5,
}


@pytest.fixture(autouse=True)
def mock_check_socket():
with patch("pathlib.Path.exists", return_value=True), patch(
"pathlib.Path.is_socket", return_value=True
"pathlib.Path.is_socket", return_value=True
), patch("pathlib.Path.is_file", return_value=True):
yield

Expand Down Expand Up @@ -164,52 +157,32 @@ def config_file():
"TracingVerbosity": "NormalVerbosity",
"TurnOnLogMetrics": True,
"TurnOnLogging": True,
"defaultBackends": [
"KatipBK"
],
"defaultScribes": [
[
"StdoutSK",
"stdout"
]
],
"defaultBackends": ["KatipBK"],
"defaultScribes": [["StdoutSK", "stdout"]],
"hasEKG": 12788,
"hasPrometheus": [
"0.0.0.0",
12798
],
"hasPrometheus": ["0.0.0.0", 12798],
"minSeverity": "Info",
"options": {
"mapBackends": {
"cardano.node.metrics": [
"EKGViewBK"
],
"cardano.node.resources": [
"EKGViewBK"
]
"cardano.node.metrics": ["EKGViewBK"],
"cardano.node.resources": ["EKGViewBK"],
},
"mapSubtrace": {
"cardano.node.metrics": {
"subtrace": "Neutral"
}
}
"mapSubtrace": {"cardano.node.metrics": {"subtrace": "Neutral"}},
},
"rotation": {
"rpKeepFilesNum": 10,
"rpLogLimitBytes": 5000000,
"rpMaxAgeHours": 24
"rpMaxAgeHours": 24,
},
"setupBackends": [
"KatipBK"
],
"setupBackends": ["KatipBK"],
"setupScribes": [
{
"scFormat": "ScText",
"scKind": "StdoutSK",
"scName": "stdout",
"scRotation": None
"scRotation": None,
}
]
],
}

with open(config_file_path, "w", encoding="utf-8") as file:
Expand Down
Loading