Skip to content
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

Pool certificates #321

Merged
merged 32 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ dist

# IDE
.idea
.code
.code
/integration-test/.env
/integration-test/tmp_configs/*
2 changes: 1 addition & 1 deletion pycardano/backend/cardano_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from pycardano.hash import DatumHash, ScriptHash
from pycardano.nativescript import NativeScript
from pycardano.network import Network
from pycardano.plutus import PlutusV1Script, PlutusV2Script, RawPlutusData, Datum
from pycardano.plutus import Datum, PlutusV1Script, PlutusV2Script, RawPlutusData
from pycardano.serialization import RawCBOR
from pycardano.transaction import (
Asset,
Expand Down
128 changes: 125 additions & 3 deletions pycardano/certificate.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Optional, Union
from typing import Optional, Tuple, Type, Union

from pycardano.exception import DeserializeException
from pycardano.hash import PoolKeyHash, ScriptHash, VerificationKeyHash
from pycardano.serialization import ArrayCBORSerializable
from pycardano.serialization import ArrayCBORSerializable, limit_primitive_type

__all__ = [
"Certificate",
"StakeCredential",
"StakeRegistration",
"StakeDeregistration",
"StakeDelegation",
"PoolRegistration",
"PoolRetirement",
]

from pycardano.pool_params import PoolParams

unit_interval = Tuple[int, int]


@dataclass(repr=False)
class StakeCredential(ArrayCBORSerializable):
Expand All @@ -25,20 +34,55 @@ def __post_init__(self):
else:
self._CODE = 1

@classmethod
@limit_primitive_type(list)
def from_primitive(
cls: Type[StakeCredential], values: Union[list, tuple]
) -> StakeCredential:
if values[0] == 0:
return cls(VerificationKeyHash(values[1]))
elif values[0] == 1:
return cls(ScriptHash(values[1]))
else:
raise DeserializeException(f"Invalid StakeCredential type {values[0]}")


@dataclass(repr=False)
class StakeRegistration(ArrayCBORSerializable):
_CODE: int = field(init=False, default=0)

stake_credential: StakeCredential

def __post_init__(self):
self._CODE = 0

@classmethod
@limit_primitive_type(list)
def from_primitive(
cls: Type[StakeRegistration], values: Union[list, tuple]
) -> StakeRegistration:
return cls(stake_credential=StakeCredential.from_primitive(values[1]))


@dataclass(repr=False)
class StakeDeregistration(ArrayCBORSerializable):
_CODE: int = field(init=False, default=1)

stake_credential: StakeCredential

def __post_init__(self):
self._CODE = 1

@classmethod
@limit_primitive_type(list)
def from_primitive(
cls: Type[StakeDeregistration], values: Union[list, tuple]
) -> StakeDeregistration:
if values[0] == 1:
return cls(StakeCredential.from_primitive(values[1]))
else:
raise DeserializeException(f"Invalid StakeDeregistration type {values[0]}")


@dataclass(repr=False)
class StakeDelegation(ArrayCBORSerializable):
Expand All @@ -48,5 +92,83 @@ class StakeDelegation(ArrayCBORSerializable):

pool_keyhash: PoolKeyHash

def __post_init__(self):
self._CODE = 2

@classmethod
@limit_primitive_type(list)
def from_primitive(
cls: Type[StakeDelegation], values: Union[list, tuple]
) -> StakeDelegation:
if values[0] == 2:
return cls(
stake_credential=StakeCredential.from_primitive(values[1]),
pool_keyhash=PoolKeyHash.from_primitive(values[2]),
)
else:
raise DeserializeException(f"Invalid StakeDelegation type {values[0]}")


@dataclass(repr=False)
class PoolRegistration(ArrayCBORSerializable):
_CODE: int = field(init=False, default=3)

pool_params: PoolParams

def __post_init__(self):
self._CODE = 3

def to_primitive(self):
pool_params = self.pool_params.to_primitive()
if isinstance(pool_params, list):
return [self._CODE, *pool_params]
return super().to_primitive()

@classmethod
@limit_primitive_type(list)
def from_primitive(
cls: Type[PoolRegistration], values: Union[list, tuple]
) -> PoolRegistration:
if values[0] == 3:
if isinstance(values[1], list):
return cls(
pool_params=PoolParams.from_primitive(values[1]),
)
else:
return cls(
pool_params=PoolParams.from_primitive(values[1:]),
)
else:
raise DeserializeException(f"Invalid PoolRegistration type {values[0]}")


@dataclass(repr=False)
class PoolRetirement(ArrayCBORSerializable):
_CODE: int = field(init=False, default=4)

pool_keyhash: PoolKeyHash
epoch: int

def __post_init__(self):
self._CODE = 4

@classmethod
@limit_primitive_type(list)
def from_primitive(
cls: Type[PoolRetirement], values: Union[list, tuple]
) -> PoolRetirement:
if values[0] == 4:
return cls(
pool_keyhash=PoolKeyHash.from_primitive(values[1]), epoch=values[2]
)
else:
raise DeserializeException(f"Invalid PoolRetirement type {values[0]}")


Certificate = Union[StakeRegistration, StakeDeregistration, StakeDelegation]
Certificate = Union[
StakeRegistration,
StakeDeregistration,
StakeDelegation,
PoolRegistration,
PoolRetirement,
]
1 change: 1 addition & 0 deletions pycardano/cip/cip14.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from nacl.encoding import RawEncoder
from nacl.hash import blake2b

from pycardano.crypto.bech32 import encode
from pycardano.hash import ScriptHash
from pycardano.transaction import AssetName
Expand Down
29 changes: 28 additions & 1 deletion pycardano/hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
"AUXILIARY_DATA_HASH_SIZE",
"POOL_KEY_HASH_SIZE",
"SCRIPT_DATA_HASH_SIZE",
"VRF_KEY_HASH_SIZE",
"POOL_METADATA_HASH_SIZE",
"REWARD_ACCOUNT_HASH_SIZE",
"ConstrainedBytes",
"VerificationKeyHash",
"ScriptHash",
Expand All @@ -20,6 +23,9 @@
"DatumHash",
"AuxiliaryDataHash",
"PoolKeyHash",
"PoolMetadataHash",
"VrfKeyHash",
"RewardAccountHash",
]

VERIFICATION_KEY_HASH_SIZE = 28
Expand All @@ -29,6 +35,9 @@
DATUM_HASH_SIZE = 32
AUXILIARY_DATA_HASH_SIZE = 32
POOL_KEY_HASH_SIZE = 28
POOL_METADATA_HASH_SIZE = 32
VRF_KEY_HASH_SIZE = 32
REWARD_ACCOUNT_HASH_SIZE = 29


T = TypeVar("T", bound="ConstrainedBytes")
Expand Down Expand Up @@ -124,7 +133,25 @@ class AuxiliaryDataHash(ConstrainedBytes):
MAX_SIZE = MIN_SIZE = AUXILIARY_DATA_HASH_SIZE


class PoolKeyHash(ConstrainedBytes):
class PoolKeyHash(VerificationKeyHash):
"""Hash of a stake pool"""

MAX_SIZE = MIN_SIZE = POOL_KEY_HASH_SIZE


class PoolMetadataHash(ConstrainedBytes):
"""Hash of a stake pool metadata"""

MAX_SIZE = MIN_SIZE = POOL_METADATA_HASH_SIZE


class VrfKeyHash(ConstrainedBytes):
"""Hash of a Cardano VRF key."""

MAX_SIZE = MIN_SIZE = VRF_KEY_HASH_SIZE


class RewardAccountHash(ConstrainedBytes):
"""Hash of a Cardano VRF key."""

MAX_SIZE = MIN_SIZE = REWARD_ACCOUNT_HASH_SIZE
37 changes: 37 additions & 0 deletions pycardano/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
"StakeSigningKey",
"StakeVerificationKey",
"StakeKeyPair",
"StakePoolSigningKey",
"StakePoolVerificationKey",
"StakePoolKeyPair",
]


Expand Down Expand Up @@ -314,3 +317,37 @@ def from_signing_key(
cls: Type[StakeKeyPair], signing_key: SigningKey
) -> StakeKeyPair:
return cls(signing_key, StakeVerificationKey.from_signing_key(signing_key))


class StakePoolSigningKey(SigningKey):
KEY_TYPE = "StakePoolSigningKey_ed25519"
DESCRIPTION = "Stake Pool Operator Signing Key"


class StakePoolVerificationKey(VerificationKey):
KEY_TYPE = "StakePoolVerificationKey_ed25519"
DESCRIPTION = "Stake Pool Operator Verification Key"


class StakePoolKeyPair:
def __init__(self, signing_key: SigningKey, verification_key: VerificationKey):
self.signing_key = signing_key
self.verification_key = verification_key

@classmethod
def generate(cls: Type[StakePoolKeyPair]) -> StakePoolKeyPair:
signing_key = StakePoolSigningKey.generate()
return cls.from_signing_key(signing_key)

@classmethod
def from_signing_key(
cls: Type[StakePoolKeyPair], signing_key: SigningKey
) -> StakePoolKeyPair:
return cls(signing_key, StakePoolVerificationKey.from_signing_key(signing_key))

def __eq__(self, other):
if isinstance(other, StakePoolKeyPair):
return (
other.signing_key == self.signing_key
and other.verification_key == self.verification_key
)
Loading
Loading