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

Refactor error handling and recategorize errors #295

Merged
merged 4 commits into from
Mar 23, 2023

Conversation

fxamacker
Copy link
Member

@fxamacker fxamacker commented Mar 8, 2023

Changes

This PR improves error handling and error passing between Atree, Cadence, and FVM.

  • Categorize errors into FatalError, ExternalError, and UserError.
  • Implement Unwrap() for FatalError, ExternalError, and UserError.
  • Add tests for error categorization, etc.

Closes #285
Updates onflow/cadence#1255

Details

Errors are categorized as early as feasible. Changes only affect the error paths (avoids affecting the happy paths).

Here, the word "pluggable" describes interfaces or callback functions that might be implemented by packages external to Atree.

Basically, when Atree:

  • Creates an error: create either FatalError or UserError.
  • Receives error from known packages: wrap the error in FatalError or UserError.
  • Receives error from pluggable interfaces or callback functions: wrap the error as ExternalError only if it is not categorized already.
  • Receives error from its own functions: there's no need to categorize error because it's already categorized, so just wrap the error with more context if needed.

Pluggable interfaces:

  • Ledger
  • BaseStorage
  • SlabStorage
  • TypeInfo
  • Value
  • Storable
  • DigesterBuilder
  • Digester

Pluggable callback functions:

  • StorableDecoder
  • TypeInfoDecoder
  • ValueComparator
  • StorableComparator
  • HashInputProvider
  • ArrayElementProvider
  • MapElementProvider
  • ArrayIterationFunc
  • MapEntryIterationFunc
  • MapElementIterationFunc

  • Targeted PR against main branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work
  • Code follows the standards mentioned here
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

Categorized errors into FatalError, ExternalError, and UserError.

FatalError, ExternalError, and UserError implement Unwrap().

The word "pluggable" here describes interfaces or callback functions that
can potentially be implemented by external packages.

Basically, when Atree:
- creates an error, create either FatalError or UserError.
- receives error from known packages, wrap the error in
  FatalError or UserError.
- receives error from pluggable interfaces or callback functions,
  wrap the error as ExternalError only if it is not categorized already.
- receives error from its own functions, then there's no need to
  categorize error because it's already categorized.  Just wrap
  the error with more context if needed.

Pluggable interfaces include:
- Ledger
- BaseStorage
- SlabStorage
- TypeInfo
- Value
- Storable
- DigesterBuilder
- Digester

Pluggable callback functions include:
- StorableDecoder
- TypeInfoDecoder
- ValueComparator
- StorableComparator
- HashInputProvider
- ArrayElementProvider
- MapElementProvider
- ArrayIterationFunc
- MapEntryIterationFunc
- MapElementIterationFunc
@fxamacker fxamacker added the enhancement New feature or request label Mar 8, 2023
@fxamacker fxamacker self-assigned this Mar 8, 2023
@codecov-commenter
Copy link

codecov-commenter commented Mar 8, 2023

Codecov Report

Merging #295 (8db5046) into main (c836704) will decrease coverage by 4.44%.
The diff coverage is 15.74%.

@@            Coverage Diff             @@
##             main     #295      +/-   ##
==========================================
- Coverage   69.05%   64.62%   -4.44%     
==========================================
  Files          14       14              
  Lines        7314     7991     +677     
==========================================
+ Hits         5051     5164     +113     
- Misses       1629     2152     +523     
- Partials      634      675      +41     
Impacted Files Coverage Δ
array_debug.go 51.65% <0.00%> (-2.52%) ⬇️
encode.go 79.36% <0.00%> (-1.29%) ⬇️
hash.go 69.86% <0.00%> (-1.97%) ⬇️
map_debug.go 51.67% <0.00%> (-3.84%) ⬇️
array.go 69.86% <14.28%> (-6.29%) ⬇️
map.go 66.79% <14.81%> (-4.89%) ⬇️
basicarray.go 49.78% <15.15%> (-3.77%) ⬇️
storage.go 74.52% <15.47%> (-4.90%) ⬇️
storable_slab.go 45.45% <25.00%> (-4.55%) ⬇️
storable.go 54.41% <30.43%> (-11.17%) ⬇️
... and 1 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

@fxamacker
Copy link
Member Author

go test -cover reports 81.3% but Codecov is ~16% lower than what is reported by Go tooling.

Copy link

@janezpodhostnik janezpodhostnik left a comment

Choose a reason for hiding this comment

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

🚀

array.go Outdated Show resolved Hide resolved
errors.go Show resolved Hide resolved
Co-authored-by: Supun Setunga <supun.setunga@gmail.com>
Copy link
Member

@turbolent turbolent left a comment

Choose a reason for hiding this comment

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

Great and thorough work! 👏

array_test.go Outdated Show resolved Hide resolved
}

if len(b) != storageIDSize {
return nil, NewStorageIDErrorf("incorrect storage id buffer length %d", len(b))
id, err := NewStorageIDFromRawBytes(b)
Copy link
Member

Choose a reason for hiding this comment

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

👍

@@ -552,11 +575,23 @@ func (e *singleElement) Get(storage SlabStorage, _ Digester, _ uint, _ Digest, c
//
// Rehashing only happens when we create new inlineCollisionGroup.
// Adding new element to existing inlineCollisionGroup doesn't require rehashing.
func (e *singleElement) Set(storage SlabStorage, address Address, b DigesterBuilder, digester Digester, level uint, hkey Digest, comparator ValueComparator, hip HashInputProvider, key Value, value Value) (element, MapValue, error) {
func (e *singleElement) Set(
Copy link
Member

Choose a reason for hiding this comment

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

👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor error handling to user, fatal, and external errors
5 participants