Skip to content

Commit b250190

Browse files
authored
feat RA-20: initial implementation of construction preprocess (#85)
* feat: initial implementation of construction preprocess * refactor: refactoring this pullrequest * refactor: renamed functions and added utility classes * refactor: added cardano metadata objects to api.json and api.yaml. Removed all unused metadata classes. Reworked the code to be working again * doc: added documentation of api extensions * chore: added tests * chore: merged main * refactor: renamed domain classes * refactor: fixes from reviewer comments
1 parent 3001249 commit b250190

File tree

77 files changed

+6656
-2552
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+6656
-2552
lines changed

api/src/main/java/org/cardanofoundation/rosetta/api/account/service/impl/AccountServiceImpl.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import lombok.RequiredArgsConstructor;
77
import lombok.extern.slf4j.Slf4j;
88

9+
import org.cardanofoundation.rosetta.common.util.CardanoAddressUtil;
10+
import org.cardanofoundation.rosetta.common.util.ValidationUtil;
911
import org.springframework.stereotype.Service;
1012
import org.openapitools.client.model.AccountBalanceRequest;
1113
import org.openapitools.client.model.AccountBalanceResponse;
@@ -21,8 +23,7 @@
2123
import org.cardanofoundation.rosetta.common.exception.ExceptionFactory;
2224
import org.cardanofoundation.rosetta.common.mapper.DataMapper;
2325
import org.cardanofoundation.rosetta.common.services.LedgerDataProviderService;
24-
import org.cardanofoundation.rosetta.common.util.CardanoAddressUtils;
25-
import org.cardanofoundation.rosetta.common.util.Validations;
26+
2627

2728
@Service
2829
@Slf4j
@@ -37,7 +38,7 @@ public AccountBalanceResponse getAccountBalance(AccountBalanceRequest accountBal
3738
Long index = null;
3839
String hash = null;
3940
String accountAddress = accountBalanceRequest.getAccountIdentifier().getAddress();
40-
if (Objects.isNull(CardanoAddressUtils.getEraAddressType(accountAddress))) {
41+
if (Objects.isNull(CardanoAddressUtil.getEraAddressType(accountAddress))) {
4142
throw ExceptionFactory.invalidAddressError(accountAddress);
4243
}
4344
PartialBlockIdentifier blockIdentifier = accountBalanceRequest.getBlockIdentifier();
@@ -58,15 +59,15 @@ public AccountCoinsResponse getAccountCoins(AccountCoinsRequest accountCoinsRequ
5859
// accountCoinsRequest.getIncludeMempool(); // TODO
5960

6061
log.debug("[accountCoins] Request received {}", accountCoinsRequest);
61-
if (Objects.isNull(CardanoAddressUtils.getEraAddressType(accountAddress))) {
62+
if (Objects.isNull(CardanoAddressUtil.getEraAddressType(accountAddress))) {
6263
log.debug("[accountCoins] Address isn't Era");
6364
throw ExceptionFactory.invalidAddressError(accountAddress);
6465
}
6566
log.debug("[accountCoins] Address is Era");
6667
if (Objects.nonNull(currencies)) {
67-
Validations.validateCurrencies(currencies);
68+
ValidationUtil.validateCurrencies(currencies);
6869
}
69-
List<Currency> currenciesRequested = Validations.filterRequestedCurrencies(currencies);
70+
List<Currency> currenciesRequested = ValidationUtil.filterRequestedCurrencies(currencies);
7071
log.debug("[accountCoins] Filter currency is {}", currenciesRequested);
7172
Block latestBlock = ledgerDataProviderService.findLatestBlock();
7273
log.debug("[accountCoins] Latest block is {}", latestBlock);

api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/PoolRegistration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import lombok.Data;
88

99
import org.cardanofoundation.rosetta.api.block.model.entity.PoolRegistrationEnity;
10-
import org.cardanofoundation.rosetta.common.model.cardano.Relay;
10+
import org.openapitools.client.model.Relay;
1111

1212
@Data
1313
@Builder
@@ -38,8 +38,8 @@ public static PoolRegistration fromEntity(PoolRegistrationEnity entity) {
3838
.cost(entity.getCost().toString())
3939
.rewardAccount(entity.getRewardAccount())
4040
.relays(entity.getRelays().stream().map(
41-
relay -> new Relay("", relay.getIpv4(), relay.getIpv6(), relay.getDnsName(),
42-
relay.getPort().toString())).toList()) // TODO check type
41+
relay -> new Relay(relay.getIpv4(), relay.getIpv6(), relay.getDnsName(),
42+
relay.getPort(), "")).toList()) // TODO check type
4343
.owners(entity.getPoolOwners())
4444
.epoch(entity.getEpoch())
4545
.slot(entity.getSlot())
Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +0,0 @@
1-
package org.cardanofoundation.rosetta.api.block.model.domain;
2-
3-
import java.util.List;
4-
5-
import lombok.AllArgsConstructor;
6-
import lombok.Builder;
7-
import lombok.Data;
8-
import lombok.NoArgsConstructor;
9-
10-
import org.cardanofoundation.rosetta.common.model.cardano.PoolMargin;
11-
import org.cardanofoundation.rosetta.common.model.cardano.PoolMetadata;
12-
import org.cardanofoundation.rosetta.common.model.cardano.Relay;
13-
14-
15-
@Data
16-
@AllArgsConstructor
17-
@NoArgsConstructor
18-
@Builder
19-
public class PoolRegistrationParams {
20-
21-
private String vrfKeyHash;
22-
private String rewardAddress;
23-
private String pledge;
24-
private String cost;
25-
private List<String> poolOwners;
26-
private List<Relay> relays;
27-
private PoolMargin margin;
28-
private String marginPercentage;
29-
private PoolMetadata poolMetadata;
30-
}

api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/ProcessOperations.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.cardanofoundation.rosetta.api.block.model.domain;
22

3+
import java.math.BigInteger;
34
import java.util.ArrayList;
45

56
import lombok.AllArgsConstructor;
@@ -24,9 +25,9 @@ public class ProcessOperations {
2425
private ArrayList<Certificate> certificates = new ArrayList<>();
2526
private ArrayList<Withdrawal> withdrawals = new ArrayList<>();
2627
private ArrayList<String> addresses = new ArrayList<>();
27-
private ArrayList<String> inputAmounts = new ArrayList<>();
28-
private ArrayList<String> outputAmounts = new ArrayList<>();
29-
private ArrayList<Long> withdrawalAmounts = new ArrayList<>();
28+
private ArrayList<BigInteger> inputAmounts = new ArrayList<>();
29+
private ArrayList<BigInteger> outputAmounts = new ArrayList<>();
30+
private ArrayList<BigInteger> withdrawalAmounts = new ArrayList<>();
3031
private double stakeKeyRegistrationsCount = 0.0;
3132
private double stakeKeyDeRegistrationsCount = 0.0;
3233
private double poolRegistrationsCount = 0.0;

api/src/main/java/org/cardanofoundation/rosetta/api/block/model/dto/PoolRegistrationDTO.java

Whitespace-only changes.

api/src/main/java/org/cardanofoundation/rosetta/api/block/model/dto/ProcessOperationsDto.java

Whitespace-only changes.

api/src/main/java/org/cardanofoundation/rosetta/api/block/service/impl/BlockServiceImpl.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import org.cardanofoundation.rosetta.api.block.model.domain.Transaction;
1212
import org.cardanofoundation.rosetta.common.exception.ExceptionFactory;
1313
import org.cardanofoundation.rosetta.common.mapper.DataMapper;
14-
import org.cardanofoundation.rosetta.common.util.CardanoAddressUtils;
14+
import org.cardanofoundation.rosetta.common.util.CardanoAddressUtil;
1515
import org.cardanofoundation.rosetta.api.block.service.BlockService;
1616
import org.cardanofoundation.rosetta.common.services.LedgerDataProviderService;
1717
import org.cardanofoundation.rosetta.common.util.FileUtils;
@@ -26,7 +26,6 @@
2626
public class BlockServiceImpl implements BlockService {
2727

2828
private final LedgerDataProviderService ledgerDataProviderService;
29-
// private final CardanoService cardanoService;
3029
@Value("${page-size:5}")
3130
private Integer pageSize;
3231
@Value("${cardano.rosetta.GENESIS_SHELLEY_PATH}")
@@ -70,7 +69,7 @@ private String getPoolDeposit() {
7069
try {
7170
content = FileUtils.fileReader(genesisPath);
7271
} catch (IOException e) {
73-
throw new RuntimeException(e);
72+
throw ExceptionFactory.unspecifiedError("Error reading genesis file");
7473
}
7574
JSONObject object = new JSONObject(content);
7675
JSONObject protocolParams = object.getJSONObject("protocolParams");
@@ -159,7 +158,7 @@ public AccountBalanceResponse findBalanceDataByAddressAndBlock(String address, L
159158
"[findBalanceDataByAddressAndBlock] Looking for utxos for address {} and block {}",
160159
address,
161160
block.getHash());
162-
if (CardanoAddressUtils.isStakeAddress(address)) {
161+
if (CardanoAddressUtil.isStakeAddress(address)) {
163162
log.debug("[findBalanceDataByAddressAndBlock] Address is StakeAddress");
164163
log.debug("[findBalanceDataByAddressAndBlock] About to get balance for {}", address);
165164
List<StakeAddressBalance> balances = ledgerDataProviderService.findStakeAddressBalanceByAddressAndBlock(address, block.getNumber());

api/src/main/java/org/cardanofoundation/rosetta/api/construction/service/impl/ConstructionApiServiceImpl.java

Lines changed: 96 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,110 +5,132 @@
55
import co.nstant.in.cbor.model.UnicodeString;
66
import com.bloxbean.cardano.client.exception.AddressExcepion;
77
import com.bloxbean.cardano.client.exception.CborSerializationException;
8+
import java.util.Optional;
89
import lombok.RequiredArgsConstructor;
910
import lombok.extern.slf4j.Slf4j;
1011
import org.cardanofoundation.rosetta.api.block.model.entity.ProtocolParams;
12+
import org.cardanofoundation.rosetta.common.enumeration.NetworkIdentifierType;
1113
import org.cardanofoundation.rosetta.common.mapper.DataMapper;
1214
import org.cardanofoundation.rosetta.common.enumeration.AddressType;
13-
import org.cardanofoundation.rosetta.common.model.cardano.ConstructionDeriveRequestMetadata;
1415

1516
import org.cardanofoundation.rosetta.common.enumeration.NetworkEnum;
1617
import org.cardanofoundation.rosetta.common.services.CardanoAddressService;
1718
import org.cardanofoundation.rosetta.common.services.CardanoService;
1819
import org.cardanofoundation.rosetta.api.construction.service.ConstructionApiService;
1920
import org.cardanofoundation.rosetta.common.services.LedgerDataProviderService;
21+
import org.cardanofoundation.rosetta.common.util.Constants;
2022
import org.openapitools.client.model.*;
2123
import org.springframework.stereotype.Service;
2224

2325
import java.io.IOException;
24-
import java.util.HashMap;
2526
import java.util.Map;
2627

2728
@Service
2829
@Slf4j
2930
@RequiredArgsConstructor
3031
public class ConstructionApiServiceImpl implements ConstructionApiService {
3132

32-
private final CardanoAddressService cardanoAddressService;
33-
private final CardanoService cardanoService;
34-
private final LedgerDataProviderService ledgerService;
35-
private final DataMapper dataMapper;
33+
private final CardanoAddressService cardanoAddressService;
34+
private final CardanoService cardanoService;
35+
private final LedgerDataProviderService ledgerService;
36+
private final DataMapper dataMapper;
3637

37-
@Override
38-
public ConstructionDeriveResponse constructionDeriveService(ConstructionDeriveRequest constructionDeriveRequest) throws IllegalAccessException, CborSerializationException {
39-
PublicKey publicKey = constructionDeriveRequest.getPublicKey();
40-
log.info("Deriving address for public key: {}", publicKey);
41-
NetworkEnum network = NetworkEnum.fromValue(constructionDeriveRequest.getNetworkIdentifier().getNetwork());
42-
if (network == null)
43-
throw new IllegalAccessException("Invalid network");
38+
@Override
39+
public ConstructionDeriveResponse constructionDeriveService(
40+
ConstructionDeriveRequest constructionDeriveRequest)
41+
throws IllegalAccessException {
42+
PublicKey publicKey = constructionDeriveRequest.getPublicKey();
43+
log.info("Deriving address for public key: {}", publicKey);
44+
NetworkEnum network = Optional.ofNullable(NetworkEnum.fromValue(
45+
constructionDeriveRequest.getNetworkIdentifier().getNetwork())).orElseThrow(() -> new IllegalAccessException("Invalid network"));
46+
// casting unspecific rosetta specification to cardano specific metadata
47+
ConstructionDeriveMetadata metadata = constructionDeriveRequest.getMetadata();
48+
// Default address type is enterprise
49+
AddressType addressType =
50+
metadata.getAddressType() != null ? AddressType.findByValue(metadata.getAddressType())
51+
: null;
52+
addressType = addressType != null ? addressType : AddressType.ENTERPRISE;
4453

45-
ConstructionDeriveRequestMetadata metadata = ConstructionDeriveRequestMetadata.fromHashMap((HashMap<String,Object>) constructionDeriveRequest.getMetadata());
46-
// Default address type is enterprise
47-
AddressType addressType = metadata != null ? AddressType.findByValue(metadata.getAddressType()) : null;
48-
addressType = addressType != null ? addressType : AddressType.ENTERPRISE;
49-
50-
PublicKey stakingCredential = null;
51-
if(addressType == AddressType.BASE) {
52-
if(metadata.getStakingCredential() == null)
53-
throw new IllegalAccessException("Staking credential is required for base address");
54-
stakingCredential = metadata.getStakingCredential();
55-
}
56-
String address = cardanoAddressService.getCardanoAddress(addressType, stakingCredential, publicKey, network);
57-
return new ConstructionDeriveResponse(null, new AccountIdentifier(address, null, null), null);
54+
PublicKey stakingCredential = null;
55+
if (addressType == AddressType.BASE) {
56+
stakingCredential = Optional.ofNullable(metadata.getStakingCredential())
57+
.orElseThrow(() -> new IllegalAccessException("Staking credential is required for base address"));
5858
}
59+
String address = cardanoAddressService.getCardanoAddress(addressType, stakingCredential,
60+
publicKey, network);
61+
return new ConstructionDeriveResponse(null, new AccountIdentifier(address, null, null), null);
62+
}
5963

60-
@Override
61-
public ConstructionPreprocessResponse constructionPreprocessService(ConstructionPreprocessRequest constructionPreprocessRequest) throws IOException, AddressExcepion, CborSerializationException, CborException {
62-
return null;
63-
}
64+
@Override
65+
public ConstructionPreprocessResponse constructionPreprocessService(
66+
ConstructionPreprocessRequest constructionPreprocessRequest)
67+
throws IOException, AddressExcepion, CborSerializationException, CborException {
68+
NetworkIdentifier networkIdentifier = constructionPreprocessRequest.getNetworkIdentifier();
69+
ConstructionPreprocessMetadata metadata = constructionPreprocessRequest.getMetadata();
70+
Double relativeTtl = cardanoService.checkOrReturnDefaultTtl(metadata.getRelativeTtl());
71+
Double transactionSize = cardanoService.calculateTxSize(
72+
NetworkIdentifierType.findByName(networkIdentifier.getNetwork()),
73+
constructionPreprocessRequest.getOperations(), 0,
74+
metadata.getDepositParameters());
75+
Map<String, Double> response = Map.of(Constants.RELATIVE_TTL, relativeTtl,
76+
Constants.TRANSACTION_SIZE,
77+
transactionSize);
78+
return new ConstructionPreprocessResponse(response, null);
79+
}
6480

65-
@Override
66-
public ConstructionMetadataResponse constructionMetadataService(ConstructionMetadataRequest constructionMetadataRequest) throws CborException, CborSerializationException {
67-
Map<String, Object> options = (Map<String, Object>) constructionMetadataRequest.getOptions();
68-
Double relativeTtl = (Double) options.get("relative_ttl");
69-
Double txSize = (Double) options.get("transaction_size");
70-
log.debug("[constructionMetadata] Calculating ttl based on {} relative ttl", relativeTtl);
71-
Long ttl = cardanoService.calculateTtl(relativeTtl.longValue());
72-
log.debug("[constructionMetadata] ttl is {}", ttl);
73-
log.debug("[constructionMetadata] updating tx size from {}", txSize);
74-
Long updatedTxSize = cardanoService.updateTxSize(txSize.longValue(), 0L, ttl);
75-
log.debug("[constructionMetadata] updated txSize size is ${updatedTxSize}");
76-
ProtocolParams protocolParams = ledgerService.findProtocolParametersFromIndexerAndConfig();
77-
log.debug("[constructionMetadata] received protocol parameters from block-service {}",
78-
protocolParams);
79-
Long suggestedFee = cardanoService.calculateTxMinimumFee(updatedTxSize,
80-
protocolParams);
81-
log.debug("[constructionMetadata] suggested fee is ${suggestedFee}");
82-
return DataMapper.mapToMetadataResponse(protocolParams, ttl, suggestedFee);
83-
}
81+
@Override
82+
public ConstructionMetadataResponse constructionMetadataService(
83+
ConstructionMetadataRequest constructionMetadataRequest)
84+
throws CborException, CborSerializationException {
85+
Map<String, Object> options = (Map<String, Object>) constructionMetadataRequest.getOptions();
86+
Double relativeTtl = (Double) options.get(Constants.RELATIVE_TTL);
87+
Double txSize = (Double) options.get(Constants.TRANSACTION_SIZE);
88+
log.debug("[constructionMetadata] Calculating ttl based on {} relative ttl", relativeTtl);
89+
Long ttl = cardanoService.calculateTtl(relativeTtl.longValue());
90+
log.debug("[constructionMetadata] ttl is {}", ttl);
91+
log.debug("[constructionMetadata] updating tx size from {}", txSize);
92+
Long updatedTxSize = cardanoService.updateTxSize(txSize.longValue(), 0L, ttl);
93+
log.debug("[constructionMetadata] updated txSize size is ${updatedTxSize}");
94+
ProtocolParams protocolParams = ledgerService.findProtocolParametersFromIndexerAndConfig();
95+
log.debug("[constructionMetadata] received protocol parameters from block-service {}",
96+
protocolParams);
97+
Long suggestedFee = cardanoService.calculateTxMinimumFee(updatedTxSize, protocolParams);
98+
log.debug("[constructionMetadata] suggested fee is ${suggestedFee}");
99+
return DataMapper.mapToMetadataResponse(protocolParams, ttl, suggestedFee);
100+
}
84101

85-
@Override
86-
public ConstructionPayloadsResponse constructionPayloadsService(ConstructionPayloadsRequest constructionPayloadsRequest) {
87-
return null;
88-
}
102+
@Override
103+
public ConstructionPayloadsResponse constructionPayloadsService(
104+
ConstructionPayloadsRequest constructionPayloadsRequest) {
105+
return null;
106+
}
89107

90-
@Override
91-
public ConstructionParseResponse constructionParseService(ConstructionParseRequest constructionParseRequest) {
92-
return null;
93-
}
108+
@Override
109+
public ConstructionParseResponse constructionParseService(
110+
ConstructionParseRequest constructionParseRequest) {
111+
return null;
112+
}
94113

95-
@Override
96-
public ConstructionCombineResponse constructionCombineService(ConstructionCombineRequest constructionCombineRequest) {
97-
return null;
98-
}
114+
@Override
115+
public ConstructionCombineResponse constructionCombineService(
116+
ConstructionCombineRequest constructionCombineRequest) {
117+
return null;
118+
}
99119

100-
@Override
101-
public TransactionIdentifierResponse constructionHashService(ConstructionHashRequest constructionHashRequest) {
102-
Array array = cardanoService.decodeExtraData(constructionHashRequest.getSignedTransaction());
103-
log.info("[constructionHash] About to get hash of signed transaction");
104-
String transactionHash = cardanoService.getHashOfSignedTransaction(
105-
((UnicodeString) array.getDataItems().get(0)).getString());
106-
log.info("[constructionHash] About to return hash of signed transaction");
107-
return new TransactionIdentifierResponse(new TransactionIdentifier(transactionHash), null);
108-
}
120+
@Override
121+
public TransactionIdentifierResponse constructionHashService(
122+
ConstructionHashRequest constructionHashRequest) {
123+
Array array = cardanoService.decodeExtraData(constructionHashRequest.getSignedTransaction());
124+
log.info("[constructionHash] About to get hash of signed transaction");
125+
String transactionHash = cardanoService.getHashOfSignedTransaction(
126+
((UnicodeString) array.getDataItems().getFirst()).getString());
127+
log.info("[constructionHash] About to return hash of signed transaction");
128+
return new TransactionIdentifierResponse(new TransactionIdentifier(transactionHash), null);
129+
}
109130

110-
@Override
111-
public TransactionIdentifierResponse constructionSubmitService(ConstructionSubmitRequest constructionSubmitRequest) {
112-
return null;
113-
}
131+
@Override
132+
public TransactionIdentifierResponse constructionSubmitService(
133+
ConstructionSubmitRequest constructionSubmitRequest) {
134+
return null;
135+
}
114136
}

api/src/main/java/org/cardanofoundation/rosetta/api/network/service/impl/NetworkServiceImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
import java.util.Optional;
1919
import lombok.RequiredArgsConstructor;
2020
import lombok.extern.slf4j.Slf4j;
21-
import org.cardanofoundation.rosetta.common.model.cardano.Producer;
22-
import org.cardanofoundation.rosetta.common.model.cardano.PublicRoot;
23-
import org.cardanofoundation.rosetta.common.model.cardano.TopologyConfig;
21+
import org.cardanofoundation.rosetta.common.model.cardano.network.Producer;
22+
import org.cardanofoundation.rosetta.common.model.cardano.network.PublicRoot;
23+
import org.cardanofoundation.rosetta.common.model.cardano.network.TopologyConfig;
2424
import org.cardanofoundation.rosetta.common.util.Constants;
2525
import org.cardanofoundation.rosetta.common.enumeration.OperationType;
2626
import org.cardanofoundation.rosetta.common.enumeration.OperationTypeStatus;

api/src/main/java/org/cardanofoundation/rosetta/common/enumeration/NetworkEnum.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
import com.bloxbean.cardano.client.common.model.Network;
44
import com.bloxbean.cardano.client.common.model.Networks;
55
import lombok.Getter;
6+
import org.cardanofoundation.rosetta.common.util.Constants;
67

78
@Getter
89
public enum NetworkEnum {
910

10-
MAINNET("mainnet", Networks.mainnet()),
11-
PREPROD("preprod", Networks.preprod()),
12-
TESTNET("testnet", Networks.testnet()),
13-
DEVNET("devnet", new Network(0b0000, 42));
11+
MAINNET(Constants.MAINNET, Networks.mainnet()),
12+
PREPROD(Constants.PREPROD, Networks.preprod()),
13+
TESTNET(Constants.TESTNET, Networks.testnet()),
14+
DEVNET(Constants.DEVNET, new Network(0b0000, 42));
1415

1516
private final String value;
1617
private final Network network;

0 commit comments

Comments
 (0)