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

Add a VM with Contract support #1493

Merged
merged 82 commits into from
Sep 12, 2024
Merged

Add a VM with Contract support #1493

merged 82 commits into from
Sep 12, 2024

Conversation

dboehm-avalabs
Copy link
Contributor

@dboehm-avalabs dboehm-avalabs commented Sep 3, 2024

Create an example VM that has the ability to deploy and run wasm smart contracts. This VM is based on the morpheus vm, but adds contract support.

vm/vm.go Outdated Show resolved Hide resolved
@aaronbuchwald
Copy link
Collaborator

Could we rename from vmwithcontracts ? WASMVM (not in love with this) or ContractVM

Any thoughts @richardpringle @samliok ?

@richardpringle
Copy link
Collaborator

Could we rename from vmwithcontracts ? WASMVM (not in love with this) or ContractVM

Any thoughts @richardpringle @samliok ?

@aaronbuchwald, we could rename it, but we should be deliberate. One issue with ProgramsVM as I heard many times is that it led people to believe that it is a particular VM, instead of just a VM utilizing a set of libraries. Anyone should be able to build a VM with programs, they shouldn't need to "customize the ProgramsVM".

examples/vmwithcontracts/storage/recorder.go Show resolved Hide resolved
vm/vm.go Outdated Show resolved Hide resolved
@richardpringle richardpringle self-assigned this Sep 12, 2024
@richardpringle richardpringle enabled auto-merge (squash) September 12, 2024 19:11
Copy link
Collaborator

@aaronbuchwald aaronbuchwald left a comment

Choose a reason for hiding this comment

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

LGTM to merge in, so we can follow up on the comments in this review.

I do think we should rename the example from vmwithcontracts to contractvm.

We may want people to use contracts as a part of their VM and not just the only way to interact with their VM, but this example is focused on contracts regardless. Either way - we need a better name than vmwithcontracts

Comment on lines +51 to +57
func (t *Call) StateKeys(_ codec.Address, _ ids.ID) state.Keys {
result := state.Keys{}
for _, stateKeyPermission := range t.SpecifiedStateKeys {
result.Add(stateKeyPermission.Key, stateKeyPermission.Permission)
}
return result
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we add a TODO with the details and let the TODO bot auto-create the issue?

Comment on lines +47 to +48

r *runtime.WasmRuntime
Copy link
Collaborator

Choose a reason for hiding this comment

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

(No changes necessary) We should treat this as an anti-pattern. Action structs should aim to be stateless, I assume this is needed to re-use the runtime, is there another way to do this?

func TestCallAction(t *testing.T) {
ts := tstate.New(1)
addr := codec.CreateAddress(0, ids.GenerateTestID())
tests := []chaintest.ActionTest{
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should add real tests here


var _ chain.Action = (*Deploy)(nil)

const MAXCREATIONSIZE = units.MiB
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: can we update this to MaxCreationSize

}

func (*Deploy) StateKeysMaxChunks() []uint16 {
return []uint16{storage.BalanceChunks}
Copy link
Collaborator

Choose a reason for hiding this comment

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

No, I'm not sure why this was marked as resolved

Comment on lines +34 to +36
return vm.NewOption(Namespace+"runtime", *runtime.NewConfig(), func(v *vm.VM, cfg runtime.Config) error {
wasmRuntime = runtime.NewRuntime(&cfg, v.Logger())
return nil
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this just using the option construct to set a global variable with params provided by the VM?

}

func WithRuntime() vm.Option {
return vm.NewOption(Namespace+"runtime", *runtime.NewConfig(), func(v *vm.VM, cfg runtime.Config) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we change the name to just runtime instead of including the controller?

Comment on lines +54 to +81
// New returns a VM with the indexer, websocket, rpc, and external subscriber apis enabled.
func New(options ...vm.Option) (*vm.VM, error) {
opts := append([]vm.Option{
indexer.With(),
ws.With(),
jsonrpc.With(),
With(), // Add Controller API
externalsubscriber.With(),
}, options...)

return NewWithOptions(opts...)
}

// NewWithOptions returns a VM with the specified options
func NewWithOptions(options ...vm.Option) (*vm.VM, error) {
opts := append([]vm.Option{
WithRuntime(),
}, options...)
return vm.New(
consts.Version,
genesis.DefaultGenesisFactory{},
&storage.StateManager{},
Action,
Auth,
auth.Engines(),
opts...,
)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's update to using defaultvm and doesn't this need to include both WithRuntime and With to include the API for this VM?

"github.com/ava-labs/hypersdk/x/programs/runtime"
)

// [accountStatePrefix] + [account]
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be accountPrefix + account + accountStatePrefix

programBytes []byte,
) ([]byte, error) {
programID := ids.ID(sha256.Sum256(programBytes))
key, _ := keys.Encode(ProgramsKey(programID[:]), len(programBytes))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we be consistent between using keys.Encode internally to the storage helper functions vs. calling it on the result?

We'll need to pass in the full bytes to the above functions, so it has the length as well.

It seems like we're doing this correctly, but it's unnecessarily difficult to follow because ProgramsKey is exported and must be wrapped with keys.Encode where it has the full value it's going to store whereas StoreProgram calls keys.Encode internally

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

Successfully merging this pull request may close these issues.

3 participants