Conversation
6f5f196 to
74a629e
Compare
There was a problem hiding this comment.
Still not 100% sure if this is the right way to go, as it looks like we have a few places where we still need TransactionInputs with notes (TransactionKernel::prepare_inputs, TransactionAdviceInputs::new) and a few places where it's nicer to have it separately (DataStore::get_transaction_inputs, NoteConsumptionChecker::try_execute_notes).
So I'd try a middle ground with two types, e.g. PartialTransactionInputs and TransactionInputs (see inline comment).
crates/miden-tx/src/executor/mod.rs
Outdated
| notes: InputNotes<InputNote>, | ||
| input_notes: InputNotes<InputNote>, | ||
| tx_args: TransactionArgs, | ||
| ) -> Result<ExecutedTransaction, TransactionExecutorError> { | ||
| let tx_inputs = | ||
| self.prepare_transaction_inputs(account_id, block_ref, notes, &tx_args).await?; | ||
| let tx_inputs = self | ||
| .prepare_transaction_inputs(account_id, block_ref, &input_notes, &tx_args) | ||
| .await?; | ||
|
|
||
| let (mut host, stack_inputs, advice_inputs) = | ||
| self.prepare_transaction(&tx_inputs, &tx_args, None).await?; | ||
| self.prepare_transaction(&tx_inputs, &input_notes, &tx_args, None).await?; |
There was a problem hiding this comment.
I think here and for TransactionKernel::prepare_inputs and in turn TransactionAdviceInputs::new it would make sense to still have a type that represents transaction inputs with notes, otherwise we just pass the notes separately.
This would be a bit cleaner, and it would also allow that type to validate the authentication paths of the input notes (what TransactionInputs::new has done so far).
So maybe having a PartialTransactionInputs and TransactionInputs type makes sense, which would be defined as described in #401 (comment).
(We could also use different names, but I can't come up with something better than TransactionInputsWithNotes and that seems less nice than the "partial" naming).
There was a problem hiding this comment.
I forgot that this is also a bit related to #1852 (comment). For that issue, we may want a type that returns more data than what would go in TransactionInputs (namely the asset witnesses), and so perhaps a different name makes sense. This would mean we no longer make that type a field in TransactionInputs (which would stay as-is), but rather inline its fields, so essentially:
// What is now TransactionInputs
pub struct TransactionExecutionInputs {
account: PartialAccount,
block_header: BlockHeader,
blockchain: PartialBlockchain,
input_notes: InputNotes<InputNote>,
}
// Would be returned by `DataStore::get_transaction_inputs`
pub struct TransactionInputs {
account: PartialAccount,
block_header: BlockHeader,
blockchain: PartialBlockchain,
// Not added in this PR.
asset_witnesses: Vec<AssetWitness>,
}I'm wondering if we could make TransactionExecutionInputs an internal type in the future (for now we need it across miden-lib and miden-tx, but if some functionality gets merged in the future, this could be made internal and then its name wouldn't matter as much).
PhilippGackstatter
left a comment
There was a problem hiding this comment.
Looks good, thank you!
I think it's a bit odd to have types named TransactionInputs and TransactionExecutionInputs where the latter, with the more specialized name contains the former, with the more generic name. Should we rename TransactionInputs into TransactionPreparationInputs so they are both similarly named? If so, we should probably also adjust the method on DataStore to DataStore::get_transaction_preparation_inputs - it's a bit long, but at least precise.
An alternative would be prepare_transaction - that'd be slightly inconsistent with the other methods, but shorter. I'd be fine with both.
Also, I think we may actually be able to use TransactionInputs as a field directly in TransactionExecutionInputs.
(I know I proposed these things before, but I couldn't think of a better naming scheme / structure then - sorry for the back and forth.)
| pub(super) tx_inputs: TransactionKernelInputs, | ||
| pub(super) mast_store: TransactionMastStore, | ||
| pub(super) advice_inputs: AdviceInputs, | ||
| pub(super) advice_inputs: AdviceInputs, // TODO: unused, something must be wrong? |
There was a problem hiding this comment.
@bobbinth @PhilippGackstatter I am confused about the Option<AdviceInputs> vs these AdviceInputs. Right now I have the former being passed into TransactionKernelInputs::new() but I have probably done something wrong to leave this one unused.
There was a problem hiding this comment.
I have left TODO statements to cover the places where there is confusion around the advice inputs
There was a problem hiding this comment.
I have peeled back the diffs to iterate from a commit that passed tests. When I move the tx_args into the input type (still named TransactionExecutionInputs for now), the tests fail here.
There was a problem hiding this comment.
It seems like one of the issues is that TransactionExecutionInputs contains TransactionArgs but we still build it separately in TransactionContextBuilder::build - and then we probably don't use it in certain TransactionExecutor APIs.
My gut feeling is that maybe combining TransactionPreparationInputs and TransactionArgs into a single type may not work too well because these types become available at different points in time, but we still want to have a type that encapsulates the tx inputs and input notes, and this creates an awkward situation where we construct TransactionExecutionInputs from TransactionPreparationInputs and InputNotes but are forced to also provide a TransactionArgs, which is not usually available at that time (for instance in MockChain::get_transaction_execution_inputs).
This may be solvable in two ways:
- Either we keep three types in total:
TransactionPreparationInputs,TransactionExecutionInputsandTransactionArgsseparately, - Or we try to "remove"
TransactionArgsfrom the public API and instead only expose its functionality throughTransactionExecutionInputswhich would now allow users to do everything that tx args did previously: set tx scripts, auth args, note args, etc.
I would try the second approach, since removing the number of types here could be beneficial to make the API clearer, but if this turns out to be too awkward to use in practice, I'd revert to the first approach.
There was a problem hiding this comment.
My gut feeling is that maybe combining
TransactionPreparationInputsandTransactionArgsinto a single type may not work too well because these types become available at different points in time, but we still want to have a type that encapsulates the tx inputs and input notes, and this creates an awkward situation where we constructTransactionExecutionInputsfromTransactionPreparationInputsandInputNotesbut are forced to also provide aTransactionArgs, which is not usually available at that time (for instance inMockChain::get_transaction_execution_inputs).
I this also applicable outside of testing scenarios? My understanding is that in "production" scenarios, TransactionArgs are built before we have TransactionInputs (or TransactionExecutionInputs). If it is only for testing purposes, maybe we can make some internal state accessible which could make things simpler.
There was a problem hiding this comment.
I this also applicable outside of testing scenarios?
Probably less so, yes. I extrapolated a bit too much from the tx context which is the only non-trivial user of the TransactionExecutor API we have in base.
6a82d8f to
9128824
Compare
| pub(super) tx_inputs: TransactionKernelInputs, | ||
| pub(super) mast_store: TransactionMastStore, | ||
| pub(super) advice_inputs: AdviceInputs, | ||
| pub(super) advice_inputs: AdviceInputs, // TODO: unused, something must be wrong? |
There was a problem hiding this comment.
It seems like one of the issues is that TransactionExecutionInputs contains TransactionArgs but we still build it separately in TransactionContextBuilder::build - and then we probably don't use it in certain TransactionExecutor APIs.
My gut feeling is that maybe combining TransactionPreparationInputs and TransactionArgs into a single type may not work too well because these types become available at different points in time, but we still want to have a type that encapsulates the tx inputs and input notes, and this creates an awkward situation where we construct TransactionExecutionInputs from TransactionPreparationInputs and InputNotes but are forced to also provide a TransactionArgs, which is not usually available at that time (for instance in MockChain::get_transaction_execution_inputs).
This may be solvable in two ways:
- Either we keep three types in total:
TransactionPreparationInputs,TransactionExecutionInputsandTransactionArgsseparately, - Or we try to "remove"
TransactionArgsfrom the public API and instead only expose its functionality throughTransactionExecutionInputswhich would now allow users to do everything that tx args did previously: set tx scripts, auth args, note args, etc.
I would try the second approach, since removing the number of types here could be beneficial to make the API clearer, but if this turns out to be too awkward to use in practice, I'd revert to the first approach.
|
I wonder if we should punt on this for now. Current approaches seem to create more issues than they are solving, and in the future, this refactoring is likely to be easier. Specifically:
But I also think that it may be worth reformulating the original issue more along the lines of what I described in #1934 (comment). Specifically, we do need something like |
PhilippGackstatter
left a comment
There was a problem hiding this comment.
Looks good to me!
I think we can merge this as it is an improvement, but my original idea of removing TransactionArgs from the public API clearly doesn't work, so now we have more public transaction related types, which is a bummer. As @bobbinth mentioned, we'll likely have to touch this again, and so we can give this another shot then.
I left a comment about making the construction of transaction contexts a bit nicer which I think would be nice to do.
I think the naming of the structs as they are now is fine - having two Transaction{Preparation,Kernel}Inputs seems cleaner than having TransactionInputs and another more specific one. If we find preparation too long, we could go with something shorter like "setup", "base" or "core".
CHANGELOG.md
Outdated
| - [BREAKING] Refactor transaction input types to `TransactionKernelInputs` and `TransactionPreparationInputs` ([#1934](https://github.com/0xMiden/miden-base/pull/1934)). | ||
| - [BREAKING] Update `DataStore` trait to return `TransactionInputs` ([#1934](https://github.com/0xMiden/miden-base/pull/1934)). |
There was a problem hiding this comment.
Depending on how we go forward with names, this needs an update in one or the other way.
| let mut tx_args = TransactionArgs::new(Default::default(), foreign_account_inputs) | ||
| .with_tx_script(tx_script); | ||
| tx_args.extend_advice_inputs(advice_inputs); |
There was a problem hiding this comment.
Not for this PR, but we could also refactor TransactionArgs::new so that it takes AdviceInputs instead of AdviceMap. That would avoid the need for the extend call.
There was a problem hiding this comment.
On second thoughts, extending the advice stack doesn't make sense from transaction args, but extending advice map or merkle store probably does make sense. I'm thinking of some custom use cases for merkle path verification, for instance. I wonder if we should refactor TransactionArgs a bit to address that. Not super pressing, though.
crates/miden-tx/src/prover/mod.rs
Outdated
| mut tx_inputs, | ||
| foreign_account_code, | ||
| advice_witness, | ||
| } = tx_witness; | ||
|
|
||
| let (stack_inputs, advice_inputs) = | ||
| TransactionKernel::prepare_inputs(&tx_inputs, &tx_args, Some(advice_witness)) | ||
| .map_err(TransactionProverError::ConflictingAdviceMapEntry)?; | ||
| tx_inputs.extend_advice_inputs(advice_witness); | ||
| let (stack_inputs, advice_inputs) = TransactionKernel::prepare_inputs(&tx_inputs) | ||
| .map_err(TransactionProverError::ConflictingAdviceMapEntry)?; |
There was a problem hiding this comment.
It's a bit awkward to carry the tx inputs and advice witness here separately and then combine them. But also, as @bobbinth mentioned, this will likely be refactored anyway, so no big deal.
bobbinth
left a comment
There was a problem hiding this comment.
Looks good! Thank you! Not a full review, but I left some comments inline. There are two main comments:
- One about adding
advice_inputstoTransactionKernelInputsand updating this field on each execution ofNoteConsumptionChecker::try_execute_notes(). - Another one about moving
TransactionKernelInputsintomiden-lib.
I'm not too sure about the benefits of the latter - so, maybe we do the first point first and see how it looks, and then we can evaluate if the second point makes sense.
| /// Extends the advice inputs with the provided ones. | ||
| pub fn extend_advice_inputs(&mut self, advice_inputs: AdviceInputs) { | ||
| self.tx_args.extend_advice_inputs(advice_inputs); | ||
| } |
There was a problem hiding this comment.
I wonder if this should be just set_advice_inputs() which would reset the value of the new advice_inputs field I mentioned in one of the previous comments.
The idea here is that in the note checker's try_execute_notes(), we'd take kernel_inputs as a mutable parameter, and then replace them with the result we get back from FastProcessor::execute() (we get back advice provider there, but I believe we can convert it to advice inputs).
There was a problem hiding this comment.
I removed extend_advice_inputs() from TransactionKernelInputs after adding init_advice_inputs to it. Not quite following how to alter try_execute_notes() w.r.t to this.
|
Also, I think this branch may not be up to date with the latest |
9315769 to
db6be8b
Compare
bobbinth
left a comment
There was a problem hiding this comment.
Looks good! Thank you! I left some more comments inline. Sorry for going back and forth on some of the things.
07b86d6 to
699f818
Compare
bobbinth
left a comment
There was a problem hiding this comment.
Looks good! Thank you! Not a full review yet, but I think this is the right overall structure. I left some comments inline, but most of these are pretty minor.
b6fba4c to
b4f02b2
Compare
bobbinth
left a comment
There was a problem hiding this comment.
Looks good! Thank you! Just a few more comments inline.
4bccca9 to
6e590ab
Compare
PhilippGackstatter
left a comment
There was a problem hiding this comment.
Looks good to me! Left some minor comments.
| let mut tx_args = TransactionArgs::new(Default::default(), foreign_account_inputs) | ||
| .with_tx_script(tx_script); | ||
| tx_args.extend_advice_inputs(advice_inputs); |
There was a problem hiding this comment.
On second thoughts, extending the advice stack doesn't make sense from transaction args, but extending advice map or merkle store probably does make sense. I'm thinking of some custom use cases for merkle path verification, for instance. I wonder if we should refactor TransactionArgs a bit to address that. Not super pressing, though.
bobbinth
left a comment
There was a problem hiding this comment.
Looks good! Thank you! I left two small comments inline - but other than that, this is basically good to merge.
Context
Fields relevant to transaction inputs could be coalesced into a single type to better express their inter-dependance.
Closes #1922.
Changes
TransactionInputstype to coalesce various fields into the one struct.TransactionWitnesstype.