neo-go
neo-go copied to clipboard
Provide way to detect fault exceptions returned by `unwrap` package functions
Is your feature request related to a problem? Please describe.
i'm using https://pkg.go.dev/github.com/nspcc-dev/[email protected]/pkg/rpcclient/unwrap and find it conventient. But i found that there is no way to detect fault exception errors:
var ErrNotFound = "smth not found"
// returns [ErrNotFound] if contract throws 'not found' exception.
func getSmth() error {
_, err := unwrap.Bool(x.invoker.Call(x.contract, method, args...))
if err != nil {
if stings.Contains(err.Error(), "not found") {
return ErrNotFound
}
return fmt.Errorf("call %q method of the Neo smart contract %s", method, x.contract)
}
}
func main() {
err := getSmth()
if err != nil {
if errors.Is(err, ErrNotFound) {
// specific behavior
}
// default behavior
}
}
in this example i base my code logic on the particular string fault exception the contract may throw. The problem is that generic invocation errors (like network or internal) may also contains this string (not this particular example, but in general). So this code is not resistant to potential string collisions and can break logic
currently i use following workaround:
res, err := x.invoker.Call(x.contract, method, args...)
if err != nil {
return fmt.Errorf("call %q method of the Neo smart contract %s", method, x.contract)
}
if res.State != vmstate.Halt.String() {
if strings.Contains(res.FaultException, "not found") {
return ErrNotFound
}
return fmt.Errorf("method %q of the Neo smart contract %s fault exception: %s", method, x.contract, res.FaultException)
}
_, err := unwrap.Bool(res, nil)
Describe the solution you'd like
type FaultException {
Message string
}
// ...
// Unwap* returns [FaultException] with fault exception thrown by the
// smart contract when resulting state is not HALT.
func Unwrap*
func getSmth() error {
_, err := unwrap.Bool(x.invoker.Call(x.contract, method, args...))
if err != nil {
var faultErr unwrap.FaultException
if errors.As(err, &faultErr) && faultErr.Message == "not found" {
return ErrNotFound
}
return fmt.Errorf("call %q method of the Neo smart contract %s", method, x.contract)
}
}
Describe alternatives you've considered
have no other ideas for now
Additional context
frequent pattern of unwrapping in the https://github.com/nspcc-dev/neofs-node
Looks like this is almost the only way to handle the problem. It's just a string in the VM and in the RPC protocol, so the only improvement possible is some way to get just this string (unwrapped from other errors).