-
Notifications
You must be signed in to change notification settings - Fork 214
SCP-2945: Only script outputs in unbalanced transactions #57
Conversation
af38edd
to
af6041d
Compare
@@ -370,7 +392,7 @@ updateUtxoIndex | |||
=> m () | |||
updateUtxoIndex = do | |||
ScriptLookups{slTxOutputs} <- ask | |||
unbalancedTx . utxoIndex <>= fmap Tx.toTxOut slTxOutputs | |||
unbalancedTx . utxoIndex <>= Map.mapMaybe toScriptOutput slTxOutputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is silently dropping public key outputs. I think that is OK, but I might be wrong. An alternative could be to let slTxOutputs
also only be ScriptOutput
s. Then callers of the unspentOutputs
function would need to choose what to do in the case of public key outputs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried this but that breaks lookupTxOutRef
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The public key inputs case for lookupTxOutRef
is used for the MustSpendPubKeyOutput
constraint. Given that we can't instruct the wallet to spend a specific public key output, maybe we should get rid of this constraint altogether? Although it still seems useful in the on-chain code, and you can definitely build a valid transaction that satisfies it. Just not with cardano-wallet
. So I think dropping the public key outputs here with mapMaybe
is OK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And cardano-wallet
might support it in the future, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, true!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I thought this would break the state machine initialisation code. Presumably it still works because the wallet selects the right input anyway.
@@ -370,7 +392,7 @@ updateUtxoIndex | |||
=> m () | |||
updateUtxoIndex = do | |||
ScriptLookups{slTxOutputs} <- ask | |||
unbalancedTx . utxoIndex <>= fmap Tx.toTxOut slTxOutputs | |||
unbalancedTx . utxoIndex <>= Map.mapMaybe toScriptOutput slTxOutputs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The public key inputs case for lookupTxOutRef
is used for the MustSpendPubKeyOutput
constraint. Given that we can't instruct the wallet to spend a specific public key output, maybe we should get rid of this constraint altogether? Although it still seems useful in the on-chain code, and you can definitely build a valid transaction that satisfies it. Just not with cardano-wallet
. So I think dropping the public key outputs here with mapMaybe
is OK.
data ScriptOutput = | ||
ScriptOutput | ||
{ scriptOutputValidatorHash :: ValidatorHash | ||
, scriptOutputValue :: Value | ||
, scriptOutputDatumHash :: DatumHash | ||
} | ||
deriving stock (Eq, Generic, Show) | ||
deriving anyclass (FromJSON, ToJSON, OpenApi.ToSchema) | ||
|
||
toScriptOutput :: ChainIndexTxOut -> Maybe ScriptOutput | ||
toScriptOutput (Tx.ScriptChainIndexTxOut _ validatorOrHash datumOrHash v) | ||
= Just $ ScriptOutput (either id validatorHash validatorOrHash) v (either id datumHash datumOrHash) | ||
toScriptOutput Tx.PublicKeyChainIndexTxOut{} | ||
= Nothing | ||
|
||
fromScriptOutput :: ScriptOutput -> ChainIndexTxOut | ||
fromScriptOutput (ScriptOutput vh v dh) = | ||
Tx.ScriptChainIndexTxOut (Address.scriptHashAddress vh) (Left vh) (Left dh) v | ||
|
||
instance Pretty ScriptOutput where | ||
pretty ScriptOutput{scriptOutputValidatorHash, scriptOutputValue} = | ||
hang 2 $ vsep ["-" <+> pretty scriptOutputValue <+> "addressed to", pretty scriptOutputValidatorHash] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe put this in Ledger.Tx
together with ChainIndexTxOut
?
# Conflicts: # playground-common/src/PSGenerator/Common.hs # plutus-contract/src/Plutus/Contract/Wallet.hs # plutus-use-cases/test/Spec/PubKey.hs
@@ -268,7 +268,7 @@ validateTxAndAddFees feeCfg slotCfg ownTxOuts utx = do | |||
-- Balance and sign just for validation | |||
tx <- handleBalanceTx ownTxOuts utx | |||
signedTx <- handleAddSignature tx | |||
let utxoIndex = Ledger.UtxoIndex $ unBalancedTxUtxoIndex utx <> (toTxOut <$> ownTxOuts) | |||
let utxoIndex = Ledger.UtxoIndex $ fmap toTxOut $ (U.fromScriptOutput <$> unBalancedTxUtxoIndex utx) <> ownTxOuts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@j-mueller After thinking some more this here seems to be the clue that there is no failure. The PubKeys are only unavailable in the lookups. But the wallet knows how to lookup its own outputs (ownTxOuts
here) so getUnspentOutput
just works!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getUnspentOutput
works, and it gives you an unspent output from the wallet. But there is no guarantee that the wallet selects the same unspent output when balanceTx
is called a second time, for the transaction that creates the token by spending this specific output.
The UTXO could have been spent in the meantime, or maybe the wallet decides that there is a different collection of UTXOs that is better suited in the second call to balanceTx
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of this, I'm inclined to think that we have to go back to creating a script output (with the PubKey contract) in a separate transaction before we can set up the state machine. What do you think @sjoerdvisscher @silky ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@j-mueller I agree, but that’s a separate issue I think? So we can merge this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, let's merge it!
Pre-submit checklist: