Skip to content

Commit

Permalink
BCFR-1086 finality violation (#966)
Browse files Browse the repository at this point in the history
* define finality violation error

Signed-off-by: Dmytro Haidashenko <dmytro.haidashenko@smartcontract.com>

* rename finality violation

Signed-off-by: Dmytro Haidashenko <dmytro.haidashenko@smartcontract.com>

* Test ContainsError

Signed-off-by: Dmytro Haidashenko <dmytro.haidashenko@smartcontract.com>

---------

Signed-off-by: Dmytro Haidashenko <dmytro.haidashenko@smartcontract.com>
Co-authored-by: Domino Valdano <domino.valdano@smartcontract.com>
  • Loading branch information
dhaidashenko and reductionista authored Dec 11, 2024
1 parent 9087f5e commit 0b03fa3
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 0 deletions.
11 changes: 11 additions & 0 deletions pkg/services/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,14 @@ func (c *HealthChecker) IsHealthy() (healthy bool, errors map[string]error) {

return
}

// ContainsError - returns true if report contains targetErr
func ContainsError(report map[string]error, targetErr error) bool {
for _, err := range report {
if errors.Is(err, targetErr) {
return true
}
}

return false
}
58 changes: 58 additions & 0 deletions pkg/services/health_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package services

import (
"errors"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

func TestContainsError(t *testing.T) {
anError := errors.New("an error")
anotherError := errors.New("another error")
testCases := []struct {
Name string
Report map[string]error
Target error
ExpectedResult bool
}{
{
Name: "nil map",
Report: nil,
Target: anError,
ExpectedResult: false,
},
{
Name: "report contains service, but it's healthy",
Report: map[string]error{"service": nil},
Target: anError,
ExpectedResult: false,
},
{
Name: "service is not healthy, but it's not caused by target error",
Report: map[string]error{"service": anotherError},
Target: anError,
ExpectedResult: false,
},
{
Name: "service is not healthy and contains wrapper target",
Report: map[string]error{"service": fmt.Errorf("wrapped error: %w", anError)},
Target: anError,
ExpectedResult: true,
},
{
Name: "service is not healthy due to multiple errors including target",
Report: map[string]error{"service": errors.Join(anError, anotherError)},
Target: anError,
ExpectedResult: true,
},
}

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
actualResult := ContainsError(tc.Report, tc.Target)
assert.Equal(t, tc.ExpectedResult, actualResult)
})
}
}
8 changes: 8 additions & 0 deletions pkg/types/contract_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
ErrContractReaderConfigMissing = UnimplementedError("ContractReader entry missing from RelayConfig")
ErrInternal = InternalError("internal error")
ErrNotFound = NotFoundError("not found")
ErrFinalityViolated = InternalError("finality violated")
)

// ContractReader defines essential read operations a chain should implement for reading contract values and events.
Expand Down Expand Up @@ -70,6 +71,13 @@ type ContractReader interface {
// The iterator returns a pair of key and sequence.
QueryKeys(ctx context.Context, filters []ContractKeyFilter, limitAndSort query.LimitAndSort) (iter.Seq2[string, Sequence], error)

// HealthReport returns a full health report of the callee including its dependencies.
// Keys are based on Name(), with nil values when healthy or errors otherwise.
// Use CopyHealth to collect reports from sub-services.
// This should run very fast, so avoid doing computation and instead prefer reporting pre-calculated state.
// On finality violation report must contain at least one ErrFinalityViolation.
HealthReport() map[string]error

mustEmbedUnimplementedContractReader()
}

Expand Down

0 comments on commit 0b03fa3

Please sign in to comment.