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

test: MockChain, CodeExecutor, TransactionContext proposals and general improvements #735

Merged
merged 17 commits into from
Jun 20, 2024

Conversation

igamigo
Copy link
Collaborator

@igamigo igamigo commented Jun 6, 2024

  • Previously, there were a series of functions created for mocking objects (such as non_fungible_faucet_2()). Most of these were moved to their own object's impl blocks. The remainders were left as helpers for specific tests, like mock_executed_transaction(), mainly because they assume too much of the use-case and wouldn't be of much help being a struct function. The kernel tests on miden-tx were moved to be a submodule of the tests module as well.

  • Introduces 3 structs:

    • CodeExecutor is a helper struct for running arbitrary code on Hosts. This struct is meant to group and replace the run_* functions. It implements a fluent API for simpler use, and so now something like this:
              let process = run_within_tx_kernel(
                  "",
                  &code,
                  StackInputs::new(vec![account_id.into()]).unwrap(),
                  MemAdviceProvider::default(),
                  None,
              )
              .unwrap();

    would look like this:

            let process = CodeExecutor::new_with_kernel(MemAdviceProvider::default())
                .stack_inputs(StackInputs::new(vec![account_id.into()]).unwrap())
                .run(&code)
                .unwrap();
    • MockChain was simplified and repurposed for simulating a blockchain for tests, essentially replacing mock_chain_data(). Since most mocking problems stem from not being able to simulate relations between objects correctly, I think having a good way to relate all entities in a struct can eventually solve most problems. It's not very complete but it serves for simulating blocks and transforming Notes into InputNotes for executing transactions (and exposes an API for getting valid TransactionInputs). There's a MockChainBuilder as well.
    • TransactionContext is meant to replace the mock_inputs_* family of functions. These functions assumed a specific set of use-cases, and were related to other mock objects such as the MockDataStore or functions such as mock_executed_transaction. For any time a tests would call mock_inputs(), for example, notes would be mocked and transformed into InputNote even when the tests weren't making use of notes. So the idea of TransactionContext is to encapsulate these possible use-cases but also expose a way of creating more hand-made scenarios. It also has a builder struct for simple initialization, although it's not the cleanest API/structure right now (planning to review this next alongside MockDataStore).

As a result of this, a decent amount of (sometimes duplicate) code was removed. The API is not necessarily less verbose than it was, but it hopefully makes some more sense semantically. I'm not sure about the names of these structs, or even if the structs themselves make sense, so it is all up for discussion.

@igamigo igamigo changed the title test: MockChain, CodeExecutor, TransactionContext proposals and improvements test: MockChain, CodeExecutor, TransactionContext proposals and general improvements Jun 6, 2024
Copy link
Contributor

@mFragaBA mFragaBA 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! Left some minor comments.

objects/src/testing/block.rs Show resolved Hide resolved
objects/src/testing/block.rs Outdated Show resolved Hide resolved
miden-tx/src/testing/tx_context.rs Show resolved Hide resolved
miden-tx/src/testing/executor.rs Show resolved Hide resolved
.collect::<Vec<_>>();
assert_eq!(account_id, self.tx_inputs.account().id());
assert_eq!(block_num, self.block_header().block_num());
assert_eq!(notes.len(), self.tx_inputs.input_notes().num_notes());
Copy link
Contributor

Choose a reason for hiding this comment

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

we should probably assert that all the requested notes are contained within self.tx_inputs.input_notes().

mock_account_code(assembler),
Account::mock(
ACCOUNT_ID_REGULAR_ACCOUNT_UPDATABLE_CODE_ON_CHAIN,
Felt::ZERO,
Copy link
Contributor

Choose a reason for hiding this comment

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

was there a reason we changed from Felt::ONE to Felt::ZERO? Was there a reason it was one instead of zero before?

objects/src/accounts/mod.rs Show resolved Hide resolved
Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Thank you! Looks good! This is not an exhaustive review (I mostly looked at CodeExecutor and TransactionContext structs) but I did leave some comments inline.

Overall, I like the idea of CodeExecutor and TransactionContext, especially for granular tests (i.e., tests which test some narrow functionality). As you've noted, I think we can improve the APIs - but this can be done in follow-up PRs.

I haven't looked too deeply into the MockChain structs, but it seems like there may be a lot of obsolete code there. On the other hand, I wonder if we should make the MockChain a more central component of higher level tests (i.e., tests which execute entire transaction flow).

For example, something like:

let chain = MockChain::new();

// this could return something like MockFungibleFaucet(Account)
let pol_faucet = chain.add_fungible_faucet("POL");

let asset = pol_faucet.mint(100);

// this would create a basic wallet account but without requiring signature
// for authentication
let alice = chain.add_wallet_account(Auth::NoAuth);

// similar to alice - but the account would be "new" (i.e., nonce=0)
let bob = chain.add_new_wallet_account(Auth::NoAuth);

// this would create a P2ID note and add it to the chain
let note = chain.add_p2id_note(&alice, &bob, asset, NoteType::OffChian);

// build transaction context for consuming note by bob's account
let tx_context = chain.build_tx_context(&bob)
    .add_input_note(note)
    .build();

let executed_tx = tx_context.execute().unwrap();

The above is just a sketch - so, could be missing some detail - but I think having something like this, would simplify higher-level tests quite a bit.

Comment on lines 45 to 53
pub fn module_file(mut self, file_path: PathBuf) -> Self {
self.file_path = Some(file_path);
self
}

pub fn imports(mut self, imports: &str) -> Self {
self.imports = imports.to_string();
self
}
Copy link
Contributor

Choose a reason for hiding this comment

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

These two functions seem to be used exclusively in epilogue tests (and they always seem to be used together). I haven't thought it through yet, but I'm wondering if there is a better way of handling these tests without this general structure (could also be done in a follow-up PR).

Comment on lines +35 to +38
pub fn extend_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
self.advice_inputs.extend(advice_inputs);
self
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't seems like this function is currently being used anywhere?

miden-tx/src/testing/executor.rs Outdated Show resolved Hide resolved
miden-tx/src/testing/executor.rs Outdated Show resolved Hide resolved
miden-tx/src/testing/tx_context.rs Outdated Show resolved Hide resolved
Comment on lines +99 to +101
pub fn set_tx_args(&mut self, tx_args: TransactionArgs) {
self.tx_args = tx_args;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why this method is needed? Shouldn't all of the properties be set via the TransactionContextBuilder?

miden-tx/src/testing/tx_context.rs Outdated Show resolved Hide resolved
Comment on lines 192 to 196
/// Populates input and expected notes with the results from [mock_notes()]
pub fn with_mock_notes(self, asset_preservation: AssetPreservationStatus) -> Self {
let (notes, output_notes) = mock_notes(&self.assembler, &asset_preservation);
self.notes(notes).expected_notes(output_notes)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe not for this PR, but the this method seems rather confusing to me. We are creating a pre-defined set of notes in a pretty opaque way (i.e., I need to read and understand what mock_notes() function is doing and then how AssetPreservationStatus is used in various places to figure out what's going on.

We should probably refactor this to get rid of AssetPreservationStatus and potentially this method altogether.

miden-tx/src/testing/tx_context.rs Outdated Show resolved Hide resolved
miden-tx/src/testing/tx_context.rs Outdated Show resolved Hide resolved
@bobbinth bobbinth mentioned this pull request Jun 19, 2024
Copy link
Contributor

@bobbinth bobbinth 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! Thank you! As mentioned in the previous review - there are still quite a few things we can refactor/improve here, but given the amount of changes here, I think it makes sense to merge it sooner rather than later.

@bobbinth bobbinth marked this pull request as ready for review June 20, 2024 07:42
@bobbinth bobbinth merged commit 13c168f into next Jun 20, 2024
12 checks passed
@bobbinth bobbinth deleted the igamigo-mock-chain branch June 20, 2024 07:42
bobbinth pushed a commit that referenced this pull request Jul 4, 2024
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