From 674048a12088ff8ac5c9485c9cea0b0ec7a4e2d2 Mon Sep 17 00:00:00 2001 From: Satya Date: Sun, 1 Mar 2026 13:51:39 +0800 Subject: [PATCH 1/2] chore: upgrade Spring Boot 3.5.11, Spring AI 1.1.2, Yaci 0.4.0, cardano-client-lib 0.7.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Upgrade Spring Boot 3.2.5 → 3.5.11, Spring Shell 3.2.4 → 3.4.1 - Upgrade Spring AI 1.0.3 → 1.1.2 with STATELESS MCP protocol - Upgrade Yaci 0.3.3 → 0.4.0, cardano-client-lib 0.6.2 → 0.7.1 - Update LocalProtocolParamSupplier for Yaci 0.4.0 Rational type changes - Remove deprecated legacy_testnet network from BlockStreamerService - Update MCP endpoint URL from /sse to /mcp (streamable HTTP transport) - Suppress noisy MCP and Spring AI warnings from CLI console output - Handle NoResourceFoundException at DEBUG level to avoid ERROR stack traces - Fix deprecated logback syntax to remove config parsing warnings - Remove duplicate MCP properties from Docker application.properties - Update Sonatype repository URL to new central endpoint --- README.md | 2 +- applications/cli/build.gradle | 20 ++++++++--------- .../cli/docker/application.properties | 5 ----- .../controller/GlobalExceptionHandler.java | 15 +++++++++++++ .../commands/tail/BlockStreamerService.java | 17 -------------- .../service/LocalProtocolParamSupplier.java | 12 +++++----- .../cli/src/main/resources/application.yml | 4 ++++ .../cli/src/main/resources/logback-spring.xml | 22 ++++++++++++++++--- mcp.json.example | 2 +- 9 files changed, 55 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index a9cce593..1395002c 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,7 @@ Copy [`mcp.json.example`](./mcp.json.example) to `.mcp.json` in your project roo { "mcpServers": { "yaci-devkit": { - "url": "http://localhost:10000/sse" + "url": "http://localhost:10000/mcp" } } } diff --git a/applications/cli/build.gradle b/applications/cli/build.gradle index d188d61a..511a74e4 100644 --- a/applications/cli/build.gradle +++ b/applications/cli/build.gradle @@ -1,6 +1,6 @@ plugins { - id 'org.springframework.boot' version '3.2.5' - id 'io.spring.dependency-management' version '1.1.4' + id 'org.springframework.boot' version '3.5.11' + id 'io.spring.dependency-management' version '1.1.7' id 'org.graalvm.buildtools.native' version '0.10.2' id 'java' id 'signing' @@ -18,17 +18,16 @@ java { } repositories { - //maven { url 'https://repo.spring.io/release' } mavenCentral() mavenLocal() maven { - url "https://oss.sonatype.org/content/repositories/snapshots" + url "https://central.sonatype.com/repository/maven-snapshots/" } } ext { - set('springShellVersion', "3.2.4") - set('springAiVersion', "1.0.3") + set('springShellVersion', "3.4.1") + set('springAiVersion', "1.1.2") } dependencies { @@ -39,13 +38,12 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-logging' implementation 'org.springframework.boot:spring-boot-starter-mustache' - implementation('com.bloxbean.cardano:yaci:0.3.3') { + implementation('com.bloxbean.cardano:yaci:0.4.0') { exclude group: 'com.bloxbean.cardano', module: 'cardano-client-core' } - implementation 'com.bloxbean.cardano:cardano-client-lib:0.6.2' - implementation 'com.bloxbean.cardano:cardano-client-backend:0.6.2' - implementation 'com.bloxbean.cardano:cardano-client-backend-blockfrost:0.6.2' - //implementation 'com.bloxbean.cardano:cardano-client-supplier-local:0.5.1' + implementation 'com.bloxbean.cardano:cardano-client-lib:0.7.1' + implementation 'com.bloxbean.cardano:cardano-client-backend:0.7.1' + implementation 'com.bloxbean.cardano:cardano-client-backend-blockfrost:0.7.1' implementation 'org.apache.commons:commons-compress:1.23.0' diff --git a/applications/cli/docker/application.properties b/applications/cli/docker/application.properties index 81cc1311..9e80581f 100644 --- a/applications/cli/docker/application.properties +++ b/applications/cli/docker/application.properties @@ -9,8 +9,3 @@ pool.keys.home=/clusters/pool-keys spring.shell.config.location=/clusters server.port=10000 -# MCP Server -spring.ai.mcp.server.enabled=true -spring.ai.mcp.server.name=yaci-devkit -spring.ai.mcp.server.version=0.1.0 - diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/cip30/controller/GlobalExceptionHandler.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/cip30/controller/GlobalExceptionHandler.java index d8e729fd..81e332b6 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/cip30/controller/GlobalExceptionHandler.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/cip30/controller/GlobalExceptionHandler.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; import java.util.HashMap; import java.util.Map; @@ -56,6 +57,20 @@ public ResponseEntity> handleIllegalArgumentException( return ResponseEntity.badRequest().body(response); } + /** + * Handle missing static resource requests (e.g., MCP client probing legacy endpoints) + */ + @ExceptionHandler(NoResourceFoundException.class) + public ResponseEntity> handleNoResourceFoundException( + NoResourceFoundException ex) { + Map response = new HashMap<>(); + response.put("code", HttpStatus.NOT_FOUND.value()); + response.put("message", "Resource not found"); + + log.debug("Resource not found: {}", ex.getMessage()); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + } + /** * Handle generic exceptions */ diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/commands/tail/BlockStreamerService.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/commands/tail/BlockStreamerService.java index 6014f25c..fc0333d6 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/commands/tail/BlockStreamerService.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/commands/tail/BlockStreamerService.java @@ -221,23 +221,6 @@ private CliConnection getConnectionInfo(String host, int port, String network, l wellKnownPoint = new Point(slot, blockHash); else wellKnownPoint = Constants.WELL_KNOWN_MAINNET_POINT; - } else if ("legacy_testnet".equals(network)) { - if (!StringUtils.hasLength(host)) { - host = Constants.TESTNET_IOHK_RELAY_ADDR; - } - - if (port == 0) { - port = Constants.TESTNET_IOHK_RELAY_PORT; - } - - if (protocolMagic == 0) { - protocolMagic = Constants.LEGACY_TESTNET_PROTOCOL_MAGIC; - } - - if (slot != 0 && StringUtils.hasLength(blockHash)) - wellKnownPoint = new Point(slot, blockHash); - else - wellKnownPoint = Constants.WELL_KNOWN_TESTNET_POINT; } else if ("preprod".equals(network)) { if (!StringUtils.hasLength(host)) { host = Constants.PREPROD_IOHK_RELAY_ADDR; diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalProtocolParamSupplier.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalProtocolParamSupplier.java index c93b42ac..2fe79572 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalProtocolParamSupplier.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalProtocolParamSupplier.java @@ -62,10 +62,10 @@ public ProtocolParams getProtocolParams() { protocolParams.setPoolDeposit(String.valueOf(protocolParamUpdate.getPoolDeposit())); protocolParams.setEMax(protocolParamUpdate.getMaxEpoch()); protocolParams.setNOpt(protocolParamUpdate.getNOpt()); - protocolParams.setA0(protocolParamUpdate.getPoolPledgeInfluence()); - protocolParams.setRho(protocolParamUpdate.getExpansionRate()); - protocolParams.setTau(protocolParamUpdate.getTreasuryGrowthRate()); - protocolParams.setDecentralisationParam(protocolParamUpdate.getDecentralisationParam()); //Deprecated. Not there + protocolParams.setA0(protocolParamUpdate.getPoolPledgeInfluence() != null? protocolParamUpdate.getPoolPledgeInfluence().safeRatio(): null); + protocolParams.setRho(protocolParamUpdate.getExpansionRate() != null? protocolParamUpdate.getExpansionRate().safeRatio(): null); + protocolParams.setTau(protocolParamUpdate.getTreasuryGrowthRate() != null? protocolParamUpdate.getTreasuryGrowthRate().safeRatio(): null); + protocolParams.setDecentralisationParam(protocolParamUpdate.getDecentralisationParam() != null? protocolParamUpdate.getDecentralisationParam().safeRatio(): null); //Deprecated. Not there //protocolParams.setExtraEntropy(protocolParamUpdate.getExtraEntropy()); //TODO protocolParams.setProtocolMajorVer(protocolParamUpdate.getProtocolMajorVer()); protocolParams.setProtocolMinorVer(protocolParamUpdate.getProtocolMinorVer()); @@ -90,8 +90,8 @@ public ProtocolParams getProtocolParams() { protocolParams.setCostModels(costModels); - protocolParams.setPriceMem(protocolParamUpdate.getPriceMem()); - protocolParams.setPriceStep(protocolParamUpdate.getPriceStep()); + protocolParams.setPriceMem(protocolParamUpdate.getPriceMem() != null? protocolParamUpdate.getPriceMem().safeRatio(): null); + protocolParams.setPriceStep(protocolParamUpdate.getPriceStep() != null? protocolParamUpdate.getPriceStep().safeRatio(): null); protocolParams.setMaxTxExMem(String.valueOf(protocolParamUpdate.getMaxTxExMem())); protocolParams.setMaxTxExSteps(String.valueOf(protocolParamUpdate.getMaxTxExSteps())); protocolParams.setMaxBlockExMem(String.valueOf(protocolParamUpdate.getMaxBlockExMem())); diff --git a/applications/cli/src/main/resources/application.yml b/applications/cli/src/main/resources/application.yml index 1a5864dc..cafbb323 100644 --- a/applications/cli/src/main/resources/application.yml +++ b/applications/cli/src/main/resources/application.yml @@ -12,11 +12,15 @@ spring: location: classpath:/banner.txt devtools: add-properties:logging: false + shell: + interactive: + enabled: true ai: mcp: server: name: yaci-devkit version: 0.1.0 + protocol: STATELESS logging: level: diff --git a/applications/cli/src/main/resources/logback-spring.xml b/applications/cli/src/main/resources/logback-spring.xml index 48237cbd..c0baa8a7 100644 --- a/applications/cli/src/main/resources/logback-spring.xml +++ b/applications/cli/src/main/resources/logback-spring.xml @@ -8,9 +8,9 @@ ${LOG_FILE} - - - + ${LOG_FILE}.%i + 1 + 20 10MB @@ -21,6 +21,22 @@ %clr(%d){faint} %clr(${PID:- }){magenta} %clr([%15.15t]){magenta} %clr(%-5p) %clr(%-40c{40}){cyan} - %m%n + + + + + + + + + + + + + + + + diff --git a/mcp.json.example b/mcp.json.example index fc429501..d868beb7 100644 --- a/mcp.json.example +++ b/mcp.json.example @@ -1,7 +1,7 @@ { "mcpServers": { "yaci-devkit": { - "url": "http://localhost:10000/sse" + "url": "http://localhost:10000/mcp" } } } From 6b36cb813a381ecbea2b5bdf814c56b1fdea4ea9 Mon Sep 17 00:00:00 2001 From: Satya Date: Mon, 6 Apr 2026 21:39:34 +0800 Subject: [PATCH 2/2] chore: default protocol version to 10, auto-select Plutus cost models, fix springdoc compatibility - Change default protocol version from 11 to 10 for Conway era devnets - Add protocolMajorVer to ClusterInfo for persisting resolved version - Auto-select plutus-costmodels-v10.json or plutus-costmodels-v11.json based on protocolMajorVer - Upgrade springdoc-openapi from 2.5.0 to 2.8.6 to fix Swagger UI with Spring Boot 3.5.x - Update Earthfile, docker-compose, and docker config for versioned cost model files --- applications/cli/.dockerignore | 2 +- applications/cli/Earthfile | 21 +- applications/cli/build.gradle | 6 +- .../cli/config/application.properties | 3 + applications/cli/config/download.properties | 10 +- applications/cli/config/node.properties | 4 +- .../cli/config/plutus-costmodels-v10.json | 646 ++++++++++++++++++ .../cli/config/plutus-costmodels-v11.json | 73 ++ .../cli/docker/application.properties | 2 +- applications/cli/docker/download-amd64.sh | 4 +- applications/cli/docker/download-arm64.sh | 4 +- applications/cli/docker/download-ogmios.sh | 2 +- .../commands/common/DownloadService.java | 14 +- .../yacicli/localcluster/ClusterInfo.java | 2 + .../yacicli/localcluster/ClusterService.java | 15 +- .../localcluster/config/GenesisConfig.java | 28 + .../localcluster/service/AccountService.java | 49 +- .../service/LocalNodeService.java | 213 ++++++ .../service/LocalProtocolParamSupplier.java | 13 +- .../genesis-templates/alonzo-genesis.json | 13 +- .../genesis-templates/conway-genesis.json | 48 +- .../devnet/genesis-templates/spec/config.json | 1 + .../templates/devnet/submit-api-config.yaml | 106 +-- .../devnet/templates/configuration.json | 1 + .../devnet/templates/configuration.yaml | 1 + config/version | 2 +- scripts/docker-compose.yml | 2 + 27 files changed, 1101 insertions(+), 184 deletions(-) create mode 100644 applications/cli/config/plutus-costmodels-v10.json create mode 100644 applications/cli/config/plutus-costmodels-v11.json diff --git a/applications/cli/.dockerignore b/applications/cli/.dockerignore index 0312f06b..a70be4c4 100644 --- a/applications/cli/.dockerignore +++ b/applications/cli/.dockerignore @@ -3,4 +3,4 @@ build/libs/yaci-cli-*-plain.jar yaci-store-*-sources.jar yaci-store-*-plain.jar yaci-store-*-javadoc.jar - +wallet-ui/node_modules/ diff --git a/applications/cli/Earthfile b/applications/cli/Earthfile index fc57a66a..6efa85f1 100644 --- a/applications/cli/Earthfile +++ b/applications/cli/Earthfile @@ -1,5 +1,14 @@ VERSION 0.8 +wallet-ui-build: + FROM node:20-slim + WORKDIR /app + COPY wallet-ui/package.json wallet-ui/package-lock.json ./ + RUN npm ci + COPY wallet-ui/ ./ + RUN npx vite build --outDir dist + SAVE ARTIFACT dist /wallet + cli-java: ARG EARTHLY_TARGET_NAME ARG EARTHLY_GIT_SHORT_HASH @@ -7,6 +16,7 @@ cli-java: FROM eclipse-temurin:21 COPY . . + COPY +wallet-ui-build/wallet src/main/resources/static/wallet RUN echo git.commit.id.abbrev=${EARTHLY_GIT_SHORT_HASH} > src/main/resources/git.properties RUN cat src/main/resources/git.properties @@ -22,6 +32,7 @@ cli-native: FROM ghcr.io/graalvm/graalvm-community:21 COPY . . + COPY +wallet-ui-build/wallet src/main/resources/static/wallet RUN echo git.commit.id.abbrev=${EARTHLY_GIT_SHORT_HASH} > src/main/resources/git.properties RUN cat src/main/resources/git.properties @@ -49,8 +60,8 @@ java-setup: docker-build: FROM ubuntu:22.04 ENV JAVA_HOME=/opt/java/openjdk - ENV STORE_VERSION=0.1.0 - ENV STORE_NATIVE_BRANCH=release/2.0.0-beta3 + ENV STORE_VERSION=2.0.0 + ENV STORE_NATIVE_BRANCH=release/2.0.x ARG TARGETOS ARG TARGETARCH @@ -94,7 +105,9 @@ docker-build: RUN mkdir -p /app/store/config COPY docker/store-application.properties /app/store/config/application.properties - RUN wget https://github.com/bloxbean/yaci-store/releases/download/v${STORE_VERSION}/yaci-store-all-${STORE_VERSION}.jar -O /app/store/yaci-store.jar + RUN wget https://github.com/bloxbean/yaci-store/releases/download/v${STORE_VERSION}/yaci-store-${STORE_VERSION}.zip -O /app/store/yaci-store.zip + RUN unzip /app/store/yaci-store.zip -d /app/store/ + RUN cp /app/store/yaci-store-${STORE_VERSION}/yaci-store.jar /app/store/yaci-store.jar RUN echo ${APP_VERSION} > /app/version @@ -116,6 +129,8 @@ docker-build: RUN mkdir -p /app/config COPY docker/application.properties /app/config/ + COPY docker/plutus-costmodels-v10.json /app/config/ + COPY docker/plutus-costmodels-v11.json /app/config/ ENV PATH="$PATH:/app/cardano-bin" ENV CARDANO_NODE_SOCKET_PATH=/clusters/nodes/default/node/node.sock diff --git a/applications/cli/build.gradle b/applications/cli/build.gradle index 511a74e4..e665dd9c 100644 --- a/applications/cli/build.gradle +++ b/applications/cli/build.gradle @@ -34,7 +34,7 @@ dependencies { implementation 'org.springframework.shell:spring-shell-starter' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.ai:spring-ai-starter-mcp-server-webmvc' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.6' implementation 'org.springframework.boot:spring-boot-starter-logging' implementation 'org.springframework.boot:spring-boot-starter-mustache' @@ -102,6 +102,7 @@ tasks.register('walletUiInstall', Exec) { commandLine 'bash', '-c', 'npm install' inputs.file('wallet-ui/package.json') outputs.dir('wallet-ui/node_modules') + onlyIf { !file('src/main/resources/static/wallet/index.html').exists() } } tasks.register('walletUiBuild', Exec) { @@ -114,6 +115,7 @@ tasks.register('walletUiBuild', Exec) { inputs.file('wallet-ui/vite.config.ts') inputs.file('wallet-ui/tailwind.config.cjs') outputs.dir('src/main/resources/static/wallet') + onlyIf { !file('src/main/resources/static/wallet/index.html').exists() } } processResources { @@ -137,7 +139,7 @@ task cliZip(type: Zip) { from('config') { into(configDir) - include '**/*.properties' + include '**/*.properties', '**/*.json' } include 'yaci-cli*' diff --git a/applications/cli/config/application.properties b/applications/cli/config/application.properties index b56712ac..07a0d6e4 100644 --- a/applications/cli/config/application.properties +++ b/applications/cli/config/application.properties @@ -7,6 +7,9 @@ server.port=10000 #Default is the user_home/.yaci-cli #yaci.cli.home=/Users/satya/yacicli +#Path to directory containing Plutus cost models JSON files (plutus-costmodels-v10.json, plutus-costmodels-v11.json) +yaci.cli.plutus-costmodels-path=./config + ogmios.enabled=false kupo.enabled=false yaci.store.enabled=false diff --git a/applications/cli/config/download.properties b/applications/cli/config/download.properties index 63830bd9..ba46dda2 100644 --- a/applications/cli/config/download.properties +++ b/applications/cli/config/download.properties @@ -1,11 +1,11 @@ #Please specify either the version or the full url for the following components -node.version=10.5.0 -ogmios.version=6.13.0 +node.version=10.6.2 +ogmios.version=6.14.0 kupo.version=2.11.0 -yaci.store.tag=rel-native-2.0.0-beta3 -yaci.store.version=2.0.0-beta3 -yaci.store.jar.version=2.0.0-beta3 +yaci.store.tag=rel-native-2.0.0 +yaci.store.version=2.0.0 +yaci.store.jar.version=2.0.0 #node.url= #ogmios.url= diff --git a/applications/cli/config/node.properties b/applications/cli/config/node.properties index d5a3d7c4..02f65ae1 100644 --- a/applications/cli/config/node.properties +++ b/applications/cli/config/node.properties @@ -65,7 +65,9 @@ #dvtPPGovGroup=0.51f #dvtTreasuryWithdrawal=0.51f -#committeeMinSize=0 +committeeMinSize=0 +ccThresholdNumerator=0 +ccThresholdDenominator=1 #committeeMaxTermLength=200 #govActionLifetime=10 #govActionDeposit=1000000000 diff --git a/applications/cli/config/plutus-costmodels-v10.json b/applications/cli/config/plutus-costmodels-v10.json new file mode 100644 index 00000000..f07d0a17 --- /dev/null +++ b/applications/cli/config/plutus-costmodels-v10.json @@ -0,0 +1,646 @@ +{ + "PlutusV1": [ + 100788, + 420, + 1, + 1, + 1000, + 173, + 0, + 1, + 1000, + 59957, + 4, + 1, + 11183, + 32, + 201305, + 8356, + 4, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 100, + 100, + 16000, + 100, + 94375, + 32, + 132994, + 32, + 61462, + 4, + 72010, + 178, + 0, + 1, + 22151, + 32, + 91189, + 769, + 4, + 2, + 85848, + 228465, + 122, + 0, + 1, + 1, + 1000, + 42921, + 4, + 2, + 24548, + 29498, + 38, + 1, + 898148, + 27279, + 1, + 51775, + 558, + 1, + 39184, + 1000, + 60594, + 1, + 141895, + 32, + 83150, + 32, + 15299, + 32, + 76049, + 1, + 13169, + 4, + 22100, + 10, + 28999, + 74, + 1, + 28999, + 74, + 1, + 43285, + 552, + 1, + 44749, + 541, + 1, + 33852, + 32, + 68246, + 32, + 72362, + 32, + 7243, + 32, + 7391, + 32, + 11546, + 32, + 85848, + 228465, + 122, + 0, + 1, + 1, + 90434, + 519, + 0, + 1, + 74433, + 32, + 85848, + 228465, + 122, + 0, + 1, + 1, + 85848, + 228465, + 122, + 0, + 1, + 1, + 270652, + 22588, + 4, + 1457325, + 64566, + 4, + 20467, + 1, + 4, + 0, + 141992, + 32, + 100788, + 420, + 1, + 1, + 81663, + 32, + 59498, + 32, + 20142, + 32, + 24588, + 32, + 20744, + 32, + 25933, + 32, + 24623, + 32, + 53384111, + 14333, + 10 + ], + "PlutusV2": [ + 100788, + 420, + 1, + 1, + 1000, + 173, + 0, + 1, + 1000, + 59957, + 4, + 1, + 11183, + 32, + 201305, + 8356, + 4, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 100, + 100, + 16000, + 100, + 94375, + 32, + 132994, + 32, + 61462, + 4, + 72010, + 178, + 0, + 1, + 22151, + 32, + 91189, + 769, + 4, + 2, + 85848, + 228465, + 122, + 0, + 1, + 1, + 1000, + 42921, + 4, + 2, + 24548, + 29498, + 38, + 1, + 898148, + 27279, + 1, + 51775, + 558, + 1, + 39184, + 1000, + 60594, + 1, + 141895, + 32, + 83150, + 32, + 15299, + 32, + 76049, + 1, + 13169, + 4, + 22100, + 10, + 28999, + 74, + 1, + 28999, + 74, + 1, + 43285, + 552, + 1, + 44749, + 541, + 1, + 33852, + 32, + 68246, + 32, + 72362, + 32, + 7243, + 32, + 7391, + 32, + 11546, + 32, + 85848, + 228465, + 122, + 0, + 1, + 1, + 90434, + 519, + 0, + 1, + 74433, + 32, + 85848, + 228465, + 122, + 0, + 1, + 1, + 85848, + 228465, + 122, + 0, + 1, + 1, + 955506, + 213312, + 0, + 2, + 270652, + 22588, + 4, + 1457325, + 64566, + 4, + 20467, + 1, + 4, + 0, + 141992, + 32, + 100788, + 420, + 1, + 1, + 81663, + 32, + 59498, + 32, + 20142, + 32, + 24588, + 32, + 20744, + 32, + 25933, + 32, + 24623, + 32, + 43053543, + 10, + 53384111, + 14333, + 10, + 43574283, + 26308, + 10 + ], + "PlutusV3": [ + 100788, + 420, + 1, + 1, + 1000, + 173, + 0, + 1, + 1000, + 59957, + 4, + 1, + 11183, + 32, + 201305, + 8356, + 4, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 16000, + 100, + 100, + 100, + 16000, + 100, + 94375, + 32, + 132994, + 32, + 61462, + 4, + 72010, + 178, + 0, + 1, + 22151, + 32, + 91189, + 769, + 4, + 2, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 1, + 1000, + 42921, + 4, + 2, + 24548, + 29498, + 38, + 1, + 898148, + 27279, + 1, + 51775, + 558, + 1, + 39184, + 1000, + 60594, + 1, + 141895, + 32, + 83150, + 32, + 15299, + 32, + 76049, + 1, + 13169, + 4, + 22100, + 10, + 28999, + 74, + 1, + 28999, + 74, + 1, + 43285, + 552, + 1, + 44749, + 541, + 1, + 33852, + 32, + 68246, + 32, + 72362, + 32, + 7243, + 32, + 7391, + 32, + 11546, + 32, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 90434, + 519, + 0, + 1, + 74433, + 32, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 1, + 85848, + 123203, + 7305, + -900, + 1716, + 549, + 57, + 85848, + 0, + 1, + 955506, + 213312, + 0, + 2, + 270652, + 22588, + 4, + 1457325, + 64566, + 4, + 20467, + 1, + 4, + 0, + 141992, + 32, + 100788, + 420, + 1, + 1, + 81663, + 32, + 59498, + 32, + 20142, + 32, + 24588, + 32, + 20744, + 32, + 25933, + 32, + 24623, + 32, + 43053543, + 10, + 53384111, + 14333, + 10, + 43574283, + 26308, + 10, + 16000, + 100, + 16000, + 100, + 962335, + 18, + 2780678, + 6, + 442008, + 1, + 52538055, + 3756, + 18, + 267929, + 18, + 76433006, + 8868, + 18, + 52948122, + 18, + 1995836, + 36, + 3227919, + 12, + 901022, + 1, + 166917843, + 4307, + 36, + 284546, + 36, + 158221314, + 26549, + 36, + 74698472, + 36, + 333849714, + 1, + 254006273, + 72, + 2174038, + 72, + 2261318, + 64571, + 4, + 207616, + 8310, + 4, + 1293828, + 28716, + 63, + 0, + 1, + 1006041, + 43623, + 251, + 0, + 1, + 100181, + 726, + 719, + 0, + 1, + 100181, + 726, + 719, + 0, + 1, + 100181, + 726, + 719, + 0, + 1, + 107878, + 680, + 0, + 1, + 95336, + 1, + 281145, + 18848, + 0, + 1, + 180194, + 159, + 1, + 1, + 158519, + 8942, + 0, + 1, + 159378, + 8813, + 0, + 1, + 107490, + 3298, + 1, + 106057, + 655, + 1, + 1964219, + 24520, + 3 + ] +} diff --git a/applications/cli/config/plutus-costmodels-v11.json b/applications/cli/config/plutus-costmodels-v11.json new file mode 100644 index 00000000..cc725ecd --- /dev/null +++ b/applications/cli/config/plutus-costmodels-v11.json @@ -0,0 +1,73 @@ +{ + "PlutusV1": [ + 100788, 420, 1, 1, 1000, 173, 0, 1, 1000, 59957, + 4, 1, 11183, 32, 201305, 8356, 4, 16000, 100, 16000, + 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 100, + 100, 16000, 100, 94375, 32, 132994, 32, 61462, 4, 72010, + 178, 0, 1, 22151, 32, 91189, 769, 4, 2, 85848, + 228465, 122, 0, 1, 1, 1000, 42921, 4, 2, 24548, + 29498, 38, 1, 898148, 27279, 1, 51775, 558, 1, 39184, + 1000, 60594, 1, 141895, 32, 83150, 32, 15299, 32, 76049, + 1, 13169, 4, 22100, 10, 28999, 74, 1, 28999, 74, + 1, 43285, 552, 1, 44749, 541, 1, 33852, 32, 68246, + 32, 72362, 32, 7243, 32, 7391, 32, 11546, 32, 85848, + 228465, 122, 0, 1, 1, 90434, 519, 0, 1, 74433, + 32, 85848, 228465, 122, 0, 1, 1, 85848, 228465, 122, + 0, 1, 1, 270652, 22588, 4, 1457325, 64566, 4, 20467, + 1, 4, 0, 141992, 32, 100788, 420, 1, 1, 81663, + 32, 59498, 32, 20142, 32, 24588, 32, 20744, 32, 25933, + 32, 24623, 32, 53384111, 14333, 10 + ], + "PlutusV2": [ + 100788, 420, 1, 1, 1000, 173, 0, 1, 1000, 59957, + 4, 1, 11183, 32, 201305, 8356, 4, 16000, 100, 16000, + 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 100, + 100, 16000, 100, 94375, 32, 132994, 32, 61462, 4, 72010, + 178, 0, 1, 22151, 32, 91189, 769, 4, 2, 85848, + 228465, 122, 0, 1, 1, 1000, 42921, 4, 2, 24548, + 29498, 38, 1, 898148, 27279, 1, 51775, 558, 1, 39184, + 1000, 60594, 1, 141895, 32, 83150, 32, 15299, 32, 76049, + 1, 13169, 4, 22100, 10, 28999, 74, 1, 28999, 74, + 1, 43285, 552, 1, 44749, 541, 1, 33852, 32, 68246, + 32, 72362, 32, 7243, 32, 7391, 32, 11546, 32, 85848, + 228465, 122, 0, 1, 1, 90434, 519, 0, 1, 74433, + 32, 85848, 228465, 122, 0, 1, 1, 85848, 228465, 122, + 0, 1, 1, 955506, 213312, 0, 2, 270652, 22588, 4, + 1457325, 64566, 4, 20467, 1, 4, 0, 141992, 32, 100788, + 420, 1, 1, 81663, 32, 59498, 32, 20142, 32, 24588, + 32, 20744, 32, 25933, 32, 24623, 32, 43053543, 10, 53384111, + 14333, 10, 43574283, 26308, 10 + ], + "PlutusV3": [ + 100788, 420, 1, 1, 1000, 173, 0, 1, 1000, 59957, + 4, 1, 11183, 32, 201305, 8356, 4, 16000, 100, 16000, + 100, 16000, 100, 16000, 100, 16000, 100, 16000, 100, 100, + 100, 16000, 100, 94375, 32, 132994, 32, 61462, 4, 72010, + 178, 0, 1, 22151, 32, 91189, 769, 4, 2, 85848, + 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, 1, + 1000, 42921, 4, 2, 24548, 29498, 38, 1, 898148, 27279, + 1, 51775, 558, 1, 39184, 1000, 60594, 1, 141895, 32, + 83150, 32, 15299, 32, 76049, 1, 13169, 4, 22100, 10, + 28999, 74, 1, 28999, 74, 1, 43285, 552, 1, 44749, + 541, 1, 33852, 32, 68246, 32, 72362, 32, 7243, 32, + 7391, 32, 11546, 32, 85848, 123203, 7305, -900, 1716, 549, + 57, 85848, 0, 1, 90434, 519, 0, 1, 74433, 32, + 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, 1, + 1, 85848, 123203, 7305, -900, 1716, 549, 57, 85848, 0, + 1, 955506, 213312, 0, 2, 270652, 22588, 4, 1457325, 64566, + 4, 20467, 1, 4, 0, 141992, 32, 100788, 420, 1, + 1, 81663, 32, 59498, 32, 20142, 32, 24588, 32, 20744, + 32, 25933, 32, 24623, 32, 43053543, 10, 53384111, 14333, 10, + 43574283, 26308, 10, 16000, 100, 16000, 100, 962335, 18, 2780678, + 6, 442008, 1, 52538055, 3756, 18, 267929, 18, 76433006, 8868, + 18, 52948122, 18, 1995836, 36, 3227919, 12, 901022, 1, 166917843, + 4307, 36, 284546, 36, 158221314, 26549, 36, 74698472, 36, 333849714, + 1, 254006273, 72, 2174038, 72, 2261318, 64571, 4, 207616, 8310, + 4, 1293828, 28716, 63, 0, 1, 1006041, 43623, 251, 0, + 1, 100181, 726, 719, 0, 1, 100181, 726, 719, 0, + 1, 100181, 726, 719, 0, 1, 107878, 680, 0, 1, + 95336, 1, 281145, 18848, 0, 1, 180194, 159, 1, 1, + 158519, 8942, 0, 1, 159378, 8813, 0, 1, 107490, 3298, + 1, 106057, 655, 1, 1964219, 24520, 3 + ] +} diff --git a/applications/cli/docker/application.properties b/applications/cli/docker/application.properties index 9e80581f..9de797f0 100644 --- a/applications/cli/docker/application.properties +++ b/applications/cli/docker/application.properties @@ -8,4 +8,4 @@ local.cluster.home=/clusters/nodes pool.keys.home=/clusters/pool-keys spring.shell.config.location=/clusters server.port=10000 - +yaci.cli.plutus-costmodels-path=/app/config diff --git a/applications/cli/docker/download-amd64.sh b/applications/cli/docker/download-amd64.sh index cdbdb738..05921d9d 100644 --- a/applications/cli/docker/download-amd64.sh +++ b/applications/cli/docker/download-amd64.sh @@ -1,5 +1,5 @@ -file=cardano-node-10.5.0-linux.tar.gz -wget https://github.com/IntersectMBO/cardano-node/releases/download/10.5.0/cardano-node-10.5.0-linux.tar.gz +file=cardano-node-10.6.2-linux-amd64.tar.gz +wget https://github.com/IntersectMBO/cardano-node/releases/download/10.6.2/cardano-node-10.6.2-linux-amd64.tar.gz mkdir /app/cardano-bin diff --git a/applications/cli/docker/download-arm64.sh b/applications/cli/docker/download-arm64.sh index 0d81adef..86866201 100755 --- a/applications/cli/docker/download-arm64.sh +++ b/applications/cli/docker/download-arm64.sh @@ -1,5 +1,5 @@ -file=cardano-10_5_0-aarch64-static-musl-ghc_9101.tar.zst -dir=cardano-10_5_0-aarch64-static-musl-ghc_9101 +file=cardano-10_6_2-aarch64-static-musl-ghc_9122.tar.zst +dir=cardano-10_5_0-aarch64-static-musl-ghc_9122 wget https://github.com/armada-alliance/cardano-node-binaries/raw/main/static-binaries/$file?raw=true -O - | tar -I zstd -xv #unzip $file diff --git a/applications/cli/docker/download-ogmios.sh b/applications/cli/docker/download-ogmios.sh index 53c80546..93f34bd9 100644 --- a/applications/cli/docker/download-ogmios.sh +++ b/applications/cli/docker/download-ogmios.sh @@ -15,7 +15,7 @@ case $1 in esac -version=v6.13.0 +version=v6.14.0 file=ogmios-${version}-${SUFFIX}-linux.zip wget https://github.com/CardanoSolutions/ogmios/releases/download/${version}/$file diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/commands/common/DownloadService.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/commands/common/DownloadService.java index 1c13f7ad..28d210d8 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/commands/common/DownloadService.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/commands/common/DownloadService.java @@ -483,10 +483,22 @@ private String resolveNodeDownloadPath() { writeLn(error("Unsupported OS : " + System.getProperty("os.name"))); } + String arch = System.getProperty("os.arch"); + String cpuArch = null; + if (arch.startsWith("aarch") || arch.startsWith("arm")) { + cpuArch = "arm64"; + } else{ + cpuArch = "amd64"; + } + + //Just a workaround, as 10.6.2 macos arm binary is not working. + if (osPrefix.equals("macos")) + cpuArch = "amd64"; + if (osPrefix == null) return null; - String url = NODE_DOWNLOAD_URL + "/" + nodeVersion + "/cardano-node-" + nodeVersion + "-" + osPrefix + ".tar.gz"; + String url = NODE_DOWNLOAD_URL + "/" + nodeVersion + "/cardano-node-" + nodeVersion + "-" + osPrefix + "-" + cpuArch + ".tar.gz"; return url; } diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/ClusterInfo.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/ClusterInfo.java index 8f1cc14c..7ced1e90 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/ClusterInfo.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/ClusterInfo.java @@ -43,6 +43,8 @@ public class ClusterInfo { @Builder.Default private int prometheusPort=12798; + private int protocolMajorVer; + private boolean localMultiNodeEnabled; private int localMultiNodeStakeRatioFactor; } diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/ClusterService.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/ClusterService.java index 5b93fccf..93733695 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/ClusterService.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/ClusterService.java @@ -343,10 +343,13 @@ private void updateGenesis(Path clusterFolder, String clusterName, ClusterInfo c srcConwayGenesisFile = clusterFolder.resolve("genesis-templates").resolve("conway-genesis.json"); } + Path srcDijkstraGenesisFile = clusterFolder.resolve("genesis-templates").resolve("dijkstra-genesis.json"); + Path destByronGenesisFile = clusterFolder.resolve("node").resolve("genesis").resolve("byron-genesis.json"); Path destShelleyGenesisFile = clusterFolder.resolve("node").resolve("genesis").resolve("shelley-genesis.json"); Path destAlonzoGenesisFile = clusterFolder.resolve("node").resolve("genesis").resolve("alonzo-genesis.json"); Path destConwayGenesisFile = clusterFolder.resolve("node").resolve("genesis").resolve("conway-genesis.json"); + Path destDijkstraGenesisFile = clusterFolder.resolve("node").resolve("genesis").resolve("dijkstra-genesis.json"); GenesisConfig genesisConfigCopy = genesisConfig.copy(); genesisConfigCopy.merge(customGenesisConfig.getMap()); @@ -375,11 +378,14 @@ private void updateGenesis(Path clusterFolder, String clusterName, ClusterInfo c values.put("activeSlotsCoeff", String.valueOf(activeSlotsCoeff)); values.put("epochLength", String.valueOf(epochLength)); - //Check if protocol version should be minimun 9 and it's conway era - if (era == Era.Conway && genesisConfigCopy.getProtocolMajorVer() < 9) { - values.put("protocolMajorVer", 10); - values.put("protocolMinorVer", 2); + //Check if protocol version should be minimum 9 and it's conway era + int resolvedProtocolMajorVer = genesisConfigCopy.getProtocolMajorVer(); + if (era == Era.Conway && resolvedProtocolMajorVer < 9) { + resolvedProtocolMajorVer = 10; + values.put("protocolMajorVer", resolvedProtocolMajorVer); + values.put("protocolMinorVer", 0); } + clusterInfo.setProtocolMajorVer(resolvedProtocolMajorVer); //Derive security param long securityParam = genesisConfigCopy.getSecurityParam(); @@ -407,6 +413,7 @@ private void updateGenesis(Path clusterFolder, String clusterName, ClusterInfo c templateEngineHelper.replaceValues(srcShelleyGenesisFile, destShelleyGenesisFile, values); templateEngineHelper.replaceValues(srcAlonzoGenesisFile, destAlonzoGenesisFile, values); templateEngineHelper.replaceValues(srcConwayGenesisFile, destConwayGenesisFile, values); + templateEngineHelper.replaceValues(srcDijkstraGenesisFile, destDijkstraGenesisFile, values); } catch (Exception e) { throw new IOException(e); } diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/config/GenesisConfig.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/config/GenesisConfig.java index 4d20b6fd..c736563c 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/config/GenesisConfig.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/config/GenesisConfig.java @@ -247,6 +247,12 @@ public class GenesisConfig { ); + //Dijkstra + private long maxRefScriptSizePerBlock = 1048576; + private long maxRefScriptSizePerTx = 204800; + private long refScriptCostStride = 25600; + private double refScriptCostMultiplier = 1.2; + //Introduced for the issue https://github.com/bloxbean/yaci-devkit/issues/65 private int conwayHardForkAtEpoch = 0; private boolean shiftStartTimeBehind = false; @@ -437,6 +443,12 @@ public Map getConfigMap() { map.put("conwayHardForkAtEpoch", conwayHardForkAtEpoch); map.put("shiftStartTimeBehind", shiftStartTimeBehind); + //Dijkstra + map.put("maxRefScriptSizePerBlock", maxRefScriptSizePerBlock); + map.put("maxRefScriptSizePerTx", maxRefScriptSizePerTx); + map.put("refScriptCostStride", refScriptCostStride); + map.put("refScriptCostMultiplier", refScriptCostMultiplier); + return map; } @@ -529,6 +541,12 @@ public GenesisConfig copy() { genesisConfig.setConwayHardForkAtEpoch(conwayHardForkAtEpoch); genesisConfig.setShiftStartTimeBehind(shiftStartTimeBehind); + //Dijkstra + genesisConfig.setMaxRefScriptSizePerBlock(maxRefScriptSizePerBlock); + genesisConfig.setMaxRefScriptSizePerTx(maxRefScriptSizePerTx); + genesisConfig.setRefScriptCostStride(refScriptCostStride); + genesisConfig.setRefScriptCostMultiplier(refScriptCostMultiplier); + return genesisConfig; } @@ -639,6 +657,16 @@ public void merge(Map updatedValues) { shiftStartTimeBehind = Boolean.parseBoolean(updatedValues.get("shiftStartTimeBehind")); if (updatedValues.get("conwayHardForkAtEpoch") != null && !updatedValues.get("conwayHardForkAtEpoch").isEmpty()) conwayHardForkAtEpoch = Integer.parseInt(updatedValues.get("conwayHardForkAtEpoch")); + + //Dijkstra + if (updatedValues.get("maxRefScriptSizePerBlock") != null && !updatedValues.get("maxRefScriptSizePerBlock").isEmpty()) + maxRefScriptSizePerBlock = Long.parseLong(updatedValues.get("maxRefScriptSizePerBlock")); + if (updatedValues.get("maxRefScriptSizePerTx") != null && !updatedValues.get("maxRefScriptSizePerTx").isEmpty()) + maxRefScriptSizePerTx = Long.parseLong(updatedValues.get("maxRefScriptSizePerTx")); + if (updatedValues.get("refScriptCostStride") != null && !updatedValues.get("refScriptCostStride").isEmpty()) + refScriptCostStride = Long.parseLong(updatedValues.get("refScriptCostStride")); + if (updatedValues.get("refScriptCostMultiplier") != null && !updatedValues.get("refScriptCostMultiplier").isEmpty()) + refScriptCostMultiplier = Double.parseDouble(updatedValues.get("refScriptCostMultiplier")); } } diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/AccountService.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/AccountService.java index 6a340d47..f2d1da13 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/AccountService.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/AccountService.java @@ -6,12 +6,14 @@ import com.bloxbean.cardano.yacicli.commands.common.RootLogService; import com.bloxbean.cardano.yacicli.localcluster.ClusterService; import com.bloxbean.cardano.yacicli.localcluster.common.LocalClientProviderHelper; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import java.io.IOException; import java.math.BigInteger; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; import java.util.List; import java.util.Map; @@ -21,12 +23,31 @@ import static com.bloxbean.cardano.yacicli.util.ConsoleWriter.writeLn; @Component -@RequiredArgsConstructor @Slf4j public class AccountService { private final ClusterService clusterService; private final LocalClientProviderHelper localQueryClientUtil; private final RootLogService rootLogService; + private final Path plutusCostModelsBasePath; + + public AccountService(ClusterService clusterService, + LocalClientProviderHelper localQueryClientUtil, + RootLogService rootLogService, + @Value("${yaci.cli.plutus-costmodels-path:./config}") String plutusCostModelsBasePath) { + this.clusterService = clusterService; + this.localQueryClientUtil = localQueryClientUtil; + this.rootLogService = rootLogService; + this.plutusCostModelsBasePath = Paths.get(plutusCostModelsBasePath); + } + + private Path resolveCostModelsFile(String clusterName) throws IOException { + var clusterInfo = clusterService.getClusterInfo(clusterName); + int protocolMajorVer = clusterInfo.getProtocolMajorVer(); + String fileName = protocolMajorVer >= 11 + ? "plutus-costmodels-v11.json" + : "plutus-costmodels-v10.json"; + return plutusCostModelsBasePath.resolve(fileName); + } public boolean topup(String clusterName, Era era, String address, double adaValue, Consumer writer) { Level orgLevel = rootLogService.getLogLevel(); @@ -74,6 +95,30 @@ public boolean mint(String clusterName, Era era, String assetName, BigInteger qu } } + public boolean updateCostModels(String clusterName, Era era, Consumer writer) { + Level orgLevel = rootLogService.getLogLevel(); + if (!rootLogService.isDebugLevel()) + rootLogService.setLogLevel(Level.OFF); + + LocalNodeService localNodeService = null; + try { + Path clusterFolder = clusterService.getClusterFolder(clusterName); + localNodeService = new LocalNodeService(clusterFolder, era, localQueryClientUtil, writer); + + Path costModelsFile = resolveCostModelsFile(clusterName); + writer.accept("Using Plutus cost models file: " + costModelsFile.getFileName()); + return localNodeService.updateCostModels(costModelsFile, msg -> writeLn(msg)); + } catch (Exception e) { + log.error("Error", e); + writer.accept(error("Plutus cost models update error: " + e.getMessage())); + return false; + } finally { + rootLogService.setLogLevel(orgLevel); + if (localNodeService != null) + localNodeService.shutdown(); + } + } + public Map> getUtxosAtDefaultAccounts(String clusterName, Era era, Consumer writer) { Level orgLevel = rootLogService.getLogLevel(); if (!rootLogService.isDebugLevel()) diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalNodeService.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalNodeService.java index cac8b407..c3a257d6 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalNodeService.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalNodeService.java @@ -2,9 +2,11 @@ import com.bloxbean.cardano.client.address.Address; import com.bloxbean.cardano.client.address.AddressProvider; +import com.bloxbean.cardano.client.address.Credential; import com.bloxbean.cardano.client.api.ProtocolParamsSupplier; import com.bloxbean.cardano.client.api.UtxoSupplier; import com.bloxbean.cardano.client.api.model.Amount; +import com.bloxbean.cardano.client.api.model.Result; import com.bloxbean.cardano.client.api.model.Utxo; import com.bloxbean.cardano.client.cip.cip20.MessageMetadata; import com.bloxbean.cardano.client.common.model.Networks; @@ -19,14 +21,30 @@ import com.bloxbean.cardano.client.function.helper.AuxDataProviders; import com.bloxbean.cardano.client.function.helper.InputBuilders; import com.bloxbean.cardano.client.function.helper.SignerProviders; +import com.bloxbean.cardano.client.api.impl.StaticTransactionEvaluator; +import com.bloxbean.cardano.client.plutus.spec.CostMdls; +import com.bloxbean.cardano.client.plutus.spec.CostModel; +import com.bloxbean.cardano.client.plutus.spec.ExUnits; +import com.bloxbean.cardano.client.plutus.spec.Language; import com.bloxbean.cardano.client.plutus.spec.PlutusData; +import com.bloxbean.cardano.client.plutus.spec.PlutusV3Script; import com.bloxbean.cardano.client.quicktx.QuickTxBuilder; +import com.bloxbean.cardano.client.quicktx.ScriptTx; import com.bloxbean.cardano.client.quicktx.Tx; import com.bloxbean.cardano.client.transaction.spec.Asset; +import com.bloxbean.cardano.client.transaction.spec.ProtocolParamUpdate; import com.bloxbean.cardano.client.transaction.spec.Transaction; +import com.bloxbean.cardano.client.transaction.spec.governance.Anchor; +import com.bloxbean.cardano.client.transaction.spec.governance.DRep; +import com.bloxbean.cardano.client.transaction.spec.governance.Vote; +import com.bloxbean.cardano.client.transaction.spec.governance.Voter; +import com.bloxbean.cardano.client.transaction.spec.governance.VoterType; +import com.bloxbean.cardano.client.transaction.spec.governance.actions.GovActionId; +import com.bloxbean.cardano.client.transaction.spec.governance.actions.ParameterChangeAction; import com.bloxbean.cardano.client.transaction.spec.script.ScriptPubkey; import com.bloxbean.cardano.client.transaction.util.TransactionUtil; import com.bloxbean.cardano.client.util.HexUtil; +import com.fasterxml.jackson.core.type.TypeReference; import com.bloxbean.cardano.yaci.core.common.TxBodyType; import com.bloxbean.cardano.yaci.core.protocol.chainsync.messages.Point; import com.bloxbean.cardano.yaci.core.protocol.localstate.api.Era; @@ -264,6 +282,201 @@ public boolean mint(String assetName, BigInteger quntity, String receiver, Consu } } + public boolean updateCostModels(Path costModelsFile, Consumer writer) { + try { + // 1. Find a funded UTXO key (same pattern as topUp) + BigInteger minBalance = BigInteger.valueOf(2_000_000_000L); // 2000 ADA to cover deposit + fees + String senderAddress = null; + SecretKey senderSkey = null; + + int i = 0; + for (Map.Entry> entry : getFundsAtGenesisKeys().entrySet()) { + String address = entry.getKey(); + Optional amountOptional = entry.getValue().stream() + .flatMap(utxo -> utxo.getAmount().stream()) + .filter(amt -> LOVELACE.equals(amt.getUnit()) && amt.getQuantity().compareTo(minBalance) > 0) + .findAny(); + if (amountOptional.isPresent()) { + senderAddress = address; + senderSkey = utxoKeys.get(i)._2; + break; + } + i++; + } + + if (senderAddress == null) { + writer.accept(error("No funded UTXO key found for governance proposal")); + return false; + } + + // 2. Load cost models from external config file + Map costModelMap = loadCostModels(costModelsFile); + + // 3. Build the ProtocolParamUpdate with all available cost models + CostMdls costMdls = new CostMdls(); + Map languageMap = Map.of( + "PlutusV1", Language.PLUTUS_V1, + "PlutusV2", Language.PLUTUS_V2, + "PlutusV3", Language.PLUTUS_V3 + ); + for (Map.Entry entry2 : costModelMap.entrySet()) { + Language language = languageMap.get(entry2.getKey()); + if (language != null) { + costMdls.add(new CostModel(language, entry2.getValue())); + } else { + writer.accept(error("Unknown Plutus version in cost models file: " + entry2.getKey())); + } + } + + ProtocolParamUpdate protocolParamUpdate = ProtocolParamUpdate.builder() + .costModels(costMdls) + .build(); + + // 4. Build the always-true PlutusV3 guardrail script + // CBOR hex: 46450101002499 -> script hash: 186e32faa80a26810392fda6d559c7ed4721a65ce1c9d4ef3e1c87b4 + PlutusV3Script guardrailScript = PlutusV3Script.builder() + .type("PlutusScriptV3") + .cborHex("46450101002499") + .build(); + + // 5. Build the ParameterChangeAction + ParameterChangeAction paramChangeAction = ParameterChangeAction.builder() + .prevGovActionId(null) + .protocolParamUpdate(protocolParamUpdate) + .policyHash(guardrailScript.getScriptHash()) + .build(); + + // 6. Build dummy anchor + Anchor anchor = Anchor.builder() + .anchorUrl("https://devkit.yaci.xyz/plutus-costmodel-update.json") + .anchorDataHash(new byte[32]) // zeroed hash for devnet + .build(); + + // 7. Build a reward address from the sender's verification key for deposit return + var senderVkey = KeyGenUtil.getPublicKeyFromPrivateKey(senderSkey); + HdPublicKey hdPublicKey = new HdPublicKey(); + hdPublicKey.setKeyData(senderVkey.getBytes()); + Address rewardAddr = AddressProvider.getRewardAddress(hdPublicKey, Networks.testnet()); + String rewardAccount = rewardAddr.toBech32(); + + // 7a. Register stake credential for the reward address + writer.accept("Registering stake credential for governance proposal..."); + var regProcessor = new LocalTransactionProcessor(localClientProvider.getTxSubmissionClient(), TxBodyType.CONWAY); + Tx regTx = new Tx() + .registerStakeAddress(rewardAddr) + .from(senderAddress); + Result regResult = new QuickTxBuilder(utxoSupplier, protocolParamsSupplier, regProcessor) + .compose(regTx) + .withSigner(SignerProviders.signerFrom(senderSkey)) + .complete(); + + if (!regResult.isSuccessful()) { + writer.accept(error("Stake credential registration failed: " + regResult.getResponse())); + return false; + } + writer.accept(success("Stake credential registered. Tx# : " + regResult.getValue())); + waitForTx(senderAddress, regResult.getValue(), writer); + + // 7b. Register DRep and delegate voting power for governance voting + writer.accept("Registering DRep and delegating voting power..."); + byte[] credHash = rewardAddr.getDelegationCredentialHash() + .orElseThrow(() -> new RuntimeException("Failed to get delegation credential hash")); + String credHashHex = HexUtil.encodeHexString(credHash); + Credential drepCredential = Credential.fromKey(credHashHex); + + var drepProcessor = new LocalTransactionProcessor(localClientProvider.getTxSubmissionClient(), TxBodyType.CONWAY); + Tx drepTx = new Tx() + .registerDRep(drepCredential) + .delegateVotingPowerTo(rewardAddr, DRep.addrKeyHash(credHashHex)) + .from(senderAddress); + Result drepResult = new QuickTxBuilder(utxoSupplier, protocolParamsSupplier, drepProcessor) + .compose(drepTx) + .withSigner(SignerProviders.signerFrom(senderSkey)) + .complete(); + + if (!drepResult.isSuccessful()) { + writer.accept(error("DRep registration failed: " + drepResult.getResponse())); + return false; + } + writer.accept(success("DRep registered and voting power delegated. Tx# : " + drepResult.getValue())); + waitForTx(senderAddress, drepResult.getValue(), writer); + + // 8. Build and submit the governance proposal using ScriptTx + var transactionProcessor = new LocalTransactionProcessor(localClientProvider.getTxSubmissionClient(), TxBodyType.CONWAY); + + ScriptTx scriptTx = new ScriptTx() + .createProposal(paramChangeAction, rewardAccount, anchor, PlutusData.unit()) + .attachProposingValidator(guardrailScript); + + // Use StaticTransactionEvaluator with fixed ex units for the always-true guardrail script + // since LocalTransactionProcessor doesn't support evaluateTx + var staticEvaluator = new StaticTransactionEvaluator( + List.of(ExUnits.builder() + .mem(BigInteger.valueOf(500000)) + .steps(BigInteger.valueOf(200000000)) + .build())); + + Result result = new QuickTxBuilder(utxoSupplier, protocolParamsSupplier, transactionProcessor) + .compose(scriptTx) + .feePayer(senderAddress) + .withSigner(SignerProviders.signerFrom(senderSkey)) + .withTxEvaluator(staticEvaluator) + .complete(); + + if (!result.isSuccessful()) { + writer.accept(error("Plutus cost models governance proposal failed: " + result.getResponse())); + return false; + } + + writer.accept(success("Plutus cost models governance proposal submitted. Tx# : " + result.getValue())); + + // 9. Vote YES on the proposal as DRep + writer.accept("Voting YES on Plutus cost models proposal..."); + waitForTx(senderAddress, result.getValue(), writer); + + Voter voter = Voter.builder() + .type(VoterType.DREP_KEY_HASH) + .credential(drepCredential) + .build(); + GovActionId govActionId = GovActionId.builder() + .transactionId(result.getValue()) + .govActionIndex(0) + .build(); + + var voteProcessor = new LocalTransactionProcessor(localClientProvider.getTxSubmissionClient(), TxBodyType.CONWAY); + Tx voteTx = new Tx() + .createVote(voter, govActionId, Vote.YES) + .from(senderAddress); + Result voteResult = new QuickTxBuilder(utxoSupplier, protocolParamsSupplier, voteProcessor) + .compose(voteTx) + .withSigner(SignerProviders.signerFrom(senderSkey)) + .complete(); + + if (!voteResult.isSuccessful()) { + writer.accept(error("DRep vote on proposal failed: " + voteResult.getResponse())); + return false; + } + writer.accept(success("DRep voted YES on Plutus cost models proposal. Tx# : " + voteResult.getValue())); + writer.accept(info("Plutus cost models will be enacted at the next epoch boundary.")); + return true; + + } catch (Exception e) { + log.error("Failed to submit Plutus cost models governance proposal", e); + writer.accept(error("Plutus cost models update failed: " + e.getMessage())); + return false; + } + } + + private Map loadCostModels(Path costModelsFile) throws IOException { + Map> raw = objectMapper.readValue(costModelsFile.toFile(), + new TypeReference>>() {}); + Map result = new HashMap<>(); + for (Map.Entry> entry : raw.entrySet()) { + result.put(entry.getKey(), entry.getValue().stream().mapToLong(Long::longValue).toArray()); + } + return result; + } + private boolean waitForTx(String receiver, String txHash, Consumer writer) { int count = 0; while (true) { diff --git a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalProtocolParamSupplier.java b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalProtocolParamSupplier.java index 2fe79572..f1c8a052 100644 --- a/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalProtocolParamSupplier.java +++ b/applications/cli/src/main/java/com/bloxbean/cardano/yacicli/localcluster/service/LocalProtocolParamSupplier.java @@ -78,7 +78,7 @@ public ProtocolParams getProtocolParams() { LinkedHashMap plutusV2CostModel = cborToCostModel(protocolParamUpdate.getCostModels().get(1), PlutusOps.getOperations(2)); LinkedHashMap plutusV3CostModel = null; - if (era == Era.Conway) { + if (era.getValue() >= Era.Conway.getValue()) { plutusV3CostModel = cborToCostModel(protocolParamUpdate.getCostModels().get(2), PlutusOps.getOperations(3)); } @@ -100,6 +100,17 @@ public ProtocolParams getProtocolParams() { protocolParams.setCollateralPercent(BigDecimal.valueOf(protocolParamUpdate.getCollateralPercent())); protocolParams.setMaxCollateralInputs(protocolParamUpdate.getMaxCollateralInputs()); protocolParams.setCoinsPerUtxoSize(String.valueOf(protocolParamUpdate.getAdaPerUtxoByte())); + + // Conway governance parameters + if (era.getValue() >= Era.Conway.getValue()) { + protocolParams.setGovActionDeposit(protocolParamUpdate.getGovActionDeposit()); + protocolParams.setDrepDeposit(protocolParamUpdate.getDrepDeposit()); + protocolParams.setDrepActivity(protocolParamUpdate.getDrepActivity()); + protocolParams.setCommitteeMinSize(protocolParamUpdate.getCommitteeMinSize()); + protocolParams.setCommitteeMaxTermLength(protocolParamUpdate.getCommitteeMaxTermLength()); + protocolParams.setGovActionLifetime(protocolParamUpdate.getGovActionLifetime()); + } + return protocolParams; } diff --git a/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/alonzo-genesis.json b/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/alonzo-genesis.json index 65771d96..ae7ee4c6 100644 --- a/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/alonzo-genesis.json +++ b/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/alonzo-genesis.json @@ -344,18 +344,7 @@ 10, 43574283, 26308, - 10{{^shiftStartTimeBehind}}, - 9999999999999, - 9999999999999, - 9999999999999, - 9999999999999, - 9999999999999, - 9999999999999, - 9999999999999, - 9999999999999, - 9999999999999, - 9999999999999 - {{/shiftStartTimeBehind}} + 10 ] }, diff --git a/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/conway-genesis.json b/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/conway-genesis.json index 4c069fab..d1208417 100644 --- a/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/conway-genesis.json +++ b/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/conway-genesis.json @@ -276,53 +276,7 @@ 43623, 251, 0, - 1, - 100181, - 726, - 719, - 0, - 1, - 100181, - 726, - 719, - 0, - 1, - 100181, - 726, - 719, - 0, - 1, - 107878, - 680, - 0, - 1, - 95336, - 1, - 281145, - 18848, - 0, - 1, - 180194, - 159, - 1, - 1, - 158519, - 8942, - 0, - 1, - 159378, - 8813, - 0, - 1, - 107490, - 3298, - 1, - 106057, - 655, - 1, - 1964219, - 24520, - 3 + 1 ], "constitution": { "anchor": { diff --git a/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/spec/config.json b/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/spec/config.json index be0ae270..70ec386b 100644 --- a/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/spec/config.json +++ b/applications/cli/src/main/resources/localcluster/templates/devnet/genesis-templates/spec/config.json @@ -3,6 +3,7 @@ "ShelleyGenesisFile": "shelley-genesis.json", "AlonzoGenesisFile": "alonzo-genesis.json", "ConwayGenesisFile": "conway-genesis.json", + "DijkstraGenesisFile": "dijkstra-genesis.json", "ApplicationName": "cardano-sl", "ApplicationVersion": 0, "LastKnownBlockVersion-Alt": 0, diff --git a/applications/cli/src/main/resources/localcluster/templates/devnet/submit-api-config.yaml b/applications/cli/src/main/resources/localcluster/templates/devnet/submit-api-config.yaml index 83529bf0..aa700b66 100644 --- a/applications/cli/src/main/resources/localcluster/templates/devnet/submit-api-config.yaml +++ b/applications/cli/src/main/resources/localcluster/templates/devnet/submit-api-config.yaml @@ -1,100 +1,10 @@ # Tx Submission Server Configuration -EnableLogMetrics: False -EnableLogging: True - -# ------------------------------------------------------------------------------ -# Logging configuration follows. - -# global filter; messages must have at least this severity to pass: -minSeverity: Info - -# global file rotation settings: -rotation: - rpLogLimitBytes: 5000000 - rpKeepFilesNum: 10 - rpMaxAgeHours: 24 - -# these backends are initialized: -setupBackends: - - AggregationBK - - KatipBK - # - EditorBK - # - EKGViewBK - -# if not indicated otherwise, then messages are passed to these backends: -defaultBackends: - - KatipBK - -# if wanted, the GUI is listening on this port: -# hasGUI: 12787 - -# if wanted, the EKG interface is listening on this port: -# hasEKG: 12788 - -# here we set up outputs of logging in 'katip': -setupScribes: - - scKind: StdoutSK - scName: stdout - scFormat: ScText - scRotation: null - -# if not indicated otherwise, then log output is directed to this: -defaultScribes: - - - StdoutSK - - stdout - -# more options which can be passed as key-value pairs: -options: - cfokey: - value: "Release-1.0.0" - mapSubtrace: - benchmark: - contents: - - GhcRtsStats - - MonotonicClock - subtrace: ObservableTrace - '#ekgview': - contents: - - - tag: Contains - contents: 'cardano.epoch-validation.benchmark' - - - tag: Contains - contents: .monoclock.basic. - - - tag: Contains - contents: 'cardano.epoch-validation.benchmark' - - - tag: Contains - contents: diff.RTS.cpuNs.timed. - - - tag: StartsWith - contents: '#ekgview.#aggregation.cardano.epoch-validation.benchmark' - - - tag: Contains - contents: diff.RTS.gcNum.timed. - subtrace: FilterTrace - 'cardano.epoch-validation.utxo-stats': - # Change the `subtrace` value to `Neutral` in order to log - # `UTxO`-related messages during epoch validation. - subtrace: NoTrace - '#messagecounters.aggregation': - subtrace: NoTrace - '#messagecounters.ekgview': - subtrace: NoTrace - '#messagecounters.switchboard': - subtrace: NoTrace - '#messagecounters.katip': - subtrace: NoTrace - '#messagecounters.monitoring': - subtrace: NoTrace - 'cardano.#messagecounters.aggregation': - subtrace: NoTrace - 'cardano.#messagecounters.ekgview': - subtrace: NoTrace - 'cardano.#messagecounters.switchboard': - subtrace: NoTrace - 'cardano.#messagecounters.katip': - subtrace: NoTrace - 'cardano.#messagecounters.monitoring': - subtrace: NoTrace - mapBackends: - cardano.epoch-validation.benchmark: - - AggregationBK - '#aggregation.cardano.epoch-validation.benchmark': - - EKGViewBK +UseTraceDispatcher: True + +TraceOptions: + "": + severity: Notice + detail: DNormal + backends: + - Stdout HumanFormatColoured diff --git a/applications/cli/src/main/resources/localcluster/templates/devnet/templates/configuration.json b/applications/cli/src/main/resources/localcluster/templates/devnet/templates/configuration.json index 750fa1e5..15be04c1 100644 --- a/applications/cli/src/main/resources/localcluster/templates/devnet/templates/configuration.json +++ b/applications/cli/src/main/resources/localcluster/templates/devnet/templates/configuration.json @@ -2,6 +2,7 @@ "AlonzoGenesisFile": "./genesis/alonzo-genesis.json", "ByronGenesisFile": "./genesis/byron-genesis.json", "ConwayGenesisFile": "./genesis/conway-genesis.json", + "DijkstraGenesisFile": "./genesis/dijkstra-genesis.json", "EnableP2P": {{enableP2P}}, "LastKnownBlockVersion-Alt": 0, "LastKnownBlockVersion-Major": {{#mainnet}}2{{/mainnet}}{{^mainnet}}2{{/mainnet}}, diff --git a/applications/cli/src/main/resources/localcluster/templates/devnet/templates/configuration.yaml b/applications/cli/src/main/resources/localcluster/templates/devnet/templates/configuration.yaml index 11dd5dac..2b03942c 100644 --- a/applications/cli/src/main/resources/localcluster/templates/devnet/templates/configuration.yaml +++ b/applications/cli/src/main/resources/localcluster/templates/devnet/templates/configuration.yaml @@ -9,6 +9,7 @@ ByronGenesisFile: ./genesis/byron-genesis.json ShelleyGenesisFile: ./genesis/shelley-genesis.json AlonzoGenesisFile: ./genesis/alonzo-genesis.json ConwayGenesisFile: ./genesis/conway-genesis.json +DijkstraGenesisFile: ./genesis/dijkstra-genesis.json SocketPath: db/node.socket EnableP2P: {{enableP2P}} diff --git a/config/version b/config/version index f0644cc5..aae83034 100644 --- a/config/version +++ b/config/version @@ -1,2 +1,2 @@ -tag=0.11.0-beta1 +tag=0.11.0-beta2-dev revision= diff --git a/scripts/docker-compose.yml b/scripts/docker-compose.yml index f63b7f99..14d28d34 100644 --- a/scripts/docker-compose.yml +++ b/scripts/docker-compose.yml @@ -13,6 +13,8 @@ services: volumes: - cluster-data:/clusters - ../config/node.properties:/app/config/node.properties + - ../config/plutus-costmodels-v10.json:/app/config/plutus-costmodels-v10.json + - ../config/plutus-costmodels-v11.json:/app/config/plutus-costmodels-v11.json env_file: - ../config/env - ../config/node.properties