Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise useful Horizon errors #95

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

joallard
Copy link
Contributor

@joallard joallard commented Jun 6, 2020

I caught this on the side while working on something else, my apologies for the missing tests; I didn't have time to figure out how to set up the accounts correctly just yet.

  1. I ran into Horizon rejecting the XDR envelopes made from a regular send_payment request. The exception raised was as such:
     Faraday::BadRequestError:
       the server responded with status 400
     # ./lib/account.rb:20:in `send_payment'

Which is not exactly helpful. Which is why I'm humbly proposing to wrap those into exceptions ourselves to raise some more useful information. It would now become:

     Stellar::HorizonError::TransactionMalformed:
       Horizon could not decode the transaction envelope in this request. A transaction should be an XDR TransactionEnvelope struct encoded using base64.  The envelope read from this request is echoed in the `extras.envelope_xdr` field of this response for your convenience.

# or

     Stellar::HorizonError::TransactionFailed:
       The transaction failed when submitted to the stellar network. extras.result_codes contained: `{"transaction"=>"tx_failed", "operations"=>["op_no_destination"]}`  Descriptions of each code can be found at: https://www.stellar.org/developers/guides/concepts/list-of-operations.html

It also makes available .extras on the exception. (On further thought, original_hash should probably be named original_response).

[...]

After being done, I saw there were already Stellar::AccountRequiresMemoError and Stellar::Horizon::Problem, we could probably clean this up together if you'd like.

Cheers!

@nebolsin
Copy link
Member

nebolsin commented Jun 7, 2020

Hi, thank you for the PR! Unfortunately, we did a mistake during the recent stellar-base/stellar-sdk merge which resulted in commit history for the base gem completely missing, and in order to fix this mistake we've had to force-push the master (and I did it just now). Could you please rebase your PR against the updated master? The new master should be identical to the old one as far as the repository content is concerned, it's just a commit history which changed, so your patches should apply perfectly. Really sorry about this mess.

Also, I would suggest separating the bug fix and the error handling into different PRs. We definitely want to fix the base64 encoding bug for the upcoming release, but since we're in the rc1 stage already, I'm not sure if we should go ahead and include the error decoding part right now (also, as you pointed out, it needs some cleanup in regards to Stellar::Horizon::Problem/Stellar::HorizonError duplication).

@nebolsin nebolsin self-assigned this Jun 7, 2020
@nebolsin nebolsin changed the base branch from master to master-missing-base-history June 7, 2020 00:25
@nebolsin nebolsin changed the base branch from master-missing-base-history to master June 7, 2020 00:26
@joallard joallard changed the title Encode Base64 strictly + Raise useful Horizon errors Raise useful Horizon errors Jun 7, 2020
@joallard
Copy link
Contributor Author

joallard commented Jun 7, 2020

Of course! Done. The Base64 fix is now in #96.

A simple test could take the form:

When I send a payment to an uncreated account
Then I get a Stellar::HorizonError::TransactionFailed error

Copy link
Contributor

@charlie-wasp charlie-wasp left a comment

Choose a reason for hiding this comment

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

Hi @joallard, thank you very much for this contribution! Looks good, I've got just a couple of small remarks on it

class HorizonError < StandardError
attr_reader :original_response, :extras

def self.make(hash)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we then assigned the hash parameter to the instance variable original_response, I believe it's better to name it the same here. Also it would make it more accurate. The same goes for the initialize method

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree!

title = nil
end

[title, detail].join(": ")
Copy link
Contributor

Choose a reason for hiding this comment

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

For non-generic class title will be nil, and this expression will result in ": detail", which is not what we would like to get 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! I'll add a compact here


class TransactionFailed < self
def make_message(detail:)
detail.sub!(
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't such substitution be useful on the generic level? In other words, can we show extras in the message for every error? If they exist, of course

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I know, extras.result_codes is only provided for TransactionFailed's. That said, I only checked 2 or 3 types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A cursory search seems to confirm.

@charlie-wasp
Copy link
Contributor

I saw there were already Stellar::AccountRequiresMemoError and Stellar::Horizon::Problem, we could probably clean this up together if you'd like

I think we can get rid of Stellar::Horizon::Problem, it seems not used anywhere.

Stellar::AccountRequiresMemoError doesn't come straight from Horizon, it's more of application-level error, so I believe we can keep it with Stellar::HorizonError separately

@sonarcloud
Copy link

sonarcloud bot commented Jun 14, 2020

Kudos, SonarCloud Quality Gate passed!

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities (and Security Hotspot 0 Security Hotspots to review)
Code Smell A 0 Code Smells

No Coverage information No Coverage information
2.9% 2.9% Duplication

def make_message(detail:, title:)
# Include title only on generic class
# Condition passes only for child classes
if self.class != HorizonError
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just noticed .instance_of? existed

instance_of?(HorizonError)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants