Skip to content

Support implicit conversions in Onotole Type System #3

@ericsson49

Description

@ericsson49

Implicit type conversion (like bool <-> int, Bytes32 -> Root, etc) are often considered to be a not really good idea.
However, there are cases with the current beacon chain specs, which demand it.

  • Modifying stable specs (like phase0) may be not desirable, e.g. see this discussion
  • Implicit conversion of a Python list to SSZ List/Vector can be clumsy and hinder readability
    For example, compare
exposed_derived_secrets=[()] * EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS

vs

exposed_derived_secrets=Vector[List[ValidatorIndex, MAX_EARLY_DERIVED_SECRET_REVEALS * SLOTS_PER_EPOCH],
                                   EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS](
   [List[ValidatorIndex, MAX_EARLY_DERIVED_SECRET_REVEALS * SLOTS_PER_EPOCH]()] *
                                   EARLY_DERIVED_SECRET_PENALTY_MAX_FUTURE_EPOCHS
)

Often, a method or a constructor performs implicit conversion, like SSZ constructors or field setters. However, it's not clear how to express the conversion explicitly with type system.
For example, BeaconState has about 29 fields and many of them support implicit conversions, in the sense that if one constructs a BeconState or sets its field with a value of a wrong but compatible type, then the implicit conversion is performed. E.g. python list can be converted to SSZ List or Vector, int can be converted to uint64, bool can be converted to boolean, etc.
That can be in theory modeled with union types, e.g. fieldA: Union[PyList[ElemType],List[ElemType,...]], however, accessing such field will become a problem. Basically, one need to specify a different type signature for getter and setters (and perhaps, for constructors/copy methods of an enclosing object).
So, this looks like a rather ugly solution.

A simpler approach is to specify a list of admissible implicit conversions. For example, there can be rules like:

  • if there is an expression expr of PyList[U] type, but its expected type is List[T,N]. Convert the expr using List[T,N](expr), provided that U is a subtype of T or can be converted to T using implicit conversion rules.
  • python bool can be converted to SSZ boolean and vice versa, using boolean(expr) or bool(expr)
  • exprs of BytesN types can be implicitly converted to corresponding BytesN subclasses (e.g. Root, BLSPubkey, etc)

Note however, the last kind of implicit conversion can still be dangerous, i.e. hide a potential bug. E.g. Root and Domain are both subclasses of Bytes32, so Domain is a subclass of Bytes32 and given the implicit conversion to Root, one can use Domain object where Root is expected. One thus may need to restrict such conversions to cases, where the lower bound is known, e.g. Bytes32 constant can be implicitly converted to Root or Domain, but not a variable of Bytes32 type,

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions