Expand description

Dynamic Typing utilities for Tuxedo runtimes

§Motivation

In Tuxedo, UTXOs are like envelopes that store to later be opened and computed on. These data can be of many different types depending on which Tuxedo pieces may operate on them. And different Tuxedo runtimes may support different data types.

In order to support type safety as well as serialization, we must do some dynamic type checking when a UTXO is taken out of storage to ensure that the data is decoded to the same type from which it was encoded. This is important because it will occasionally be the case that serialized data may validly decode to more than one type.

§Example Attack

To understand the importance of the type checking, consider a concrete Tuxedo runtime that has both a bitcoin-like cryptocurrency and a crypto-kitties-like NFT game. Imagine a user spends a moderate amount of money breeding cryptokitties until they have an Attack Kitty. And Attack Kitty is one whose serialized data has the property that it would also validly decode into a coin in the cryptocurrency and spent accordingly. In the worst case (best for the attacker) the value of the coin would exceed the value spent breeding the cryptokitties.

§Methodology

To solve this problem we associate a four-byte type identifier with each data type that can be stored in a UTXO. When a UTXO is stored, the type identifier is stored along with the serialized data. When the UTXO is later read from storage, the type identifier is checked against the type into which the data is being decoded. Currently this read-time checking is the job of the piece developer, although that may be able to improve in the future.

§Comparison with sp_std::any

The Rust standard library, and also the sp-std crate offer utilities for dynamic typing as well. We have considered and are still considering using that crate instead of these custom utilities.

§In favor of sp_std::any

  • The compiler guarantees unique type ids for every type, whereas this utility requires the developer to avoid collisions (hopefully macros can improve this slightly)
  • Using that crate would be less code for Tuxedo developers to maintain

§In favor of this custom utility

  • sp_std::any does not make the type_id public. This makes it impossible to encode it and store it along with the serialized data which is the whole point. This could be hacked around by, for example, hashing the Debug strong, but that is ugly

Modules§

Structs§

  • A piece of encoded data with a type id associated Strongly typed data can be extracted

Enums§

  • Errors that can occur when casting dynamically typed data into strongly typed data.

Traits§

  • A trait that must be implemented for any data that can be contained in a UTXO. It is not recommended to implement this trait directly for primitive types, but rather to use the newtype pattern: https://doc.rust-lang.org/book/ch19-04-advanced-types.html. Using a new type allows strong type disambiguation between bespoke use-cases in which the same primitive may be stored.