[compiler][vm] add visibility modifier to structs/enums: step 5#18489
[compiler][vm] add visibility modifier to structs/enums: step 5#18489rahxephon89 wants to merge 1 commit intoteng/add-wellform-check-for-struct-apisfrom
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
06824ad to
41b73e1
Compare
0bb5405 to
54ce6ce
Compare
41b73e1 to
2aed166
Compare
54ce6ce to
12ef626
Compare
2aed166 to
760ad44
Compare
12ef626 to
2e6c361
Compare
42360a0 to
ac79908
Compare
2e6c361 to
c253dbf
Compare
9a7e33b to
a6252ac
Compare
c253dbf to
b0f9e72
Compare
a6252ac to
ce33809
Compare
b0f9e72 to
da3998a
Compare
ce33809 to
4b0a271
Compare
da3998a to
35d544b
Compare
dd786c6 to
beb910c
Compare
35d544b to
3442487
Compare
beb910c to
1480203
Compare
3442487 to
4731fc1
Compare
e0883c6 to
6d1d8a2
Compare
de306aa to
15cf4ba
Compare
15cf4ba to
fc1c26d
Compare
6d1d8a2 to
a6b0c8f
Compare
fc1c26d to
d31e4d0
Compare
a6b0c8f to
261f387
Compare
f37ad1b to
b30d55a
Compare
261f387 to
41858a6
Compare
| return false; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Duplicated loop logic in validate_fields_recursively function
Low Severity
The validate_fields_recursively function has nearly identical loop logic in both branches. Both iterate over fields and call is_valid_txn_arg, differing only in whether type substitution is applied. This could be consolidated into a single loop where the type to validate is conditionally substituted, reducing code duplication.
b30d55a to
8f27993
Compare
41858a6 to
e241d27
Compare
8f27993 to
dd7a3d2
Compare
1732302 to
8ac52fd
Compare
dd7a3d2 to
966306b
Compare
8ac52fd to
ca38b6b
Compare
966306b to
a6c536f
Compare
georgemitenkov
left a comment
There was a problem hiding this comment.
Why do we need a tag in WithVariants layout here?
| WithVariants(Vec<MoveVariantLayout>), | ||
| /// Like WithTypes, this carries the type tag for proper type identification. | ||
| WithVariants { | ||
| type_: StructTag, |
There was a problem hiding this comment.
Question: why this change? Looking through PR I do not see any usages of type_? But maybe I am missing something
| "Invalid MoveTypeLayout -> StructTag conversion--needed MoveLayoutType::WithTypes or WithVariants" | ||
| ), | ||
| WithTypes { type_, .. } => Ok(type_.clone()), | ||
| WithTypes { type_, .. } | WithVariants { type_, .. } => Ok(type_.clone()), |
There was a problem hiding this comment.
I see, so it is used here. Do we need this for API? Or why exactly?
| /// Whether this VM should support public copy structs/enums as transaction arguments. | ||
| /// When enabled, non-private structs and enums with the copy ability can be used as | ||
| /// transaction arguments if they have public pack functions with the Pack attribute. | ||
| pub enable_public_struct_args: bool, |
There was a problem hiding this comment.
I think having feature gate by v10 format lesehwere is better. For Move VM txn args are irrelevant, so I am not sure this is the best place to add this thing. Just gating in txn_arg_validation is good enough?
| ), | ||
| LayoutType::WithTypes => { | ||
| let mid = m.self_id(); | ||
| // All type_arguments layouts can now be converted to TypeTags |
There was a problem hiding this comment.
nit: looks like useless comment?
| match layout_type { | ||
| LayoutType::WithTypes => { | ||
| let mid = m.self_id(); | ||
| // All type_arguments layouts can now be converted to TypeTags |
There was a problem hiding this comment.
nit: looks like useless comment?
| @@ -263,6 +265,7 @@ impl StructLayoutBuilder { | |||
| match layout_type { | |||
There was a problem hiding this comment.
Can we factor out his so that:
if m.self_id().is_option() {
build_option_layout_from_definition(...)
} else {
build_any_variant_layout_from_definition(...)
}
| .collect::<anyhow::Result<Vec<_>>>()?; | ||
|
|
||
| Ok(match layout_type { | ||
| LayoutType::Runtime => MoveStructLayout::RuntimeVariants( |
There was a problem hiding this comment.
Why we support it here, but not for option? I think we do not need this here and only WithTypes need to be supported, and if so, we can process all layouts here and do not even match on layout type: check it is with_types in advance.
| Vector(ety) => self.is_valid_txn_arg_type(ety), | ||
| Struct(mid, sid, inst) => { | ||
| let qid = mid.qualified(*sid); | ||
| self.is_allowed_input_struct(qid) || self.is_public_copy_struct(qid, inst) |
There was a problem hiding this comment.
Is this correct: we would allow Option<NonPublicStruct> here. Don't we need to check inst for Option (because we know it is a field)? How did it work before could you construct None of non-public type, bit not Some(..)?
| public entry fun test_option_point(sender: &signer, opt_point: std::option::Option<Point>) acquires TestResult { | ||
| let result = borrow_global_mut<TestResult>(std::signer::address_of(sender)); | ||
| if (std::option::is_some(&opt_point)) { | ||
| let p = std::option::destroy_some(opt_point); |
There was a problem hiding this comment.
nit: imports and use . syntax?
| ); | ||
| assert_success!(result); | ||
|
|
||
| // Now disable VM_BINARY_FORMAT_V10 feature flag, which disables public struct/enum args |
There was a problem hiding this comment.
we should never disable it though, because if you published v10 bytecode it becomes unloadable? is it better to split feature gating and having a dedicated feature for controlling such args? in a sense that this scenario is not really possible? what can happen is v9 bytecode is published and Point is non-public. We fail to run functions/ Then we enable v10. Running this entry starts to work?
|
|
||
| // Verify view function returns deserialization error as ErrorMessage | ||
| // (not MoveAbort, since CODE_DESERIALIZATION_ERROR is not an abort) | ||
| match view_result.values { |
There was a problem hiding this comment.
Do we need a match? can unwrap in tests
| } | ||
|
|
||
| #[view] | ||
| public fun view_point(p: Point): u64 { |
There was a problem hiding this comment.
Q: can we return Point struct from this view function, does it work even for non-public structs?
ca38b6b to
52495b2
Compare
a6c536f to
810bb48
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| Some(String::from("Pack function did not return value")), | ||
| ) | ||
| })? | ||
| .0) |
There was a problem hiding this comment.
Pack function return count not validated, pop/index mismatch
Low Severity
In construct_public_copy_struct, the return type count check only verifies return_tys().is_empty() (line 630), unlike load_constructor_function which checks return_tys().len() != 1. Additionally, the type matching uses return_tys()[0] (first return type) while the result extraction uses ret_vals.pop() (last return value). For a hypothetical pack function returning multiple values, these would reference different items.
52495b2 to
c07e5bd
Compare
810bb48 to
fb023bd
Compare



Description
This PR
a. public (have public pack functions with #[struct_api(pack)] attribute)
b. have the copy ability
c. all field types are also valid transaction arguments
Note that this PR does not contain code to support public structs in CLI because it requires encoding the type information.
How Has This Been Tested?
new e2e move tests and api tests.
Key Areas to Review
Whether the validation logic is correct and complete;
Whether the test cases give good coverage;
Whether this change may cause any compatibility issues.
Type of Change
Which Components or Systems Does This Change Impact?
Checklist
Note
High Risk
Touches VM transaction argument validation/construction and core layout representations, which are consensus-critical and can affect transaction acceptance, gas, and compatibility. Also introduces new parsing paths for enums/generics that could reject/accept transactions differently if edge cases are missed.
Overview
Adds end-to-end support for passing public
copyMove structs/enums as transaction (and view) arguments, beyond the existing whitelist.On the VM side, transaction argument validation now accepts public
copystructs/enums by loading/cachingpack$...functions, recursively validating field types (including generic instantiations), and constructing arguments by executing the appropriate pack function (including enum variant packs). The feature is gated via a new VM config flagenable_public_struct_args(enabled forVM_BINARY_FORMAT_V10).On the API side, JSON-to-BCS conversion gains enum JSON parsing and handles generic entry functions by instantiating parameter types with provided type arguments before decoding. Core Move layout plumbing is updated so
MoveStructLayout::WithVariantscarries aStructTag, and enum layouts are produced by bytecode layout builders, with follow-on adjustments in BCS/string native utilities.Adds extensive new API and e2e tests covering positive/negative cases (nested structs, vectors,
Option, enums/variants, generic containers, and feature-flag on/off behavior).Written by Cursor Bugbot for commit fb023bd. This will update automatically on new commits. Configure here.