substrate icon indicating copy to clipboard operation
substrate copied to clipboard

Runtime API versioning

Open tdimitrov opened this issue 3 years ago • 1 comments

Related to issue #11577

Add support for multiple versions of a Runtime API. The purpose is to have one main version of the API, which is considered stable and multiple extensions (also referred as versioned methods) to it. Effectively from substrate point of view these are just different versions of the same API. It's up to the implementor to add semantics.

How it works

Some methods of the API trait can be tagged with #[api_version(N)] attribute where N is version number bigger than the main one. Let's call them versioned methods for brevity. Then the implementor of the API decides which version to implement.

Example (from https://github.com/paritytech/substrate/issues/11577#issuecomment-1145347025):

decl_runtime_apis! {
    #{api_version(10)]
    trait Test {
         fn something() -> Vec<u8>;
         #[api_version(11)]
         fn new_cool_function() -> u32;
    }
}
impl_runtime_apis! {
    #[api_version(11)]
    impl Test for Runtime {
         fn something() -> Vec<u8> { vec![1, 2, 3] }

         fn new_cool_function() -> u32 {
             10
         }
    }
}

Version safety checks

By default in the API trait all staging methods has got a default implementation calling unimplemented!(). This is a problem because if the developer wants to implement version 11 in the example above and forgets to add fn new_cool_function() in impl_runtime_apis! the runtime will crash when the function is executed.

To overcome this decl_runtime_apis! generates multiple dummy traits for each version it finds in the declaration. These traits contain all required methods and have no default implementations. Then when the developer implements a specific version a dummy implementation of a versioned trait (besides the actual one) is generated. If the developer has forgotten to add a method - a compilation error will be generated.

TODOs

  • [x] Version safety check
  • [ ] Better version generation - decl_runtime_apis! should generate an array with all valid versions. impl_runtime_apis! should return one of these versions instead of what's in its attribute so that a nonexistent version can't be implemented by mistake.
  • [x] Integration tests of primitives/api are messed up a bit. More specifically primitives/api/test/tests/decl_and_impl.rs
  • [ ] Integration test covering the new functionality.
  • [x] Some duplicated code

tdimitrov avatar Jul 05 '22 08:07 tdimitrov

Please add some documentation with examples to the crate

rphmeier avatar Jul 16 '22 01:07 rphmeier

Ty for all the hard work @tdimitrov :) (And especially going through all of this with me :sweat_smile:)

bkchr avatar Aug 12 '22 19:08 bkchr

Thanks for the kind words, @bkchr

(And especially going through all of this with me sweat_smile)

On the contrary - it was fun and I learned a lot!

tdimitrov avatar Aug 12 '22 20:08 tdimitrov