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

Feature gate builtin consumes static units during processing instruction #30702

Conversation

tao-stones
Copy link
Contributor

@tao-stones tao-stones commented Mar 13, 2023

Problem

For below mentioned feature gated issue, PR #30680 presented one possible solution to charge default units if (and only if) builtins don't manually deduct units after process_instruction(). @Lichtso pointed out two issues with it:

  1. the prerequisite add default_cost as mandatory field for Builtin #30639 conflicts with the undergoing refactoring works; (detail here)
  2. the preferred practice is to deduct units before processing, not after.

@Lichtso and I huddled offline, proposed to update all builtins to consume statically defined units at beginning of process_instruction. The pros: above mentioned 2 concerns are addressed; the cons: it is not easy to abandon builtin costs (re)defined in runtime/src/block_cost_limits.rs, which adds cost of maintenance. (with previous approach, i was planning to remove that HashMap from block_cost_limit, instead fetch builtin cost from bank.builtins.default_compute_unit_cost)

Summary of Changes

  • add feature gate
  • implement second proposal.

Feature Gate Issue: #30620

@tao-stones tao-stones added the feature-gate Pull Request adds or modifies a runtime feature gate label Mar 13, 2023
@tao-stones tao-stones requested a review from Lichtso March 14, 2023 00:05
Lichtso
Lichtso previously approved these changes Mar 14, 2023
@tao-stones tao-stones requested a review from joncinque March 14, 2023 15:30
joncinque
joncinque previously approved these changes Mar 15, 2023
Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

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

The change looks good to me! To prevent this in the future, do you want to add something in the native instruction processor which errors if no compute units are used? This can be addressed in a followup with a separate feature gate if you prefer.

@tao-stones tao-stones dismissed stale reviews from joncinque and Lichtso via ce1c510 March 16, 2023 15:08
@tao-stones tao-stones force-pushed the feature-gate-builtin-consumes-static-units-per-ix branch from ce1c510 to e121b44 Compare March 16, 2023 16:01
@tao-stones
Copy link
Contributor Author

To prevent this in the future, do you want to add something in the native instruction processor which errors if no compute units are used? This can be addressed in a followup with a separate feature gate if you prefer.

Like this idea, makes sense to include this change in same feature gate. But can you say more about it? Not super clear what "native instruction processor" refer to, and how that would prevent future native program to consume units.

As for error, would a new InstructionError::InstructionNotConsumeUnits suffice?

@tao-stones tao-stones force-pushed the feature-gate-builtin-consumes-static-units-per-ix branch from e121b44 to 33af2ef Compare March 16, 2023 18:19
@tao-stones
Copy link
Contributor Author

Also I wish to refactor the hardcoded number into named constants. so
this
invoke_context.consume_checked(150)?;
would becomes:
invoke_context.consume_checked(solana_sdk::system_program::DEFAULT_COMPUTE_UNIT_COST)?;
and their tests as well.
I'm thinking to add const right next to each program id declarion, so

crate::declare_id!(...);
pub const DEFAUL_COMPUT_UNIT_COST: u64 = ....;

Would this break any convention? @joncinque @Lichtso

@tao-stones tao-stones force-pushed the feature-gate-builtin-consumes-static-units-per-ix branch from 33af2ef to 90f05ad Compare March 16, 2023 22:34
@joncinque
Copy link
Contributor

Like this idea, makes sense to include this change in same feature gate. But can you say more about it? Not super clear what "native instruction processor" refer to, and how that would prevent future native program to consume units.

In your other PR, you checked to see if consumed compute units was 0 before deducting the default amount at https://github.com/solana-labs/solana/pull/30680/files#diff-9ac236825ce9b87946d6820e3ec3096bc841818c66037b38b6d98142318f4b0aR783-R791

How about returning an error if consumed compute units is 0?

@joncinque
Copy link
Contributor

Also I wish to refactor the hardcoded number into named constants

If it's only used in one place, I think it's fine to keep the hardcoded amounts, but it's a matter of taste

@tao-stones
Copy link
Contributor Author

In your other PR, you checked to see if consumed compute units was 0 before ...

Aaah, gotcha! The word "native" threw me off, thought it's something else 😜 Thanks for explaining,

Also I wish to refactor the hardcoded number into named constants

If it's only used in one place, I think it's fine to keep the hardcoded amounts, but it's a matter of taste

Yeah ok, let's leave this one out for now. It can be done as separately without needing another feature gate.

@tao-stones
Copy link
Contributor Author

you checked to see if consumed compute units was 0 ...

Aaah, gotcha. Sorry "native" threw me off early, thought referring to something else 😜 . comment 254da8b does it.

@tao-stones tao-stones force-pushed the feature-gate-builtin-consumes-static-units-per-ix branch 2 times, most recently from da7a35d to b5f3f27 Compare March 17, 2023 20:13
@@ -769,6 +773,17 @@ impl<'a> InvokeContext<'a> {
let post_remaining_units = self.get_remaining();
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);

// startign from feature `native_programs_consume_cu`, all builtin programs should consume
Copy link
Contributor Author

@tao-stones tao-stones Mar 17, 2023

Choose a reason for hiding this comment

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

Adding this to enforce future native programs to consume units.

// programs that do not consume units.
let mut deactivate_feature_set = HashSet::default();
deactivate_feature_set.insert(solana_sdk::feature_set::native_programs_consume_cu::id());

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Existing mock/test programs do not consume units, the enforcement added above not only breaks all tests under program-test/tests and some zk-token-proof tests, it also breaks downstream tests (such as spl). I deactivated this feature for ProgramTest here to continue support existing tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

No problem, that makes sense for these, especially in "native" mode. We could eventually change program-test to consume some default amount in "native" mode.

@@ -281,7 +281,7 @@ impl RentDebits {
}

pub type BankStatusCache = StatusCache<Result<()>>;
#[frozen_abi(digest = "3qia1Zm8X66bzFaBuC8ahz3hADRRATyUPRV36ZzrSois")]
#[frozen_abi(digest = "FT6XYtzchg9h2JACEKKf8FZD5skSnPzKY4YrJ1jUWr8U")]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

abi change due to adding InstructionError

@codecov
Copy link

codecov bot commented Mar 18, 2023

Codecov Report

Merging #30702 (d661745) into master (5a05e9b) will decrease coverage by 0.1%.
The diff coverage is 59.5%.

@@            Coverage Diff            @@
##           master   #30702     +/-   ##
=========================================
- Coverage    81.5%    81.5%   -0.1%     
=========================================
  Files         726      726             
  Lines      204809   204914    +105     
=========================================
+ Hits       167027   167080     +53     
- Misses      37782    37834     +52     

@tao-stones tao-stones requested review from Lichtso and joncinque March 18, 2023 02:20
@tao-stones
Copy link
Contributor Author

@joncinque @Lichtso adding check to enforce builtin to consume units broke a ton tests all over place :) Took time to use the opportunity to learn some details about runtime and program_test. This PR is cleaned up, ready for another review.

Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

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

Thanks for fixing up all those tests, this is looking really close!

// programs that do not consume units.
let mut deactivate_feature_set = HashSet::default();
deactivate_feature_set.insert(solana_sdk::feature_set::native_programs_consume_cu::id());

Copy link
Contributor

Choose a reason for hiding this comment

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

No problem, that makes sense for these, especially in "native" mode. We could eventually change program-test to consume some default amount in "native" mode.

program-test/src/lib.rs Outdated Show resolved Hide resolved
program-runtime/src/invoke_context.rs Outdated Show resolved Hide resolved
programs/sbf/tests/programs.rs Outdated Show resolved Hide resolved
sdk/program/src/instruction.rs Outdated Show resolved Hide resolved
.feature_set
.is_active(&native_programs_consume_cu::id())
{
return Err(InstructionError::BuiltinProgramsMustConsumeUnits);
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that I think about it more -- consuming 0 units is a programmer error and not a user error, so we could be even more aggressive and assert.

On the flipside, since the runtime is used by other developers, like in all of the program tests, they should probably get a nice error rather than an assert. I'm leaning toward keeping this as an error, but I wanted to bring up the discussion to see how you thought.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great observation! I agree it'd be a programmer error. Also agree runtime is library other developers use; so it'd be great, as good SDK, to return meaningful errors for unsupported user invokes. I'd vote for keep error too.

@tao-stones tao-stones force-pushed the feature-gate-builtin-consumes-static-units-per-ix branch 2 times, most recently from a77cb21 to 6c199dc Compare March 21, 2023 03:52
@tao-stones tao-stones requested a review from joncinque March 21, 2023 05:42
@tao-stones tao-stones force-pushed the feature-gate-builtin-consumes-static-units-per-ix branch from 6c199dc to de8a840 Compare March 21, 2023 19:34
joncinque
joncinque previously approved these changes Mar 23, 2023
Copy link
Contributor

@joncinque joncinque left a comment

Choose a reason for hiding this comment

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

Looks good to me, but be sure to get feedback from @Lichtso too, to make sure that it interacts properly with any runtime changes

Lichtso
Lichtso previously approved these changes Mar 24, 2023
- return error if builtin did not consume units, as a way to enforce builtin to consume units;
- updated related tests
…re to continue support existing mock/test programs that do not consume units
@tao-stones tao-stones dismissed stale reviews from Lichtso and joncinque via d661745 March 24, 2023 14:28
@tao-stones tao-stones force-pushed the feature-gate-builtin-consumes-static-units-per-ix branch from de8a840 to d661745 Compare March 24, 2023 14:28
@tao-stones tao-stones merged commit 3e500d9 into solana-labs:master Mar 24, 2023
@tao-stones tao-stones deleted the feature-gate-builtin-consumes-static-units-per-ix branch March 24, 2023 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-gate Pull Request adds or modifies a runtime feature gate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants