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

Reinstate the SigningProcess API #384

Merged
merged 1 commit into from
Apr 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ are some modifications to be made)
-}

data EmulatorControl r where
SetSigningProcess :: Wallet -> SigningProcess -> EmulatorControl ()
SetSigningProcess :: Wallet -> Maybe SigningProcess -> EmulatorControl ()
AgentState :: Wallet -> EmulatorControl WalletState
FreezeContractInstance :: ContractInstanceId -> EmulatorControl ()
ThawContractInstance :: ContractInstanceId -> EmulatorControl ()
Expand Down
65 changes: 43 additions & 22 deletions plutus-contract/src/Wallet/Emulator/Wallet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import Ledger.Constraints.OffChain (UnbalancedTx (UnbalancedTx, unBalancedTxTx))
import Ledger.Constraints.OffChain qualified as U
import Ledger.Credential (Credential (PubKeyCredential, ScriptCredential))
import Ledger.Tx qualified as Tx
import Ledger.Validation (addSignature, evaluateTransactionFee, fromPlutusIndex, fromPlutusTx)
import Ledger.Validation (addSignature, evaluateTransactionFee, fromPlutusIndex, fromPlutusTx, getRequiredSigners)
import Ledger.Value qualified as Value
import Plutus.ChainIndex (PageQuery)
import Plutus.ChainIndex qualified as ChainIndex
Expand All @@ -81,7 +81,7 @@ import Wallet.Emulator.NodeClient (NodeClientState, emptyNodeClientState)


newtype SigningProcess = SigningProcess {
unSigningProcess :: forall effs. (Member (Error WAPI.WalletAPIError) effs) => [PaymentPubKeyHash] -> Tx -> Eff effs Tx
unSigningProcess :: forall effs. (Member (Error WAPI.WalletAPIError) effs) => [PaymentPubKeyHash] -> CardanoTx -> Eff effs CardanoTx
}

instance Show SigningProcess where
Expand Down Expand Up @@ -194,10 +194,12 @@ makePrisms ''WalletEvent

-- | The state used by the mock wallet environment.
data WalletState = WalletState {
_mockWallet :: MockWallet, -- ^ mock wallet with the user's private key
_mockWallet :: MockWallet, -- ^ Mock wallet with the user's private key.
_nodeClient :: NodeClientState,
_chainIndexEmulatorState :: ChainIndexEmulatorState,
_signingProcess :: SigningProcess
_signingProcess :: Maybe SigningProcess
-- ^ Override the signing process.
-- Used for testing multi-agent use cases.
} deriving Show

makeLenses ''WalletState
Expand All @@ -219,8 +221,7 @@ ownAddress = flip Ledger.pubKeyAddress Nothing
-- | An empty wallet using the given private key.
-- for that wallet as the sole watched address.
fromMockWallet :: MockWallet -> WalletState
fromMockWallet mw = WalletState mw emptyNodeClientState mempty sp where
sp = signWithPrivateKey (CW.paymentPrivateKey mw)
fromMockWallet mw = WalletState mw emptyNodeClientState mempty Nothing

-- | Empty wallet state for an emulator 'Wallet'. Returns 'Nothing' if the wallet
-- is not known in the emulator.
Expand Down Expand Up @@ -266,7 +267,12 @@ handleWallet = \case
logInfo $ FinishedBalancing txCTx
pure txCTx

walletAddSignatureH :: (Member (State WalletState) effs, Member (LogMsg TxBalanceMsg) effs) => CardanoTx -> Eff effs CardanoTx
walletAddSignatureH ::
( Member (State WalletState) effs
, Member (LogMsg TxBalanceMsg) effs
, Member (Error WalletAPIError) effs
)
=> CardanoTx -> Eff effs CardanoTx
walletAddSignatureH txCTx = do
logInfo $ SigningTx txCTx
handleAddSignature txCTx
Expand Down Expand Up @@ -294,7 +300,7 @@ handleBalance ::
, Member ChainIndexQueryEffect effs
, Member (State WalletState) effs
, Member (LogMsg TxBalanceMsg) effs
, Member (Error WAPI.WalletAPIError) effs
, Member (Error WalletAPIError) effs
)
=> UnbalancedTx
-> Eff effs CardanoTx
Expand Down Expand Up @@ -330,17 +336,32 @@ handleBalance utx' = do
handleError _ (Right v) = pure v

handleAddSignature ::
Member (State WalletState) effs
( Member (State WalletState) effs
, Member (Error WalletAPIError) effs
)
=> CardanoTx
-> Eff effs CardanoTx
handleAddSignature tx = do
(PaymentPrivateKey privKey) <- gets ownPaymentPrivateKey
pure $ Tx.cardanoTxMap (Ledger.addSignature' privKey) (addSignatureCardano privKey) tx
msp <- gets _signingProcess
case msp of
Nothing -> do
PaymentPrivateKey privKey <- gets ownPaymentPrivateKey
pure $ addSignature' privKey tx
Just (SigningProcess sp) -> do
let ctx = case tx of
Tx.CardanoApiTx (Tx.SomeTx ctx' AlonzoEraInCardanoMode) -> ctx'
Tx.Both _ (Tx.SomeTx ctx' AlonzoEraInCardanoMode) -> ctx'
_ -> error "handleAddSignature: Need a Cardano API Tx from the Alonzo era to get the required signers"
reqSigners = getRequiredSigners ctx
sp reqSigners tx

addSignature' :: PrivateKey -> CardanoTx -> CardanoTx
addSignature' privKey = Tx.cardanoTxMap (Ledger.addSignature' privKey) addSignatureCardano
where
addSignatureCardano :: PrivateKey -> SomeCardanoApiTx -> SomeCardanoApiTx
addSignatureCardano privKey (Tx.SomeTx ctx AlonzoEraInCardanoMode)
addSignatureCardano :: SomeCardanoApiTx -> SomeCardanoApiTx
addSignatureCardano (Tx.SomeTx ctx AlonzoEraInCardanoMode)
= Tx.SomeTx (addSignature privKey ctx) AlonzoEraInCardanoMode
addSignatureCardano _ _ = error "Wallet.Emulator.Wallet.handleAddSignature: Expected an Alonzo tx"
addSignatureCardano _ = error "Wallet.Emulator.Wallet.addSignature': Expected an Alonzo tx"

ownOutputs :: forall effs.
( Member ChainIndexQueryEffect effs
Expand Down Expand Up @@ -580,36 +601,36 @@ signWallet wllt = SigningProcess $
signTxnWithKey
:: (Member (Error WAPI.WalletAPIError) r)
=> MockWallet
-> Tx
-> CardanoTx
-> PaymentPubKeyHash
-> Eff r Tx
-> Eff r CardanoTx
signTxnWithKey mw = signTxWithPrivateKey (CW.paymentPrivateKey mw)

-- | Sign the transaction with the private key, if the hash is that of the
-- private key.
signTxWithPrivateKey
:: (Member (Error WAPI.WalletAPIError) r)
=> PaymentPrivateKey
-> Tx
-> CardanoTx
-> PaymentPubKeyHash
-> Eff r Tx
-> Eff r CardanoTx
signTxWithPrivateKey (PaymentPrivateKey pk) tx pkh@(PaymentPubKeyHash pubK) = do
let ownPaymentPubKey = Ledger.toPublicKey pk
if Ledger.pubKeyHash ownPaymentPubKey == pubK
then pure (Ledger.addSignature' pk tx)
then pure (addSignature' pk tx)
else throwError (WAPI.PaymentPrivateKeyNotFound pkh)

-- | Sign the transaction with the given private keys,
-- ignoring the list of public keys that the 'SigningProcess' is passed.
signPrivateKeys :: [PaymentPrivateKey] -> SigningProcess
signPrivateKeys signingKeys = SigningProcess $ \_ tx ->
pure (foldr (Ledger.addSignature' . unPaymentPrivateKey) tx signingKeys)
pure (foldr (addSignature' . unPaymentPrivateKey) tx signingKeys)

data SigningProcessControlEffect r where
SetSigningProcess :: SigningProcess -> SigningProcessControlEffect ()
SetSigningProcess :: Maybe SigningProcess -> SigningProcessControlEffect ()
makeEffect ''SigningProcessControlEffect

type SigningProcessEffs = '[State SigningProcess, Error WAPI.WalletAPIError]
type SigningProcessEffs = '[State (Maybe SigningProcess), Error WAPI.WalletAPIError]

handleSigningProcessControl :: (Members SigningProcessEffs effs) => Eff (SigningProcessControlEffect ': effs) ~> Eff effs
handleSigningProcessControl = interpret $ \case
Expand Down
1 change: 1 addition & 0 deletions plutus-ledger/src/Ledger/Tx/CardanoAPI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module Ledger.Tx.CardanoAPI(
, fromCardanoFee
, fromCardanoValidityRange
, fromCardanoScriptInEra
, fromCardanoPaymentKeyHash
, fromCardanoScriptData
, fromTxScriptValidity
, scriptDataFromCardanoTxBody
Expand Down
6 changes: 6 additions & 0 deletions plutus-ledger/src/Ledger/Validation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module Ledger.Validation(
initialState,
evaluateTransactionFee,
evaluateMinLovelaceOutput,
getRequiredSigners,
addSignature,
hasValidationErrors,
-- * Modifying the state
Expand Down Expand Up @@ -47,6 +48,7 @@ import Cardano.Ledger.Alonzo.Rules.Utxos (constructValidated)
import Cardano.Ledger.Alonzo.Scripts (ExUnits (ExUnits))
import Cardano.Ledger.Alonzo.Tools qualified as C.Ledger
import Cardano.Ledger.Alonzo.Tx (ValidatedTx (..))
import Cardano.Ledger.Alonzo.TxBody (TxBody (TxBody, reqSignerHashes))
import Cardano.Ledger.Alonzo.TxWitness (RdmrPtr, txwitsVKey)
import Cardano.Ledger.BaseTypes (Globals (..))
import Cardano.Ledger.Core (PParams, Tx)
Expand Down Expand Up @@ -293,6 +295,10 @@ plutusTxToTxBodyContent
plutusTxToTxBodyContent requiredSigners =
P.toCardanoTxBodyContent requiredSigners (Just emulatorProtocolParameters) emulatorNetworkId

getRequiredSigners :: C.Api.Tx C.Api.AlonzoEra -> [P.PaymentPubKeyHash]
getRequiredSigners (C.Api.ShelleyTx _ (ValidatedTx TxBody { reqSignerHashes = rsq } _ _ _)) =
foldMap (pure . P.PaymentPubKeyHash . P.fromCardanoPaymentKeyHash . C.Api.PaymentKeyHash . C.Ledger.coerceKeyRole) rsq

addSignature
:: P.PrivateKey
-> C.Api.Tx C.Api.AlonzoEra
Expand Down
9 changes: 6 additions & 3 deletions plutus-use-cases/src/Plutus/Contracts/MultiSig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,11 @@ typedValidator = Scripts.mkTypedValidatorParam @MultiSig
-- | Lock some funds in a 'MultiSig' contract.
lock :: AsContractError e => Promise () MultiSigSchema e ()
lock = endpoint @"lock" $ \(ms, vl) -> do
let tx = Constraints.mustPayToTheScript () vl
let inst = typedValidator ms
void $ submitTxConstraints inst tx
let tx = Constraints.mustPayToTheScript () vl
lookups = Constraints.typedValidatorLookups inst
mkTxConstraints lookups tx
>>= void . submitUnbalancedTx . Constraints.adjustUnbalancedTx

-- | The @"unlock"@ endpoint, unlocking some funds with a list
-- of signatures.
Expand All @@ -91,4 +93,5 @@ unlock = endpoint @"unlock" $ \(ms, pks) -> do
<> foldMap Constraints.mustBeSignedBy pks
lookups = Constraints.typedValidatorLookups inst
<> Constraints.unspentOutputs utx
void $ submitTxConstraintsWith lookups tx
mkTxConstraints lookups tx
>>= void . submitUnbalancedTx . Constraints.adjustUnbalancedTx
9 changes: 4 additions & 5 deletions plutus-use-cases/test/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import Spec.Future qualified
import Spec.Game qualified
import Spec.GameStateMachine qualified
import Spec.Governance qualified
import Spec.SealedBidAuction qualified
import Spec.SimpleEscrow qualified
-- import qualified Spec.MultiSig
import Spec.MultiSig qualified
import Spec.MultiSigStateMachine qualified
import Spec.PingPong qualified
import Spec.Prism qualified
import Spec.PubKey qualified
import Spec.Rollup qualified
import Spec.SealedBidAuction qualified
import Spec.SimpleEscrow qualified
import Spec.Stablecoin qualified
import Spec.TokenAccount qualified
import Spec.Uniswap qualified
Expand All @@ -42,8 +42,7 @@ tests = localOption limit $ testGroup "use cases" [
Spec.Vesting.tests,
Spec.ErrorHandling.tests,
Spec.Future.tests,
-- disable temporarily, because we need to adopt the signing API
-- Spec.MultiSig.tests,
Spec.MultiSig.tests,
Spec.MultiSigStateMachine.tests,
Spec.Currency.tests,
Spec.PubKey.tests,
Expand Down
6 changes: 3 additions & 3 deletions plutus-use-cases/test/Spec/MultiSig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import Wallet.Emulator.Wallet (signPrivateKeys)
tests :: TestTree
tests = testGroup "multisig"
[ checkPredicate "2 out of 5"
(assertFailedTransaction (\_ err _ -> case err of {ScriptFailure (EvaluationError ["not enough signatures"] _) -> True; _ -> False }))
(assertFailedTransaction (\_ err _ -> case err of {ScriptFailure (EvaluationError ("not enough signatures":_) _) -> True; _ -> False }))
failingTrace

, checkPredicate "3 out of 5"
Expand All @@ -40,7 +40,7 @@ failingTrace = do
hdl <- Trace.activateContractWallet w1 theContract
Trace.callEndpoint @"lock" hdl (multiSig, Ada.lovelaceValueOf 10)
_ <- Trace.waitNSlots 1
Trace.setSigningProcess w1 (signPrivateKeys [CW.paymentPrivateKey (CW.knownMockWallet 1), CW.paymentPrivateKey (CW.knownMockWallet 2)])
Trace.setSigningProcess w1 (Just $ signPrivateKeys [CW.paymentPrivateKey (CW.knownMockWallet 1), CW.paymentPrivateKey (CW.knownMockWallet 2)])
Trace.callEndpoint @"unlock" hdl (multiSig, fmap mockWalletPaymentPubKeyHash [w1, w2])
void $ Trace.waitNSlots 1

Expand All @@ -51,7 +51,7 @@ succeedingTrace = do
hdl <- Trace.activateContractWallet w1 theContract
Trace.callEndpoint @"lock" hdl (multiSig, Ada.lovelaceValueOf 10)
_ <- Trace.waitNSlots 1
Trace.setSigningProcess w1 (signPrivateKeys [CW.paymentPrivateKey (CW.knownMockWallet 1), CW.paymentPrivateKey (CW.knownMockWallet 2), CW.paymentPrivateKey (CW.knownMockWallet 3)])
Trace.setSigningProcess w1 (Just $ signPrivateKeys [CW.paymentPrivateKey (CW.knownMockWallet 1), CW.paymentPrivateKey (CW.knownMockWallet 2), CW.paymentPrivateKey (CW.knownMockWallet 3)])
Trace.callEndpoint @"unlock" hdl (multiSig, fmap mockWalletPaymentPubKeyHash [w1, w2, w3])
void $ Trace.waitNSlots 1

Expand Down
Loading