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

feat: add a read-only mode to sends #1150

Merged
merged 3 commits into from
Nov 28, 2022
Merged

feat: add a read-only mode to sends #1150

merged 3 commits into from
Nov 28, 2022

Conversation

Stebalien
Copy link
Member

Adds a read-only mode for sends.

  1. Adds "flags" to the sends syscall. We can extend it in the future to support additional flags.
  2. Adds the concept of "read-only" layers to both the event accumulator and the state tree. This means we can track the read-only state at the lowest level.

The general approach here is to reject mutations at the mutation site instead of early. That means we'll charge gas first. The alternative would be to check up-front at the top of the syscall, but that's non-trivial because a send may automatically create an actor in some cases.

@codecov-commenter
Copy link

codecov-commenter commented Nov 26, 2022

Codecov Report

Merging #1150 (6463bc3) into master (9c35c30) will increase coverage by 1.12%.
The diff coverage is 23.88%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1150      +/-   ##
==========================================
+ Coverage   48.63%   49.75%   +1.12%     
==========================================
  Files         128      128              
  Lines       11610    11385     -225     
==========================================
+ Hits         5646     5665      +19     
+ Misses       5964     5720     -244     
Impacted Files Coverage Δ
fvm/src/call_manager/default.rs 0.00% <0.00%> (ø)
fvm/src/call_manager/mod.rs 21.42% <ø> (+8.09%) ⬆️
fvm/src/executor/default.rs 0.89% <0.00%> (+0.12%) ⬆️
fvm/src/kernel/default.rs 11.58% <0.00%> (-1.30%) ⬇️
fvm/src/syscalls/send.rs 0.00% <0.00%> (ø)
sdk/src/error.rs 0.00% <0.00%> (ø)
sdk/src/send.rs 0.00% <0.00%> (ø)
sdk/src/sself.rs 0.00% <0.00%> (ø)
sdk/src/vm.rs 0.00% <0.00%> (ø)
shared/src/error/mod.rs 0.00% <0.00%> (ø)
... and 17 more

@Stebalien Stebalien force-pushed the feat/readonly branch 5 times, most recently from 0c155c5 to 89888c1 Compare November 28, 2022 02:55
// right now. It doesn't really cost anything anyways.
pub struct SendFlags: u64 {
/// Send in "read-only" mode.
const READ_ONLY = 0b00000001;
Copy link
Member Author

Choose a reason for hiding this comment

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

In the future, we may want other flags like:

  • Isolated (can't make sub-calls).
  • Silent (events are ignored). We could even split READ_ONLY into DENY_MUTATIONS and SILENT, but I don't want to do that now because there are some security concerns.
  • "Pure" (can't read contextual information like the epoch, time, randomness, etc.).

/// - Value transfers are forbidden.
/// - Events are discarded.
pub fn read_only() -> bool {
super::message::MESSAGE_CONTEXT.flags.read_only()
Copy link
Member Author

Choose a reason for hiding this comment

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

See #1151. This really doesn't belong in fvm_sdk::message.

@@ -147,6 +147,8 @@ pub enum ErrorNumber {
Forbidden = 11,
/// The passed buffer is too small.
BufferTooSmall = 12,
/// The actor is executing in a read-only context.
ReadOnly = 13,
Copy link
Member Author

Choose a reason for hiding this comment

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

I considered using an existing error but:

  • IllegalOperation is ambiguous on set_root (returned both if the actor has already been deleted, or is in read-only mode).
  • Forbidden is ambiguous on self_destruct if the beneficiary is self.

In general, I'm starting to regret having "common" errors and am becoming convinced we want more specific ones. We can still share errors between syscalls, but errors like ActorDeleted is probably better than IllegalOperation.

@Stebalien Stebalien force-pushed the feat/readonly branch 2 times, most recently from 4b68c86 to 6463bc3 Compare November 28, 2022 03:01
@Stebalien Stebalien requested a review from vyzo November 28, 2022 03:02
@vyzo
Copy link
Contributor

vyzo commented Nov 28, 2022

Shouldnt events be allowed in readonly mode?

Copy link
Contributor

@vyzo vyzo left a comment

Choose a reason for hiding this comment

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

first pass on the phone, will do another one on the computer.

@@ -168,10 +168,11 @@ where

fn with_transaction(
&mut self,
read_only: bool,
Copy link
Contributor

Choose a reason for hiding this comment

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

What's a reaonly transaction?

Kind of nonsensical, but i guess convenient in not having to change existing code.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it is kind of subtle... I'm effectively just counting how many times I've entered "read-only" mode so I can exit when I get back to the top.

fn append_event(&mut self, evt: StampedEvent) {
self.events.push(evt)
if !self.is_read_only() {
Copy link
Contributor

Choose a reason for hiding this comment

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

So they are allowed, just not emitted.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes.

)
})
.or_fatal()?
self.assert_writable()?;
Copy link
Contributor

Choose a reason for hiding this comment

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

subtle.

@Stebalien
Copy link
Member Author

Shouldnt events be allowed in readonly mode?

They are, they're just dropped.

  • This matches EVM behavior.
  • This avoids a potential security issue where an attacker might be able to cause another actor to emit an event even if the change won't be committed.

Eventually, I'd like to split "read-only" into multiple limits, but this is a good place to start.

@Stebalien
Copy link
Member Author

@raulk FYI, I kept it as "read-only" because it's now actually read-only (we're rejecting calls to set_root instead of just reverting them). Happy to rename if you can think of a better name.

Copy link
Contributor

@vyzo vyzo left a comment

Choose a reason for hiding this comment

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

ship it!

@Stebalien Stebalien merged commit 8a22156 into master Nov 28, 2022
@Stebalien Stebalien deleted the feat/readonly branch November 28, 2022 23:01
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.

3 participants