From 77e1033029eb7c93c26510ca723f91c9426e66c1 Mon Sep 17 00:00:00 2001 From: shleger Date: Thu, 21 Mar 2024 15:24:27 +0800 Subject: [PATCH] feat: RA-43 Refactoring and testing /block endpoint [no final asserts] (#88) * feat: RA-43 added h2 config and maven profile, implement BlockApi * feat: RA-43 refactored findBlock method, added to pom assertj and modelmapper * feat: RA-43 pull main * feat: RA-43 add exception and test * feat: RA-43 rename and reformat * feat: RA-43 add tests * feat: RA-43 add tests * feat: RA-43 extract bean to h2 configuration * feat: RA-43 merge with master * feat: RA-43 reformat * feat: RA-43 pull main with merge errors in BlockToBlockResponse.java OperationDataMapper.java PoolRegistration.java * feat: RA-43 fix merger with main * feat: RA-43 h2 run OK * feat: RA-43 rm @Slf4j from configuration bean --- .env.h2 | 45 ++ api/api.iml | 10 - api/pom.xml | 54 +- .../rosetta/RosettaApiApplication.java | 66 +- .../repository/AddressBalanceRepository.java | 2 +- .../service/impl/AccountServiceImpl.java | 49 +- .../block/controller/BlockApiDelegate.java | 55 -- ...eImplementation.java => BlockApiImpl.java} | 38 +- .../block/mapper/BlockToBlockResponse.java | 129 ++++ .../api/block/mapper/OperationDataMapper.java | 292 +++++++++ .../rosetta/api/block/model/domain/Block.java | 4 +- .../api/block/model/domain/BlockHeader.java | 25 + .../api/block/model/domain/BlockMetadata.java | 19 + .../block/model/domain/PoolRegistration.java | 2 +- .../block/model/entity/BlockAwareEntity.java | 19 +- .../block/model/entity/DelegationEntity.java | 44 +- .../api/block/model/entity/DelegationId.java | 12 +- .../block/model/entity/EpochParamEntity.java | 47 +- .../model/entity/PoolRegistrationEnity.java | 84 +-- .../model/entity/PoolRegistrationId.java | 13 +- .../model/entity/PoolRetirementEntity.java | 41 +- .../block/model/entity/PoolRetirementId.java | 12 +- .../block/model/entity/ProtocolParams.java | 400 ++++++------ .../entity/StakeAddressBalanceEntity.java | 40 +- .../model/entity/StakeAddressBalanceId.java | 17 +- .../model/entity/StakeRegistrationEntity.java | 51 +- .../model/entity/StakeRegistrationId.java | 12 +- .../api/block/model/entity/TxInputEntity.java | 48 +- .../api/block/model/entity/TxOuput.java | 18 +- .../block/model/entity/TxScriptEntity.java | 78 ++- .../api/block/model/entity/TxnEntity.java | 127 ++-- .../api/block/model/entity/UtxoKey.java | 16 +- .../model/repository/BlockRepository.java | 33 +- .../repository/DelegationRepository.java | 9 +- .../repository/EpochParamRepository.java | 9 +- .../PoolRegistrationRepository.java | 12 +- .../repository/PoolRetirementRepository.java | 12 +- .../repository/StakeAddressRepository.java | 17 +- .../StakeRegistrationRepository.java | 12 +- .../block/model/repository/TxRepository.java | 4 +- .../api/block/service/BlockService.java | 18 +- .../api/block/service/BlockServiceImpl.java | 144 +++++ .../block/service/impl/BlockServiceImpl.java | 178 ----- .../common/annotation/OpenApiMapper.java | 22 + .../common/annotation/PersistenceMapper.java | 22 + .../common/exception/ApiException.java | 6 +- .../rosetta/common/mapper/DataMapper.java | 62 -- .../common/mapper/OperationDataMapper.java | 268 -------- .../services/impl/CardanoServiceImpl.java | 8 +- ...ressUtil.java => CardanoAddressUtils.java} | 10 +- .../common/util/ParseConstructionUtil.java | 12 +- .../common/util/ProcessContructionUtil.java | 8 +- .../common/util/ValidateParseUtil.java | 22 +- .../resources/config/application-devh2.yaml | 126 ++++ .../block/controller/BlockApiImplTest.java | 26 + .../mapper/BlockToBlockResponseTest.java | 68 ++ .../service/impl/BlockServiceImplTest.java | 187 ++++++ .../common/util/CardanoAddressUtilTest.java | 44 +- pom.xml | 17 + style/idea-code-style.xml | 609 ++++++++++++++++++ yaci-indexer/pom.xml | 16 + .../rosetta/yaciindexer/ConfigurationH2.java | 31 + .../yaciindexer/YaciIndexerApplication.java | 8 +- 63 files changed, 2634 insertions(+), 1255 deletions(-) create mode 100644 .env.h2 delete mode 100644 api/api.iml delete mode 100644 api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiDelegate.java rename api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/{BlockApiDelegateImplementation.java => BlockApiImpl.java} (50%) create mode 100644 api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/BlockToBlockResponse.java create mode 100644 api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/OperationDataMapper.java create mode 100644 api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockHeader.java create mode 100644 api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockMetadata.java create mode 100644 api/src/main/java/org/cardanofoundation/rosetta/api/block/service/BlockServiceImpl.java delete mode 100644 api/src/main/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImpl.java create mode 100644 api/src/main/java/org/cardanofoundation/rosetta/common/annotation/OpenApiMapper.java create mode 100644 api/src/main/java/org/cardanofoundation/rosetta/common/annotation/PersistenceMapper.java delete mode 100644 api/src/main/java/org/cardanofoundation/rosetta/common/mapper/OperationDataMapper.java rename api/src/main/java/org/cardanofoundation/rosetta/common/util/{CardanoAddressUtil.java => CardanoAddressUtils.java} (97%) create mode 100644 api/src/main/resources/config/application-devh2.yaml create mode 100644 api/src/test/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiImplTest.java create mode 100644 api/src/test/java/org/cardanofoundation/rosetta/api/block/mapper/BlockToBlockResponseTest.java create mode 100644 api/src/test/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImplTest.java create mode 100644 style/idea-code-style.xml create mode 100644 yaci-indexer/src/main/java/org/cardanofoundation/rosetta/yaciindexer/ConfigurationH2.java diff --git a/.env.h2 b/.env.h2 new file mode 100644 index 000000000..3c6791b1d --- /dev/null +++ b/.env.h2 @@ -0,0 +1,45 @@ +#Use envfile plugin for IDEA +#https://plugins.jetbrains.com/plugin/7861-envfile + +API_SPRING_PROFILES_ACTIVE=devh2 + +NETWORK=devkit # devkit, mainnet, testnet, preprod +PROTOCOL_MAGIC=42 + +#common env +DB_ADMIN_USER_NAME=rosetta_db_admin +DB_ADMIN_USER_SECRET=weakpwd#123_d + +DB_IMAGE_NAME=h2 +DB_IMAGE_TAG=14.11-bullseye +DB_NAME=rosetta-java-preprod +DB_HOST=db # Service name in docker-compose or local db +DB_PORT=5432 +DB_SCHEMA=${NETWORK} +MAXIMUM_POOL_SIZE=80 +JDBC_BATCH_SIZE=1000 +SCHEMA=${NETWORK} +CARDANO_NODE_HOST=localhost # Service name in docker-compose or local cardano node +CARDANO_NODE_PORT=3001 # Uncomment if you are using local cardano node +CARDANO_NODE_VERSION=8.1.2 +LOG=INFO + +#api env +API_SPRING_PROFILES_ACTIVE_API=dev +API_EXPOSED_PORT=8081 +API_BIND_PORT=8081 +TRANSACTION_TTL=3000 + +DB_CONNECTION_PARAMS_PROVIDER_TYPE=ENVIRONMENT +DB_DRIVER_CLASS_NAME=org.h2.Driver + +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 + +PRINT_EXCEPTION=true + +#api env +API_SPRING_PROFILES_ACTIVE_YACI_INDEXER=postgres # database profiles: h2, postgres +INDEXER_NODE_PORT=3001 \ No newline at end of file diff --git a/api/api.iml b/api/api.iml deleted file mode 100644 index 3658ed7dc..000000000 --- a/api/api.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/api/pom.xml b/api/pom.xml index 6aab8f810..79eb027e9 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -11,6 +11,9 @@ api api Rosetta API implementation for Cardano. + + 4.8.3 + jar @@ -137,7 +140,7 @@ com.github.spotbugs spotbugs-annotations - 4.8.3 + ${spotbugs-annotations.version} @@ -212,27 +215,6 @@ 3.41.0 compile - - - - - - - - - - - - - - - - - - - - - javax.servlet servlet-api @@ -245,7 +227,20 @@ 3.7.0 compile - + + org.modelmapper + modelmapper + + + org.modelmapper.extensions + modelmapper-spring + + + org.assertj + assertj-core + ${assertj-core.version} + test + @@ -420,4 +415,17 @@ + + + h2-api + + + com.h2database + h2 + runtime + + + + + diff --git a/api/src/main/java/org/cardanofoundation/rosetta/RosettaApiApplication.java b/api/src/main/java/org/cardanofoundation/rosetta/RosettaApiApplication.java index af14c86e0..d832e9d33 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/RosettaApiApplication.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/RosettaApiApplication.java @@ -1,9 +1,8 @@ package org.cardanofoundation.rosetta; -import io.swagger.v3.oas.annotations.OpenAPIDefinition; -import io.swagger.v3.oas.annotations.info.Info; +import java.util.List; import jakarta.servlet.DispatcherType; -import org.openapitools.jackson.nullable.JsonNullableModule; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; @@ -12,35 +11,46 @@ import org.springframework.context.annotation.Profile; import org.springframework.core.Ordered; import org.springframework.web.filter.ForwardedHeaderFilter; - -import java.util.List; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.modelmapper.ModelMapper; +import org.openapitools.jackson.nullable.JsonNullableModule; @SpringBootApplication @EntityScan({ - "org.cardanofoundation.rosetta.api.account.model.entity", - "org.cardanofoundation.rosetta.api.block.model.entity", - "org.cardanofoundation.rosetta.api.construction.model.entity", - "org.cardanofoundation.rosetta.api.network.model.entity", - "org.cardanofoundation.rosetta.api.common.model.entity"}) + "org.cardanofoundation.rosetta.api.account.model.entity", + "org.cardanofoundation.rosetta.api.block.model.entity", + "org.cardanofoundation.rosetta.api.construction.model.entity", + "org.cardanofoundation.rosetta.api.network.model.entity", + "org.cardanofoundation.rosetta.api.common.model.entity"}) @OpenAPIDefinition(info = @Info(title = "APIs", version = "1.0", description = "Rosetta APIs v1.0")) public class RosettaApiApplication { - public static void main(String[] args) { - SpringApplication.run(RosettaApiApplication.class, args); - } - - @Bean - public FilterRegistrationBean forwardedHeaderFilter() { - final ForwardedHeaderFilter filter = new ForwardedHeaderFilter(); - final FilterRegistrationBean registration = new FilterRegistrationBean<>(filter); - registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR); - registration.setOrder(Ordered.HIGHEST_PRECEDENCE); - registration.setUrlPatterns(List.of("/**")); - return registration; - } - @Bean - @Profile("!test-integration") - public JsonNullableModule jsonNullableModule() { - return new JsonNullableModule(); - } + + public static void main(String[] args) { + SpringApplication.run(RosettaApiApplication.class, args); + } + + @Bean + public FilterRegistrationBean forwardedHeaderFilter() { + final ForwardedHeaderFilter filter = new ForwardedHeaderFilter(); + final FilterRegistrationBean registration = new FilterRegistrationBean<>( + filter); + registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, + DispatcherType.ERROR); + registration.setOrder(Ordered.HIGHEST_PRECEDENCE); + registration.setUrlPatterns(List.of("/**")); + return registration; + } + + @Bean + public ModelMapper modelMapper() { + return new ModelMapper(); + } + + @Bean + @Profile("!test-integration") + public JsonNullableModule jsonNullableModule() { + return new JsonNullableModule(); + } } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/account/model/repository/AddressBalanceRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/account/model/repository/AddressBalanceRepository.java index 6769846be..ea7ac7350 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/account/model/repository/AddressBalanceRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/account/model/repository/AddressBalanceRepository.java @@ -12,7 +12,7 @@ public interface AddressBalanceRepository extends JpaRepository { -// @Query(value = + // @Query(value = // "SELECT new AddressBalanceEntity (b.address, b.unit, MAX(b.slot), b.quantity, b.addrFull, b.policy, b.assetName, b.paymentCredential, b.stakeAddress, b.blockHash, b.epoch) " + // "FROM AddressBalanceEntity b " + // "WHERE b.address = :address AND b.blockNumber <= :number " + diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/account/service/impl/AccountServiceImpl.java b/api/src/main/java/org/cardanofoundation/rosetta/api/account/service/impl/AccountServiceImpl.java index 39bafc912..0f3253fbc 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/account/service/impl/AccountServiceImpl.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/account/service/impl/AccountServiceImpl.java @@ -6,7 +6,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.cardanofoundation.rosetta.common.util.CardanoAddressUtil; +import org.cardanofoundation.rosetta.common.util.CardanoAddressUtils; import org.cardanofoundation.rosetta.common.util.ValidationUtil; import org.springframework.stereotype.Service; import org.openapitools.client.model.AccountBalanceRequest; @@ -16,10 +16,11 @@ import org.openapitools.client.model.Currency; import org.openapitools.client.model.PartialBlockIdentifier; +import org.cardanofoundation.rosetta.api.account.model.domain.AddressBalance; import org.cardanofoundation.rosetta.api.account.model.domain.Utxo; import org.cardanofoundation.rosetta.api.account.service.AccountService; import org.cardanofoundation.rosetta.api.block.model.domain.Block; -import org.cardanofoundation.rosetta.api.block.service.BlockService; +import org.cardanofoundation.rosetta.api.block.model.domain.StakeAddressBalance; import org.cardanofoundation.rosetta.common.exception.ExceptionFactory; import org.cardanofoundation.rosetta.common.mapper.DataMapper; import org.cardanofoundation.rosetta.common.services.LedgerDataProviderService; @@ -30,7 +31,6 @@ @RequiredArgsConstructor public class AccountServiceImpl implements AccountService { - private final BlockService blockService; private final LedgerDataProviderService ledgerDataProviderService; @Override @@ -38,7 +38,7 @@ public AccountBalanceResponse getAccountBalance(AccountBalanceRequest accountBal Long index = null; String hash = null; String accountAddress = accountBalanceRequest.getAccountIdentifier().getAddress(); - if (Objects.isNull(CardanoAddressUtil.getEraAddressType(accountAddress))) { + if (Objects.isNull(CardanoAddressUtils.getEraAddressType(accountAddress))) { throw ExceptionFactory.invalidAddressError(accountAddress); } PartialBlockIdentifier blockIdentifier = accountBalanceRequest.getBlockIdentifier(); @@ -49,7 +49,8 @@ public AccountBalanceResponse getAccountBalance(AccountBalanceRequest accountBal hash = blockIdentifier.getHash(); } - return blockService.findBalanceDataByAddressAndBlock(accountAddress, index, hash); + return findBalanceDataByAddressAndBlock(accountAddress, index, hash); + } @Override @@ -59,7 +60,7 @@ public AccountCoinsResponse getAccountCoins(AccountCoinsRequest accountCoinsRequ // accountCoinsRequest.getIncludeMempool(); // TODO log.debug("[accountCoins] Request received {}", accountCoinsRequest); - if (Objects.isNull(CardanoAddressUtil.getEraAddressType(accountAddress))) { + if (Objects.isNull(CardanoAddressUtils.getEraAddressType(accountAddress))) { log.debug("[accountCoins] Address isn't Era"); throw ExceptionFactory.invalidAddressError(accountAddress); } @@ -76,4 +77,40 @@ public AccountCoinsResponse getAccountCoins(AccountCoinsRequest accountCoinsRequ log.debug("[accountCoins] found {} Utxos for Address {}", utxos.size(), accountAddress); return DataMapper.mapToAccountCoinsResponse(latestBlock, utxos); } + + private AccountBalanceResponse findBalanceDataByAddressAndBlock(String address, Long number, + String hash) { + Block blockDto; + if (number != null || hash != null) { + blockDto = ledgerDataProviderService.findBlock(number, hash); + } else { + blockDto = ledgerDataProviderService.findLatestBlock(); + } + + if (Objects.isNull(blockDto)) { + log.error("[findBalanceDataByAddressAndBlock] Block not found"); + throw ExceptionFactory.blockNotFoundException(); + } + log.info( + "[findBalanceDataByAddressAndBlock] Looking for utxos for address {} and block {}", + address, + blockDto.getHash()); + if (CardanoAddressUtils.isStakeAddress(address)) { + log.debug("[findBalanceDataByAddressAndBlock] Address is StakeAddress"); + log.debug("[findBalanceDataByAddressAndBlock] About to get balance for {}", address); + List balances = ledgerDataProviderService.findStakeAddressBalanceByAddressAndBlock( + address, blockDto.getNumber()); + if (Objects.isNull(balances) || balances.isEmpty()) { + log.error("[findBalanceDataByAddressAndBlock] No balance found for {}", address); + throw ExceptionFactory.invalidAddressError(); + } + return DataMapper.mapToStakeAddressBalanceResponse(blockDto, balances.getFirst()); + } else { + log.debug("[findBalanceDataByAddressAndBlock] Address isn't StakeAddress"); + + List balances = ledgerDataProviderService.findBalanceByAddressAndBlock( + address, blockDto.getNumber()); + return DataMapper.mapToAccountBalanceResponse(blockDto, balances); + } + } } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiDelegate.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiDelegate.java deleted file mode 100644 index 593165da1..000000000 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiDelegate.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.cardanofoundation.rosetta.api.block.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.openapitools.client.model.BlockRequest; -import org.openapitools.client.model.BlockResponse; -import org.openapitools.client.model.BlockTransactionRequest; -import org.openapitools.client.model.BlockTransactionResponse; -import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -/** - * @author Sotatek-HoangNguyen9 - * @since 12/04/2023 16:54 - */ -@Validated -@Tag(name = "v1-api", description = "The Cardano Block API") -public interface BlockApiDelegate { - @Operation( - operationId = "getBlockByBlockIdentifier", - summary = "Get a block by its Block Identifier", - responses = { - @ApiResponse(responseCode = "200", description = "", content = @Content(mediaType = "application/json")), - @ApiResponse(responseCode = "400", description = "Invalid `body`") - } - ) - @RequestMapping( - method = RequestMethod.POST, - value = "/block", - produces = { "application/json;charset=utf-8" }, - consumes = { "application/json;charset=utf-8" } - ) - ResponseEntity block(BlockRequest blockRequest); - - @Operation( - operationId = "getBlockTransaction", - summary = "Get a transaction in a block by its Transaction Identifier", - responses = { - @ApiResponse(responseCode = "200", description = "", content = @Content(mediaType = "application/json")), - @ApiResponse(responseCode = "400", description = "Invalid `body`") - } - ) - @RequestMapping( - method = RequestMethod.POST, - value = "/block/transaction", - produces = { "application/json;charset=utf-8" }, - consumes = { "application/json;charset=utf-8" } - ) - ResponseEntity blockTransaction( - BlockTransactionRequest blockTransactionRequest); -} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiDelegateImplementation.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiImpl.java similarity index 50% rename from api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiDelegateImplementation.java rename to api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiImpl.java index e3f09d4e0..22570d0b3 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiDelegateImplementation.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiImpl.java @@ -1,25 +1,42 @@ package org.cardanofoundation.rosetta.api.block.controller; +import java.util.Optional; + import lombok.RequiredArgsConstructor; -import org.cardanofoundation.rosetta.api.block.service.BlockService; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.NativeWebRequest; +import org.openapitools.client.api.BlockApi; import org.openapitools.client.model.BlockRequest; import org.openapitools.client.model.BlockResponse; import org.openapitools.client.model.BlockTransactionRequest; import org.openapitools.client.model.BlockTransactionResponse; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.openapitools.client.model.PartialBlockIdentifier; + +import org.cardanofoundation.rosetta.api.block.mapper.BlockToBlockResponse; +import org.cardanofoundation.rosetta.api.block.model.domain.Block; +import org.cardanofoundation.rosetta.api.block.service.BlockService; @RestController @RequiredArgsConstructor -public class BlockApiDelegateImplementation implements BlockApiDelegate { +public class BlockApiImpl implements BlockApi { private final BlockService blockService; + private final BlockToBlockResponse mapper; + @Override - public ResponseEntity block( - @RequestBody BlockRequest blockRequest) { - return ResponseEntity.ok(blockService.getBlockByBlockRequest(blockRequest)); + public ResponseEntity block(@RequestBody BlockRequest blockRequest) { + + PartialBlockIdentifier bid = blockRequest.getBlockIdentifier(); + String hash = bid.getHash(); + Long index = bid.getIndex(); + + Block block = blockService.findBlock(index, hash); + + return ResponseEntity.ok(mapper.toDto(block)); } @Override @@ -27,5 +44,10 @@ public ResponseEntity blockTransaction( @RequestBody BlockTransactionRequest blockTransactionRequest) { return ResponseEntity.ok(blockService.getBlockTransaction(blockTransactionRequest)); } + + @Override + public Optional getRequest() { + throw new UnsupportedOperationException("TODO implement"); + } } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/BlockToBlockResponse.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/BlockToBlockResponse.java new file mode 100644 index 000000000..0e3d04cd7 --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/BlockToBlockResponse.java @@ -0,0 +1,129 @@ +package org.cardanofoundation.rosetta.api.block.mapper; + +import java.util.ArrayList; +import java.util.List; + +import lombok.AllArgsConstructor; + +import org.modelmapper.ModelMapper; +import org.modelmapper.spi.MappingContext; +import org.openapitools.client.model.BlockIdentifier; +import org.openapitools.client.model.BlockMetadata; +import org.openapitools.client.model.BlockResponse; +import org.openapitools.client.model.Operation; +import org.openapitools.client.model.OperationStatus; +import org.openapitools.client.model.TransactionIdentifier; +import org.openapitools.client.model.TransactionMetadata; + +import org.cardanofoundation.rosetta.api.block.model.domain.Block; +import org.cardanofoundation.rosetta.common.annotation.OpenApiMapper; + +import static org.cardanofoundation.rosetta.common.util.RosettaConstants.SUCCESS_OPERATION_STATUS; + +@OpenApiMapper +@AllArgsConstructor +public class BlockToBlockResponse { + + final ModelMapper modelMapper; + + /** + * Maps a list of Block model to a Rosetta compatible BlockResponse. + * + * @param model The block from where the balances are calculated into the past + * @return The Rosetta compatible BlockResponse + */ + public BlockResponse toDto(Block model) { + + return modelMapper + .createTypeMap(Block.class, BlockResponse.class) + .addMappings(mapper -> { + mapper.map(Block::getHash, (dest, v) -> currentId(dest).setHash(v)); + mapper.map(Block::getNumber, (dest, v) -> currentId(dest).setIndex(v)); + + mapper.map(Block::getPreviousBlockHash, (dest, v) -> parentId(dest).setHash(v)); + mapper.map(Block::getPreviousBlockNumber, (dest, v) -> parentId(dest).setIndex(v)); + + mapper.map(Block::getCreatedAt, (dest, v) -> dest.getBlock().setTimestamp(v)); + }) + .setPostConverter(ctx -> { + ctx.getDestination().getBlock().setMetadata( + BlockMetadata.builder() + .transactionsCount(source(ctx).getTransactionsCount()) + .createdBy(source(ctx).getCreatedBy()) + .size(source(ctx).getSize()) + .epochNo(source(ctx).getEpochNo()) + .slotNo(source(ctx).getSlotNo()) + .build() + ); + + ctx.getDestination().getBlock().setTransactions( + mapToRosettaTransactions(source(ctx).getTransactions(), source(ctx).getPoolDeposit()) + ); + + return ctx.getDestination(); + }).map(model); + + } + + private static Block source(MappingContext ctx) { + return ctx.getSource(); + } + + + /** + * Maps a list of TransactionDtos to a list of Rosetta compatible Transactions. + * + * @param transactions The transactions to be mapped + * @param poolDeposit The pool deposit + * @return The list of Rosetta compatible Transactions + */ + public static List mapToRosettaTransactions( + List transactions, + String poolDeposit) { + List rosettaTransactions = new ArrayList<>(); + for (org.cardanofoundation.rosetta.api.block.model.domain.Transaction transactionDto : transactions) { + rosettaTransactions.add(mapToRosettaTransaction(transactionDto, poolDeposit)); + } + return rosettaTransactions; + } + + /** + * Maps a TransactionDto to a Rosetta compatible Transaction. + * + * @param transactionDto The transaction to be mapped + * @param poolDeposit The pool deposit + * @return The Rosetta compatible Transaction + */ + public static org.openapitools.client.model.Transaction mapToRosettaTransaction( + org.cardanofoundation.rosetta.api.block.model.domain.Transaction transactionDto, + String poolDeposit) { + org.openapitools.client.model.Transaction rosettaTransaction = new org.openapitools.client.model.Transaction(); + TransactionIdentifier identifier = new TransactionIdentifier(); + identifier.setHash(transactionDto.getHash()); + rosettaTransaction.setTransactionIdentifier(identifier); + + OperationStatus status = new OperationStatus(); +// status.setStatus(Boolean.TRUE.equals(transactionDto.getValidContract()) ? SUCCESS_OPERATION_STATUS.getStatus() : INVALID_OPERATION_STATUS.getStatus()); + status.setStatus(SUCCESS_OPERATION_STATUS.getStatus()); // TODO need to check the right status + List operations = OperationDataMapper.getAllOperations(transactionDto, poolDeposit, + status); + + rosettaTransaction.setMetadata(TransactionMetadata.builder() + .size(transactionDto.getSize()) // Todo size is not available + .scriptSize(transactionDto.getScriptSize()) // TODO script size is not available + .build()); + rosettaTransaction.setOperations(operations); + return rosettaTransaction; + + } + + private static BlockIdentifier parentId(BlockResponse dest) { + return dest.getBlock().getParentBlockIdentifier(); + } + + private static BlockIdentifier currentId(BlockResponse dest) { + return dest.getBlock().getBlockIdentifier(); + } + + +} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/OperationDataMapper.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/OperationDataMapper.java new file mode 100644 index 000000000..124fbecdb --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/OperationDataMapper.java @@ -0,0 +1,292 @@ +package org.cardanofoundation.rosetta.api.block.mapper; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import lombok.extern.slf4j.Slf4j; + +import com.bloxbean.cardano.yaci.core.model.certs.CertificateType; +import org.apache.commons.codec.binary.Hex; +import org.jetbrains.annotations.NotNull; +import org.openapitools.client.model.AccountIdentifier; +import org.openapitools.client.model.Amount; +import org.openapitools.client.model.CoinAction; +import org.openapitools.client.model.CoinChange; +import org.openapitools.client.model.Currency; +import org.openapitools.client.model.Operation; +import org.openapitools.client.model.OperationIdentifier; +import org.openapitools.client.model.OperationMetadata; +import org.openapitools.client.model.OperationStatus; +import org.openapitools.client.model.PoolRegistrationParams; +import org.openapitools.client.model.TokenBundleItem; + +import org.cardanofoundation.rosetta.api.account.model.domain.Utxo; +import org.cardanofoundation.rosetta.api.account.model.entity.Amt; +import org.cardanofoundation.rosetta.api.block.model.domain.Delegation; +import org.cardanofoundation.rosetta.api.block.model.domain.PoolRegistration; +import org.cardanofoundation.rosetta.api.block.model.domain.PoolRetirement; +import org.cardanofoundation.rosetta.api.block.model.domain.StakeRegistration; +import org.cardanofoundation.rosetta.api.block.model.domain.Transaction; +import org.cardanofoundation.rosetta.common.enumeration.OperationType; +import org.cardanofoundation.rosetta.common.mapper.DataMapper; +import org.cardanofoundation.rosetta.common.util.Constants; + +import static org.cardanofoundation.rosetta.common.util.Constants.ADA; +import static org.cardanofoundation.rosetta.common.util.Constants.ADA_DECIMALS; + +@Slf4j +class OperationDataMapper { + + @NotNull + public static List getAllOperations(Transaction transactionDto, String poolDeposit, + OperationStatus status) { + List> totalOperations = new ArrayList<>(); + List inputsAsOperations = getInputTransactionsasOperations(transactionDto, status); + totalOperations.add(inputsAsOperations); +// TODO Withdrawal currently not supported via Yaci-store. Will implemented it as soon as the PR is merged. +// List withdrawalsAsOperations = getWithdrawlOperations(transactionDto, status, totalOperations); +// totalOperations.add(withdrawalsAsOperations); + + List stakeRegistrationOperations = getStakeRegistrationOperations(transactionDto, + status, totalOperations); + totalOperations.add(stakeRegistrationOperations); + + List delegationOperations = getDelegationOperations(transactionDto, status, + totalOperations); + totalOperations.add(delegationOperations); + + List poolRegistrationOperations = getPoolRegistrationOperations(transactionDto, + status, totalOperations, poolDeposit); + totalOperations.add(poolRegistrationOperations); + + List poolRetirementOperations = getPoolRetirementOperations(transactionDto, status, + totalOperations); + totalOperations.add(poolRetirementOperations); + + List relatedOperations = getOperationIndexes(inputsAsOperations); + + List outputsAsOperations = getOutputsAsOperations(transactionDto, totalOperations, + status, relatedOperations); + + totalOperations.add(outputsAsOperations); + List operations = totalOperations.stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); + return operations; + } + +// @NotNull +// private static List getWithdrawlOperations(TransactionDto transactionDto, OperationStatus status, List> totalOperations) { +// return IntStream.range(0, +// transactionDto.getWithdrawals().size()) +// .mapToObj(index -> { +// Withdrawal withdrawal = transaction.getWithdrawals().get(index); +// return Operation.builder() +// .operationIdentifier(OperationIdentifier.builder().index( +// getOperationCurrentIndex(totalOperations, index)).build()) +// .type(OperationType.WITHDRAWAL.getValue()) +// .status(status.getStatus()) +// .account(AccountIdentifier.builder().address(withdrawal.getStakeAddress()).build()) +// .metadata(OperationMetadata.builder() +// .withdrawalAmount(DataMapper.mapAmount("-" + withdrawal.getAmount())) +// .build()) +// .build(); +// }).toList(); +// } + + @NotNull + public static List getInputTransactionsasOperations(Transaction transactionDto, + OperationStatus status) { + + return IntStream.range(0, nullable(transactionDto.getInputs()).size()) + .mapToObj(index -> { + Utxo utxoModel = transactionDto.getInputs().get(index); + return createOperation((long) index, + Constants.INPUT, + status.getStatus(), + utxoModel.getOwnerAddr(), + DataMapper.mapValue(utxoModel.getLovelaceAmount().toString(), true), + null, + null, + DataMapper.getCoinChange(utxoModel.getOutputIndex(), utxoModel.getTxHash(), + CoinAction.SPENT), + mapToOperationMetaData(true, utxoModel.getAmounts())); + }).toList(); + } + + private static List nullable(List list) { + return Optional.ofNullable(list).orElse(Collections.emptyList()); + } + + public static List getPoolRegistrationOperations(Transaction transactionDto, + OperationStatus status, List> totalOperations, String poolDeposit) { + return IntStream.range(0, nullable(transactionDto.getPoolRegistrations()).size()) + .mapToObj(index -> { + PoolRegistration poolRegistration = transactionDto.getPoolRegistrations().get(index); + return Operation.builder() + .operationIdentifier(OperationIdentifier.builder().index( + getOperationCurrentIndex(totalOperations, index)).build()) + .type(OperationType.POOL_REGISTRATION.getValue()) + .status(status.getStatus()) + .account(AccountIdentifier.builder().address(poolRegistration.getPoolId()).build()) + .metadata(OperationMetadata.builder() + .depositAmount(DataMapper.mapAmount(poolDeposit)) + .poolRegistrationParams(PoolRegistrationParams.builder() + .pledge(poolRegistration.getPledge()) + .rewardAddress(poolRegistration.getRewardAccount()) + .cost(poolRegistration.getCost()) + .poolOwners(poolRegistration.getOwners().stream().toList()) + .marginPercentage(poolRegistration.getMargin()) + .vrfKeyHash(poolRegistration.getVrfKeyHash()) + .relays(poolRegistration.getRelays()) + .build()) + .build()) + .build(); + }).toList(); + } + + public static List getPoolRetirementOperations(Transaction transactionDto, + OperationStatus status, List> totalOperations) { + return IntStream.range(0, + nullable(transactionDto.getPoolRetirements()).size()) + .mapToObj(index -> { + PoolRetirement poolRetirement = transactionDto.getPoolRetirements().get(index); + return Operation.builder() + .operationIdentifier(OperationIdentifier.builder().index( + getOperationCurrentIndex(totalOperations, index)).build()) + .type(OperationType.POOL_RETIREMENT.getValue()) + .status(status.getStatus()) + .account(AccountIdentifier.builder().address(poolRetirement.getPoolId()).build()) + .metadata(OperationMetadata.builder() + .epoch(poolRetirement.getEpoch()) + .build()) + .build(); + }).toList(); + } + + public static List getStakeRegistrationOperations(Transaction transactionDto, + OperationStatus status, List> totalOperations) { + return IntStream.range(0, + nullable(transactionDto.getStakeRegistrations()).size()) + .mapToObj(index -> { + StakeRegistration stakeRegistration = transactionDto.getStakeRegistrations().get(index); + OperationType operationType = + stakeRegistration.getType().equals(CertificateType.STAKE_REGISTRATION) + ? OperationType.STAKE_KEY_REGISTRATION : + stakeRegistration.getType().equals(CertificateType.STAKE_DEREGISTRATION) + ? OperationType.STAKE_KEY_DEREGISTRATION : null; + if (operationType == null) { + log.error("Invalid stake registration type {}", stakeRegistration.getType()); + return null; + } + return Operation.builder() + .operationIdentifier(OperationIdentifier.builder().index( + getOperationCurrentIndex(totalOperations, index)).build()) + .type(operationType.getValue()) + .status(status.getStatus()) + .account(AccountIdentifier.builder().address(stakeRegistration.getAddress()).build()) + .metadata(OperationMetadata.builder() + + .depositAmount(DataMapper.mapAmount("2000000", ADA, ADA_DECIMALS, + null)) // TODO need to get this from protocolparams + .build()) + .build(); + }).toList(); + } + + public static List getDelegationOperations(Transaction transaction, + OperationStatus status, List> totalOperations) { + return IntStream.range(0, + nullable(transaction.getDelegations()).size()) + .mapToObj(index -> { + Delegation delegation = transaction.getDelegations().get(index); + return Operation.builder() + .operationIdentifier(OperationIdentifier.builder().index( + getOperationCurrentIndex(totalOperations, index)).build()) + .type(OperationType.STAKE_DELEGATION.getValue()) + .status(status.getStatus()) + .account(AccountIdentifier.builder().address(delegation.getAddress()).build()) + .metadata(OperationMetadata.builder() + .poolKeyHash(delegation.getPoolId()) + .build()) + .build(); + }).toList(); + } + + @NotNull + public static List getOutputsAsOperations(Transaction transaction, + List> totalOperations, OperationStatus status, + List relatedOperations) { + return IntStream.range(0, nullable(transaction.getOutputs()).size()) + .mapToObj(index -> { + Utxo utxoModel = transaction.getOutputs().get(index); + return createOperation(getOperationCurrentIndex(totalOperations, index), + Constants.OUTPUT, + status.getStatus(), + utxoModel.getOwnerAddr(), + DataMapper.mapValue(utxoModel.getLovelaceAmount().toString(), false), + relatedOperations, + Long.valueOf(utxoModel.getOutputIndex()), + DataMapper.getCoinChange(utxoModel.getOutputIndex(), utxoModel.getTxHash(), + CoinAction.CREATED), + mapToOperationMetaData(false, utxoModel.getAmounts())); + }).toList(); + } + + public static Operation createOperation(Long index, String type, String status, String address, + String value, List relatedOperations, Long networkIndex, + CoinChange coinChange, OperationMetadata tokenBundleMetadata) { + return Operation.builder() + .operationIdentifier(OperationIdentifier.builder() + .index(index) + .networkIndex(networkIndex).build() + ) + .type(type) + .status(status) + .account(AccountIdentifier.builder() + .address(address).build() + ) + .amount(DataMapper.mapAmount(value, null, null, null)) + .coinChange(coinChange) + .relatedOperations(relatedOperations) + .metadata(tokenBundleMetadata).build(); + } + + private static OperationMetadata mapToOperationMetaData(boolean spent, List amounts) { + OperationMetadata operationMetadata = new OperationMetadata(); + for (Amt amount : amounts) { + if (!amount.getAssetName().equals(Constants.LOVELACE)) { + TokenBundleItem tokenBundleItem = new TokenBundleItem(); + tokenBundleItem.setPolicyId(amount.getPolicyId()); + Amount amt = new Amount(); + amt.setValue(DataMapper.mapValue(amount.getQuantity().toString(), spent)); + String hexAssetName = Hex.encodeHexString(amount.getAssetName().getBytes()); + amt.setCurrency(Currency.builder() + .symbol(hexAssetName) + .decimals(0) + .build()); + tokenBundleItem.setTokens(List.of(amt)); + operationMetadata.addTokenBundleItem(tokenBundleItem); + } + } + return operationMetadata; + } + + public static long getOperationCurrentIndex(List> operationsList, + int relativeIndex) { + return relativeIndex + operationsList.stream() + .mapToLong(List::size) + .sum(); + } + + public static List getOperationIndexes(List operations) { + return operations.stream() + .map(operation -> OperationIdentifier.builder().index(operation.getOperationIdentifier() + .getIndex()).build()).collect(Collectors.toList()); + } +} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/Block.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/Block.java index 57bbfe61e..ce5fba545 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/Block.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/Block.java @@ -27,13 +27,15 @@ public class Block { private Integer epochNo; private Long slotNo; private List transactions; + private String poolDeposit; public static Block fromBlock(BlockEntity block) { return Block.builder() .number(block.getNumber()) .hash(block.getHash()) .createdAt(TimeUnit.SECONDS.toMillis(block.getBlockTimeInSeconds())) - .previousBlockHash(block.getPrev() != null ? block.getPrev().getHash() : block.getHash()) // TODO EPAM: check for genesis block + .previousBlockHash(block.getPrev() != null ? block.getPrev().getHash() + : block.getHash()) // TODO EPAM: check for genesis block .previousBlockNumber(block.getPrev() != null ? block.getPrev().getNumber() : 0) .transactionsCount(block.getNoOfTxs()) .size(Math.toIntExact(block.getBlockBodySize())) diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockHeader.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockHeader.java new file mode 100644 index 000000000..ff724fac0 --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockHeader.java @@ -0,0 +1,25 @@ +package org.cardanofoundation.rosetta.api.block.model.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import com.bloxbean.cardano.yaci.core.model.HeaderBody; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class BlockHeader { + + private HeaderBody headerBody; + private String bodySignature; + + @Override + public String toString() { + return "BlockHeader{" + + "headerBody=" + headerBody + + '}'; + } +} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockMetadata.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockMetadata.java new file mode 100644 index 000000000..91a3a2565 --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockMetadata.java @@ -0,0 +1,19 @@ +package org.cardanofoundation.rosetta.api.block.model.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Data +public class BlockMetadata { + + private Long transactionsCount; + private String createdBy; + private Integer size; + private Integer epochNo; + private Long slotNo; +} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/PoolRegistration.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/PoolRegistration.java index e1b343672..6990c4115 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/PoolRegistration.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/PoolRegistration.java @@ -46,4 +46,4 @@ public static PoolRegistration fromEntity(PoolRegistrationEnity entity) { .blockHash(entity.getBlockHash()) .build(); } -} +} \ No newline at end of file diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/BlockAwareEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/BlockAwareEntity.java index 94d47c57f..0f4f2dcde 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/BlockAwareEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/BlockAwareEntity.java @@ -1,14 +1,15 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.time.LocalDateTime; import jakarta.persistence.Column; import jakarta.persistence.MappedSuperclass; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; -import org.hibernate.annotations.UpdateTimestamp; -import java.time.LocalDateTime; +import org.hibernate.annotations.UpdateTimestamp; @Data @MappedSuperclass @@ -17,14 +18,14 @@ @SuperBuilder public class BlockAwareEntity { - @Column(name = "block") - private Long blockNumber; + @Column(name = "block") + private Long blockNumber; - @Column(name = "block_time") - private Long blockTime; + @Column(name = "block_time") + private Long blockTime; - @UpdateTimestamp - @Column(name = "update_datetime") - private LocalDateTime updateDateTime; + @UpdateTimestamp + @Column(name = "update_datetime") + private LocalDateTime updateDateTime; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/DelegationEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/DelegationEntity.java index 1446f83c8..c6a43a5dd 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/DelegationEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/DelegationEntity.java @@ -1,6 +1,11 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -14,29 +19,30 @@ @Table(name = "delegation") @IdClass(DelegationId.class) public class DelegationEntity extends BlockAwareEntity { - @Id - @Column(name = "tx_hash") - private String txHash; - @Id - @Column(name = "cert_index") - private long certIndex; + @Id + @Column(name = "tx_hash") + private String txHash; + + @Id + @Column(name = "cert_index") + private long certIndex; - @Column(name = "credential") - private String credential; + @Column(name = "credential") + private String credential; - @Column(name = "pool_id") - private String poolId; + @Column(name = "pool_id") + private String poolId; - @Column(name = "address") - private String address; + @Column(name = "address") + private String address; - @Column(name = "epoch") - private Integer epoch; + @Column(name = "epoch") + private Integer epoch; - @Column(name = "slot") - private Long slot; + @Column(name = "slot") + private Long slot; - @Column(name = "block_hash") - private String blockHash; + @Column(name = "block_hash") + private String blockHash; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/DelegationId.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/DelegationId.java index 01b5d23f5..acd120916 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/DelegationId.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/DelegationId.java @@ -1,15 +1,15 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.io.Serializable; import jakarta.persistence.Column; -import lombok.EqualsAndHashCode; -import java.io.Serializable; +import lombok.EqualsAndHashCode; @EqualsAndHashCode public class DelegationId implements Serializable { - @Column(name = "tx_hash") - private String txHash; - @Column(name = "cert_index") - private long certIndex; + @Column(name = "tx_hash") + private String txHash; + @Column(name = "cert_index") + private long certIndex; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/EpochParamEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/EpochParamEntity.java index 6775a3224..818a3b6a8 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/EpochParamEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/EpochParamEntity.java @@ -1,12 +1,18 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import io.hypersistence.utils.hibernate.type.json.JsonType; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.PrePersist; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import lombok.extern.slf4j.Slf4j; + +import io.hypersistence.utils.hibernate.type.json.JsonType; import org.hibernate.annotations.Type; @Data @@ -17,27 +23,30 @@ @Table(name = "epoch_param") @Slf4j public class EpochParamEntity extends BlockAwareEntity { - @Id - @Column(name = "epoch") - private Integer epoch; - @Type(JsonType.class) - @Column(name = "params", columnDefinition = "json") - private ProtocolParams params; + @Id + @Column(name = "epoch") + private Integer epoch; + + @Type(JsonType.class) + @Column(name = "params", columnDefinition = "json") + private ProtocolParams params; - @Column(name = "cost_model_hash") - private String costModelHash; + @Column(name = "cost_model_hash") + private String costModelHash; - @Column(name = "slot") - private Long slot; + @Column(name = "slot") + private Long slot; - @PrePersist - public void preSave() { - if (this.getParams() == null) - return; + @PrePersist + public void preSave() { + if (this.getParams() == null) { + return; + } - //reset these fields - if (this.getParams().getCostModels() != null) - this.getParams().setCostModels(null); + //reset these fields + if (this.getParams().getCostModels() != null) { + this.getParams().setCostModels(null); } + } } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRegistrationEnity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRegistrationEnity.java index e7b36fa89..37300e704 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRegistrationEnity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRegistrationEnity.java @@ -1,19 +1,24 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import com.bloxbean.cardano.yaci.core.model.Relay; -import io.hypersistence.utils.hibernate.type.json.JsonType; -import jakarta.persistence.*; +import java.math.BigInteger; +import java.util.List; +import java.util.Set; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; + +import com.bloxbean.cardano.yaci.core.model.Relay; +import io.hypersistence.utils.hibernate.type.json.JsonType; import org.hibernate.annotations.DynamicUpdate; import org.hibernate.annotations.Type; -import java.math.BigInteger; -import java.util.List; -import java.util.Set; - @Data @NoArgsConstructor @AllArgsConstructor @@ -23,51 +28,52 @@ @IdClass(PoolRegistrationId.class) @DynamicUpdate public class PoolRegistrationEnity extends BlockAwareEntity { - @Id - @Column(name = "tx_hash") - private String txHash; - @Id - @Column(name = "cert_index") - private int certIndex; + @Id + @Column(name = "tx_hash") + private String txHash; + + @Id + @Column(name = "cert_index") + private int certIndex; - @Column(name = "pool_id") - private String poolId; + @Column(name = "pool_id") + private String poolId; - @Column(name = "vrf_key") - private String vrfKeyHash; + @Column(name = "vrf_key") + private String vrfKeyHash; - @Column(name = "pledge") - private BigInteger pledge; + @Column(name = "pledge") + private BigInteger pledge; - @Column(name = "cost") - private BigInteger cost; + @Column(name = "cost") + private BigInteger cost; - @Column(name = "margin") - private Double margin; + @Column(name = "margin") + private Double margin; - @Column(name = "reward_account") - private String rewardAccount; + @Column(name = "reward_account") + private String rewardAccount; - @Type(JsonType.class) - private Set poolOwners; + @Type(JsonType.class) + private Set poolOwners; - @Type(JsonType.class) - private List relays; + @Type(JsonType.class) + private List relays; - @Column(name = "metadata_url") - private String metadataUrl; + @Column(name = "metadata_url") + private String metadataUrl; - @Column - private String metadataHash; + @Column + private String metadataHash; - @Column(name = "epoch") - private Integer epoch; + @Column(name = "epoch") + private Integer epoch; - @Column(name = "slot") - private Long slot; + @Column(name = "slot") + private Long slot; - @Column(name = "block_hash") - private String blockHash; + @Column(name = "block_hash") + private String blockHash; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRegistrationId.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRegistrationId.java index d5cbbc021..62375666c 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRegistrationId.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRegistrationId.java @@ -1,15 +1,16 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.io.Serializable; import jakarta.persistence.Column; -import lombok.EqualsAndHashCode; -import java.io.Serializable; +import lombok.EqualsAndHashCode; @EqualsAndHashCode public class PoolRegistrationId implements Serializable { - @Column(name = "tx_hash") - private String txHash; - @Column(name = "cert_index") - private int certIndex; + @Column(name = "tx_hash") + private String txHash; + + @Column(name = "cert_index") + private int certIndex; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRetirementEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRetirementEntity.java index 4e0264088..855e680bc 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRetirementEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRetirementEntity.java @@ -1,10 +1,16 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; + import org.hibernate.annotations.DynamicUpdate; @Data @@ -16,26 +22,27 @@ @IdClass(PoolRetirementId.class) @DynamicUpdate public class PoolRetirementEntity extends BlockAwareEntity { - @Id - @Column(name = "tx_hash") - private String txHash; - @Id - @Column(name = "cert_index") - private int certIndex; + @Id + @Column(name = "tx_hash") + private String txHash; + + @Id + @Column(name = "cert_index") + private int certIndex; - @Column(name = "pool_id") - private String poolId; + @Column(name = "pool_id") + private String poolId; - @Column(name = "retirement_epoch") - private int retirementEpoch; + @Column(name = "retirement_epoch") + private int retirementEpoch; - @Column(name = "epoch") - private Integer epoch; //current epoch + @Column(name = "epoch") + private Integer epoch; //current epoch - @Column(name = "slot") - private Long slot; + @Column(name = "slot") + private Long slot; - @Column(name = "block_hash") - private String blockHash; + @Column(name = "block_hash") + private String blockHash; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRetirementId.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRetirementId.java index d8d3b6e6a..4b5a71348 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRetirementId.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/PoolRetirementId.java @@ -1,16 +1,16 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.io.Serializable; import jakarta.persistence.Column; -import lombok.EqualsAndHashCode; -import java.io.Serializable; +import lombok.EqualsAndHashCode; @EqualsAndHashCode public class PoolRetirementId implements Serializable { - @Column(name = "tx_hash") - private String txHash; + @Column(name = "tx_hash") + private String txHash; - @Column(name = "cert_index") - private int certIndex; + @Column(name = "cert_index") + private int certIndex; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/ProtocolParams.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/ProtocolParams.java index c72d237f7..779d94180 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/ProtocolParams.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/ProtocolParams.java @@ -1,20 +1,21 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; import org.json.JSONObject; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Map; - @Data @NoArgsConstructor @AllArgsConstructor @@ -23,49 +24,50 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class ProtocolParams { - private Integer minFeeA; //0 - private Integer minFeeB; //1 - private Integer maxBlockSize; //2 - private Integer maxTxSize; //3 - private Integer maxBlockHeaderSize; //4 - private BigInteger keyDeposit; //5 - private BigInteger poolDeposit; //6 - private Integer maxEpoch; //7 - @JsonProperty("nopt") - private Integer nOpt; //8 - private BigDecimal poolPledgeInfluence; //rational //9 - private BigDecimal expansionRate; //unit interval //10 - private BigDecimal treasuryGrowthRate; //11 - private BigDecimal decentralisationParam; //12 - private String extraEntropy; //13 - private Integer protocolMajorVer; //14 - private Integer protocolMinorVer; //14 - private BigInteger minUtxo; //TODO //15 - - private BigInteger minPoolCost; //16 - private BigInteger adaPerUtxoByte; //17 - //private String nonce; - - //Alonzo changes - private Map costModels; //18 - private String costModelsHash; - - //ex_unit_prices - private BigDecimal priceMem; //19 - private BigDecimal priceStep; //19 - - //max tx ex units - private BigInteger maxTxExMem; //20 - private BigInteger maxTxExSteps; //20 - - //max block ex units - private BigInteger maxBlockExMem; //21 - private BigInteger maxBlockExSteps; //21 - - private Long maxValSize; //22 - - private Integer collateralPercent; //23 - private Integer maxCollateralInputs; //24 + + private Integer minFeeA; //0 + private Integer minFeeB; //1 + private Integer maxBlockSize; //2 + private Integer maxTxSize; //3 + private Integer maxBlockHeaderSize; //4 + private BigInteger keyDeposit; //5 + private BigInteger poolDeposit; //6 + private Integer maxEpoch; //7 + @JsonProperty("nopt") + private Integer nOpt; //8 + private BigDecimal poolPledgeInfluence; //rational //9 + private BigDecimal expansionRate; //unit interval //10 + private BigDecimal treasuryGrowthRate; //11 + private BigDecimal decentralisationParam; //12 + private String extraEntropy; //13 + private Integer protocolMajorVer; //14 + private Integer protocolMinorVer; //14 + private BigInteger minUtxo; //TODO //15 + + private BigInteger minPoolCost; //16 + private BigInteger adaPerUtxoByte; //17 + //private String nonce; + + //Alonzo changes + private Map costModels; //18 + private String costModelsHash; + + //ex_unit_prices + private BigDecimal priceMem; //19 + private BigDecimal priceStep; //19 + + //max tx ex units + private BigInteger maxTxExMem; //20 + private BigInteger maxTxExSteps; //20 + + //max block ex units + private BigInteger maxBlockExMem; //21 + private BigInteger maxBlockExSteps; //21 + + private Long maxValSize; //22 + + private Integer collateralPercent; //23 + private Integer maxCollateralInputs; //24 // //Cost per UTxO word for Alonzo. // //Cost per UTxO byte for Babbage and later. @@ -73,161 +75,161 @@ public class ProtocolParams { // @Deprecated // private String coinsPerUtxoWord; - //Conway era fields + //Conway era fields // private PoolVotingThresholds poolVotingThresholds; //25 // private DrepVoteThresholds drepVotingThresholds; //26 - private Integer committeeMinSize; //27 - private Integer committeeMaxTermLength; //28 - private Integer govActionLifetime; //29 - private BigInteger govActionDeposit; //30 - private BigInteger drepDeposit; //31 - private Integer drepActivity; //32 - - // TODO clarify if parameters are correctly set - public static ProtocolParams fromJSONObject(JSONObject shelleyJsonObject) { - ProtocolParams p = new ProtocolParams(); - JSONObject shelleyProtocolParams = shelleyJsonObject.getJSONObject("protocolParams"); - p.setMinFeeA(shelleyProtocolParams.getInt("minFeeA")); - p.setMinFeeB(shelleyProtocolParams.getInt("minFeeB")); - p.setMaxBlockSize(shelleyProtocolParams.getInt("maxBlockBodySize")); - p.setMaxTxSize(shelleyProtocolParams.getInt("maxTxSize")); - p.setMaxBlockHeaderSize(shelleyProtocolParams.getInt("maxBlockHeaderSize")); - p.setKeyDeposit(shelleyProtocolParams.getBigInteger("keyDeposit")); - p.setPoolDeposit(shelleyProtocolParams.getBigInteger("poolDeposit")); - p.setNOpt(shelleyProtocolParams.getInt("nOpt")); - p.setDecentralisationParam(shelleyProtocolParams.getBigDecimal("decentralisationParam")); - p.setExtraEntropy(shelleyProtocolParams.getJSONObject("extraEntropy").getString("tag")); - JSONObject protolVersion = shelleyProtocolParams.getJSONObject("protocolVersion"); - p.setProtocolMajorVer(protolVersion.getInt("major")); - p.setProtocolMinorVer(protolVersion.getInt("minor")); - p.setMinUtxo(shelleyProtocolParams.getBigInteger("minUTxOValue")); - p.setMinPoolCost(shelleyProtocolParams.getBigInteger("minPoolCost")); - p.setAdaPerUtxoByte(shelleyProtocolParams.getBigInteger("minFeeA")); - - return p; - } - - public void merge(ProtocolParams other) { - if (this.minFeeA == null) { - this.minFeeA = other.minFeeA; - } - if (this.minFeeB == null) { - this.minFeeB = other.minFeeB; - } - if (this.maxBlockSize == null) { - this.maxBlockSize = other.maxBlockSize; - } - if (this.maxTxSize == null) { - this.maxTxSize = other.maxTxSize; - } - if (this.maxBlockHeaderSize == null) { - this.maxBlockHeaderSize = other.maxBlockHeaderSize; - } - if (this.keyDeposit == null) { - this.keyDeposit = other.keyDeposit; - } - if (this.poolDeposit == null) { - this.poolDeposit = other.poolDeposit; - } - if (this.maxEpoch == null) { - this.maxEpoch = other.maxEpoch; - } - if (this.nOpt == null) { - this.nOpt = other.nOpt; - } - if (this.poolPledgeInfluence == null) { - this.poolPledgeInfluence = other.poolPledgeInfluence; - } - if (this.expansionRate == null) { - this.expansionRate = other.expansionRate; - } - if (this.treasuryGrowthRate == null) { - this.treasuryGrowthRate = other.treasuryGrowthRate; - } - if (this.decentralisationParam == null) { - this.decentralisationParam = other.decentralisationParam; - } - if (this.extraEntropy == null) { - this.extraEntropy = other.extraEntropy; - } - if (this.protocolMajorVer == null) { - this.protocolMajorVer = other.protocolMajorVer; - } - if (this.protocolMinorVer == null) { - this.protocolMinorVer = other.protocolMinorVer; - } - if (this.minUtxo == null) { - this.minUtxo = other.minUtxo; - } - if (this.minPoolCost == null) { - this.minPoolCost = other.minPoolCost; - } - if (this.adaPerUtxoByte == null) { - this.adaPerUtxoByte = other.adaPerUtxoByte; - } - if (this.costModels == null) { - if (this.costModels == null) { - this.costModels = other.getCostModels(); - } else { - var keys = other.getCostModels().keySet(); - keys.forEach(key -> this.costModels.put(key, other.costModels.get(key))); - } - } - - if (this.costModelsHash == null) { - this.costModelsHash = other.costModelsHash; - } - - if (this.priceMem == null) { - this.priceMem = other.priceMem; - } - if (this.priceStep == null) { - this.priceStep = other.priceStep; - } - if (this.maxTxExMem == null) { - this.maxTxExMem = other.maxTxExMem; - } - if (this.maxTxExSteps == null) { - this.maxTxExSteps = other.maxTxExSteps; - } - if (this.maxBlockExMem == null) { - this.maxBlockExMem = other.maxBlockExMem; - } - if (this.maxBlockExSteps == null) { - this.maxBlockExSteps = other.maxBlockExSteps; - } - if (this.maxValSize == null) { - this.maxValSize = other.maxValSize; - } - if (this.collateralPercent == null) { - this.collateralPercent = other.collateralPercent; - } - if (this.maxCollateralInputs == null) { - this.maxCollateralInputs = other.maxCollateralInputs; - } + private Integer committeeMinSize; //27 + private Integer committeeMaxTermLength; //28 + private Integer govActionLifetime; //29 + private BigInteger govActionDeposit; //30 + private BigInteger drepDeposit; //31 + private Integer drepActivity; //32 + + // TODO clarify if parameters are correctly set + public static ProtocolParams fromJSONObject(JSONObject shelleyJsonObject) { + ProtocolParams p = new ProtocolParams(); + JSONObject shelleyProtocolParams = shelleyJsonObject.getJSONObject("protocolParams"); + p.setMinFeeA(shelleyProtocolParams.getInt("minFeeA")); + p.setMinFeeB(shelleyProtocolParams.getInt("minFeeB")); + p.setMaxBlockSize(shelleyProtocolParams.getInt("maxBlockBodySize")); + p.setMaxTxSize(shelleyProtocolParams.getInt("maxTxSize")); + p.setMaxBlockHeaderSize(shelleyProtocolParams.getInt("maxBlockHeaderSize")); + p.setKeyDeposit(shelleyProtocolParams.getBigInteger("keyDeposit")); + p.setPoolDeposit(shelleyProtocolParams.getBigInteger("poolDeposit")); + p.setNOpt(shelleyProtocolParams.getInt("nOpt")); + p.setDecentralisationParam(shelleyProtocolParams.getBigDecimal("decentralisationParam")); + p.setExtraEntropy(shelleyProtocolParams.getJSONObject("extraEntropy").getString("tag")); + JSONObject protolVersion = shelleyProtocolParams.getJSONObject("protocolVersion"); + p.setProtocolMajorVer(protolVersion.getInt("major")); + p.setProtocolMinorVer(protolVersion.getInt("minor")); + p.setMinUtxo(shelleyProtocolParams.getBigInteger("minUTxOValue")); + p.setMinPoolCost(shelleyProtocolParams.getBigInteger("minPoolCost")); + p.setAdaPerUtxoByte(shelleyProtocolParams.getBigInteger("minFeeA")); + + return p; + } + + public void merge(ProtocolParams other) { + if (this.minFeeA == null) { + this.minFeeA = other.minFeeA; + } + if (this.minFeeB == null) { + this.minFeeB = other.minFeeB; + } + if (this.maxBlockSize == null) { + this.maxBlockSize = other.maxBlockSize; + } + if (this.maxTxSize == null) { + this.maxTxSize = other.maxTxSize; + } + if (this.maxBlockHeaderSize == null) { + this.maxBlockHeaderSize = other.maxBlockHeaderSize; + } + if (this.keyDeposit == null) { + this.keyDeposit = other.keyDeposit; + } + if (this.poolDeposit == null) { + this.poolDeposit = other.poolDeposit; + } + if (this.maxEpoch == null) { + this.maxEpoch = other.maxEpoch; + } + if (this.nOpt == null) { + this.nOpt = other.nOpt; + } + if (this.poolPledgeInfluence == null) { + this.poolPledgeInfluence = other.poolPledgeInfluence; + } + if (this.expansionRate == null) { + this.expansionRate = other.expansionRate; + } + if (this.treasuryGrowthRate == null) { + this.treasuryGrowthRate = other.treasuryGrowthRate; + } + if (this.decentralisationParam == null) { + this.decentralisationParam = other.decentralisationParam; + } + if (this.extraEntropy == null) { + this.extraEntropy = other.extraEntropy; + } + if (this.protocolMajorVer == null) { + this.protocolMajorVer = other.protocolMajorVer; + } + if (this.protocolMinorVer == null) { + this.protocolMinorVer = other.protocolMinorVer; + } + if (this.minUtxo == null) { + this.minUtxo = other.minUtxo; + } + if (this.minPoolCost == null) { + this.minPoolCost = other.minPoolCost; + } + if (this.adaPerUtxoByte == null) { + this.adaPerUtxoByte = other.adaPerUtxoByte; + } + if (this.costModels == null) { + if (this.costModels == null) { + this.costModels = other.getCostModels(); + } else { + var keys = other.getCostModels().keySet(); + keys.forEach(key -> this.costModels.put(key, other.costModels.get(key))); + } + } + + if (this.costModelsHash == null) { + this.costModelsHash = other.costModelsHash; + } + + if (this.priceMem == null) { + this.priceMem = other.priceMem; + } + if (this.priceStep == null) { + this.priceStep = other.priceStep; + } + if (this.maxTxExMem == null) { + this.maxTxExMem = other.maxTxExMem; + } + if (this.maxTxExSteps == null) { + this.maxTxExSteps = other.maxTxExSteps; + } + if (this.maxBlockExMem == null) { + this.maxBlockExMem = other.maxBlockExMem; + } + if (this.maxBlockExSteps == null) { + this.maxBlockExSteps = other.maxBlockExSteps; + } + if (this.maxValSize == null) { + this.maxValSize = other.maxValSize; + } + if (this.collateralPercent == null) { + this.collateralPercent = other.collateralPercent; + } + if (this.maxCollateralInputs == null) { + this.maxCollateralInputs = other.maxCollateralInputs; + } // if (other.poolVotingThresholds == null) { // this.poolVotingThresholds = other.poolVotingThresholds; // } // if (other.drepVotingThresholds == null) { // this.drepVotingThresholds = other.drepVotingThresholds; // } - if (this.committeeMinSize == null) { - this.committeeMinSize = other.committeeMinSize; - } - if (this.committeeMaxTermLength == null) { - this.committeeMaxTermLength = other.committeeMaxTermLength; - } - if (this.govActionLifetime == null) { - this.govActionLifetime = other.govActionLifetime; - } - if (this.govActionDeposit == null) { - this.govActionDeposit = other.govActionDeposit; - } - if (this.drepDeposit == null) { - this.drepDeposit = other.drepDeposit; - } - if (this.drepActivity == null) { - this.drepActivity = other.drepActivity; - } + if (this.committeeMinSize == null) { + this.committeeMinSize = other.committeeMinSize; + } + if (this.committeeMaxTermLength == null) { + this.committeeMaxTermLength = other.committeeMaxTermLength; + } + if (this.govActionLifetime == null) { + this.govActionLifetime = other.govActionLifetime; + } + if (this.govActionDeposit == null) { + this.govActionDeposit = other.govActionDeposit; + } + if (this.drepDeposit == null) { + this.drepDeposit = other.drepDeposit; + } + if (this.drepActivity == null) { + this.drepActivity = other.drepActivity; } + } } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeAddressBalanceEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeAddressBalanceEntity.java index f38fc09ec..2e21ddddd 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeAddressBalanceEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeAddressBalanceEntity.java @@ -1,13 +1,18 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import jakarta.persistence.*; +import java.math.BigInteger; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; -import org.hibernate.annotations.DynamicUpdate; -import java.math.BigInteger; +import org.hibernate.annotations.DynamicUpdate; @Data @NoArgsConstructor @@ -18,23 +23,24 @@ @IdClass(StakeAddressBalanceId.class) @DynamicUpdate public class StakeAddressBalanceEntity extends BlockAwareEntity { - @Id - @Column(name = "address") - private String address; - @Id - @Column(name = "slot") - private Long slot; + @Id + @Column(name = "address") + private String address; + + @Id + @Column(name = "slot") + private Long slot; - @Column(name = "quantity") - private BigInteger quantity; + @Column(name = "quantity") + private BigInteger quantity; - @Column(name = "stake_credential") - private String stakeCredential; + @Column(name = "stake_credential") + private String stakeCredential; - @Column(name = "block_hash") - private String blockHash; + @Column(name = "block_hash") + private String blockHash; - @Column(name = "epoch") - private Integer epoch; + @Column(name = "epoch") + private Integer epoch; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeAddressBalanceId.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeAddressBalanceId.java index b98cd3f0f..86c109338 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeAddressBalanceId.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeAddressBalanceId.java @@ -1,9 +1,13 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.io.Serializable; import jakarta.persistence.Column; -import lombok.*; -import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @NoArgsConstructor @@ -11,8 +15,9 @@ @EqualsAndHashCode @Builder public class StakeAddressBalanceId implements Serializable { - @Column(name = "address") - private String address; - @Column(name = "slot") - private Long slot; + + @Column(name = "address") + private String address; + @Column(name = "slot") + private Long slot; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeRegistrationEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeRegistrationEntity.java index 895f7ed5b..09c6ed71d 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeRegistrationEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeRegistrationEntity.java @@ -1,12 +1,20 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import com.bloxbean.cardano.yaci.core.model.certs.CertificateType; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import com.bloxbean.cardano.yaci.core.model.certs.CertificateType; + @Data @NoArgsConstructor @AllArgsConstructor @@ -15,30 +23,31 @@ @Table(name = "stake_registration") @IdClass(StakeRegistrationId.class) public class StakeRegistrationEntity extends BlockAwareEntity { - @Id - @Column(name = "tx_hash") - private String txHash; - @Id - @Column(name = "cert_index") - private long certIndex; + @Id + @Column(name = "tx_hash") + private String txHash; + + @Id + @Column(name = "cert_index") + private long certIndex; - @Column(name = "credential") - private String credential; + @Column(name = "credential") + private String credential; - @Column(name = "type") - @Enumerated(EnumType.STRING) - private CertificateType type; + @Column(name = "type") + @Enumerated(EnumType.STRING) + private CertificateType type; - @Column(name = "address") - private String address; + @Column(name = "address") + private String address; - @Column(name = "epoch") - private Integer epoch; + @Column(name = "epoch") + private Integer epoch; - @Column(name = "slot") - private Long slot; + @Column(name = "slot") + private Long slot; - @Column(name = "block_hash") - private String blockHash; + @Column(name = "block_hash") + private String blockHash; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeRegistrationId.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeRegistrationId.java index c17979cdb..5c86bd10b 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeRegistrationId.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/StakeRegistrationId.java @@ -1,15 +1,15 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.io.Serializable; import jakarta.persistence.Column; -import lombok.EqualsAndHashCode; -import java.io.Serializable; +import lombok.EqualsAndHashCode; @EqualsAndHashCode public class StakeRegistrationId implements Serializable { - @Column(name = "tx_hash") - private String txHash; - @Column(name = "cert_index") - private long certIndex; + @Column(name = "tx_hash") + private String txHash; + @Column(name = "cert_index") + private long certIndex; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxInputEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxInputEntity.java index 288b9e1a5..a16ea223b 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxInputEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxInputEntity.java @@ -1,13 +1,20 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; -import org.cardanofoundation.rosetta.api.account.model.entity.UtxoId; + import org.hibernate.annotations.DynamicUpdate; +import org.cardanofoundation.rosetta.api.account.model.entity.UtxoId; + @Data @NoArgsConstructor @AllArgsConstructor @@ -17,28 +24,29 @@ @IdClass(UtxoId.class) @DynamicUpdate public class TxInputEntity { - @Id - @Column(name = "tx_hash") - private String txHash; - @Id - @Column(name = "output_index") - private Integer outputIndex; - @Column(name = "spent_at_slot") - private Long spentAtSlot; + @Id + @Column(name = "tx_hash") + private String txHash; + @Id + @Column(name = "output_index") + private Integer outputIndex; + + @Column(name = "spent_at_slot") + private Long spentAtSlot; - @Column(name = "spent_at_block") - private Long spentAtBlock; + @Column(name = "spent_at_block") + private Long spentAtBlock; - @Column(name = "spent_at_block_hash") - private String spentAtBlockHash; + @Column(name = "spent_at_block_hash") + private String spentAtBlockHash; - @Column(name = "spent_block_time") - private Long spentBlockTime; + @Column(name = "spent_block_time") + private Long spentBlockTime; - @Column(name = "spent_epoch") - private Integer spentEpoch; + @Column(name = "spent_epoch") + private Integer spentEpoch; - @Column(name = "spent_tx_hash") - private String spentTxHash; + @Column(name = "spent_tx_hash") + private String spentTxHash; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxOuput.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxOuput.java index 39360486d..5a8c0b96d 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxOuput.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxOuput.java @@ -1,13 +1,14 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.io.Serializable; +import java.util.List; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.cardanofoundation.rosetta.api.account.model.entity.Amt; -import java.io.Serializable; -import java.util.List; +import org.cardanofoundation.rosetta.api.account.model.entity.Amt; //Not used @Data @@ -15,10 +16,11 @@ @AllArgsConstructor @Builder public class TxOuput implements Serializable { - private String address; - private List amounts; - private String dataHash; - private String inlineDatum; - private String referenceScriptHash; + private String address; + + private List amounts; + private String dataHash; + private String inlineDatum; + private String referenceScriptHash; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxScriptEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxScriptEntity.java index c27677bf7..ca902a626 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxScriptEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxScriptEntity.java @@ -1,15 +1,24 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import com.bloxbean.cardano.client.plutus.spec.RedeemerTag; -import jakarta.persistence.*; +import java.math.BigInteger; +import java.util.UUID; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; -import org.cardanofoundation.rosetta.common.enumeration.ScriptType; -import java.math.BigInteger; -import java.util.UUID; +import com.bloxbean.cardano.client.plutus.spec.RedeemerTag; + +import org.cardanofoundation.rosetta.common.enumeration.ScriptType; @Data @NoArgsConstructor @@ -18,46 +27,47 @@ @Entity @Table(name = "transaction_scripts") public class TxScriptEntity extends BlockAwareEntity { - @Id - @GeneratedValue(strategy = GenerationType.UUID) - @Column(name = "id", updatable = false, nullable = false) - private UUID id; - @Column(name = "tx_hash") - private String txHash; + @Id + @GeneratedValue(strategy = GenerationType.UUID) + @Column(name = "id", updatable = false, nullable = false) + private UUID id; + + @Column(name = "tx_hash") + private String txHash; - @Column(name = "script_hash") - private String scriptHash; + @Column(name = "script_hash") + private String scriptHash; - @Column(name = "slot") - private Long slot; + @Column(name = "slot") + private Long slot; - @Column(name = "block_hash") - private String blockHash; + @Column(name = "block_hash") + private String blockHash; - @Column(name = "script_type") - private ScriptType type; + @Column(name = "script_type") + private ScriptType type; - @Column(name = "redeemer_cbor") - private String redeemerCbor; + @Column(name = "redeemer_cbor") + private String redeemerCbor; - @Column(name = "datum_hash") - private String datumHash; + @Column(name = "datum_hash") + private String datumHash; - @Column(name = "unit_mem") - private BigInteger unitMem; + @Column(name = "unit_mem") + private BigInteger unitMem; - @Column(name = "unit_steps") - private BigInteger unitSteps; + @Column(name = "unit_steps") + private BigInteger unitSteps; - @Enumerated(EnumType.STRING) - @Column(name = "purpose") - private RedeemerTag purpose; + @Enumerated(EnumType.STRING) + @Column(name = "purpose") + private RedeemerTag purpose; - @Column(name = "redeemer_index") - private Integer redeemerIndex; + @Column(name = "redeemer_index") + private Integer redeemerIndex; - @Column(name = "redeemer_datahash") - private String redeemerDatahash; + @Column(name = "redeemer_datahash") + private String redeemerDatahash; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxnEntity.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxnEntity.java index f68dcaba8..64add08fe 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxnEntity.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/TxnEntity.java @@ -1,19 +1,29 @@ package org.cardanofoundation.rosetta.api.block.model.entity; -import io.hypersistence.utils.hibernate.type.json.JsonType; -import jakarta.persistence.*; +import java.math.BigInteger; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Set; +import jakarta.persistence.Column; +import jakarta.persistence.ConstraintMode; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; + +import io.hypersistence.utils.hibernate.type.json.JsonType; import org.hibernate.annotations.Type; import org.hibernate.annotations.UpdateTimestamp; -import java.math.BigInteger; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Set; - @Data @NoArgsConstructor @AllArgsConstructor @@ -21,74 +31,75 @@ @Entity @Table(name = "transaction") public class TxnEntity { - @Id - @Column(name = "tx_hash") - private String txHash; - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "block_hash", - foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT, name = "none")) - private BlockEntity block; + @Id + @Column(name = "tx_hash") + private String txHash; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "block_hash", + foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT, name = "none")) + private BlockEntity block; - @Column(name = "slot") - private Long slot; + @Column(name = "slot") + private Long slot; - @Type(JsonType.class) - @Column(name = "inputs") - private List inputKeys; + @Type(JsonType.class) + @Column(name = "inputs") + private List inputKeys; - @Type(JsonType.class) - @Column(name = "outputs") - private List outputKeys; + @Type(JsonType.class) + @Column(name = "outputs") + private List outputKeys; - @Column(name = "fee") - private BigInteger fee; + @Column(name = "fee") + private BigInteger fee; - @Column(name = "ttl") - private Long ttl; + @Column(name = "ttl") + private Long ttl; - @Column(name = "auxiliary_datahash") - private String auxiliaryDataHash; + @Column(name = "auxiliary_datahash") + private String auxiliaryDataHash; - @Column(name = "validity_interval_start") - private Long validityIntervalStart; + @Column(name = "validity_interval_start") + private Long validityIntervalStart; - @Column(name = "script_datahash") - private String scriptDataHash; + @Column(name = "script_datahash") + private String scriptDataHash; - @OneToMany(mappedBy = "txHash") - private List script; + @OneToMany(mappedBy = "txHash") + private List script; - @Type(JsonType.class) - @Column(name = "collateral_inputs") - private List collateralInputs; + @Type(JsonType.class) + @Column(name = "collateral_inputs") + private List collateralInputs; - @Type(JsonType.class) - @Column(name = "required_signers") - private Set requiredSigners; + @Type(JsonType.class) + @Column(name = "required_signers") + private Set requiredSigners; - @Column(name = "network_id") - private Integer netowrkId; + @Column(name = "network_id") + private Integer netowrkId; - @Type(JsonType.class) - @Column(name = "collateral_return") - private UtxoKey collateralReturn; + @Type(JsonType.class) + @Column(name = "collateral_return") + private UtxoKey collateralReturn; - @Type(JsonType.class) - @Column(name = "collateral_return_json") - private TxOuput collateralReturnJson; + @Type(JsonType.class) + @Column(name = "collateral_return_json") + private TxOuput collateralReturnJson; - @Column(name = "total_collateral") - private BigInteger totalCollateral; + @Column(name = "total_collateral") + private BigInteger totalCollateral; - @Type(JsonType.class) - @Column(name = "reference_inputs") - private List referenceInputs; + @Type(JsonType.class) + @Column(name = "reference_inputs") + private List referenceInputs; - @Column(name = "invalid") - private Boolean invalid; + @Column(name = "invalid") + private Boolean invalid; - @UpdateTimestamp - @Column(name = "update_datetime") - private LocalDateTime updateDateTime; + @UpdateTimestamp + @Column(name = "update_datetime") + private LocalDateTime updateDateTime; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/UtxoKey.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/UtxoKey.java index 1f355fe00..6776d8d39 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/UtxoKey.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/entity/UtxoKey.java @@ -1,10 +1,15 @@ package org.cardanofoundation.rosetta.api.block.model.entity; +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; + import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.*; - -import java.io.Serializable; @Getter @NoArgsConstructor @@ -13,6 +18,7 @@ @Builder @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class UtxoKey implements Serializable { - private String txHash; - private Integer outputIndex; + + private String txHash; + private Integer outputIndex; } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/BlockRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/BlockRepository.java index e5dd6e706..6edbfbdd1 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/BlockRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/BlockRepository.java @@ -2,26 +2,31 @@ import java.util.List; -import org.cardanofoundation.rosetta.api.block.model.entity.BlockEntity; -import org.cardanofoundation.rosetta.api.block.model.entity.TxnEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.cardanofoundation.rosetta.api.block.model.entity.BlockEntity; +import org.cardanofoundation.rosetta.api.block.model.entity.TxnEntity; + public interface BlockRepository extends JpaRepository { - @Query(value = - "SELECT b " + - "FROM BlockEntity b " + - "WHERE b.prev.hash IS NULL") - List findGenesisBlock(); - List findByNumber(Long blockNumber); - List findByHash(String blockHash); - List findByNumberAndHash(Long blockNumber, String blockHash); - - @Query("SELECT number FROM BlockEntity " + - "ORDER BY number DESC LIMIT 1") - Long findLatestBlockNumber(); + + @Query(value = + "SELECT b " + + "FROM BlockEntity b " + + "WHERE b.prev.hash IS NULL") + List findGenesisBlock(); + + List findByNumber(Long blockNumber); + + List findByHash(String blockHash); + + List findByNumberAndHash(Long blockNumber, String blockHash); + + @Query("SELECT number FROM BlockEntity " + + "ORDER BY number DESC LIMIT 1") + Long findLatestBlockNumber(); @Query("SELECT tx " + "FROM TxnEntity tx " diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/DelegationRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/DelegationRepository.java index 99155cc97..891661292 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/DelegationRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/DelegationRepository.java @@ -1,12 +1,13 @@ package org.cardanofoundation.rosetta.api.block.model.repository; -import org.cardanofoundation.rosetta.api.block.model.entity.DelegationEntity; -import org.cardanofoundation.rosetta.api.block.model.entity.DelegationId; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; +import org.cardanofoundation.rosetta.api.block.model.entity.DelegationEntity; +import org.cardanofoundation.rosetta.api.block.model.entity.DelegationId; public interface DelegationRepository extends JpaRepository { - List findByTxHash(String txHash); + List findByTxHash(String txHash); } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/EpochParamRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/EpochParamRepository.java index 847bcd81b..ccba3f726 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/EpochParamRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/EpochParamRepository.java @@ -1,12 +1,13 @@ package org.cardanofoundation.rosetta.api.block.model.repository; -import org.cardanofoundation.rosetta.api.block.model.entity.EpochParamEntity; -import org.cardanofoundation.rosetta.api.block.model.entity.ProtocolParams; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.cardanofoundation.rosetta.api.block.model.entity.EpochParamEntity; +import org.cardanofoundation.rosetta.api.block.model.entity.ProtocolParams; + public interface EpochParamRepository extends JpaRepository { - @Query("SELECT e.params FROM EpochParamEntity e ORDER BY e.epoch DESC LIMIT 1") - ProtocolParams findLatestProtocolParams(); + @Query("SELECT e.params FROM EpochParamEntity e ORDER BY e.epoch DESC LIMIT 1") + ProtocolParams findLatestProtocolParams(); } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/PoolRegistrationRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/PoolRegistrationRepository.java index 8e4f37a5b..fdd9aac67 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/PoolRegistrationRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/PoolRegistrationRepository.java @@ -1,12 +1,14 @@ package org.cardanofoundation.rosetta.api.block.model.repository; -import org.cardanofoundation.rosetta.api.block.model.entity.PoolRegistrationEnity; -import org.cardanofoundation.rosetta.api.block.model.entity.PoolRegistrationId; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; +import org.cardanofoundation.rosetta.api.block.model.entity.PoolRegistrationEnity; +import org.cardanofoundation.rosetta.api.block.model.entity.PoolRegistrationId; -public interface PoolRegistrationRepository extends JpaRepository { +public interface PoolRegistrationRepository extends + JpaRepository { - List findByTxHash(String txHash); + List findByTxHash(String txHash); } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/PoolRetirementRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/PoolRetirementRepository.java index 76f46cd82..9f54f22f3 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/PoolRetirementRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/PoolRetirementRepository.java @@ -1,12 +1,14 @@ package org.cardanofoundation.rosetta.api.block.model.repository; -import org.cardanofoundation.rosetta.api.block.model.entity.PoolRetirementEntity; -import org.cardanofoundation.rosetta.api.block.model.entity.PoolRetirementId; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; +import org.cardanofoundation.rosetta.api.block.model.entity.PoolRetirementEntity; +import org.cardanofoundation.rosetta.api.block.model.entity.PoolRetirementId; -public interface PoolRetirementRepository extends JpaRepository { +public interface PoolRetirementRepository extends + JpaRepository { - List findByTxHash(String txHash); + List findByTxHash(String txHash); } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/StakeAddressRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/StakeAddressRepository.java index d42e536ca..566e7d426 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/StakeAddressRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/StakeAddressRepository.java @@ -1,16 +1,19 @@ package org.cardanofoundation.rosetta.api.block.model.repository; -import org.cardanofoundation.rosetta.api.block.model.entity.StakeAddressBalanceEntity; -import org.cardanofoundation.rosetta.api.block.model.entity.StakeAddressBalanceId; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.List; +import org.cardanofoundation.rosetta.api.block.model.entity.StakeAddressBalanceEntity; +import org.cardanofoundation.rosetta.api.block.model.entity.StakeAddressBalanceId; -public interface StakeAddressRepository extends JpaRepository { +public interface StakeAddressRepository extends + JpaRepository { - @Query(value = - "SELECT b from StakeAddressBalanceEntity b WHERE b.slot in (SELECT MAX(c.slot) FROM StakeAddressBalanceEntity c WHERE c.address = :address AND c.blockNumber <= :number) AND b.address = :address") - List findStakeAddressBalanceByAddressAndBlockNumber(@Param("address") String address, @Param("number") Long number); + @Query(value = + "SELECT b from StakeAddressBalanceEntity b WHERE b.slot in (SELECT MAX(c.slot) FROM StakeAddressBalanceEntity c WHERE c.address = :address AND c.blockNumber <= :number) AND b.address = :address") + List findStakeAddressBalanceByAddressAndBlockNumber( + @Param("address") String address, @Param("number") Long number); } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/StakeRegistrationRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/StakeRegistrationRepository.java index a80c94003..f68788a15 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/StakeRegistrationRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/StakeRegistrationRepository.java @@ -1,12 +1,14 @@ package org.cardanofoundation.rosetta.api.block.model.repository; -import org.cardanofoundation.rosetta.api.block.model.entity.StakeRegistrationEntity; -import org.cardanofoundation.rosetta.api.block.model.entity.StakeRegistrationId; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; +import org.cardanofoundation.rosetta.api.block.model.entity.StakeRegistrationEntity; +import org.cardanofoundation.rosetta.api.block.model.entity.StakeRegistrationId; -public interface StakeRegistrationRepository extends JpaRepository{ +public interface StakeRegistrationRepository extends + JpaRepository { - List findByTxHash(String txHash); + List findByTxHash(String txHash); } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/TxRepository.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/TxRepository.java index 5dcc69ee7..b82c4f60f 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/TxRepository.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/model/repository/TxRepository.java @@ -1,10 +1,12 @@ package org.cardanofoundation.rosetta.api.block.model.repository; import java.util.List; -import org.cardanofoundation.rosetta.api.block.model.entity.TxnEntity; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.query.Param; +import org.cardanofoundation.rosetta.api.block.model.entity.TxnEntity; + public interface TxRepository extends JpaRepository { List findTransactionsByBlockHash(@Param("blockHash") String blockHash); diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/BlockService.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/BlockService.java index 81ee369ab..40743f0bd 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/BlockService.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/BlockService.java @@ -1,25 +1,13 @@ package org.cardanofoundation.rosetta.api.block.service; -import java.util.List; +import org.openapitools.client.model.BlockTransactionRequest; +import org.openapitools.client.model.BlockTransactionResponse; -import org.cardanofoundation.rosetta.api.block.model.domain.Transaction; import org.cardanofoundation.rosetta.api.block.model.domain.Block; -import org.openapitools.client.model.*; public interface BlockService { - AccountBalanceResponse findBalanceDataByAddressAndBlock(String address, - Long number, - String hash); - - Block findBlock(Long number, String hash); - - - BlockResponse getBlockByBlockRequest(BlockRequest blockRequest); - -// List fillTransactions(List transactions); - - List findTransactionsByBlock(Block block); + Block findBlock(Long index, String hash); BlockTransactionResponse getBlockTransaction(BlockTransactionRequest blockTransactionRequest); diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/BlockServiceImpl.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/BlockServiceImpl.java new file mode 100644 index 000000000..8ea1d6849 --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/BlockServiceImpl.java @@ -0,0 +1,144 @@ +package org.cardanofoundation.rosetta.api.block.service; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.json.JSONObject; +import org.openapitools.client.model.BlockIdentifier; +import org.openapitools.client.model.BlockTransactionRequest; +import org.openapitools.client.model.BlockTransactionResponse; + +import org.cardanofoundation.rosetta.api.block.mapper.BlockToBlockResponse; +import org.cardanofoundation.rosetta.api.block.model.domain.Block; +import org.cardanofoundation.rosetta.api.block.model.domain.Transaction; +import org.cardanofoundation.rosetta.common.exception.ApiException; +import org.cardanofoundation.rosetta.common.exception.ExceptionFactory; +import org.cardanofoundation.rosetta.common.services.LedgerDataProviderService; +import org.cardanofoundation.rosetta.common.util.FileUtils; + +import static java.util.Objects.nonNull; + +@Slf4j +@Service +@RequiredArgsConstructor +public class BlockServiceImpl implements BlockService { + + private final LedgerDataProviderService ledgerDataProviderService; + @Value("${cardano.rosetta.GENESIS_SHELLEY_PATH}") + private String genesisPath; + + + @Override + public Block findBlock(Long index, String hash) { + + log.info("[block] Looking for block: hash={}, index={}", hash, index); + Block block = ledgerDataProviderService.findBlock(index, hash); + if (nonNull(block)) { + log.info("[block] Block was found, hash={}", block.getHash()); + + List transactionsFound = findTransactionsByBlock(block); + block.setTransactions(transactionsFound); + block.setPoolDeposit(getPoolDeposit()); + + log.debug("[block] full data {}", block); + return block; + } + log.error("[block] Block was not found"); + throw ExceptionFactory.blockNotFoundException(); + } + + private String getPoolDeposit() { + String content; + try { + content = FileUtils.fileReader(genesisPath); + } catch (IOException e) { + throw new ApiException("Could not read genesis file path", e); + } + JSONObject object = new JSONObject(content); + JSONObject protocolParams = object.getJSONObject("protocolParams"); + // TODO Check if this is the right way to get poolDeposit + String poolDeposit = String.valueOf(protocolParams.get("poolDeposit")); + log.debug("[poolDeposit] poolDeposit is [{}]", poolDeposit); + return poolDeposit; + } + + private List findTransactionsByBlock(Block block) { + boolean blockMightContainTransactions = + block.getTransactionsCount() != 0 || block.getPreviousBlockHash().equals(block.getHash()); + log.debug("[findTransactionsByBlock] Does requested block contains transactions? : {}" + , blockMightContainTransactions); + if (blockMightContainTransactions) { + return ledgerDataProviderService.findTransactionsByBlock(block.getNumber(), block.getHash()); + } else { + return Collections.emptyList(); + } + } + + @Override + public BlockTransactionResponse getBlockTransaction(BlockTransactionRequest request) { + BlockIdentifier blockIdentifier = request.getBlockIdentifier(); + BlockTransactionResponse response = new BlockTransactionResponse(); + List transactionsByBlock = ledgerDataProviderService.findTransactionsByBlock( + blockIdentifier.getIndex(), blockIdentifier.getHash()); + if (transactionsByBlock != null) { + Optional first = transactionsByBlock + .stream() + .filter(tr -> tr.getHash() + .equals(request.getTransactionIdentifier().getHash())) + .findFirst(); + if (first.isPresent()) { + String poolDeposit = getPoolDeposit(); + response.setTransaction( + //TODO saa: add refactor mapper to use the new model + BlockToBlockResponse.mapToRosettaTransaction(first.get(), poolDeposit) + ); + } + } + return response; + } + +//TODO saa why this findBlock? +// @Override +// public Block findBlock(Long number, String hash) { +// boolean searchBlockZero; +// if (nonNull(number)) { +// searchBlockZero = (number == 0); +// } else { +// searchBlockZero = false; +// } +// if (searchBlockZero) { +// log.info("[findBlock] Looking for genesis block"); +// GenesisBlock genesis = ledgerDataProviderService.findGenesisBlock(); +// boolean isHashInvalidIfGiven = hash != null && !genesis.getHash().equals(hash); +// if (isHashInvalidIfGiven) { +// log.error("[findBlock] The requested block has an invalid block hash parameter"); +// throw ExceptionFactory.blockNotFoundException(); +// } +// if (nonNull(genesis)) { +// return ledgerDataProviderService.findBlock(null, genesis.getHash()); +// } else { +// return ledgerDataProviderService.findBlock(null, null); +// } +// } +// boolean searchLatestBlock = (isNull(hash)) && (isNull(number)); +// +// log.info("[findBlock] Do we have to look for latestBlock? {}", searchLatestBlock); +// Long blockNumber = searchLatestBlock ? ledgerDataProviderService.findLatestBlockNumber() : number; +// log.info("[findBlock] Looking for block with blockNumber {}", blockNumber); +// Block response = ledgerDataProviderService.findBlock(blockNumber, hash); +// if (nonNull(response)) { +// log.info("[findBlock] Block was found"); +// } +// log.debug("[findBlock] Returning response: " + response); +// return response; +// } + + +} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImpl.java b/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImpl.java deleted file mode 100644 index cdde0e64d..000000000 --- a/api/src/main/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImpl.java +++ /dev/null @@ -1,178 +0,0 @@ -package org.cardanofoundation.rosetta.api.block.service.impl; - -import java.io.IOException; -import java.util.*; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.cardanofoundation.rosetta.api.account.model.domain.AddressBalance; -import org.cardanofoundation.rosetta.api.block.model.domain.Block; -import org.cardanofoundation.rosetta.api.block.model.domain.GenesisBlock; -import org.cardanofoundation.rosetta.api.block.model.domain.StakeAddressBalance; -import org.cardanofoundation.rosetta.api.block.model.domain.Transaction; -import org.cardanofoundation.rosetta.common.exception.ExceptionFactory; -import org.cardanofoundation.rosetta.common.mapper.DataMapper; -import org.cardanofoundation.rosetta.common.util.CardanoAddressUtil; -import org.cardanofoundation.rosetta.api.block.service.BlockService; -import org.cardanofoundation.rosetta.common.services.LedgerDataProviderService; -import org.cardanofoundation.rosetta.common.util.FileUtils; -import org.json.JSONObject; -import org.openapitools.client.model.*; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@RequiredArgsConstructor -public class BlockServiceImpl implements BlockService { - - private final LedgerDataProviderService ledgerDataProviderService; - @Value("${page-size:5}") - private Integer pageSize; - @Value("${cardano.rosetta.GENESIS_SHELLEY_PATH}") - private String genesisPath; - - @Override - public BlockResponse getBlockByBlockRequest(BlockRequest blockRequest) { - PartialBlockIdentifier blockIdentifier = blockRequest.getBlockIdentifier(); - String hash = blockIdentifier.getHash(); - Long index = blockIdentifier.getIndex(); - log.info("[block] Looking for block: hash={}, index={}", hash, index); - Block block = ledgerDataProviderService.findBlock(index, hash); - if (Objects.nonNull(block)) { - log.info("[block] Block was found"); - List transactionsFound = this.findTransactionsByBlock(block); - - log.debug("[block] transactionsFound is " + transactionsFound.toString()); - String poolDeposit = getPoolDeposit(); - if (transactionsFound.size() > pageSize) { - log.info( - "[block] Returning only transactions hashes since the number of them is bigger than {}" - , pageSize); - return BlockResponse.builder() - .block(DataMapper.mapToRosettaBlock(block, poolDeposit)) -// .otherTransactions(transactionsFound.stream().map(transactionDto -> new TransactionIdentifier().hash(transactionDto.getHash())).toList()) - .build(); - } - log.info("[block] Looking for blocks transactions full data"); - - - return BlockResponse.builder() - .block(DataMapper.mapToRosettaBlock(block, poolDeposit)) - .build(); - } - log.error("[block] Block was not found"); - throw ExceptionFactory.blockNotFoundException(); - } - - private String getPoolDeposit() { - String content; - try { - content = FileUtils.fileReader(genesisPath); - } catch (IOException e) { - throw ExceptionFactory.unspecifiedError("Error reading genesis file"); - } - JSONObject object = new JSONObject(content); - JSONObject protocolParams = object.getJSONObject("protocolParams"); - String poolDeposit = String.valueOf(protocolParams.get("poolDeposit")); // TODO Check if this is the right way to get poolDeposit - log.debug("[poolDeposit] poolDeposit is " + poolDeposit); - return poolDeposit; - } - - @Override - public List findTransactionsByBlock(Block block) { - boolean blockMightContainTransactions = - block.getTransactionsCount() != 0 || block.getPreviousBlockHash().equals(block.getHash()); - log.debug("[findTransactionsByBlock] Does requested block contains transactions? : {}" - , blockMightContainTransactions); - if (blockMightContainTransactions) { - return ledgerDataProviderService.findTransactionsByBlock(block.getNumber(), block.getHash()); - } else { - return Collections.emptyList(); - } - } - - @Override - public BlockTransactionResponse getBlockTransaction(BlockTransactionRequest blockTransactionRequest) { - BlockIdentifier blockIdentifier = blockTransactionRequest.getBlockIdentifier(); - BlockTransactionResponse response = new BlockTransactionResponse(); - List transactionsByBlock = ledgerDataProviderService.findTransactionsByBlock(blockIdentifier.getIndex(), blockIdentifier.getHash()); - if(transactionsByBlock != null) { - Optional first = transactionsByBlock.stream().filter(transactionDto -> transactionDto.getHash().equals(blockTransactionRequest.getTransactionIdentifier().getHash())).findFirst(); - if(first.isPresent()) { - String poolDeposit = getPoolDeposit(); - response.setTransaction(DataMapper.mapToRosettaTransaction(first.get(), poolDeposit)); - } - } - return response; - } - - @Override - public Block findBlock(Long number, String hash) { - boolean searchBlockZero; - if (Objects.nonNull(number)) { - searchBlockZero = (number == 0); - } else { - searchBlockZero = false; - } - if (searchBlockZero) { - log.info("[findBlock] Looking for genesis block"); - GenesisBlock genesis = ledgerDataProviderService.findGenesisBlock(); - boolean isHashInvalidIfGiven = hash != null && !genesis.getHash().equals(hash); - if (isHashInvalidIfGiven) { - log.error("[findBlock] The requested block has an invalid block hash parameter"); - throw ExceptionFactory.blockNotFoundException(); - } - if (Objects.nonNull(genesis)) { - return ledgerDataProviderService.findBlock(null, genesis.getHash()); - } else { - return ledgerDataProviderService.findBlock(null, null); - } - } - boolean searchLatestBlock = (Objects.isNull(hash)) && (Objects.isNull(number)); - - log.info("[findBlock] Do we have to look for latestBlock? {}", searchLatestBlock); - Long blockNumber = searchLatestBlock ? ledgerDataProviderService.findLatestBlockNumber() : number; - log.info("[findBlock] Looking for block with blockNumber {}", blockNumber); - Block response = ledgerDataProviderService.findBlock(blockNumber, hash); - if (Objects.nonNull(response)) { - log.info("[findBlock] Block was found"); - } - log.debug("[findBlock] Returning response: " + response); - return response; - } - - @Override - public AccountBalanceResponse findBalanceDataByAddressAndBlock(String address, Long number, String hash) { - Block block; - if(number != null || hash != null) { - block = ledgerDataProviderService.findBlock(number, hash); - } else { - block = ledgerDataProviderService.findLatestBlock(); - } - - if (Objects.isNull(block)) { - log.error("[findBalanceDataByAddressAndBlock] Block not found"); - throw ExceptionFactory.blockNotFoundException(); - } - log.info( - "[findBalanceDataByAddressAndBlock] Looking for utxos for address {} and block {}", - address, - block.getHash()); - if (CardanoAddressUtil.isStakeAddress(address)) { - log.debug("[findBalanceDataByAddressAndBlock] Address is StakeAddress"); - log.debug("[findBalanceDataByAddressAndBlock] About to get balance for {}", address); - List balances = ledgerDataProviderService.findStakeAddressBalanceByAddressAndBlock(address, block.getNumber()); - if(Objects.isNull(balances) || balances.isEmpty()) { - log.error("[findBalanceDataByAddressAndBlock] No balance found for {}", address); - throw ExceptionFactory.invalidAddressError(); - } - return DataMapper.mapToStakeAddressBalanceResponse(block, balances.getFirst()); - } else { - log.debug("[findBalanceDataByAddressAndBlock] Address isn't StakeAddress"); - - List balances = ledgerDataProviderService.findBalanceByAddressAndBlock(address, block.getNumber()); - return DataMapper.mapToAccountBalanceResponse(block, balances); - } - } - -} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/annotation/OpenApiMapper.java b/api/src/main/java/org/cardanofoundation/rosetta/common/annotation/OpenApiMapper.java new file mode 100644 index 000000000..c379d615f --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/annotation/OpenApiMapper.java @@ -0,0 +1,22 @@ +package org.cardanofoundation.rosetta.common.annotation; + +import org.springframework.core.annotation.AliasFor; +import org.springframework.stereotype.Component; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Component +public @interface OpenApiMapper { + + /** + * The value may indicate a suggestion for a logical component name, + * to be turned into a Spring bean in case of an autodetected component. + * @return the suggested component name, if any (or empty String otherwise) + */ + @AliasFor(annotation = Component.class) + String value() default ""; + +} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/annotation/PersistenceMapper.java b/api/src/main/java/org/cardanofoundation/rosetta/common/annotation/PersistenceMapper.java new file mode 100644 index 000000000..a64c74a3a --- /dev/null +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/annotation/PersistenceMapper.java @@ -0,0 +1,22 @@ +package org.cardanofoundation.rosetta.common.annotation; + +import org.springframework.core.annotation.AliasFor; +import org.springframework.stereotype.Component; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Component +public @interface PersistenceMapper { + + /** + * The value may indicate a suggestion for a logical component name, + * to be turned into a Spring bean in case of an autodetected component. + * @return the suggested component name, if any (or empty String otherwise) + */ + @AliasFor(annotation = Component.class) + String value() default ""; + +} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/exception/ApiException.java b/api/src/main/java/org/cardanofoundation/rosetta/common/exception/ApiException.java index d61c0bcde..81c8f644c 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/common/exception/ApiException.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/exception/ApiException.java @@ -9,11 +9,15 @@ public class ApiException extends RuntimeException { @Serial private static final long serialVersionUID = 7966468689369382174L; - private final Error error; + private Error error; public ApiException(Error error) { super(); this.error = error; } + public ApiException(String message, Throwable throwable) { + super(message, throwable); + } + } diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/mapper/DataMapper.java b/api/src/main/java/org/cardanofoundation/rosetta/common/mapper/DataMapper.java index e5979e405..c1557dcd4 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/common/mapper/DataMapper.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/mapper/DataMapper.java @@ -1,7 +1,6 @@ package org.cardanofoundation.rosetta.common.mapper; import com.bloxbean.cardano.client.common.model.Network; -import java.text.Normalizer.Form; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Hex; import org.cardanofoundation.rosetta.api.account.model.domain.AddressBalance; @@ -61,43 +60,6 @@ public static NetworkStatusResponse mapToNetworkStatusResponse(NetworkStatus net .build(); } - /** - * Maps a list of AddressBalanceDTOs to a Rosetta compatible AccountBalanceResponse. - * @param block The block from where the balances are calculated into the past - * @param poolDeposit The pool deposit - * @return The Rosetta compatible AccountBalanceResponse - */ - public static org.openapitools.client.model.Block mapToRosettaBlock(Block block, String poolDeposit) { - org.openapitools.client.model.Block rosettaBlock = org.openapitools.client.model.Block.builder().build(); - rosettaBlock.setBlockIdentifier(BlockIdentifier.builder() - .index(block.getNumber()).hash(block.getHash()).build()); - rosettaBlock.setParentBlockIdentifier(BlockIdentifier.builder() - .index(block.getPreviousBlockNumber()).hash(block.getPreviousBlockHash()).build()); - rosettaBlock.setTimestamp(block.getCreatedAt()); - rosettaBlock.setTransactions(mapToRosettaTransactions(block.getTransactions(), poolDeposit)); - rosettaBlock.metadata(BlockMetadata.builder() - .transactionsCount(block.getTransactionsCount()) - .createdBy(block.getCreatedBy()) - .size(block.getSize()) - .epochNo(block.getEpochNo()) - .slotNo(block.getSlotNo()) - .build()); - return rosettaBlock; - } - - /** - * Maps a list of TransactionDtos to a list of Rosetta compatible Transactions. - * @param transactions The transactions to be mapped - * @param poolDeposit The pool deposit - * @return The list of Rosetta compatible Transactions - */ - public static List mapToRosettaTransactions(List transactions, String poolDeposit) { - List rosettaTransactions = new ArrayList<>(); - for(Transaction transactionDto : transactions) { - rosettaTransactions.add(mapToRosettaTransaction(transactionDto, poolDeposit)); - } - return rosettaTransactions; - } /** * Basic mapping if a value is spent or not. @@ -117,30 +79,6 @@ public static CoinChange getCoinChange(int index, String hash, CoinAction coinAc .coinAction(coinAction).build(); } - /** - * Maps a TransactionDto to a Rosetta compatible Transaction. - * @param transactionDto The transaction to be mapped - * @param poolDeposit The pool deposit - * @return The Rosetta compatible Transaction - */ - public static org.openapitools.client.model.Transaction mapToRosettaTransaction(Transaction transactionDto, String poolDeposit) { - org.openapitools.client.model.Transaction rosettaTransaction = new org.openapitools.client.model.Transaction(); - TransactionIdentifier identifier = new TransactionIdentifier(); - identifier.setHash(transactionDto.getHash()); - rosettaTransaction.setTransactionIdentifier(identifier); - - OperationStatus status = new OperationStatus(); - status.setStatus(SUCCESS_OPERATION_STATUS.getStatus()); // TODO need to check the right status - List operations = OperationDataMapper.getAllOperations(transactionDto, poolDeposit, status); - - rosettaTransaction.setMetadata(TransactionMetadata.builder() - .size(transactionDto.getSize()) // Todo size is not available - .scriptSize(transactionDto.getScriptSize()) // TODO script size is not available - .build()); - rosettaTransaction.setOperations(operations); - return rosettaTransaction; - - } /** * Creates a Rosetta compatible Amount for ADA. The value is the amount in lovelace and the currency is ADA. diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/mapper/OperationDataMapper.java b/api/src/main/java/org/cardanofoundation/rosetta/common/mapper/OperationDataMapper.java deleted file mode 100644 index e45062ced..000000000 --- a/api/src/main/java/org/cardanofoundation/rosetta/common/mapper/OperationDataMapper.java +++ /dev/null @@ -1,268 +0,0 @@ -package org.cardanofoundation.rosetta.common.mapper; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import lombok.extern.slf4j.Slf4j; - -import com.bloxbean.cardano.yaci.core.model.certs.CertificateType; -import org.apache.commons.codec.binary.Hex; -import org.jetbrains.annotations.NotNull; -import org.openapitools.client.model.AccountIdentifier; -import org.openapitools.client.model.Amount; -import org.openapitools.client.model.CoinAction; -import org.openapitools.client.model.CoinChange; -import org.openapitools.client.model.Currency; -import org.openapitools.client.model.Operation; -import org.openapitools.client.model.OperationIdentifier; -import org.openapitools.client.model.OperationStatus; - -import org.cardanofoundation.rosetta.api.account.model.domain.Utxo; -import org.cardanofoundation.rosetta.api.account.model.entity.Amt; -import org.cardanofoundation.rosetta.api.block.model.domain.Delegation; -import org.cardanofoundation.rosetta.api.block.model.domain.PoolRegistration; -import org.cardanofoundation.rosetta.api.block.model.domain.PoolRetirement; -import org.cardanofoundation.rosetta.api.block.model.domain.StakeRegistration; -import org.cardanofoundation.rosetta.api.block.model.domain.Transaction; -import org.cardanofoundation.rosetta.common.enumeration.OperationType; -import org.cardanofoundation.rosetta.common.util.Constants; -import org.openapitools.client.model.*; - -import static org.cardanofoundation.rosetta.common.util.Constants.ADA; -import static org.cardanofoundation.rosetta.common.util.Constants.ADA_DECIMALS; - -@Slf4j -public class OperationDataMapper { - - @NotNull - public static List getAllOperations(Transaction transactionDto, String poolDeposit, OperationStatus status) { - List> totalOperations = new ArrayList<>(); - List inputsAsOperations = getInputTransactionsasOperations(transactionDto, status); - totalOperations.add(inputsAsOperations); -// TODO Withdrawal currently not supported via Yaci-store. Will implemented it as soon as the PR is merged. -// List withdrawalsAsOperations = getWithdrawlOperations(transactionDto, status, totalOperations); -// totalOperations.add(withdrawalsAsOperations); - - List stakeRegistrationOperations = getStakeRegistrationOperations(transactionDto, status, totalOperations); - totalOperations.add(stakeRegistrationOperations); - - List delegationOperations = getDelegationOperations(transactionDto, status, totalOperations); - totalOperations.add(delegationOperations); - - List poolRegistrationOperations = getPoolRegistrationOperations(transactionDto, status, totalOperations, poolDeposit); - totalOperations.add(poolRegistrationOperations); - - List poolRetirementOperations = getPoolRetirementOperations(transactionDto, status, totalOperations); - totalOperations.add(poolRetirementOperations); - - List relatedOperations = getOperationIndexes(inputsAsOperations); - - List outputsAsOperations = getOutputsAsOperations(transactionDto, totalOperations, status, relatedOperations); - - totalOperations.add(outputsAsOperations); - List operations = totalOperations.stream() - .flatMap(Collection::stream) - .collect(Collectors.toList()); - return operations; - } - -// @NotNull -// private static List getWithdrawlOperations(TransactionDto transactionDto, OperationStatus status, List> totalOperations) { -// return IntStream.range(0, -// transactionDto.getWithdrawals().size()) -// .mapToObj(index -> { -// Withdrawal withdrawal = transaction.getWithdrawals().get(index); -// return Operation.builder() -// .operationIdentifier(OperationIdentifier.builder().index( -// getOperationCurrentIndex(totalOperations, index)).build()) -// .type(OperationType.WITHDRAWAL.getValue()) -// .status(status.getStatus()) -// .account(AccountIdentifier.builder().address(withdrawal.getStakeAddress()).build()) -// .metadata(OperationMetadata.builder() -// .withdrawalAmount(DataMapper.mapAmount("-" + withdrawal.getAmount())) -// .build()) -// .build(); -// }).toList(); -// } - - @NotNull - public static List getInputTransactionsasOperations(Transaction transactionDto, OperationStatus status) { - List inputsAsOperations = IntStream.range(0, transactionDto.getInputs().size()) - .mapToObj(index -> { - Utxo utxoModel = transactionDto.getInputs().get(index); - return createOperation((long) index, - Constants.INPUT, - status.getStatus(), - utxoModel.getOwnerAddr(), - DataMapper.mapValue(utxoModel.getLovelaceAmount().toString(), true), - null, - null, - DataMapper.getCoinChange(utxoModel.getOutputIndex(), utxoModel.getTxHash(), - CoinAction.SPENT), - mapToOperationMetaData(true, utxoModel.getAmounts())); - }).toList(); - return inputsAsOperations; - } - - public static List getPoolRegistrationOperations(Transaction transactionDto, OperationStatus status, List> totalOperations, String poolDeposit) { - return IntStream.range(0, - transactionDto.getPoolRegistrations().size()) - .mapToObj(index -> { - PoolRegistration poolRegistration = transactionDto.getPoolRegistrations().get(index); - return Operation.builder() - .operationIdentifier(OperationIdentifier.builder().index( - getOperationCurrentIndex(totalOperations, index)).build()) - .type(OperationType.POOL_REGISTRATION.getValue()) - .status(status.getStatus()) - .account(AccountIdentifier.builder().address(poolRegistration.getPoolId()).build()) - .metadata(OperationMetadata.builder() - .depositAmount(DataMapper.mapAmount(poolDeposit)) - .poolRegistrationParams(PoolRegistrationParams.builder() - .pledge(poolRegistration.getPledge()) - .rewardAddress(poolRegistration.getRewardAccount()) - .cost(poolRegistration.getCost()) - .poolOwners(poolRegistration.getOwners().stream().toList()) - .marginPercentage(poolRegistration.getMargin()) - .vrfKeyHash(poolRegistration.getVrfKeyHash()) - .relays(poolRegistration.getRelays()) - .build()) - .build()) - .build(); - }).toList(); - } - - public static List getPoolRetirementOperations(Transaction transactionDto, OperationStatus status, List> totalOperations) { - return IntStream.range(0, - transactionDto.getPoolRetirements().size()) - .mapToObj(index -> { - PoolRetirement poolRetirement = transactionDto.getPoolRetirements().get(index); - return Operation.builder() - .operationIdentifier(OperationIdentifier.builder().index( - getOperationCurrentIndex(totalOperations, index)).build()) - .type(OperationType.POOL_RETIREMENT.getValue()) - .status(status.getStatus()) - .account(AccountIdentifier.builder().address(poolRetirement.getPoolId()).build()) - .metadata(OperationMetadata.builder() - .epoch(poolRetirement.getEpoch()) - .build()) - .build(); - }).toList(); - } - - public static List getStakeRegistrationOperations(Transaction transactionDto, OperationStatus status, List> totalOperations) { - return IntStream.range(0, - transactionDto.getStakeRegistrations().size()) - .mapToObj(index -> { - StakeRegistration stakeRegistration = transactionDto.getStakeRegistrations().get(index); - OperationType operationType = stakeRegistration.getType().equals(CertificateType.STAKE_REGISTRATION) ? OperationType.STAKE_KEY_REGISTRATION : - stakeRegistration.getType().equals(CertificateType.STAKE_DEREGISTRATION) ? OperationType.STAKE_KEY_DEREGISTRATION : null; - if(operationType == null) { - log.error("Invalid stake registration type {}", stakeRegistration.getType()); - return null; - } - return Operation.builder() - .operationIdentifier(OperationIdentifier.builder().index( - getOperationCurrentIndex(totalOperations, index)).build()) - .type(operationType.getValue()) - .status(status.getStatus()) - .account(AccountIdentifier.builder().address(stakeRegistration.getAddress()).build()) - .metadata(OperationMetadata.builder() - - .depositAmount(DataMapper.mapAmount("2000000", ADA, ADA_DECIMALS, null)) // TODO need to get this from protocolparams - .build()) - .build(); - }).toList(); - } - - public static List getDelegationOperations(Transaction transaction, OperationStatus status, List> totalOperations) { - return IntStream.range(0, - transaction.getDelegations().size()) - .mapToObj(index -> { - Delegation delegation = transaction.getDelegations().get(index); - return Operation.builder() - .operationIdentifier(OperationIdentifier.builder().index( - getOperationCurrentIndex(totalOperations, index)).build()) - .type(OperationType.STAKE_DELEGATION.getValue()) - .status(status.getStatus()) - .account(AccountIdentifier.builder().address(delegation.getAddress()).build()) - .metadata(OperationMetadata.builder() - .poolKeyHash(delegation.getPoolId()) - .build()) - .build(); - }).toList(); - } - - @NotNull - public static List getOutputsAsOperations(Transaction transaction, List> totalOperations, OperationStatus status, List relatedOperations) { - List outputsAsOperations = IntStream.range(0, transaction.getOutputs().size()) - .mapToObj(index -> { - Utxo utxoModel = transaction.getOutputs().get(index); - return createOperation(getOperationCurrentIndex(totalOperations, index), - Constants.OUTPUT, - status.getStatus(), - utxoModel.getOwnerAddr(), - DataMapper.mapValue(utxoModel.getLovelaceAmount().toString(), false), - relatedOperations, - Long.valueOf(utxoModel.getOutputIndex()), - DataMapper.getCoinChange(utxoModel.getOutputIndex(), utxoModel.getTxHash(), - CoinAction.CREATED), - mapToOperationMetaData(false, utxoModel.getAmounts())); - }).toList(); - return outputsAsOperations; - } - - public static Operation createOperation(Long index, String type, String status, String address, - String value, List relatedOperations, Long networkIndex, - CoinChange coinChange, OperationMetadata tokenBundleMetadata) { - return Operation.builder() - .operationIdentifier(OperationIdentifier.builder() - .index(index) - .networkIndex(networkIndex).build() - ) - .type(type) - .status(status) - .account(AccountIdentifier.builder() - .address(address).build() - ) - .amount(DataMapper.mapAmount(value, null, null, null)) - .coinChange(coinChange) - .relatedOperations(relatedOperations) - .metadata(tokenBundleMetadata).build(); - } - - private static OperationMetadata mapToOperationMetaData(boolean spent, List amounts) { - OperationMetadata operationMetadata = new OperationMetadata(); - for (Amt amount : amounts) { - if(!amount.getAssetName().equals(Constants.LOVELACE)) { - TokenBundleItem tokenBundleItem = new TokenBundleItem(); - tokenBundleItem.setPolicyId(amount.getPolicyId()); - Amount amt = new Amount(); - amt.setValue(DataMapper.mapValue(amount.getQuantity().toString(), spent)); - String hexAssetName = Hex.encodeHexString(amount.getAssetName().getBytes()); - amt.setCurrency(Currency.builder() - .symbol(hexAssetName) - .decimals(0) - .build()); - tokenBundleItem.setTokens(List.of(amt)); - operationMetadata.addTokenBundleItem(tokenBundleItem); - } - } - return operationMetadata; - } - - public static long getOperationCurrentIndex(List> operationsList, - int relativeIndex) { - return relativeIndex + operationsList.stream() - .mapToLong(List::size) - .sum(); - } - - public static List getOperationIndexes(List operations) { - return operations.stream() - .map(operation -> OperationIdentifier.builder().index(operation.getOperationIdentifier() - .getIndex()).build()).collect(Collectors.toList()); - } -} diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/services/impl/CardanoServiceImpl.java b/api/src/main/java/org/cardanofoundation/rosetta/common/services/impl/CardanoServiceImpl.java index 6cc711044..740a3c81e 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/common/services/impl/CardanoServiceImpl.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/services/impl/CardanoServiceImpl.java @@ -33,7 +33,7 @@ import org.cardanofoundation.rosetta.common.model.cardano.transaction.UnsignedTransaction; import org.cardanofoundation.rosetta.common.services.CardanoService; import org.cardanofoundation.rosetta.common.services.LedgerDataProviderService; -import org.cardanofoundation.rosetta.common.util.CardanoAddressUtil; +import org.cardanofoundation.rosetta.common.util.CardanoAddressUtils; import org.cardanofoundation.rosetta.common.util.Constants; import org.cardanofoundation.rosetta.common.util.OperationParseUtil; import org.cardanofoundation.rosetta.common.util.ValidateParseUtil; @@ -135,12 +135,12 @@ public Signatures signatureProcessor(EraAddressType eraAddressType, AddressType public Double calculateTxSize(NetworkIdentifierType networkIdentifierType, List operations, int ttl, DepositParameters depositParameters) throws IOException, CborException, AddressExcepion, CborSerializationException { UnsignedTransaction unsignedTransaction = createUnsignedTransaction(networkIdentifierType, operations, ttl, !ObjectUtils.isEmpty(depositParameters) ? depositParameters : new DepositParameters(Constants.DEFAULT_KEY_DEPOSIT.toString(), Constants.DEFAULT_POOL_DEPOSIT.toString())); List signaturesList = (unsignedTransaction.addresses()).stream().map(address -> { - EraAddressType eraAddressType = CardanoAddressUtil.getEraAddressType(address); + EraAddressType eraAddressType = CardanoAddressUtils.getEraAddressType(address); if (eraAddressType != null) { return signatureProcessor(eraAddressType, null, address); } // since pool key hash are passed as address, ed25519 hashes must be included - if (CardanoAddressUtil.isEd25519KeyHash(address)) { + if (CardanoAddressUtils.isEd25519KeyHash(address)) { return signatureProcessor(null, AddressType.POOL_KEY_HASH, address); } throw ExceptionFactory.invalidAddressError(address); @@ -208,7 +208,7 @@ public TransactionWitnessSet getWitnessesForTransaction(List signatu signaturesList.forEach(signature -> { VerificationKey vkey = new VerificationKey(); vkey.setCborHex(ObjectUtils.isEmpty(signature) ? null : signature.publicKey()); - EraAddressType eraAddressType = CardanoAddressUtil.getEraAddressType(signature.address()); + EraAddressType eraAddressType = CardanoAddressUtils.getEraAddressType(signature.address()); if (!ObjectUtils.isEmpty(signature)) { if (!ObjectUtils.isEmpty(signature.address()) && eraAddressType == EraAddressType.BYRON) { // byron case diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtil.java b/api/src/main/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtils.java similarity index 97% rename from api/src/main/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtil.java rename to api/src/main/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtils.java index 8b9419354..dea81e69f 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtil.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtils.java @@ -20,24 +20,20 @@ import com.bloxbean.cardano.client.util.HexUtil; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.validator.routines.InetAddressValidator; -import org.openapitools.client.model.Amount; -import org.openapitools.client.model.Currency; import org.openapitools.client.model.PublicKey; import org.cardanofoundation.rosetta.common.enumeration.EraAddressType; import org.cardanofoundation.rosetta.common.enumeration.NetworkIdentifierType; import org.cardanofoundation.rosetta.common.enumeration.StakeAddressPrefix; import org.cardanofoundation.rosetta.common.exception.ExceptionFactory; -import org.openapitools.client.model.PublicKey; -import java.util.Arrays; import java.util.Objects; import org.openapitools.client.model.Relay; @Slf4j -public class CardanoAddressUtil { +public class CardanoAddressUtils { - private CardanoAddressUtil() { + private CardanoAddressUtils() { } @@ -238,7 +234,7 @@ public static HdPublicKey publicKeyToHdPublicKey(PublicKey publicKey) { log.error("[getPublicKey] Staking key not provided"); throw ExceptionFactory.missingStakingKeyError(); } - boolean checkKey = CardanoAddressUtil.isKeyValid(publicKey.getHexBytes(), + boolean checkKey = CardanoAddressUtils.isKeyValid(publicKey.getHexBytes(), publicKey.getCurveType().toString()); if (!checkKey) { log.info("[getPublicKey] Staking key has an invalid format"); diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/util/ParseConstructionUtil.java b/api/src/main/java/org/cardanofoundation/rosetta/common/util/ParseConstructionUtil.java index a7f0e0249..5e4333aa1 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/common/util/ParseConstructionUtil.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/util/ParseConstructionUtil.java @@ -52,19 +52,19 @@ public static List getOwnerAddressesFromPoolRegistrations(String network Set owners = poolRegistration.getPoolOwners(); for(String owner : owners) { if (networkId.equals(NetworkIdentifierType.CARDANO_TESTNET_NETWORK.getNetworkId())) { - Address address = CardanoAddressUtil.getAddress(null, + Address address = CardanoAddressUtils.getAddress(null, HexUtil.decodeHexString(owner), Constants.STAKE_KEY_HASH_HEADER_KIND, Networks.testnet(), Reward); poolOwners.add(address.getAddress()); } if (networkId.equals(NetworkIdentifierType.CARDANO_PREPROD_NETWORK.getNetworkId())) { - Address address = CardanoAddressUtil.getAddress(null, + Address address = CardanoAddressUtils.getAddress(null, HexUtil.decodeHexString(owner), Constants.STAKE_KEY_HASH_HEADER_KIND, Networks.preprod(), Reward); poolOwners.add(address.getAddress()); } if (networkId.equals(NetworkIdentifierType.CARDANO_MAINNET_NETWORK.getNetworkId())) { - Address address = CardanoAddressUtil.getAddress(null, + Address address = CardanoAddressUtils.getAddress(null, HexUtil.decodeHexString(owner), Constants.STAKE_KEY_HASH_HEADER_KIND, Networks.mainnet(), Reward); poolOwners.add(address.getAddress()); @@ -80,21 +80,21 @@ public static String getRewardAddressFromPoolRegistration(String networkId, Pool cutRewardAccount = poolRegistration.getRewardAccount().substring(2); } if (networkId.equals(NetworkIdentifierType.CARDANO_TESTNET_NETWORK.getNetworkId())) { - return CardanoAddressUtil.getAddress(null, + return CardanoAddressUtils.getAddress(null, HexUtil.decodeHexString(cutRewardAccount), Constants.STAKE_KEY_HASH_HEADER_KIND, Networks.testnet(), Reward) .getAddress(); } if (networkId.equals(NetworkIdentifierType.CARDANO_PREPROD_NETWORK.getNetworkId())) { - return CardanoAddressUtil.getAddress(null, + return CardanoAddressUtils.getAddress(null, HexUtil.decodeHexString(cutRewardAccount), Constants.STAKE_KEY_HASH_HEADER_KIND, Networks.preprod(), Reward) .getAddress(); } if (networkId.equals(NetworkIdentifierType.CARDANO_MAINNET_NETWORK.getNetworkId())) { - return CardanoAddressUtil.getAddress(null, + return CardanoAddressUtils.getAddress(null, HexUtil.decodeHexString(cutRewardAccount), Constants.STAKE_KEY_HASH_HEADER_KIND, Networks.mainnet(), Reward) diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/util/ProcessContructionUtil.java b/api/src/main/java/org/cardanofoundation/rosetta/common/util/ProcessContructionUtil.java index fa5de67f8..224ca8e53 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/common/util/ProcessContructionUtil.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/util/ProcessContructionUtil.java @@ -55,7 +55,7 @@ public static Certificate getStakeRegistrationCertificateFromOperation(Operation log.info("[processStakeKeyRegistration] About to process stake key registration"); OperationMetadata operationMetadata = operation.getMetadata(); - StakeCredential credential = CardanoAddressUtil.getStakingCredentialFromStakeKey(operationMetadata.getStakingCredential()); + StakeCredential credential = CardanoAddressUtils.getStakingCredentialFromStakeKey(operationMetadata.getStakingCredential()); return new StakeRegistration(credential); } @@ -67,12 +67,12 @@ public static StakeCertificate getStakeCertificateFromOperation( OperationMetadata operationMetadata = operation.getMetadata(); PublicKey publicKey = ObjectUtils.isEmpty(operation.getMetadata()) ? null : operationMetadata.getStakingCredential(); - StakeCredential credential = CardanoAddressUtil.getStakingCredentialFromStakeKey(publicKey); + StakeCredential credential = CardanoAddressUtils.getStakingCredentialFromStakeKey(publicKey); HdPublicKey hdPublicKey = new HdPublicKey(); if (publicKey != null) { hdPublicKey.setKeyData(HexUtil.decodeHexString(publicKey.getHexBytes())); } - String address = CardanoAddressUtil.generateRewardAddress(networkIdentifierType, hdPublicKey); + String address = CardanoAddressUtils.generateRewardAddress(networkIdentifierType, hdPublicKey); if (operation.getType().equals(OperationType.STAKE_DELEGATION.getValue())) { if (operationMetadata.getPoolKeyHash() == null) { throw ExceptionFactory.missingPoolKeyError(); @@ -97,7 +97,7 @@ public static ProcessWithdrawalReturn getWithdrawalsReturnFromOperation( hdPublicKey.setKeyData( HexUtil.decodeHexString(operationMetadata.getStakingCredential().getHexBytes())); } - String address = CardanoAddressUtil.generateRewardAddress(networkIdentifierType, hdPublicKey); + String address = CardanoAddressUtils.generateRewardAddress(networkIdentifierType, hdPublicKey); HdPublicKey hdPublicKey1 = new HdPublicKey(); hdPublicKey1.setKeyData( HexUtil.decodeHexString(operationMetadata.getStakingCredential().getHexBytes())); diff --git a/api/src/main/java/org/cardanofoundation/rosetta/common/util/ValidateParseUtil.java b/api/src/main/java/org/cardanofoundation/rosetta/common/util/ValidateParseUtil.java index 1bca2f3ea..008b1b78b 100644 --- a/api/src/main/java/org/cardanofoundation/rosetta/common/util/ValidateParseUtil.java +++ b/api/src/main/java/org/cardanofoundation/rosetta/common/util/ValidateParseUtil.java @@ -82,7 +82,7 @@ public static TransactionInput validateAndParseTransactionInput(Operation input) public static TransactionOutput validateAndParseTransactionOutput(Operation output) { Object address; try { - address = ObjectUtils.isEmpty(output.getAccount()) ? null : CardanoAddressUtil.generateAddress(output.getAccount().getAddress()); + address = ObjectUtils.isEmpty(output.getAccount()) ? null : CardanoAddressUtils.generateAddress(output.getAccount().getAddress()); } catch (Exception error) { throw ExceptionFactory.transactionOutputDeserializationError("Invalid input: " + output.getAccount().getAddress() + " " + error.getMessage()); } @@ -143,7 +143,7 @@ public static List validateAndParseTokenBundle(List } public static void validateCheckKey(String policyId) { - boolean checckKey = CardanoAddressUtil.isPolicyIdValid(policyId); + boolean checckKey = CardanoAddressUtils.isPolicyIdValid(policyId); if (!checckKey) { log.error("[validateAndParseTokenBundle] PolicyId {} is not valid", policyId); throw ExceptionFactory.transactionOutputsParametersMissingError("PolicyId " + policyId + " is not valid"); @@ -151,7 +151,7 @@ public static void validateCheckKey(String policyId) { } public static void validateTokenName(String tokenName) { - boolean checkTokenName = CardanoAddressUtil.isTokenNameValid(tokenName); + boolean checkTokenName = CardanoAddressUtils.isTokenNameValid(tokenName); if (!checkTokenName) { log.error("validateAndParseTokenBundle] Token name {} is not valid", tokenName); throw ExceptionFactory.transactionOutputsParametersMissingError("Token name " + tokenName + " is not valid"); @@ -285,7 +285,7 @@ public static List vali if (!ObjectUtils.isEmpty(relay.getPort())) { validatePort(relay.getPort().toString()); } - com.bloxbean.cardano.client.transaction.spec.cert.Relay generatedRelay = CardanoAddressUtil.generateSpecificRelay(relay); + com.bloxbean.cardano.client.transaction.spec.cert.Relay generatedRelay = CardanoAddressUtils.generateSpecificRelay(relay); generatedRelays.add(generatedRelay); } @@ -361,7 +361,7 @@ public static String validateAndParseVotingKey(PublicKey votingKey) { log.error("[validateAndParsePublicKey] Voting key not provided"); throw ExceptionFactory.missingVotingKeyError(); } - boolean checkKey = CardanoAddressUtil.isKeyValid(votingKey.getHexBytes(), votingKey.getCurveType().toString()); + boolean checkKey = CardanoAddressUtils.isKeyValid(votingKey.getHexBytes(), votingKey.getCurveType().toString()); if (!checkKey) { log.info("[validateAndParsePublicKey] Voting key has an invalid format"); throw ExceptionFactory.invalidVotingKeyFormat(); @@ -377,7 +377,7 @@ public static VoteRegistrationMetadata validateAndParseVoteRegistrationMetadata( if (ObjectUtils.isEmpty(voteRegistrationMetadata.getStakeKey().getHexBytes())) { throw ExceptionFactory.missingStakingKeyError(); } - boolean checkKey = CardanoAddressUtil.isKeyValid(voteRegistrationMetadata.getStakeKey().getHexBytes(), voteRegistrationMetadata.getStakeKey().getCurveType().toString()); + boolean checkKey = CardanoAddressUtils.isKeyValid(voteRegistrationMetadata.getStakeKey().getHexBytes(), voteRegistrationMetadata.getStakeKey().getCurveType().toString()); if (!checkKey) { throw ExceptionFactory.invalidStakingKeyFormat(); } @@ -404,14 +404,14 @@ public static VoteRegistrationMetadata validateAndParseVoteRegistrationMetadata( if (ObjectUtils.isEmpty(voteRegistrationMetadata.getVotingSignature())) { throw ExceptionFactory.invalidVotingSignature(); } - if (!CardanoAddressUtil.isEd25519Signature(voteRegistrationMetadata.getVotingSignature())) { + if (!CardanoAddressUtils.isEd25519Signature(voteRegistrationMetadata.getVotingSignature())) { log.error("[validateAndParseVoteRegistrationMetadata] Voting signature has an invalid format"); throw ExceptionFactory.invalidVotingSignature(); } - String votingKeyHex = CardanoAddressUtil.add0xPrefix(parsedVotingKey); - String stakeKeyHex = CardanoAddressUtil.add0xPrefix(parsedStakeKey); - String rewardAddressHex = CardanoAddressUtil.add0xPrefix(parsedAddress); - String votingSignatureHex = CardanoAddressUtil.add0xPrefix(voteRegistrationMetadata.getVotingSignature()); + String votingKeyHex = CardanoAddressUtils.add0xPrefix(parsedVotingKey); + String stakeKeyHex = CardanoAddressUtils.add0xPrefix(parsedStakeKey); + String rewardAddressHex = CardanoAddressUtils.add0xPrefix(parsedAddress); + String votingSignatureHex = CardanoAddressUtils.add0xPrefix(voteRegistrationMetadata.getVotingSignature()); return new VoteRegistrationMetadata(PublicKey.builder().hexBytes(stakeKeyHex).build(), PublicKey.builder().hexBytes(votingKeyHex).build(), rewardAddressHex, voteRegistrationMetadata.getVotingNonce(), votingSignatureHex); } diff --git a/api/src/main/resources/config/application-devh2.yaml b/api/src/main/resources/config/application-devh2.yaml new file mode 100644 index 000000000..80223794d --- /dev/null +++ b/api/src/main/resources/config/application-devh2.yaml @@ -0,0 +1,126 @@ +server: + port: ${API_BIND_PORT:8081} + compression: + enabled: true + mime-types: text/html,text/plain,text/css,application/javascript,application/json + min-response-size: 1024 + + + +spring: + jackson: + default-property-inclusion: NON_NULL + serialization: + write-dates-as-timestamps: false + servlet: + multipart: + max-file-size: 8MB + max-request-size: 16MB + datasource: + driver-class-name: org.h2.Driver + username: ${DB_ADMIN_USER_NAME:rosetta_db_admin} + password: ${DB_ADMIN_USER_SECRET:weakpwd#123_d} + url: jdbc:h2:tcp://localhost:9090/mem:rosetta-java-preprod + jpa: + properties: + hibernate: + dialect: org.hibernate.dialect.H2Dialect + format_sql: true + jdbc: + lob: + non-contextual-creation: true + hibernate: + ddl-auto: none + show-sql: true + liquibase: + enabled: false + +api: + exception: + isPrintStackTrace : {PRINT_EXCEPTION:true} + + + +cardano: + rosetta: + version: + ${ROSETTA_VERSION} + implementation-version: + '@project.version@' + networks: + [ + { + id: + mainnet, + node-version: + cardano node 1.30.1, + indexer: + { + type: + ledgersync, + endpoint-url: + http://localhost:8080 + }, + node-bridge: + { + type: + ledgersync, + endpoint-url: + http://localhost:8080 + } + }, + { + id: + preprod, + protocol-magic: 1, + node-version: + cardano node 1.30.1, + indexer: + { + type: + ledgersync, + endpoint-url: + http://localhost:8080 + }, + node-bridge: + { + type: + ledgersync, + endpoint-url: + http://localhost:8080 + } + }, + { + id: + preview, + protocol-magic: 2, + node-version: + cardano node 1.30.1, + indexer: + { + type: + ledgersync, + endpoint-url: + http://localhost:8080 + }, + node-bridge: + { + type: + ledgersync, + endpoint-url: + http://localhost:8080 + } + } + + ] + TOPOLOGY_FILEPATH: ${TOPOLOGY_FILEPATH} + GENESIS_SHELLEY_PATH: ${GENESIS_SHELLEY_PATH} + CARDANO_NODE_VERSION: ${CARDANO_NODE_VERSION} + EXEMPTION_TYPES_PATH: ${EXEMPTION_TYPES_PATH} + +page-size: ${PAGE_SIZE:5} + +cardano-transaction-submitter: + networkMagic: ${PROTOCOL_MAGIC:1} + transaction: + ttl: ${TRANSACTION_TTL:3000} diff --git a/api/src/test/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiImplTest.java b/api/src/test/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiImplTest.java new file mode 100644 index 000000000..730d1cddf --- /dev/null +++ b/api/src/test/java/org/cardanofoundation/rosetta/api/block/controller/BlockApiImplTest.java @@ -0,0 +1,26 @@ +package org.cardanofoundation.rosetta.api.block.controller; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.test.context.SpringBootTest; + +//TODO saa impl +@SpringBootTest +class BlockApiImplTest { + + @Test + void block() { + + } + + @Test + void blockTransaction() { + } + + @Test + void getRequest() { + } +} \ No newline at end of file diff --git a/api/src/test/java/org/cardanofoundation/rosetta/api/block/mapper/BlockToBlockResponseTest.java b/api/src/test/java/org/cardanofoundation/rosetta/api/block/mapper/BlockToBlockResponseTest.java new file mode 100644 index 000000000..043c3fbdf --- /dev/null +++ b/api/src/test/java/org/cardanofoundation/rosetta/api/block/mapper/BlockToBlockResponseTest.java @@ -0,0 +1,68 @@ +package org.cardanofoundation.rosetta.api.block.mapper; + +import java.util.List; + +import org.modelmapper.ModelMapper; +import org.openapitools.client.model.BlockResponse; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.cardanofoundation.rosetta.api.block.model.domain.Block; +import org.cardanofoundation.rosetta.api.block.model.domain.Transaction; + +import static org.assertj.core.api.Assertions.assertThat; + +class BlockToBlockResponseTest { + + private ModelMapper modelMapper; + + @BeforeEach + void setUp() { + modelMapper = new ModelMapper(); + } + + @Test + void toDto_Ok() { //TODO how to we agree to name tests? Maybe shouldMapDtoOK? + + BlockToBlockResponse my = new BlockToBlockResponse(modelMapper); + my.modelMapper.validate(); + + Block block = newBlock(); + BlockResponse resp = my.toDto(newBlock()); + + assertThat(block.getHash()).isEqualTo(resp.getBlock().getBlockIdentifier().getHash()); + assertThat(block.getNumber()).isEqualTo(resp.getBlock().getBlockIdentifier().getIndex()); + + assertThat(block.getPreviousBlockHash()).isEqualTo( + resp.getBlock().getParentBlockIdentifier().getHash()); + + assertThat(block.getPreviousBlockNumber()).isEqualTo( + resp.getBlock().getParentBlockIdentifier().getIndex()); + + + + } + + private Block newBlock() { + return new Block( + "hash", + 1L, + 2L, + "prevHashBlock", + 21L, + 3L, + "createdAt", + 4, 5, + 6L, newTransactions(), + "poolDeposit"); + } + + private List newTransactions() { + return List.of(new Transaction()); //TODO saa: fill TransactionDto with data + } + + +} + + diff --git a/api/src/test/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImplTest.java b/api/src/test/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImplTest.java new file mode 100644 index 000000000..5951a6248 --- /dev/null +++ b/api/src/test/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImplTest.java @@ -0,0 +1,187 @@ +package org.cardanofoundation.rosetta.api.block.service.impl; + +import java.util.Collections; +import java.util.List; + +import org.springframework.test.util.ReflectionTestUtils; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openapitools.client.model.NetworkIdentifier; +import org.openapitools.client.model.PartialBlockIdentifier; +import org.openapitools.client.model.SubNetworkIdentifier; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.cardanofoundation.rosetta.api.block.model.domain.Block; +import org.cardanofoundation.rosetta.api.block.model.domain.Transaction; +import org.cardanofoundation.rosetta.api.block.service.BlockServiceImpl; +import org.cardanofoundation.rosetta.common.exception.ApiException; +import org.cardanofoundation.rosetta.common.services.LedgerDataProviderService; +import org.cardanofoundation.rosetta.common.util.RosettaConstants.RosettaErrorType; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class BlockServiceImplTest { + + @Mock + private LedgerDataProviderService ledgerDataProviderService; + @InjectMocks + private BlockServiceImpl blockService; + + @Test + void getBlockByBlockRequest_OK() { + + //given + long index = 1; + String hash = "hash1"; + + String genesisPath = "../config/preprod/shelley-genesis.json"; + ReflectionTestUtils.setField(blockService, "genesisPath", genesisPath); + + Block expected = newBlock(); + when(ledgerDataProviderService.findBlock(index, hash)) + .thenReturn(expected); + when(ledgerDataProviderService.findTransactionsByBlock(index, hash)) + .thenReturn(newTransactionList()); + + //when + Block block = blockService.findBlock(index, hash); + + //then + assertThat(block).isEqualTo(expected); + + } + + @Test + void getBlockByBlockRequest_OK_emptyTransactions() { + + //given + long index = 1; + String hash = "hash1"; + + String genesisPath = "../config/preprod/shelley-genesis.json"; + ReflectionTestUtils.setField(blockService, "genesisPath", genesisPath); + + when(ledgerDataProviderService.findBlock(index, hash)) + .thenReturn(newBlock()); + when(ledgerDataProviderService.findTransactionsByBlock(index, hash)) + .thenReturn(null); + + //when + Block block = blockService.findBlock(index, hash); + + //then + assertThat(block.getTransactions()).isNull(); + + + } + + @Test + void getBlockByBlockRequest_blockNotFoundException() { + + //given + String genesisPath = "../config/preprod/shelley-genesis.json"; + ReflectionTestUtils.setField(blockService, "genesisPath", genesisPath); + + when(ledgerDataProviderService.findBlock(anyLong(), anyString())) + .thenReturn(newBlock()); + + //when + try { + blockService.findBlock(1L, "hash"); + } catch (ApiException e) { + //then + assertThat(e.getError().getCode()) + .isEqualTo(RosettaErrorType.BLOCK_NOT_FOUND.getCode()); + } + + + } + + @Test + void getBlockByBlockRequest_canNotReadGenesis() { + + //given + long index = 1; + String hash = "hash1"; + + String genesisPath = "badPath"; + ReflectionTestUtils.setField(blockService, "genesisPath", genesisPath); + + + when(ledgerDataProviderService.findBlock(index, hash)) + .thenReturn(newBlock()); + when(ledgerDataProviderService.findTransactionsByBlock(index, hash)) + .thenReturn(newTransactionList()); + + //when + try { + blockService.findBlock(index, hash); + } catch (ApiException e) { + //then + assertThat(e.getMessage()) + .isEqualTo("Could not read genesis file path"); + } + + + } + + private List newTransactionList() { + Transaction e1 = new Transaction("hash1", "blockHash1", 1L, + "fee1", 2L, true, 3L, + Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), + Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + return List.of(e1); + } + + private Block newBlock() { + return new Block( + "hash1", + 1L, + 2L, + "prevHashBlock1", + 21L, + 3L, + "createdAt1", + 4, 5, + 6L, null, + "poolDeposit1"); + } + + private NetworkIdentifier newNetworkIdentifier() { + NetworkIdentifier nid = new NetworkIdentifier(); + return NetworkIdentifier + .builder() + .network("network1") + .blockchain("cardano-dev") + .subNetworkIdentifier(newSubNetworkIdentifier()) + .build(); + } + + private SubNetworkIdentifier newSubNetworkIdentifier() { + return SubNetworkIdentifier + .builder() + .network("network") + .metadata("metadata") + .build(); + } + + private PartialBlockIdentifier newPartialBlockIdentifier() { + return null; + } + + + + @Test + void getBlockTransaction() { + //TODO saa: impl + } + + +} \ No newline at end of file diff --git a/api/src/test/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtilTest.java b/api/src/test/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtilTest.java index 2577767f5..dd302c80e 100644 --- a/api/src/test/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtilTest.java +++ b/api/src/test/java/org/cardanofoundation/rosetta/common/util/CardanoAddressUtilTest.java @@ -16,9 +16,7 @@ import com.bloxbean.cardano.client.util.HexUtil; import org.cardanofoundation.rosetta.common.enumeration.EraAddressType; import org.cardanofoundation.rosetta.common.enumeration.NetworkIdentifierType; -import org.cardanofoundation.rosetta.common.util.CardanoAddressUtil; -import org.cardanofoundation.rosetta.common.util.Constants; import org.junit.jupiter.api.Test; import org.openapitools.client.model.CurveType; import org.openapitools.client.model.PublicKey; @@ -31,10 +29,10 @@ public class CardanoAddressUtilTest { @Test public void isStakeAddressTest() { String validStakeAddress = "stake_test1uz89q57sawqdmfgeapdl3cypgjldk4y9lzqg2q422wzywucvsxnhw"; - assertTrue(CardanoAddressUtil.isStakeAddress(validStakeAddress)); + assertTrue(CardanoAddressUtils.isStakeAddress(validStakeAddress)); String invalidStakeAddress = "addr_test1uz89q57sawqdmfgeapdl3cypgjldk4y9lzqg2q422wzywucvsxn"; - assertFalse(CardanoAddressUtil.isStakeAddress(invalidStakeAddress)); + assertFalse(CardanoAddressUtils.isStakeAddress(invalidStakeAddress)); } @Test @@ -43,7 +41,7 @@ public void getAddressTest() { HdKeyPair stakeHdKeyPair = account.stakeHdKeyPair(); HdKeyPair paymentHdKeyPair = account.hdKeyPair(); - Address address = CardanoAddressUtil.getAddress(paymentHdKeyPair.getPublicKey().getKeyHash(), + Address address = CardanoAddressUtils.getAddress(paymentHdKeyPair.getPublicKey().getKeyHash(), stakeHdKeyPair.getPublicKey().getKeyHash(), (byte) 0x00, Networks.mainnet(), AddressType.Base); @@ -56,34 +54,34 @@ public void isKeyValidTest() { HdKeyPair paymentKeyPair = account.hdKeyPair(); // key data will result in a valid Key String hexPublicKeyData = HexUtil.encodeHexString(paymentKeyPair.getPublicKey().getKeyData()); - assertTrue(CardanoAddressUtil.isKeyValid(hexPublicKeyData, Constants.VALID_CURVE_TYPE)); + assertTrue(CardanoAddressUtils.isKeyValid(hexPublicKeyData, Constants.VALID_CURVE_TYPE)); // key hash will result in an invalid Key String hexPublicKeyHash = HexUtil.encodeHexString(paymentKeyPair.getPublicKey().getKeyHash()); - assertFalse(CardanoAddressUtil.isKeyValid(hexPublicKeyHash, Constants.VALID_CURVE_TYPE)); + assertFalse(CardanoAddressUtils.isKeyValid(hexPublicKeyHash, Constants.VALID_CURVE_TYPE)); } @Test public void generateSpecificRelayTest() { Relay relay = new Relay("127.0.0.1", "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b", "relay.io", 3001, Constants.SINGLE_HOST_ADDR); - SingleHostAddr singleHostAddr = (SingleHostAddr) CardanoAddressUtil.generateSpecificRelay( + SingleHostAddr singleHostAddr = (SingleHostAddr) CardanoAddressUtils.generateSpecificRelay( relay); assertEquals("2001:db8:3c4d:15:0:0:1a2f:1a2b", singleHostAddr.getIpv6().getHostAddress()); assertEquals(3001, singleHostAddr.getPort()); relay.setType(Constants.SINGLE_HOST_NAME); - SingleHostName singleHostName = (SingleHostName) CardanoAddressUtil.generateSpecificRelay( + SingleHostName singleHostName = (SingleHostName) CardanoAddressUtils.generateSpecificRelay( relay); assertEquals("relay.io", singleHostName.getDnsName()); relay.setType(Constants.MULTI_HOST_NAME); - MultiHostName multiHostName = (MultiHostName) CardanoAddressUtil.generateSpecificRelay(relay); + MultiHostName multiHostName = (MultiHostName) CardanoAddressUtils.generateSpecificRelay(relay); assertEquals("relay.io", multiHostName.getDnsName()); } @Test public void generateAddressTest() { Account account = new Account(testMnemonic); - Address address = (Address) CardanoAddressUtil.generateAddress( + Address address = (Address) CardanoAddressUtils.generateAddress( account.getBaseAddress().getAddress()); assertEquals(account.getBaseAddress().getAddress(), address.getAddress()); } @@ -93,7 +91,7 @@ public void getEraAddressTypeTest() { Account account = new Account(Networks.preprod(), testMnemonic); String address = account.getBaseAddress().getAddress(); System.out.println(address); - EraAddressType eraAddressType = CardanoAddressUtil.getEraAddressType( + EraAddressType eraAddressType = CardanoAddressUtils.getEraAddressType( account.getBaseAddress().getAddress()); assertEquals(EraAddressType.SHELLEY, eraAddressType); } @@ -101,53 +99,53 @@ public void getEraAddressTypeTest() { @Test public void isPolicyIdValidTest() { String validPolicyID = "5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d114"; - assertTrue(CardanoAddressUtil.isPolicyIdValid(validPolicyID)); + assertTrue(CardanoAddressUtils.isPolicyIdValid(validPolicyID)); String invalidPolicyID = "5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415"; - assertFalse(CardanoAddressUtil.isPolicyIdValid(invalidPolicyID)); + assertFalse(CardanoAddressUtils.isPolicyIdValid(invalidPolicyID)); } @Test public void isTokenNameValidTest() { String validTokenName = "5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d1149307a4b6"; - assertTrue(CardanoAddressUtil.isTokenNameValid(validTokenName)); + assertTrue(CardanoAddressUtils.isTokenNameValid(validTokenName)); } @Test public void isEmptyHexStringTest() { String emptyHex = "\\x"; - assertTrue(CardanoAddressUtil.isEmptyHexString(emptyHex)); + assertTrue(CardanoAddressUtils.isEmptyHexString(emptyHex)); String notEmptyHEx = "1234abcd"; - assertFalse(CardanoAddressUtil.isEmptyHexString(notEmptyHEx)); + assertFalse(CardanoAddressUtils.isEmptyHexString(notEmptyHEx)); } @Test public void generateRewardAddress() { Account account = new Account(testMnemonic); - String rewardAddress = CardanoAddressUtil.generateRewardAddress(NetworkIdentifierType.CARDANO_MAINNET_NETWORK, account.hdKeyPair().getPublicKey()); + String rewardAddress = CardanoAddressUtils.generateRewardAddress(NetworkIdentifierType.CARDANO_MAINNET_NETWORK, account.hdKeyPair().getPublicKey()); assertEquals("stake1ux5t8wq55e09usmh07ymxry8atzwxwt2nwwzfngg6esffxgfvzpaw", rewardAddress); } @Test public void generateBaseAddressTest() { Account account = new Account(testMnemonic); - String baseAddress = CardanoAddressUtil.generateBaseAddress(NetworkIdentifierType.CARDANO_MAINNET_NETWORK, account.hdKeyPair().getPublicKey(), account.stakeHdKeyPair().getPublicKey()); + String baseAddress = CardanoAddressUtils.generateBaseAddress(NetworkIdentifierType.CARDANO_MAINNET_NETWORK, account.hdKeyPair().getPublicKey(), account.stakeHdKeyPair().getPublicKey()); assertEquals(account.baseAddress(), baseAddress); } @Test public void generateEnterpriseAddressTest() { Account account = new Account(testMnemonic); - String enterpriseAddress = CardanoAddressUtil.generateEnterpriseAddress(NetworkIdentifierType.CARDANO_MAINNET_NETWORK, account.hdKeyPair().getPublicKey()); + String enterpriseAddress = CardanoAddressUtils.generateEnterpriseAddress(NetworkIdentifierType.CARDANO_MAINNET_NETWORK, account.hdKeyPair().getPublicKey()); assertEquals(account.enterpriseAddress(), enterpriseAddress); } @Test public void isEd25519KeyHashTest() { String validKeyHash = "5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef064415d114"; - assertTrue(CardanoAddressUtil.isEd25519KeyHash(validKeyHash)); + assertTrue(CardanoAddressUtils.isEd25519KeyHash(validKeyHash)); String invalidKeyHash = "5d16cc1a177b5d9ba9cfa9793b07e60f1fb70fea1f8aef06441gg"; - assertFalse(CardanoAddressUtil.isEd25519KeyHash(invalidKeyHash)); + assertFalse(CardanoAddressUtils.isEd25519KeyHash(invalidKeyHash)); } @Test @@ -156,7 +154,7 @@ public void getStakingCredentialFromStakeKeyTest() { PublicKey publicKey = PublicKey.builder() .hexBytes(HexUtil.encodeHexString(account.stakeHdKeyPair().getPublicKey().getKeyData())).curveType( CurveType.EDWARDS25519).build(); - StakeCredential stakingCredentialFromStakeKey = CardanoAddressUtil.getStakingCredentialFromStakeKey( + StakeCredential stakingCredentialFromStakeKey = CardanoAddressUtils.getStakingCredentialFromStakeKey( publicKey); assertEquals(HexUtil.encodeHexString(account.stakeHdKeyPair().getPublicKey().getKeyHash()), HexUtil.encodeHexString(stakingCredentialFromStakeKey.getHash())); } diff --git a/pom.xml b/pom.xml index a22aeb381..25519944b 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,8 @@ 1.21.0 4.8.3.0 1.13.0 + 3.2.0 + 3.25.3 @@ -127,6 +129,20 @@ swagger-annotations ${version.swagger-annotations} + + org.modelmapper + modelmapper + ${modelmapper.version} + + + org.modelmapper.extensions + modelmapper-spring + ${modelmapper.version} + + + org.assertj + assertj-core + @@ -163,4 +179,5 @@ + diff --git a/style/idea-code-style.xml b/style/idea-code-style.xml new file mode 100644 index 000000000..61a28b6b7 --- /dev/null +++ b/style/idea-code-style.xml @@ -0,0 +1,609 @@ + + + + + + diff --git a/yaci-indexer/pom.xml b/yaci-indexer/pom.xml index 8fa923c55..6f794a782 100644 --- a/yaci-indexer/pom.xml +++ b/yaci-indexer/pom.xml @@ -100,6 +100,11 @@ postgresql 42.7.1 + + com.h2database + h2 + provided + @@ -111,4 +116,15 @@ + + + h2-yaci-indexer + + + com.h2database + h2 + + + + diff --git a/yaci-indexer/src/main/java/org/cardanofoundation/rosetta/yaciindexer/ConfigurationH2.java b/yaci-indexer/src/main/java/org/cardanofoundation/rosetta/yaciindexer/ConfigurationH2.java new file mode 100644 index 000000000..ce0775ac2 --- /dev/null +++ b/yaci-indexer/src/main/java/org/cardanofoundation/rosetta/yaciindexer/ConfigurationH2.java @@ -0,0 +1,31 @@ +package org.cardanofoundation.rosetta.yaciindexer; + +import java.sql.SQLException; + +//import lombok.extern.slf4j.Slf4j; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.h2.tools.Server; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +@Configuration +@ConditionalOnClass(org.h2.tools.Server.class) +public class ConfigurationH2 { + + //With lombok @Slf4j, the following error is thrown: + // Fatal error compiling: java.lang.NoSuchFieldError: + //Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field 'com.sun.tools.javac.tree.JCTree qualid' + // https://stackoverflow.com/a/77171271 does not work + private static Logger log = LoggerFactory.getLogger(ConfigurationH2.class); + @Bean(initMethod = "start", destroyMethod = "stop") + public Server inMemoryH2DatabaseaServer() throws SQLException { + int port = 9090; + log.debug("Starting H2 database server on tcp port: {}", port); + return Server.createTcpServer( + "-tcp", "-tcpAllowOthers", "-tcpPort", String.valueOf(port)); + } +} diff --git a/yaci-indexer/src/main/java/org/cardanofoundation/rosetta/yaciindexer/YaciIndexerApplication.java b/yaci-indexer/src/main/java/org/cardanofoundation/rosetta/yaciindexer/YaciIndexerApplication.java index 75f2ca829..47c8515a3 100644 --- a/yaci-indexer/src/main/java/org/cardanofoundation/rosetta/yaciindexer/YaciIndexerApplication.java +++ b/yaci-indexer/src/main/java/org/cardanofoundation/rosetta/yaciindexer/YaciIndexerApplication.java @@ -2,12 +2,14 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; @SpringBootApplication +@Import(ConfigurationH2.class) public class YaciIndexerApplication { - public static void main(String[] args) { - SpringApplication.run(YaciIndexerApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(YaciIndexerApplication.class, args); + } }