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

util: error management poc #1469

Closed
wants to merge 32 commits into from
Closed

Conversation

gabrocheleau
Copy link
Contributor

@gabrocheleau gabrocheleau commented Sep 10, 2021

This PR implements a new error management pattern for a couple errors from the vm package (see #1440, #1439).

This new error management pattern adds an ErrorLogger to the utils package. This ErrorLogger has a throwError method that can be used as a replacement for throw new Error('...'). The throwError method takes an ErrorCode (enum) as a first arg (defaults to UNKNOWN_ERROR), which allows for easier error identification & testing and also adjusts the shape of the second argument. For example, an ErrorCode can be linked to a particular error shape to allow additional error details to be provided (e.g. the InvalidParamError error shape allows a user to pass in an additional param error detail).

Part of #1717

@codecov
Copy link

codecov bot commented Sep 10, 2021

Codecov Report

Merging #1469 (77c2170) into master (7330c4a) will decrease coverage by 0.06%.
The diff coverage is 76.59%.

Impacted file tree graph

Flag Coverage Δ
block 85.57% <ø> (ø)
blockchain 83.82% <ø> (ø)
client 75.73% <ø> (-0.09%) ⬇️
common 94.19% <ø> (ø)
devp2p 82.56% <ø> (-0.21%) ⬇️
ethash 90.76% <ø> (ø)
trie 80.02% <ø> (-0.63%) ⬇️
tx 88.20% <ø> (ø)
util 92.56% <91.66%> (-0.06%) ⬇️
vm 81.22% <27.27%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

@gabrocheleau gabrocheleau changed the title [WIP] vm: error management poc vm: error management poc Sep 29, 2021
@gabrocheleau
Copy link
Contributor Author

Ok, this is now ready to review :)

@gabrocheleau gabrocheleau changed the title vm: error management poc util: error management poc Feb 10, 2022
@holgerd77
Copy link
Member

Is this already in a "Updated as a new suggestion" state or do you want to give this some more round? (completely haven't looked into the code yet, so just a plain question)

@gabrocheleau
Copy link
Contributor Author

Is this already in a "Updated as a new suggestion" state or do you want to give this some more round? (completely haven't looked into the code yet, so just a plain question)

The general error handling pattern is where I want it to be, so I think we could brainstorm on the taxonomy from that, if that's what you had in mind. I need to improve and fix the makeError method though as there are some tests that are not passing using that errorLogger + the stack trace is not properly carried through,

@holgerd77
Copy link
Member

Ah, then maybe let's wait until you've fixed these things, I guess this should be settled first that things like stack traces are actually working with the intended concept (if I get your message correctly), and we do not need to rethink/rework some basic things.

@holgerd77 holgerd77 mentioned this pull request Feb 16, 2022
51 tasks
@gabrocheleau
Copy link
Contributor Author

Ah, then maybe let's wait until you've fixed these things, I guess this should be settled first that things like stack traces are actually working with the intended concept (if I get your message correctly), and we do not need to rethink/rework some basic things.

All right, the stack trace preservation issue has been fixed and I've simplified the makeError method. Should be good to serve as a basis for discussion and further development with the rest of the team.

@holgerd77
Copy link
Member

Ok, great 🙂 , one small (?) nit: can you see that the tests are passing (so for Util and VM)?

@holgerd77
Copy link
Member

holgerd77 commented Feb 22, 2022

@gabrocheleau thanks for fixing (small nit: please drop a note when you do, this is otherwise hard to spot)! 🙂 👍

Ok, great, then we can start discussing this as some base line.

Do you want to give a short 6-line summary what you did and how things work?

@holgerd77
Copy link
Member

Hi there, again, can you give a short description here on the concept going beyond the pure code?

@gabrocheleau
Copy link
Contributor Author

gabrocheleau commented Feb 28, 2022

Hi there, again, can you give a short description here on the concept going beyond the pure code?

Yes, apologies, missed the initial comment! Added a description to this PR's original post. Let me know if that works :)

@holgerd77
Copy link
Member

Hi there, again, can you give a short description here on the concept going beyond the pure code?

Yes, apologies, missed the initial comment! Added a description to this PR's original post. Let me know if that works :)

Cool, thanks a lot! 🙂 👍

Copy link
Member

@holgerd77 holgerd77 left a comment

Choose a reason for hiding this comment

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

Hi there,
would like to re-pick this up. In a first round I have some very basic renaming suggestions, so that we get to a comfortably usable API.

Also, basic re-activation request:
can you please re-submit this as a 2-3-commit-PR towards develop?

Thanks! 🙂

}
}

export const errorLog = new ErrorLogger()
Copy link
Member

Choose a reason for hiding this comment

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

I am generally not satisfied with the naming scheme we have here.

Can you do the following:

  1. Rename errors.ts (and related) to customError.ts (singular)
  2. Remove the class wrapping for ErrorLogger, have this as plain methods
  3. Export the ErrorCode enum as types
  4. Rename throwError to throw

Then we can use this with a single-item import as follows:

import { customError } from 'ethereumjs-util'

customError.throw(customError.types.INVALID_PARAM)

Not sure, we could also shorten and rename to just error, but I fear that this is too generic and might interfere in some unpredictable ways, it's also not so transparent regarding the use of our own custom error class.

Copy link
Member

Choose a reason for hiding this comment

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

(then please also adopt the test file name)

Error.captureStackTrace(error, this.throwError)
}

throw error
Copy link
Member

Choose a reason for hiding this comment

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

This is misplaced here, the name of the method says something else, can you please move this to throwError?

return true
}
return false
}
Copy link
Member

Choose a reason for hiding this comment

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

I am still highly sceptical on all this TypeScript magic TBH. The code is very hard to read (and therefore to maintain), I am also fearing a bit some unforseable JavaScript usage side effects, not sure if this is valid or not.

I have a - somewhat - stronger tendency to radically simplify here and throw all this sub-interfacing with InvalidParamError, UnknownError,... away, remove as much advanced TypeScript specifics as possible and just rely with a basic CustomError interface/class/whatever and solely keep the code property for distinction and integrate the ability from unknown-error to pass in an arbitrary list of key-value pairs with error information.

What do others think? @ryanio, @g11tech am I too conservative here? 🤔 I still do not feel settled on this code, especially this is something we would apply so broadly within the code base.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like lodestar error approach, similar to the code approach: generic lodestar error defined here (allows one to specify how to serialize it for log because we had the issue of dumping circular objects): https://github.com/ChainSafe/lodestar/blob/master/packages/utils/src/errors.ts
then finally extended to be used e.g. https://github.com/ChainSafe/lodestar/tree/master/packages/lodestar/src/chain/errors

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After reviewing Lodestar's approach, I quite like it and I feel like it would provide similar benefits to the approach used here but with simpler code.

Copy link
Member

Choose a reason for hiding this comment

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

@gabrocheleau ok, nice, I've some additional comments I might be able to do later the day or tomorrow, then we should be ready to rework this and get to some final state to be applied throughout the code base! 🙂

Copy link
Member

@holgerd77 holgerd77 May 25, 2022

Choose a reason for hiding this comment

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

When "tomorrow" gets to 16 days, lol 😬 😜.

Anyhow.

Yes, I think this Lodestar approach is going very much into a good direction, I am also feeling a lot more confident on something like this in favor to defining our own custom "throwSomething()" function, remaining on dealing with original "Errors" or sub classes seems to be a lot more robust and side effects free to me.

So I would roughly suggest that:

  1. We do the generic code - similar to errors.ts in a dedicated Utils package, as we already planned on the alternative layout

I think it then makes sense to define the respective errors like in the Lodestar errors folder on a "per package" basis on our side - e.g. for the block package - I don't see too much overlap on this between the packages. This simplifies things for structuring and drawing lines (and if we have some few redundancy here it also wouldn't hurt).

Additionally/eventually we can also define a few generic errors in Util as well, but rather as a second step if really necessary.

Just in between: here is a search for the Lodestar BlockErrorCode.PARENT_UNKNOWN error, just to get a glimpse on error usage.

If I get this right there are no "prose error strings" (like 'The parent hash of the uncle header is not part of the canonical chain') in Lodestar but just these capital AGGREGATOR_INDEX_TOO_HIGH = "ATTESTATION_ERROR_AGGREGATOR_INDEX_TOO_HIGH" aggregated error strings.

I would like to keep/stick to our prose approach, already for the reason that we have all this already written down. So I guess this would be one of the major deviations from the Lodestar approach.

WDYT? This is just a first round proposal - this would again need some draft implementation to verify - and is generally open for further discussion and evolution.

Copy link
Contributor

Choose a reason for hiding this comment

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

i agree the more user friendly(readable) error strings are beneficial. 👍

@holgerd77
Copy link
Member

Update: maybe wait with an update here, I have some additions thoughts and eventually an alternative suggestion on a simplified approach on this.

@gabrocheleau
Copy link
Contributor Author

Closing in favor of #1910

@holgerd77 holgerd77 deleted the vm/error-management-poc branch June 30, 2022 12:35
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.

3 participants