[ECR-2914] LC: Implemented get transaction endpoint support - #725
Conversation
| import com.google.gson.JsonSerializer; | ||
| import java.lang.reflect.Type; | ||
|
|
||
| final class TransactionMessageJsonSerializer implements JsonSerializer<TransactionMessage>, |
There was a problem hiding this comment.
Are there any needs for TransactionMessage serialization to JSON in other ways?
There was a problem hiding this comment.
I'd leave it as it is for now.
| @@ -32,8 +30,6 @@ | |||
| * if execution has failed. | |||
| * Errors might be either service-defined or unexpected. Service-defined errors consist of an error | |||
| * code and an optional description. Unexpected errors include only a description. | |||
| * | |||
| * @see TransactionExecutionException | |||
There was a problem hiding this comment.
the link becomes broken because TransactionExecutionException locates in the core module.
There was a problem hiding this comment.
I see, would you add a back reference to TransactionExecutionException, if there isn't one already?
There was a problem hiding this comment.
I added a reference at TransactionExecutionException to this class
| if (response.code() == HTTP_NOT_FOUND) { | ||
| return Optional.empty(); | ||
| } else if (!response.isSuccessful()) { | ||
| throw new RuntimeException("Execution wasn't success: " + response.toString()); |
There was a problem hiding this comment.
Either successful or a success
| private String blockingExecutePlainText(Request request) { | ||
| return blockingExecute(request, response -> { | ||
| if (!response.isSuccessful()) { | ||
| throw new RuntimeException("Execution wasn't success: " + response.toString()); |
| } else if (executionStatus.getType() == GetTxResponseExecutionStatus.ERROR) { | ||
| return TransactionResult.error(executionStatus.getCode(), executionStatus.getDescription()); | ||
| } else { | ||
| throw new IllegalArgumentException("Unexpected transaction execution status" |
There was a problem hiding this comment.
Some delimiter at the end?
dmitry-timofeev
left a comment
There was a problem hiding this comment.
Good, thanks 👍
I'd ponder on some questions/suggestions below.
| .registerTypeAdapter(PublicKey.class, new PublicKeyJsonSerializer()) | ||
| .registerTypeAdapterFactory(StoredConfigurationAdapterFactory.create()) | ||
| .setLongSerializationPolicy(LongSerializationPolicy.STRING); | ||
| .setLongSerializationPolicy(LongSerializationPolicy.STRING) |
There was a problem hiding this comment.
Nit: I'd possibly group related things together (type adapters, then long serialization policy, or vice-versa).
| @@ -32,8 +30,6 @@ | |||
| * if execution has failed. | |||
| * Errors might be either service-defined or unexpected. Service-defined errors consist of an error | |||
| * code and an optional description. Unexpected errors include only a description. | |||
| * | |||
| * @see TransactionExecutionException | |||
There was a problem hiding this comment.
I see, would you add a back reference to TransactionExecutionException, if there isn't one already?
| } | ||
|
|
||
| @Test | ||
| void transactionMessageSerializesAsValue() { |
There was a problem hiding this comment.
Shan't we make round-trip tests?
There is one below.
| @ParameterizedTest | ||
| @MethodSource("source") | ||
| void roundTripTest(TransactionMessage msg) { | ||
| String json = json().toJson(msg); |
There was a problem hiding this comment.
This test relies on the fact that JsonSerializer includes a TransactionMessage adapter, correct? Shan't we use Gson here directly? Or move this test to JsonSerializerTest? I'd prefer to keep it here, separate.
| String getUserAgentInfo(); | ||
|
|
||
| /** | ||
| * Returns transaction with current status. Or {@code Optional.empty()} if |
There was a problem hiding this comment.
Returns the information about the transaction; or {@code Optional.empty()} if ??
| byte[] actualMessageBytes = HEX_ENCODER.decode(encodedTxMessage); | ||
| TransactionMessage actualTxMessage = TransactionMessage.fromBytes(actualMessageBytes); | ||
|
|
||
| assertThat(actualTxMessage, is(txMessage)); |
There was a problem hiding this comment.
Don't we longer check that we sent a properly encoded transaction?
There was a problem hiding this comment.
we rely on Gson instance here. But I agree, let's have some checks in case of regression.
| } | ||
|
|
||
| @Test | ||
| void getTransactionNotFound() throws InterruptedException { |
There was a problem hiding this comment.
Shan't we add a happy result?
| TransactionResponse transactionResponse = ExplorerApiHelper.parseGetTxResponse(json); | ||
|
|
||
| assertThat(transactionResponse.getStatus(), is(TransactionStatus.IN_POOL)); | ||
| assertThat(transactionResponse.getMessage(), notNullValue()); |
There was a problem hiding this comment.
Shan't we extract the message as a constant and assert that we get exactly that?
| @NonNull | ||
| TransactionMessage message; | ||
| /** | ||
| * Transaction execution result; {@code null} - for in-pool transactions. |
There was a problem hiding this comment.
What if we define the getter that throws IllegalStateE instead? That will roughly align the behaviour of this class with Optional.
Alternatively we can return Optional<TransactionResult|TransactionLocation>, but in that case the clients who have checked the status would be penalized with an additional ifPresent/isPresent + get.
What do you think would be more convenient:
nullOptional- not-
nullwith a required check of the status?
There was a problem hiding this comment.
By going with the third approach you will also need to check the status before calling getter. Only one thing that can be considered as a proc (comparing with the first approach) is to have some error description instead of NPE
There was a problem hiding this comment.
That's not one thing:
- You get an error early, rather than in undefined time range. And yes, it has an error description.
- There is a clear connection between the tx status and possible absence of a value — you don't have to check both values for
nulls "just in case" if you have checked if the transaction is committed.
| import com.google.gson.JsonSerializer; | ||
| import java.lang.reflect.Type; | ||
|
|
||
| final class TransactionMessageJsonSerializer implements JsonSerializer<TransactionMessage>, |
| return TransactionResult.successful(); | ||
| } else if (executionStatus.getType() == GetTxResponseExecutionStatus.ERROR) { | ||
| return TransactionResult.error(executionStatus.getCode(), executionStatus.getDescription()); | ||
| } else if (executionStatus.getType() == GetTxResponseExecutionStatus.PANIC) { |
There was a problem hiding this comment.
Is there a test for that?
dmitry-timofeev
left a comment
There was a problem hiding this comment.
👍 , I'd also consider adding isCommitted
| * @throws IllegalStateException if the transaction is not committed yet | ||
| */ | ||
| public TransactionResult getExecutionResult() { | ||
| checkState(status == COMMITTED, |
There was a problem hiding this comment.
I think we must add such a convenience method if we require the clients to check for transaction status:
/**
* Returns true if this transaction is {@linkplain TransactionStatus#COMMITTED committed} to the blockchain;
* false — otherwise.
*/
boolean isCommitted();
| TransactionLocation location; | ||
|
|
||
| /** | ||
| * Returns transaction execution result. |
There was a problem hiding this comment.
+ Not available unless the transaction is {@linkplain #isCommitted committed} to the blockchain?
| @SerializedName("in-pool") | ||
| IN_POOL, | ||
| /** | ||
| * Shows that transaction is committed to the blockchain. |
There was a problem hiding this comment.
+
Please note that a committed transaction has not necessarily completed
successfully — use the {@linplain TransactionResult execution result}
to check that.
dmitry-timofeev
left a comment
There was a problem hiding this comment.
💯
Looks great (but check please if changelog needs to be updated)
Overview
See: https://jira.bf.local/browse/ECR-2914
TransactionResultmoved to the common module.TransactionLocationmoved to the common module.TransactionMessage.Definition of Done