Skip to content

Conversation

bullet-tooth
Copy link
Contributor

@bullet-tooth bullet-tooth commented Feb 20, 2019

Overview


See: https://jira.bf.local/browse/ECR-2914

  • TransactionResult moved to the common module.
  • TransactionLocation moved to the common module.
  • Created JSON serializer for TransactionMessage.
  • Implemented get transaction endpoint support

Definition of Done

  • There are no TODOs left in the code
  • Change is covered by automated tests
  • The coding guidelines are followed
  • Public API has Javadoc
  • Method preconditions are checked and documented in the Javadoc of the method
  • Changelog is updated if needed (in case of notable or breaking changes)
  • The continuous integration build passes

import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;

final class TransactionMessageJsonSerializer implements JsonSerializer<TransactionMessage>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any needs for TransactionMessage serialization to JSON in other ways?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't say 🤷‍♂️ @vitvakatu , @MakarovS ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the link becomes broken because TransactionExecutionException locates in the core module.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, would you add a back reference to TransactionExecutionException, if there isn't one already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a reference at TransactionExecutionException to this class

@bullet-tooth bullet-tooth requested a review from dip56 February 20, 2019 14:58
@coveralls
Copy link

coveralls commented Feb 20, 2019

Coverage Status

Coverage decreased (-0.003%) to 85.499% when pulling 5c2ed59 on ecr-2914-2 into 68871c8 on master.

Copy link
Contributor

@MakarovS MakarovS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if (response.code() == HTTP_NOT_FOUND) {
return Optional.empty();
} else if (!response.isSuccessful()) {
throw new RuntimeException("Execution wasn't success: " + response.toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

} else if (executionStatus.getType() == GetTxResponseExecutionStatus.ERROR) {
return TransactionResult.error(executionStatus.getCode(), executionStatus.getDescription());
} else {
throw new IllegalArgumentException("Unexpected transaction execution status"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some delimiter at the end?

Copy link
Contributor

@dmitry-timofeev dmitry-timofeev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, thanks 👍

I'd ponder on some questions/suggestions below.

.registerTypeAdapter(PublicKey.class, new PublicKeyJsonSerializer())
.registerTypeAdapterFactory(StoredConfigurationAdapterFactory.create())
.setLongSerializationPolicy(LongSerializationPolicy.STRING);
.setLongSerializationPolicy(LongSerializationPolicy.STRING)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, would you add a back reference to TransactionExecutionException, if there isn't one already?

}

@Test
void transactionMessageSerializesAsValue() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shan't we make round-trip tests?

There is one below.

@ParameterizedTest
@MethodSource("source")
void roundTripTest(TransactionMessage msg) {
String json = json().toJson(msg);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we longer check that we sent a properly encoded transaction?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we rely on Gson instance here. But I agree, let's have some checks in case of regression.

}

@Test
void getTransactionNotFound() throws InterruptedException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shan't we add a happy result?

TransactionResponse transactionResponse = ExplorerApiHelper.parseGetTxResponse(json);

assertThat(transactionResponse.getStatus(), is(TransactionStatus.IN_POOL));
assertThat(transactionResponse.getMessage(), notNullValue());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. null
  2. Optional
  3. not-null with a required check of the status?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not one thing:

  1. You get an error early, rather than in undefined time range. And yes, it has an error description.
  2. 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>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't say 🤷‍♂️ @vitvakatu , @MakarovS ?

return TransactionResult.successful();
} else if (executionStatus.getType() == GetTxResponseExecutionStatus.ERROR) {
return TransactionResult.error(executionStatus.getCode(), executionStatus.getDescription());
} else if (executionStatus.getType() == GetTxResponseExecutionStatus.PANIC) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

@dmitry-timofeev dmitry-timofeev self-requested a review February 22, 2019 07:47
Copy link
Contributor

@dmitry-timofeev dmitry-timofeev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 , I'd also consider adding isCommitted

* @throws IllegalStateException if the transaction is not committed yet
*/
public TransactionResult getExecutionResult() {
checkState(status == COMMITTED,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+ 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.
Copy link
Contributor

@dmitry-timofeev dmitry-timofeev Feb 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+

Please note that a committed transaction has not necessarily completed 
successfully — use the {@linplain TransactionResult execution result} 
to check that.

Copy link
Contributor

@dmitry-timofeev dmitry-timofeev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

Looks great (but check please if changelog needs to be updated)

@dmitry-timofeev dmitry-timofeev merged commit f8fbcdf into master Feb 25, 2019
@dmitry-timofeev dmitry-timofeev deleted the ecr-2914-2 branch February 25, 2019 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants