Skip to content

Commit 47c880d

Browse files
committed
Refactor and tests
1 parent a561451 commit 47c880d

File tree

13 files changed

+1185
-132
lines changed

13 files changed

+1185
-132
lines changed

integration-test/configs/local-chang/conway-genesis.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,7 @@
288288
"anchor": {
289289
"url": "ipfs://QmQq5hWDNzvDR1ForEktAHrdCQmfSL2u5yctNpzDwoSBu4",
290290
"dataHash": "23b43bebac48a4acc39e578715aa06635d6d900fa3ea7441dfffd6e43b914f7b"
291-
},
292-
"script": "edcd84c10e36ae810dc50847477083069db796219b39ccde790484e0"
291+
}
293292
},
294293
"committee": {
295294
"members": {

integration-test/run_tests.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ docker compose -f docker-compose-chang.yml up -d
7272

7373
export PAYMENT_KEY="$ROOT"/configs/local-chang/shelley/utxo-keys/utxo1.skey
7474
export EXTENDED_PAYMENT_KEY="$ROOT"/keys/extended.skey
75+
export POOL_COLD_KEY="$ROOT"/keys/pool/cold.skey
76+
export POOL_PAYMENT_KEY="$ROOT"/keys/pool/payment.skey
77+
export POOL_STAKE_KEY="$ROOT"/keys/pool/stake.skey
7578
export POOL_ID=$(cat "$ROOT"/keys/pool/pool.id)
7679

7780
sleep 10

integration-test/test/base.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class TestBase:
3434

3535
payment_key_path = os.environ.get("PAYMENT_KEY")
3636
extended_key_path = os.environ.get("EXTENDED_PAYMENT_KEY")
37+
pool_cold_key_path = os.environ.get("POOL_COLD_KEY")
38+
pool_payment_key_path = os.environ.get("POOL_PAYMENT_KEY")
39+
pool_stake_key_path = os.environ.get("POOL_STAKE_KEY")
3740
if not payment_key_path or not extended_key_path:
3841
raise Exception(
3942
"Cannot find payment key. Please specify environment variable PAYMENT_KEY and extended_key_path"
@@ -44,6 +47,12 @@ class TestBase:
4447
extended_payment_vkey = PaymentExtendedVerificationKey.from_signing_key(
4548
extended_payment_skey
4649
)
50+
pool_cold_skey = PaymentSigningKey.load(pool_cold_key_path)
51+
pool_cold_vkey = PaymentVerificationKey.from_signing_key(pool_cold_skey)
52+
pool_payment_skey = PaymentSigningKey.load(pool_payment_key_path)
53+
pool_payment_vkey = PaymentVerificationKey.from_signing_key(pool_payment_skey)
54+
pool_stake_skey = StakeSigningKey.load(pool_stake_key_path)
55+
pool_stake_vkey = StakeVerificationKey.from_signing_key(pool_stake_skey)
4756

4857
payment_key_pair = PaymentKeyPair.generate()
4958
stake_key_pair = StakeKeyPair.generate()

integration-test/test/test_certificate.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ def test_stake_delegation(self):
4040
stake_credential = StakeCredential(
4141
self.stake_key_pair.verification_key.hash()
4242
)
43-
stake_registration = StakeRegistration(stake_credential)
4443
pool_hash = PoolKeyHash(bytes.fromhex(os.environ.get("POOL_ID").strip()))
45-
# stake_delegation = StakeDelegation(stake_credential, pool_keyhash=pool_hash)
4644

4745
drep = DRep(
4846
DRepKind.VERIFICATION_KEY_HASH,
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import os
2+
import time
3+
4+
from retry import retry
5+
6+
from pycardano import *
7+
8+
from .base import TEST_RETRIES, TestBase
9+
10+
11+
class TestGovernanceAction(TestBase):
12+
@retry(tries=TEST_RETRIES, backoff=1.3, delay=2, jitter=(0, 10))
13+
def test_governance_action_and_voting(self):
14+
# Create new stake key pair
15+
stake_key_pair = StakeKeyPair.generate()
16+
17+
# Create addresses for testing
18+
address = Address(
19+
self.payment_vkey.hash(),
20+
stake_key_pair.verification_key.hash(),
21+
self.NETWORK,
22+
)
23+
24+
# Load pool cold key for signing
25+
# pool_cold_skey = PaymentSigningKey.load(self.pool_cold_key_path)
26+
27+
# First, ensure we have enough funds
28+
utxos = self.chain_context.utxos(address)
29+
30+
if not utxos:
31+
giver_address = Address(self.payment_vkey.hash(), network=self.NETWORK)
32+
33+
builder = TransactionBuilder(self.chain_context)
34+
builder.add_input_address(giver_address)
35+
builder.add_output(TransactionOutput(address, 110000000000))
36+
37+
signed_tx = builder.build_and_sign([self.payment_skey], giver_address)
38+
print("############### Funding Transaction created ###############")
39+
print(signed_tx)
40+
print(signed_tx.to_cbor_hex())
41+
print("############### Submitting funding transaction ###############")
42+
self.chain_context.submit_tx(signed_tx)
43+
time.sleep(5)
44+
45+
# Step 1: Register as a DRep first
46+
drep_credential = DRepCredential(stake_key_pair.verification_key.hash())
47+
anchor = Anchor(
48+
url="https://test-drep.com",
49+
data_hash=AnchorDataHash(bytes.fromhex("0" * 64)),
50+
)
51+
52+
drep_registration = RegDRepCert(
53+
drep_credential=drep_credential,
54+
coin=500000000,
55+
anchor=anchor,
56+
)
57+
58+
stake_credential = StakeCredential(stake_key_pair.verification_key.hash())
59+
pool_hash = PoolKeyHash(bytes.fromhex(os.environ.get("POOL_ID").strip()))
60+
61+
drep = DRep(
62+
DRepKind.VERIFICATION_KEY_HASH,
63+
stake_key_pair.verification_key.hash(),
64+
)
65+
66+
all_in_one_cert = StakeRegistrationAndDelegationAndVoteDelegation(
67+
stake_credential, pool_hash, drep, 1000000
68+
)
69+
70+
# Create transaction for DRep registration
71+
builder = TransactionBuilder(self.chain_context)
72+
builder.add_input_address(address)
73+
builder.add_output(TransactionOutput(address, 35000000))
74+
builder.certificates = [drep_registration, all_in_one_cert]
75+
76+
signed_tx = builder.build_and_sign(
77+
[stake_key_pair.signing_key, self.payment_skey],
78+
address,
79+
)
80+
print("############### DRep Registration Transaction created ###############")
81+
print(signed_tx)
82+
print(signed_tx.to_cbor_hex())
83+
print("############### Submitting DRep registration ###############")
84+
self.chain_context.submit_tx(signed_tx)
85+
time.sleep(5)
86+
87+
# Step 2: Create and submit parameter change action
88+
info_proposal = InfoAction()
89+
90+
# Create transaction for parameter change
91+
builder = TransactionBuilder(self.chain_context)
92+
builder.add_input_address(address)
93+
builder.add_output(TransactionOutput(address, 35000000))
94+
reward_account = Address(
95+
staking_part=stake_key_pair.verification_key.hash(), network=self.NETWORK
96+
)
97+
builder.add_proposal(
98+
100000000000,
99+
bytes(reward_account),
100+
info_proposal,
101+
Anchor(
102+
url="https://test-info.com",
103+
data_hash=AnchorDataHash(bytes.fromhex("0" * 64)),
104+
),
105+
)
106+
107+
# Sign with both payment key and pool cold key for governance action
108+
signed_tx = builder.build_and_sign(
109+
[self.payment_skey, stake_key_pair.signing_key],
110+
address,
111+
)
112+
print("############### Gov Action Transaction created ###############")
113+
print(signed_tx)
114+
print(signed_tx.to_cbor_hex())
115+
print("############### Submitting gov action transaction ###############")
116+
self.chain_context.submit_tx(signed_tx)
117+
time.sleep(5)
118+
119+
# Get the governance action ID from the transaction
120+
gov_action_id = GovActionId(
121+
transaction_id=signed_tx.id,
122+
gov_action_index=0, # First governance action in the transaction
123+
)
124+
125+
# Step 3: Vote for the action as a DRep
126+
drep_voter = Voter(
127+
credential=stake_key_pair.verification_key.hash(),
128+
voter_type=VoterType.DREP,
129+
)
130+
131+
# Step 4: Vote for the action as a stake pool
132+
pool_id = os.environ.get("POOL_ID").strip()
133+
134+
# Create transaction for voting
135+
builder = TransactionBuilder(self.chain_context)
136+
builder.add_input_address(address)
137+
builder.add_output(TransactionOutput(address, 35000000))
138+
139+
# Add DRep vote using the helper method
140+
builder.add_vote(
141+
voter=drep_voter,
142+
gov_action_id=gov_action_id,
143+
vote=Vote.YES,
144+
anchor=Anchor(
145+
url="https://test-drep.com",
146+
data_hash=AnchorDataHash(bytes.fromhex("0" * 64)),
147+
),
148+
)
149+
150+
# Add pool vote using the helper method
151+
pool_voter = Voter(
152+
credential=VerificationKeyHash(bytes.fromhex(pool_id)),
153+
voter_type=VoterType.STAKING_POOL,
154+
)
155+
builder.add_vote(
156+
voter=pool_voter,
157+
gov_action_id=gov_action_id,
158+
vote=Vote.YES,
159+
anchor=Anchor(
160+
url="https://test-pool.com",
161+
data_hash=AnchorDataHash(bytes.fromhex("0" * 64)),
162+
),
163+
)
164+
165+
# Sign with all required keys
166+
signed_tx = builder.build_and_sign(
167+
[
168+
stake_key_pair.signing_key,
169+
self.payment_skey,
170+
self.pool_cold_skey,
171+
],
172+
address,
173+
)
174+
print("############### Voting Transaction created ###############")
175+
print(signed_tx)
176+
print(signed_tx.to_cbor_hex())
177+
print("############### Submitting voting transaction ###############")
178+
self.chain_context.submit_tx(signed_tx)
179+
180+
print("############### Test completed successfully ###############")

pycardano/certificate.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ def from_primitive(
8888
else:
8989
raise DeserializeException(f"Invalid StakeCredential type {values[0]}")
9090

91+
def __hash__(self):
92+
return hash(self.to_cbor())
93+
9194

9295
@dataclass(repr=False)
9396
class DRepCredential(StakeCredential):

0 commit comments

Comments
 (0)