Runtime API versioning
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/apiare messed up a bit. More specificallyprimitives/api/test/tests/decl_and_impl.rs - [ ] Integration test covering the new functionality.
- [x] Some duplicated code
Please add some documentation with examples to the crate
Ty for all the hard work @tdimitrov :) (And especially going through all of this with me :sweat_smile:)
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!