From d4405204a63e80c0ec69a05da8606b1f5cac5bcd Mon Sep 17 00:00:00 2001 From: Jerry Date: Sat, 2 May 2026 21:00:49 -0700 Subject: [PATCH] Support v10.7.1 and dijkstra genesis --- .../configs/local-chang/config.json | 1 + .../configs/local-chang/conway-genesis.json | 42 +++--- .../configs/local-chang/dijkstra-genesis.json | 6 + .../configs/local-chang/topology.json | 17 ++- integration-test/docker-compose-chang.yml | 4 +- integration-test/keys/pool/topology.json | 19 ++- integration-test/run_tests.sh | 4 + integration-test/setup_governance.sh | 121 ++++++++++++++++++ integration-test/test/test_governance.py | 23 +++- 9 files changed, 201 insertions(+), 36 deletions(-) create mode 100644 integration-test/configs/local-chang/dijkstra-genesis.json create mode 100755 integration-test/setup_governance.sh diff --git a/integration-test/configs/local-chang/config.json b/integration-test/configs/local-chang/config.json index cc839351..108e0372 100644 --- a/integration-test/configs/local-chang/config.json +++ b/integration-test/configs/local-chang/config.json @@ -3,6 +3,7 @@ "ShelleyGenesisFile": "./shelley-genesis.json", "AlonzoGenesisFile": "./alonzo-genesis.json", "ConwayGenesisFile": "./conway-genesis.json", + "DijkstraGenesisFile": "./dijkstra-genesis.json", "SocketPath": "db/node.socket", "Protocol": "Cardano", "PBftSignatureThreshold": 0.6, diff --git a/integration-test/configs/local-chang/conway-genesis.json b/integration-test/configs/local-chang/conway-genesis.json index 67bcacdc..f3219ed1 100644 --- a/integration-test/configs/local-chang/conway-genesis.json +++ b/integration-test/configs/local-chang/conway-genesis.json @@ -6,25 +6,25 @@ } }, "poolVotingThresholds": { - "committeeNormal": 0.65, - "committeeNoConfidence": 0.65, - "hardForkInitiation": 0.51, - "motionNoConfidence": 0.6, - "ppSecurityGroup": 0.6 + "committeeNormal": 0, + "committeeNoConfidence": 0, + "hardForkInitiation": 0, + "motionNoConfidence": 0, + "ppSecurityGroup": 0 }, "dRepVotingThresholds": { - "motionNoConfidence": 0.67, - "committeeNormal": 0.67, - "committeeNoConfidence": 0.65, - "updateToConstitution": 0.75, - "hardForkInitiation": 0.6, - "ppNetworkGroup": 0.67, - "ppEconomicGroup": 0.67, - "ppTechnicalGroup": 0.67, - "ppGovGroup": 0.75, - "treasuryWithdrawal": 0.67 + "motionNoConfidence": 0, + "committeeNormal": 0, + "committeeNoConfidence": 0, + "updateToConstitution": 0, + "hardForkInitiation": 0, + "ppNetworkGroup": 0, + "ppEconomicGroup": 0, + "ppTechnicalGroup": 0, + "ppGovGroup": 0, + "treasuryWithdrawal": 0 }, - "committeeMinSize": 5, + "committeeMinSize": 0, "committeeMaxTermLength": 146, "govActionLifetime": 14, "govActionDeposit": 100000000000, @@ -291,13 +291,7 @@ } }, "committee": { - "members": { - "scriptHash-7ceede7d6a89e006408e6b7c6acb3dd094b3f6817e43b4a36d01535b": 500, - "scriptHash-6095e643ea6f1cccb6e463ec34349026b3a48621aac5d512655ab1bf": 500, - "scriptHash-27999ed757d6dac217471ae61d69b1b067b8b240d9e3ff36eb66b5d0": 500, - "scriptHash-87f867a31c0f81360d4d7dcddb6b025ba8383db9bf77a2af7797799d": 500, - "scriptHash-a19a7ba1caede8f3ab3e5e2a928b3798d7d011af18fbd577f7aeb0ec": 500 - }, - "threshold": 0.67 + "members": {}, + "threshold": 0 } } \ No newline at end of file diff --git a/integration-test/configs/local-chang/dijkstra-genesis.json b/integration-test/configs/local-chang/dijkstra-genesis.json new file mode 100644 index 00000000..c33c6755 --- /dev/null +++ b/integration-test/configs/local-chang/dijkstra-genesis.json @@ -0,0 +1,6 @@ +{ + "maxRefScriptSizePerBlock": 1048576, + "maxRefScriptSizePerTx": 204800, + "refScriptCostStride": 25600, + "refScriptCostMultiplier": 1.2 +} diff --git a/integration-test/configs/local-chang/topology.json b/integration-test/configs/local-chang/topology.json index dc92f2e8..f60bf0ea 100644 --- a/integration-test/configs/local-chang/topology.json +++ b/integration-test/configs/local-chang/topology.json @@ -1,9 +1,18 @@ { - "Producers": [ + "bootstrapPeers": null, + "localRoots": [ { - "addr": "172.20.0.102", - "port": 3000, + "accessPoints": [ + { + "address": "172.20.0.102", + "port": 3000 + } + ], + "advertise": false, + "trustable": true, "valency": 1 } - ] + ], + "publicRoots": [], + "useLedgerAfterSlot": -1 } diff --git a/integration-test/docker-compose-chang.yml b/integration-test/docker-compose-chang.yml index 790b5b2a..fbceb277 100644 --- a/integration-test/docker-compose-chang.yml +++ b/integration-test/docker-compose-chang.yml @@ -9,7 +9,7 @@ networks: services: cardano-node: - image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-10.5.1} + image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-10.7.1} platform: linux/amd64 entrypoint: bash environment: @@ -35,7 +35,7 @@ services: max-file: "10" cardano-pool: - image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-10.5.1} + image: ghcr.io/intersectmbo/cardano-node:${CARDANO_NODE_VERSION:-10.7.1} platform: linux/amd64 entrypoint: bash environment: diff --git a/integration-test/keys/pool/topology.json b/integration-test/keys/pool/topology.json index d39e3422..96167463 100644 --- a/integration-test/keys/pool/topology.json +++ b/integration-test/keys/pool/topology.json @@ -1,9 +1,18 @@ { - "Producers": [ + "bootstrapPeers": null, + "localRoots": [ { - "addr": "172.20.0.101", - "port": 3000, + "accessPoints": [ + { + "address": "172.20.0.101", + "port": 3000 + } + ], + "advertise": false, + "trustable": true, "valency": 1 } - ] -} \ No newline at end of file + ], + "publicRoots": [], + "useLedgerAfterSlot": -1 +} diff --git a/integration-test/run_tests.sh b/integration-test/run_tests.sh index 8d32d0f9..2111c847 100755 --- a/integration-test/run_tests.sh +++ b/integration-test/run_tests.sh @@ -92,6 +92,10 @@ while true; do sleep 2 done +# cardano-node 10.7+ no longer auto-inits PlutusV2 cost model at Babbage HF. +# Submit a Conway parameter-update action to add it before running tests. +docker exec integration-test-cardano-pool-1 bash /code/setup_governance.sh + poetry run pytest -m "not (CardanoCLI)" -s -vv "$ROOT"/test --cov=pycardano --cov-config=../.coveragerc --cov-report=xml:../coverage.xml # Cleanup diff --git a/integration-test/setup_governance.sh b/integration-test/setup_governance.sh new file mode 100755 index 00000000..56c0e3a6 --- /dev/null +++ b/integration-test/setup_governance.sh @@ -0,0 +1,121 @@ +#!/bin/bash +# Submit a Conway governance action to add PlutusV2 cost model. +# Runs inside the cardano-pool-1 container via `docker exec`. +# cardano-node 10.7+ no longer auto-initializes PlutusV2 cost model at +# the Babbage hard fork, so it has to be added by an explicit parameter +# update action. conway-genesis is set up with zero thresholds so the +# action ratifies trivially. + +set -euo pipefail + +NETWORK="${NETWORK:-local-chang}" +TESTNET_MAGIC="${TESTNET_MAGIC:-42}" +CFG=/code/tmp_configs/$NETWORK +POOL=/code/keys/pool +COST_MODEL_FILE=/tmp/v2-cost-model.json +ANCHOR_FILE=/tmp/anchor.json +ACTION_FILE=/tmp/v2.action +TX_RAW=/tmp/v2.tx.raw +TX_SIGNED=/tmp/v2.tx.signed +ANCHOR_PORT=18080 + +export CARDANO_NODE_SOCKET_PATH=/ipc/node.socket + +# Submit the gov action from the pool's wallet (full.addr ≈ 450K ADA) rather +# than utxo1 (which the integration tests need intact). The deposit (100K) +# returns to the pool's own stake key after enactment, so funds stay within +# the pool wallet — utxo1 is never touched. +PAYMENT_ADDR=$(cat "$POOL/full.addr") + +echo "[gov] Building V2 cost-model file from alonzo-genesis…" +# alonzo-genesis stores PlutusV2 either as a dict (legacy) or a list. Normalize +# to a list of values sorted by key (canonical order matches list form). +jq '.costModels.PlutusV2 + | if type == "object" + then to_entries | sort_by(.key) | map(.value) + else . + end + | { PlutusV2: . }' "$CFG/alonzo-genesis.json" > "$COST_MODEL_FILE" +echo "[gov] V2 length: $(jq '.PlutusV2 | length' "$COST_MODEL_FILE")" + +# cardano-cli `transaction build` always verifies that --anchor-url is +# fetchable and its body hashes to --anchor-data-hash. Serve a tiny static +# anchor file locally over http so the verification succeeds offline. +echo '{"title":"add PlutusV2 cost model","authors":["pycardano-tests"]}' > "$ANCHOR_FILE" +ANCHOR_HASH=$(cardano-cli hash anchor-data --file-text "$ANCHOR_FILE") +echo "[gov] anchor hash: $ANCHOR_HASH" + +ANCHOR_LEN=$(stat -c%s "$ANCHOR_FILE") +RESPONSE_FILE=/tmp/anchor.http +{ + printf 'HTTP/1.0 200 OK\r\n' + printf 'Content-Type: application/json\r\n' + printf 'Content-Length: %d\r\n' "$ANCHOR_LEN" + printf '\r\n' + cat "$ANCHOR_FILE" +} > "$RESPONSE_FILE" + +socat -d TCP-LISTEN:"$ANCHOR_PORT",fork,reuseaddr SYSTEM:"cat $RESPONSE_FILE" & +SOCAT_PID=$! +trap 'kill $SOCAT_PID 2>/dev/null || true' EXIT +sleep 1 +echo "[gov] anchor server up on :$ANCHOR_PORT (pid $SOCAT_PID)" + +ANCHOR_URL="http://127.0.0.1:$ANCHOR_PORT/anchor.json" + +echo "[gov] Creating parameter-update action…" +cardano-cli conway governance action create-protocol-parameters-update \ + --testnet \ + --governance-action-deposit 100000000000 \ + --deposit-return-stake-verification-key-file "$POOL/stake.vkey" \ + --anchor-url "$ANCHOR_URL" \ + --anchor-data-hash "$ANCHOR_HASH" \ + --cost-model-file "$COST_MODEL_FILE" \ + --out-file "$ACTION_FILE" + +echo "[gov] Selecting UTxO at $PAYMENT_ADDR…" +TX_IN=$(cardano-cli conway query utxo \ + --address "$PAYMENT_ADDR" \ + --testnet-magic "$TESTNET_MAGIC" \ + --output-json | jq -r 'keys[0]') +echo "[gov] tx-in: $TX_IN" + +echo "[gov] Building transaction with proposal…" +cardano-cli conway transaction build \ + --testnet-magic "$TESTNET_MAGIC" \ + --tx-in "$TX_IN" \ + --change-address "$PAYMENT_ADDR" \ + --proposal-file "$ACTION_FILE" \ + --out-file "$TX_RAW" + +echo "[gov] Signing…" +cardano-cli conway transaction sign \ + --testnet-magic "$TESTNET_MAGIC" \ + --tx-body-file "$TX_RAW" \ + --signing-key-file "$POOL/payment.skey" \ + --out-file "$TX_SIGNED" + +echo "[gov] Submitting…" +cardano-cli conway transaction submit \ + --testnet-magic "$TESTNET_MAGIC" \ + --tx-file "$TX_SIGNED" + +echo "[gov] Waiting for V2 cost model to appear on chain…" +for i in $(seq 1 60); do + if cardano-cli conway query protocol-parameters --testnet-magic "$TESTNET_MAGIC" 2>/dev/null \ + | jq -e '.costModels.PlutusV2' >/dev/null; then + echo "[gov] V2 cost model is now on chain (after ${i} iterations)." + # Record the ratified action's id so test_governance can chain to it. + # `cardano-cli ... transaction txid` returns JSON like {"txhash":"..."}. + TX_ID=$(cardano-cli conway transaction txid --tx-file "$TX_SIGNED" | jq -r '.txhash // .') + printf '{"tx_id":"%s","index":0}\n' "$TX_ID" > "$CFG/last_param_action.json" + echo "[gov] wrote prev-action id to $CFG/last_param_action.json (tx=$TX_ID)" + exit 0 + fi + sleep 5 +done + +echo "[gov] ERROR: V2 cost model did not appear within timeout." >&2 +cardano-cli conway query protocol-parameters --testnet-magic "$TESTNET_MAGIC" \ + | jq '.costModels | keys' >&2 +exit 1 diff --git a/integration-test/test/test_governance.py b/integration-test/test/test_governance.py index f55600c0..dd5da410 100644 --- a/integration-test/test/test_governance.py +++ b/integration-test/test/test_governance.py @@ -1,3 +1,4 @@ +import json import os import time @@ -8,6 +9,24 @@ from .base import TEST_RETRIES, TestBase +def _load_prev_param_update_action(): + """Read the gov action id of the last ratified parameter update written by + setup_governance.sh (if any). Returns None if the file is absent — e.g. on + a chain that has never had a parameter update ratified.""" + here = os.path.dirname(os.path.abspath(__file__)) + path = os.path.join( + here, "..", "tmp_configs", "local-chang", "last_param_action.json" + ) + if not os.path.exists(path): + return None + with open(path) as f: + data = json.load(f) + return GovActionId( + transaction_id=TransactionId(bytes.fromhex(data["tx_id"])), + gov_action_index=data["index"], + ) + + class TestGovernanceAction(TestBase): @retry(tries=TEST_RETRIES, backoff=1.3, delay=2, jitter=(0, 10)) def test_governance_action_and_voting(self): @@ -90,7 +109,9 @@ def test_governance_action_and_voting(self): max_transaction_size=26384, ) - parameter_change_action = ParameterChangeAction(None, param_update, None) + parameter_change_action = ParameterChangeAction( + _load_prev_param_update_action(), param_update, None + ) # Create transaction for parameter change builder = TransactionBuilder(self.chain_context)