koinos / koinos-types

The Rosetta Stone of the Koinos ecosystem. Allows for the interpretation of Koinos data structures in a multitude of languages. Useful in the development of microservices, clients, and smart contracts.
MIT License
12 stars 3 forks source link

Opaque rt #44

Closed mvandeberg closed 4 years ago

mvandeberg commented 4 years ago

Closes open-orchard/koinos#235

Implement and test Opaque rt type and multihash basetype changes

theoreticalbts commented 4 years ago

Why is signature_data a variable_blob? Why not make it opaque< sig_block_data > / opaque< sig_transaction_data >?

theoreticalbts commented 4 years ago

active_block_data loses transactions and extensions fields. Is this intentional?

theoreticalbts commented 4 years ago

Todo list:

mvandeberg commented 4 years ago

Ready for re-review

theoreticalbts commented 4 years ago

I went ahead and added a state transition diagram as a comment. There are lots of cases in opaque<T> that have potential problems. Let's figure out some rules for addressing them.

I suggest the following:

In the current code, rule (1) (the normal case) seems to work everywhere.

Rule (2) seems to work everywhere except calling lock() on Unboxed, where there's an unnecessary call to serialize().

Rule (3) is undefined-ish behavior in the current code: In two cases we put it into the "illegal" !_native && !_blob state, in the third state we dereference the optional.

theoreticalbts commented 4 years ago

Now that I look further into the code, I'm not sure the naming of the states in my comment matches up completely with the nomenclature in the code. For example the is_unboxed() function will return _native.has_value(), which will be true in both the Unboxed and Unlocked state. So we should probably rename either the is_unboxed() method or the Unboxed state.

theoreticalbts commented 4 years ago

I'm not a fan of defining operator variable_blob&. This apparently is C++ syntax which says if x is an opaque<T>, you can say variable_blob( x ) and it will invokes a method on the opaque class in defiance of all logic. That is opaque::to_variable_blob( x ) or x.to_variable_blob().

theoreticalbts commented 4 years ago

The get_blob() function returns a reference to the internal _blob member, which can be cleared by state changes. One of the following three mitigations should be deployed:

This also applies to get_native(), get_const_native(), get_native(), and the equality overrides (how many of those are there!?)

theoreticalbts commented 4 years ago

I'm not totally comfortable with the overridden assignment operator returning something other than *this. Are we sure the overridden assignment operator is correct?

theoreticalbts commented 4 years ago

I think this code may be actually become more readable if we get rid of is_unboxed() and is_locked() methods entirely. This solves the problem of conflicting with the names I picked for the states, but the main motivation is actually that if you see something like:

         if( !is_unboxed() ) throw pack::opaque_not_unboxed( "Opaque type not unboxed." );
         return &(*_native);

you have to think for a moment if you want is_unboxed() or is_unlocked() or maybe something else entirely. But it's quite clear if you instead say:

         if( !_native.has_value() ) throw pack::opaque_not_unboxed( "Opaque type not unboxed." );
         return &(*_native);

Then you can immediately see this is good defensive programming, you're checking the optional you're dereferencing before you dereference it.

theoreticalbts commented 4 years ago

We should probably unit test all 12 state transition cases. And also things like a = b = c where c is a variable_blob, if you insist on overriding the assignment operator.