Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(lib/runtime): CheckRuntimeVersion independent from existing runtime instance #2687

Merged
merged 6 commits into from
Aug 15, 2022

Conversation

qdm12
Copy link
Contributor

@qdm12 qdm12 commented Jul 21, 2022

Changes

Blocked by #2686 and #2685

  • CheckRuntimeVersion as function instead of instance method
    • No dependency on existing instance
    • Fix: do not modify parent instance allocator
    • Fix: close temporary instance on exit
    • Remove CheckRuntimeVersion from Instance interface
  • ext_misc_runtime_version_version_1 uses CheckRuntimeVersion

Tests

Issues

#2418

Primary Reviewer

@timwu20

@qdm12 qdm12 changed the base branch from development to qdm12/wasmer/setupvm-function July 21, 2022 14:17
@qdm12 qdm12 force-pushed the qdm12/wasmer/setupvm-function branch from 649b9ad to 8375fdf Compare July 21, 2022 14:18
@qdm12 qdm12 force-pushed the qdm12/wasmer/setupvm-function branch from 8375fdf to 2ee6693 Compare July 22, 2022 20:25
@qdm12 qdm12 force-pushed the qdm12/wasmer/checkversion branch from 0ab702b to 8d5d087 Compare July 22, 2022 20:29
@codecov
Copy link

codecov bot commented Jul 22, 2022

Codecov Report

Merging #2687 (6bce0f6) into development (2e57b1e) will decrease coverage by 0.02%.
The diff coverage is 71.42%.

@@               Coverage Diff               @@
##           development    #2687      +/-   ##
===============================================
- Coverage        62.81%   62.79%   -0.03%     
===============================================
  Files              213      213              
  Lines            27069    27057      -12     
===============================================
- Hits             17003    16990      -13     
- Misses            8514     8519       +5     
+ Partials          1552     1548       -4     

@qdm12 qdm12 marked this pull request as ready for review July 22, 2022 22:07
Base automatically changed from qdm12/wasmer/setupvm-function to development July 26, 2022 20:24
@qdm12 qdm12 force-pushed the qdm12/wasmer/checkversion branch from 8d5d087 to 327170d Compare July 26, 2022 20:30
@@ -16,7 +16,6 @@ import (
// Instance is the interface a v0.8 runtime instance must implement
type Instance interface {
UpdateRuntimeCode([]byte) error
CheckRuntimeVersion([]byte) (Version, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why you removed this function from the interface since it creates a new instance to do the version check, but how will we mock this out now? We'd have to change the function signatures of all callers of this function to include a func([]byte) (Version, error)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say it's better to not mock it, since:

  • it's fast
  • it's all CPU/in-memory and no IO
  • it's predictable
  • it adds testing depth which we should crave for when those 3 above are true

If you still want to mock it somewhere though, then you can set it as a functional field on the receiving struct like

type Service struct {
  checkRuntimeVersion(code []byte) (version Version, err error)
}

func New() *Service {
  return &Service{
    checkRuntimeVersion: wasmer.CheckRuntimeVersion,
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's fast at all. It's instantiating a wasmer instance, loading the code in, binding the imports, etc. Now all of the unit tests are runtime specific if we remove it from the Instance interface.

Why aren't we just implementing a RuntimeVersion() (Version, error) (no blob) on Instance. Then anyone who needs to version check needs to instantiate an instance via NewInstance.

Copy link
Contributor Author

@qdm12 qdm12 Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It takes 500ms to load the version, so not that fast indeed.
But if you have a look, there was no configuration of the CheckRuntimeVersion mock method expectation, so it won't change a thing with our code as it is.
And as I mentioned above, if in the future we want to mock the runtime check (for test coverage or testing speed), we can just set it as a field on the receiving struct (like we would with timeNow func() time.Time to mock time).

Also (in my opinionated opinion), having a function as a method just for the sake of it being part of an interface for testing is a bit weird, especially if it doesn't depend on the struct/implementation at all (wasn't the case before though, but it is now).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at the interface again. The Instance interface includes a Version() (Version, error) method. I think we should remove CheckRuntimeVersion from the runtime package and make this a private method in dot/state and a helper function for the tests. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, although that would require to export a bunch of things such as setupVM, the wasmer Instance struct fields vm and ctx, and I think ultimately we should keep this in the wasmer package since it's quite tightly coupled with wasmer thingies? I would rather export CheckRuntimeVersion than these other function/fields, what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need to export those private functions? To check a version of a given wasm blob, you instantiate an instance by calling NewInstance(code []byte, cfg runtime.InstanceConfig) and call Version() on that instance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, sorry I misunderstood.
I changed CheckRuntimeVersion to use NewInstance, simplifying it a bit / reducing code duplication (although it sets up extra stuff it doesn't need, but that's a dep injection problem for another day).

On the other hand, ext_misc_runtime_version_version_1 in wasmer/imports.go uses CheckRuntimeVersion so I think we should still keep it in the wasmer package? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have dissonance with having a function on the public package API that achieves the same functionality that can be achieved by instantiating an instance and calling a receiver method on that instance. But that would lead to code duplication cause we use it in various places. I gave it a shot in this commit, and I'm not really happy with it. So I'm ok with leaving with leaving it in the wasmer package.

@@ -16,7 +16,6 @@ import (
// Instance is the interface a v0.8 runtime instance must implement
type Instance interface {
UpdateRuntimeCode([]byte) error
CheckRuntimeVersion([]byte) (Version, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have dissonance with having a function on the public package API that achieves the same functionality that can be achieved by instantiating an instance and calling a receiver method on that instance. But that would lead to code duplication cause we use it in various places. I gave it a shot in this commit, and I'm not really happy with it. So I'm ok with leaving with leaving it in the wasmer package.

lib/runtime/wasmer/instance.go Outdated Show resolved Hide resolved
Comment on lines 159 to 161
// CheckRuntimeVersion finds the runtime version by initiating a temporary
// runtime instance using the WASM code provided, and querying it.
func CheckRuntimeVersion(code []byte) (version runtime.Version, err error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like @timwu20 mentioned there isn't really a need for this function to remain in the runtime/wasmer package anymore, might make more sense for it to be in dot/state

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept it there to avoid replicating 3 times (lib/runtime/wasmer, dot/state, and somewhere else too) as per what Tim described.

Also it might get a bit more complex due to Core_version being deprecated, and we won't need to create an instance anymore for newer runtimes, so we should definitely have it in one place. (see paritytech/substrate#8688)

@qdm12
Copy link
Contributor Author

qdm12 commented Aug 10, 2022

I have dissonance with having a function on the public package API that achieves the same functionality that can be achieved by instantiating an instance and calling a receiver method on that instance.

If it's stateless, I would say it's fine to have as a 'pure' function (without interfacing etc.). The caller can always have it as a function struct field (or other).

But that would lead to code duplication cause we use it in various places. I gave it a shot in this commit, and I'm not really happy with it. So I'm ok with leaving with leaving it in the wasmer package.
there isn't really a need for this function to remain in the runtime/wasmer package anymore, might make more sense for it to be in dot/state

Yeah I would rather have it in the wasmer package as a helper function than duplicated in 3 places.

@qdm12 qdm12 requested a review from timwu20 August 11, 2022 14:47
@qdm12 qdm12 merged commit 2444d0b into development Aug 15, 2022
@qdm12 qdm12 deleted the qdm12/wasmer/checkversion branch August 15, 2022 19:09
rrtti pushed a commit to polkadot-fellows/seeding that referenced this pull request Sep 29, 2022
I am Quentin Mc Gaw, a software engineer working the Go Polkadot host **Gossamer**.
I have been working full time on Gossamer since October 2021, mostly on the state trie and storage.
I have also made a [few minor pull requests](https://github.com/w3f/polkadot-spec/pulls?q=is%3Apr+is%3Aclosed+author%3Aqdm12) to the Polkadot specification repository.

I am requesting to join the Fellowship at rank 1.

## Main contributions

### Gossamer

- Fix memory leaks
  - Trie encoding buffer pools usage fixed [#2009](ChainSafe/gossamer#2009)
  - Fix state map of tries memory leak [#2286](ChainSafe/gossamer#2286)
  - Fix sync benchmark [#2234](ChainSafe/gossamer#2234)
- Trie proof fixes ([#2604](ChainSafe/gossamer#2604), [#2661](ChainSafe/gossamer#2661))
- Fix end to end tests orchestration ([#2470](ChainSafe/gossamer#2470), [#2452](ChainSafe/gossamer#2452), [#2385](ChainSafe/gossamer#2385), [#2370](ChainSafe/gossamer#2370))
- State trie statistics ([#2378](ChainSafe/gossamer#2378), [#2310](ChainSafe/gossamer#2310), [#2272](ChainSafe/gossamer#2272))
- State trie fixes and improvements
  - Only deep copy nodes when mutation is certain [#2352](ChainSafe/gossamer#2352) and [#2223](ChainSafe/gossamer#2223)
  - Only deep copy necessary fields of a node [#2384](ChainSafe/gossamer#2384)
  - Use Merkle values for database keys instead of always hash [#2725](ChainSafe/gossamer#2725)
  - Opportunistic parallel Merkle value commputing [#2081](ChainSafe/gossamer#2081)
- Grandpa capped number of tracked messages ([#2490](ChainSafe/gossamer#2490), [#2485](ChainSafe/gossamer#2485))
- Add pprof HTTP service for profiling [#1991](ChainSafe/gossamer#1991)

Ongoing work:

- State trie lazy loading and caching
- State trie v1 support ([#2736](ChainSafe/gossamer#2736), [#2747](ChainSafe/gossamer#2747), [#2687](ChainSafe/gossamer#2687), [#2686](ChainSafe/gossamer#2686), [#2685](ChainSafe/gossamer#2685), [#2673](ChainSafe/gossamer#2673), [#2611](ChainSafe/gossamer#2611), [#2530](ChainSafe/gossamer#2530))

### Polkadot specification

➡️ [Pull requests from qdm12](https://github.com/w3f/polkadot-spec/pulls?q=is%3Apr+is%3Aclosed+author%3Aqdm12)
@github-actions
Copy link

🎉 This PR is included in version 0.7.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants