Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d77ec38
fix: enable peer discovery by default.
Oct 2, 2025
7cff2c3
chore: disable peer discovery by default
Oct 28, 2025
ea5a95e
fix: add Ouroboros Genesis support for Cardano Node 10.5.1+ (#637)
matiwinnetou Oct 30, 2025
de6ce72
chore: upgrade to version 2.0.0-beta with yaci-store 2.0.0-beta4
matiwinnetou Oct 29, 2025
0702298
refactor: cardano-rosetta schema instead of network specific schema (…
matiwinnetou Oct 29, 2025
98f0a34
chore: upgrade PostgreSQL from 14.11 to 18.0 (#426)
matiwinnetou Oct 29, 2025
c56e490
refactor: finalize single Docker deployment removal (#635)
matiwinnetou Oct 29, 2025
1832fe3
fix: adjust pool retirement epoch to work with fresh devkit chains
Oct 30, 2025
6ce3f00
docs: add H2 database connection documentation for test data
Oct 30, 2025
4f68b11
feat: limit and randomize peer discovery to 25 peers
Nov 4, 2025
fb888ff
chore: disable PEER_DISCOVERY by default for mainnet
Nov 4, 2025
8fc598c
chore: bump version to 2.0.0
Nov 4, 2025
67b091d
fix: grant schema privileges to database user for PostgreSQL 15+
matiwinnetou Nov 4, 2025
e15720c
chore: revert version to 2.0.0-beta
Nov 4, 2025
e9c364d
chore: regenerate JOOQ classes from database schema (#643)
matiwinnetou Nov 5, 2025
3b85f7e
fix: removal of specific db schema
Nov 5, 2025
d6bdffa
feat: update search indices to use tx_index for proper transaction or…
Nov 5, 2025
99d2e4c
refactor: remove duplicate transaction index on block_hash and tx_index
Nov 6, 2025
cb7aad0
chore: 2.1.0 beta versions
Nov 5, 2025
da62f24
fix: implement support for tx_index column from Yaci-Store 2.0.0-beta…
Nov 5, 2025
b748d04
refactor: operations service refactoring plus unit tests.
Nov 14, 2025
45c05cd
test: fix duplicate DRep vote delegation operations in golden files
Nov 14, 2025
d298f0c
test: fix duplicate operations in golden files and add operation
linconvidal Nov 18, 2025
2662b12
ci: make construction API test failures fail the preprod tests workflow
linconvidal Nov 18, 2025
d59b99c
feat: sort operations by index and add unit test
Nov 21, 2025
9778ea5
Merge remote-tracking branch 'origin/main' into develop
Nov 25, 2025
38d1b52
Merge remote-tracking branch 'origin/main' into develop3
Nov 25, 2025
512799d
chore: yaci-store beta5 upgrade.
Nov 25, 2025
121b0ee
tests: disabled tests for postman collection as we now have tests fro…
Nov 25, 2025
9de4f61
refactor: operations parsing refak (#649)
matiwinnetou Nov 25, 2025
2b7196c
Merge remote-tracking branch 'origin/develop3' into develop
Nov 25, 2025
7669e32
feat: enable CBOR transaction body in yaci-store configuration
Nov 26, 2025
f6bf7c3
Merge remote-tracking branch 'origin/develop3' into develop
Nov 26, 2025
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
8 changes: 4 additions & 4 deletions .env.IntegrationTest
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ NETWORK=devkit
PROTOCOL_MAGIC=42

## Postgres image
PG_VERSION_TAG=REL_14_11
PG_VERSION_TAG=REL_18_0

## Yaci image
YACI_VERSION=0.10.5
Expand All @@ -16,10 +16,10 @@ DB_SECRET=weakpwd#123_d
DB_HOST=db
# Service name in docker-compose or local db
DB_PORT=5432
DB_SCHEMA=${NETWORK}
DB_SCHEMA=public
DB_PATH=data
UPDATE_GENESIS_BLOCK_QUERY="UPDATE devkit.block SET number = 0 WHERE number = -1; UPDATE devkit.block SET prev_hash = 'Genesis' WHERE number = 1"
#UPDATE_GENESIS_BLOCK_QUERY="UPDATE devkit.block SET prev_hash = 'Genesis' WHERE number = 1"
UPDATE_GENESIS_BLOCK_QUERY="UPDATE \"public\".block SET number = 0 WHERE number = -1; UPDATE \"public\".block SET prev_hash = 'Genesis' WHERE number = 1"
#UPDATE_GENESIS_BLOCK_QUERY="UPDATE \"public\".block SET prev_hash = 'Genesis' WHERE number = 1"

## Cardano Node variables
CARDANO_NODE_HOST=yaci-cli
Expand Down
4 changes: 2 additions & 2 deletions .env.docker-compose
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ PROTOCOL_MAGIC=764824073
# mainnet 764824073, preprod 1, preview 2, devkit 42

## Postgres image
PG_VERSION_TAG=REL_14_11
PG_VERSION_TAG=REL_18_0

## Postgres variables
DB_NAME=rosetta-java
Expand All @@ -16,7 +16,7 @@ DB_SECRET=weakpwd#123_d
DB_HOST=db
# Service name in docker-compose or local db
DB_PORT=5432
DB_SCHEMA=${NETWORK}
DB_SCHEMA=public
DB_PATH=data

## Cardano Node variables
Expand Down
4 changes: 2 additions & 2 deletions .env.docker-compose-preprod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ PROTOCOL_MAGIC=1
# mainnet 764824073, preprod 1, preview 2, devkit 42

## Postgres image
PG_VERSION_TAG=REL_14_11
PG_VERSION_TAG=REL_18_0

## Postgres variables
DB_NAME=rosetta-java
Expand All @@ -16,7 +16,7 @@ DB_SECRET=weakpwd#123_d
DB_HOST=db
# Service name in docker-compose or local db
DB_PORT=5432
DB_SCHEMA=${NETWORK}
DB_SCHEMA=public
DB_PATH=/opt/rosetta-java-preprod/sql_data

## Cardano Node variables
Expand Down
10 changes: 5 additions & 5 deletions .env.h2
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ API_PORT=8082
PRINT_EXCEPTION=true

ROSETTA_VERSION=1.4.13
TOPOLOGY_FILEPATH=./config/${NETWORK}/topology.json
GENESIS_SHELLEY_PATH=./config/${NETWORK}/shelley-genesis.json
GENESIS_BYRON_PATH=./config/${NETWORK}/byron-genesis.json
GENESIS_ALONZO_PATH=./config/${NETWORK}/alonzo-genesis.json
GENESIS_CONWAY_PATH=./config/${NETWORK}/conway-genesis.json
TOPOLOGY_FILEPATH=./config/node/${NETWORK}/topology.json
GENESIS_SHELLEY_PATH=./config/node/${NETWORK}/shelley-genesis.json
GENESIS_BYRON_PATH=./config/node/${NETWORK}/byron-genesis.json
GENESIS_ALONZO_PATH=./config/node/${NETWORK}/alonzo-genesis.json
GENESIS_CONWAY_PATH=./config/node/${NETWORK}/conway-genesis.json
SEARCH_LIMIT=100

## Yaci Indexer env
Expand Down
10 changes: 5 additions & 5 deletions .env.h2-testdata
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ API_PORT=8082
PRINT_EXCEPTION=true

ROSETTA_VERSION=1.4.13
TOPOLOGY_FILEPATH=./config/${NETWORK}/topology.json
GENESIS_SHELLEY_PATH=./config/${NETWORK}/shelley-genesis.json
GENESIS_BYRON_PATH=./config/${NETWORK}/byron-genesis.json
GENESIS_ALONZO_PATH=./config/${NETWORK}/alonzo-genesis.json
GENESIS_CONWAY_PATH=./config/${NETWORK}/conway-genesis.json
TOPOLOGY_FILEPATH=./config/node/${NETWORK}/topology.json
GENESIS_SHELLEY_PATH=./config/node/${NETWORK}/shelley-genesis.json
GENESIS_BYRON_PATH=./config/node/${NETWORK}/byron-genesis.json
GENESIS_ALONZO_PATH=./config/node/${NETWORK}/alonzo-genesis.json
GENESIS_CONWAY_PATH=./config/node/${NETWORK}/conway-genesis.json
SEARCH_LIMIT=100

## Yaci Indexer env
Expand Down
14 changes: 3 additions & 11 deletions .github/actions/build_docker_images/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,19 +133,11 @@ runs:
tags: cardanofoundation/cardano-rosetta-java-mithril:${{ steps.envver.outputs.mithril_version }}
push: true

- name: All-in-one - Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ./docker/Dockerfile
tags: cardanofoundation/cardano-rosetta-java:${{ inputs.tag }}
push: true

- name: All-in-one - Build and push Docker latest image
- name: Mithril - Build and push Docker latest image
uses: docker/build-push-action@v4
if: ${{ inputs.isRelease == 'true' }}
with:
context: .
file: ./docker/Dockerfile
tags: cardanofoundation/cardano-rosetta-java:latest
file: ./docker/dockerfiles/mithril/Dockerfile
tags: cardanofoundation/cardano-rosetta-java-mithril:latest
push: true
8 changes: 6 additions & 2 deletions .github/workflows/integration-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,27 @@ jobs:
python-version: '3.12'
- name: "Install uv"
run: curl -LsSf https://astral.sh/uv/install.sh | sh

# - name: "Install mesh-cli"
# run: curl -sSfL https://raw.githubusercontent.com/coinbase/mesh-cli/master/scripts/install.sh | sh -s

# https://github.com/coinbase/mesh-cli/issues/422
- name: "Install mesh-cli"
run: curl -sSfL https://raw.githubusercontent.com/coinbase/mesh-cli/v0.10.3/scripts/install.sh | sed -e 's/^REPO=.*/REPO=mesh-cli/' | sh -s

- name: "Run tests"
run: newman run ./postmanTests/rosetta-java.postman_collection.json -e postmanTests/Rosetta-java-env.postman_environment.json -r cli
# - name: "Run tests"
# run: newman run ./postmanTests/rosetta-java.postman_collection.json -e postmanTests/Rosetta-java-env.postman_environment.json -r cli

- name: "Run construction API tests with schema validation"
run: |
cd ./tests/integration
~/.local/bin/uv run test_construction_api.py \
-u http://localhost:8082 \
--network-id devkit \
--openapi ../../api/src/main/resources/rosetta-specifications-1.4.15/api.yaml

- name: "Run rosetta check:data tests"
run: ./bin/rosetta-cli check:data --configuration-file ./rosetta-cli-tests/data/byron_sample.json

- name: "Tear down environment"
run: docker compose --env-file .env.IntegrationTest -f docker-integration-test-environment.yaml down
5 changes: 2 additions & 3 deletions .github/workflows/pr-preprod-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,8 @@ jobs:
# Output test result
echo "construction_result=${CONSTRUCTION_RESULT:-0}" >> $GITHUB_OUTPUT

# Don't fail the whole job if construction tests fail
# These are informational for now
exit 0
# Fail if construction tests failed
exit ${CONSTRUCTION_RESULT:-0}
env:
ROSETTA_URL: http://localhost:8082
CARDANO_NETWORK: preprod
Expand Down
26 changes: 15 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,25 @@ cd api && mvn spring-boot:run
mvn clean package
```

### Docker Commands
### Docker Compose Commands
```bash
# Build from source
docker build -t rosetta-java -f ./docker/Dockerfile .
# Start all services (full stack)
docker compose --env-file .env.docker-compose --env-file .env.docker-compose-profile-mid-level up -d

# Run with docker-compose (full stack)
docker-compose up -d

# Run specific services
docker-compose up -d api indexer postgres
# Start specific services
docker compose up -d cardano-node db
docker compose up -d api yaci-indexer

# View logs
docker logs rosetta -f
docker exec rosetta tail -f /logs/node.log
docker exec rosetta tail -f /logs/indexer.log
docker compose logs -f api
docker compose logs -f yaci-indexer
docker compose logs -f cardano-node

# Stop all services
docker compose down

# Restart a service
docker compose restart api
```

## Architecture Overview
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import java.math.BigInteger;
import java.util.*;

import static org.cardanofoundation.rosetta.common.util.Constants.ADA;
import static org.cardanofoundation.rosetta.common.util.Constants.ADA_DECIMALS;

@Component
@RequiredArgsConstructor
public class AccountMapperUtil {
Expand Down Expand Up @@ -76,7 +79,7 @@ public List<Coin> mapUtxosToCoins(List<Utxo> utxos,
Amt adaAsset = utxo.getAmounts().stream()
.filter(amt -> Constants.LOVELACE.equals(amt.getUnit()))
.findFirst()
.orElseGet(() -> new Amt(null, Constants.ADA, BigInteger.ZERO));
.orElseGet(() -> new Amt(null, ADA, BigInteger.ZERO));

String coinIdentifier = "%s:%d".formatted(utxo.getTxHash(), utxo.getOutputIndex());

Expand Down Expand Up @@ -144,8 +147,8 @@ private static int getDecimalsWithFallback(@NotNull TokenRegistryCurrencyData me

private CurrencyResponse getAdaCurrency() {
return CurrencyResponse.builder()
.symbol(Constants.ADA)
.decimals(Constants.ADA_DECIMALS)
.symbol(ADA)
.decimals(ADA_DECIMALS)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.math.BigInteger;
import java.util.List;
import jakarta.annotation.Nullable;
import jakarta.persistence.Column;
import jakarta.persistence.ConstraintMode;
import jakarta.persistence.Entity;
Expand Down Expand Up @@ -50,6 +51,10 @@ public class TxnEntity {
@Column(name = "fee")
private BigInteger fee;

@Column(name = "tx_index")
@Nullable
private Integer txIndex;

@OneToMany(mappedBy = "txHash")
private List<TxScriptEntity> script;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public List<TxnEntity> findTransactionsByBlockHash(String blockHash) {
TRANSACTION.OUTPUTS,
TRANSACTION.FEE,
TRANSACTION.SLOT,
TRANSACTION.TX_INDEX,
BLOCK.HASH.as("joined_block_hash"),
BLOCK.NUMBER.as("joined_block_number"),
BLOCK.SLOT.as("joined_block_slot"),
Expand All @@ -133,6 +134,7 @@ public List<TxnEntity> findTransactionsByBlockHash(String blockHash) {
.leftJoin(BLOCK).on(TRANSACTION.BLOCK_HASH.eq(BLOCK.HASH))
.leftJoin(TRANSACTION_SIZE).on(TRANSACTION.TX_HASH.eq(TRANSACTION_SIZE.TX_HASH))
.where(TRANSACTION.BLOCK_HASH.eq(blockHash))
.orderBy(TRANSACTION.TX_INDEX.asc())
.fetch(queryBuilder::mapRecordToTxnEntity);
}

Expand Down Expand Up @@ -182,12 +184,12 @@ protected int executeCountQuery(Condition conditions, @Nullable Boolean isSucces
* Ensures count and results queries use identical conditions and JOINs.
* Currency conditions use EXISTS subqueries - no JOIN needed.
*/
protected List<? extends org.jooq.Record> executeResultsQuery(Condition conditions,
@Nullable Boolean isSuccess,
protected List<? extends org.jooq.Record> executeResultsQuery(Condition conditions,
@Nullable Boolean isSuccess,
OffsetBasedPageRequest offsetBasedPageRequest) {
return buildBaseResultsQuery(isSuccess)
.where(conditions)
.orderBy(TRANSACTION.SLOT.desc())
.orderBy(TRANSACTION.SLOT.desc(), TRANSACTION.TX_INDEX.desc())
.limit(offsetBasedPageRequest.getLimit())
.offset(offsetBasedPageRequest.getOffset())
.fetch();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@ public interface CurrencyConditionBuilder {
Condition buildCurrencyCondition(Currency currency);
}

public SelectJoinStep<Record11<String, String, JSONB, JSONB, Long, Long, String, Long, Long, Integer, Integer>> buildTransactionSelectQuery(DSLContext dsl) {
public SelectJoinStep<Record12<String, String, JSONB, JSONB, Long, Long, Integer, String, Long, Long, Integer, Integer>> buildTransactionSelectQuery(DSLContext dsl) {
return dsl.select(
TRANSACTION.TX_HASH,
TRANSACTION.BLOCK_HASH,
TRANSACTION.INPUTS,
TRANSACTION.OUTPUTS,
TRANSACTION.FEE,
TRANSACTION.SLOT,
TRANSACTION.TX_INDEX,
BLOCK.HASH.as("joined_block_hash"),
BLOCK.NUMBER.as("joined_block_number"),
BLOCK.SLOT.as("joined_block_slot"),
Expand Down Expand Up @@ -161,6 +162,8 @@ public TxnEntity mapRecordToTxnEntity(org.jooq.Record record) {
@Nullable BigInteger fee = Optional.ofNullable(record.get(TRANSACTION.FEE))
.map(BigInteger::valueOf).orElse(null);

@Nullable Integer txIndex = record.get(TRANSACTION.TX_INDEX);

@Nullable BlockEntity blockEntity = null;
String blockHashFromRecord = record.get("joined_block_hash", String.class);
if (blockHashFromRecord != null) {
Expand All @@ -178,6 +181,7 @@ public TxnEntity mapRecordToTxnEntity(org.jooq.Record record) {
.inputKeys(readUtxoKeys(inputs, txHash))
.outputKeys(readUtxoKeys(outputs, txHash))
.fee(fee)
.txIndex(txIndex)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public class CardanoConstructionServiceImpl implements CardanoConstructionServic

private final LedgerBlockService ledgerBlockService;
private final ProtocolParamService protocolParamService;
private final OperationService operationService;
private final TransactionOperationParser transactionOperationParser;
private final RestTemplate restTemplate;
private final OfflineSlotService offlineSlotService;

Expand All @@ -89,22 +89,27 @@ public class CardanoConstructionServiceImpl implements CardanoConstructionServic
@Override
public TransactionParsed parseTransaction(Network network, String transaction, boolean signed) {
Array decodeTransaction = decodeTransaction(transaction);

try {
TransactionData convertedTr = CborArrayToTransactionData.convert(decodeTransaction, signed);
List<Operation> operations = operationService.getOperationsFromTransactionData(convertedTr, network);
List<Operation> operations = transactionOperationParser.getOperationsFromTransactionData(convertedTr, network);
List<AccountIdentifier> accountIdentifierSigners = new ArrayList<>();

if (signed) {
log.info("[parseSignedTransaction] About to get signatures from parsed transaction");
List<String> accumulator = convertedTr.transactionExtraData().operations().stream()
.map(o -> operationService.getSignerFromOperation(network, o))
.map(o -> transactionOperationParser.getSignerFromOperation(network, o))
.flatMap(List::stream)
.toList();

accountIdentifierSigners = getUniqueAccountIdentifiers(accumulator);
}

return new TransactionParsed(operations, accountIdentifierSigners);
} catch (CborException | CborDeserializationException | CborSerializationException error) {
log.error("{} [parseTransaction] Cant instantiate transaction from transaction bytes",
error.getMessage(), error);

throw ExceptionFactory.invalidTransactionError();
}
}
Expand Down Expand Up @@ -624,7 +629,7 @@ private TransactionBody deserializeTransactionBody(String unsignedTransaction) {
private List<AccountIdentifier> getUniqueAccountIdentifiers(List<String> addresses) {
return new HashSet<>(addresses)
.stream()
.map(s -> new AccountIdentifier(s, null, null))
.map(address -> new AccountIdentifier(address, null, null))
.toList();
}

Expand Down
Loading
Loading