diff --git a/cabal.project b/cabal.project index 4a49e5b210..dd55445bc8 100644 --- a/cabal.project +++ b/cabal.project @@ -63,8 +63,8 @@ package yet-another-logger source-repository-package type: git location: https://github.com/kadena-io/pact.git - tag: 495c8738acaa0157958ab23a06cd94abbc99d2d5 - --sha256: 1dn322m5mx43bn3ki37zdk9daknnr6sz8y7d89si75m84rl0w27k + tag: b707d930dcc1b6340777195fc60b8e3fe8827f11 + --sha256: 0i2hdvzxjbq3ikzj8qv8bhqv9g6kslk70vb2s0lyslgirps6ynlz source-repository-package type: git diff --git a/src/Chainweb/Pact/RestAPI/Server.hs b/src/Chainweb/Pact/RestAPI/Server.hs index 603db5ed1f..f56d7a39a1 100644 --- a/src/Chainweb/Pact/RestAPI/Server.hs +++ b/src/Chainweb/Pact/RestAPI/Server.hs @@ -8,6 +8,7 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} @@ -454,17 +455,23 @@ spvHandler l cdb cid (SpvRequest rk (Pact.ChainId ptid)) = do <> sshow e Right i -> return i - tid <- chainIdFromText ptid - p <- liftIO (try $ createTransactionOutputProof cdb tid cid bhe idx) >>= \case + p <- if + | Just netID <- T.stripPrefix "crossnet:" ptid -> + liftIO $ try $ createCrossNetworkTransactionOutputProof cdb netID cid bhe idx + | Just tid <- chainIdFromText ptid -> + liftIO $ try $ createTransactionOutputProof cdb tid cid bhe idx + | otherwise -> + toErr "Invalid proof target: not a chain ID or crossnet:" + + case p of Left e@SpvExceptionTargetNotReachable{} -> toErr $ "SPV target not reachable: " <> _spvExceptionMsg e Left e@SpvExceptionVerificationFailed{} -> toErr $ "SPV verification failed: " <> _spvExceptionMsg e Left e -> toErr $ "Internal error: SPV verification failed: " <> _spvExceptionMsg e - Right q -> return q + Right q -> return $! b64 q - return $! b64 p where pe = _webPactExecutionService $ view CutDB.cutDbPactService cdb ph = Pact.fromUntypedHash $ unRequestKey rk diff --git a/src/Chainweb/Pact/SPV.hs b/src/Chainweb/Pact/SPV.hs index 416e3fede1..ae8e7decb9 100644 --- a/src/Chainweb/Pact/SPV.hs +++ b/src/Chainweb/Pact/SPV.hs @@ -150,7 +150,7 @@ verifySPV bdb bh typ proof = runExceptT $ go typ proof -- Chainweb tx output proof "TXOUT" -> do u <- except $ extractProof enableBridge o - unless (view outputProofChainId u == cid) $ + unless (view outputProofTarget u == ProofTargetChain cid) $ forkedThrower bh "cannot redeem spv proof on wrong target chain" -- SPV proof verification is a 3 step process: @@ -272,7 +272,7 @@ verifyCont bdb bh (ContProof cp) = runExceptT $ do case decodeStrict' t of Nothing -> forkedThrower bh "unable to decode continuation proof" Just u - | view outputProofChainId u /= cid -> + | ProofTargetChain tcid <- view outputProofTarget u, tcid /= cid -> forkedThrower bh "cannot redeem continuation proof on wrong target chain" | otherwise -> do diff --git a/src/Chainweb/Pact/Utils.hs b/src/Chainweb/Pact/Utils.hs index c42ad1e1e7..5806e1bccf 100644 --- a/src/Chainweb/Pact/Utils.hs +++ b/src/Chainweb/Pact/Utils.hs @@ -64,6 +64,9 @@ toTxCreationTime (Time timespan) = +-- TODO: This will fail for k: accounts that correspond to WebAuthn public +-- keys. Consider extending it when we integrate WebAuthn with k: accounts. +-- Note: This function is only used in Rosetta as a validation step. validateKAccount :: T.Text -> Bool validateKAccount acctName = case T.take 2 acctName of @@ -85,7 +88,6 @@ generateKAccountFromPubKey pubKey in Just $ "k:" <> pubKeyText | otherwise = Nothing - -- Warning: Only use if already certain that PublicKeyText -- is valid. -- Note: We are assuming the k: account is ED25519. diff --git a/src/Chainweb/Rosetta/RestAPI/Server.hs b/src/Chainweb/Rosetta/RestAPI/Server.hs index 44a19f9fbe..c016a1ebe7 100644 --- a/src/Chainweb/Rosetta/RestAPI/Server.hs +++ b/src/Chainweb/Rosetta/RestAPI/Server.hs @@ -345,7 +345,7 @@ constructionParseH :: ChainwebVersion -> ConstructionParseReq -> Handler ConstructionParseResp -constructionParseH v (ConstructionParseReq net isSigned tx) = +constructionParseH v (ConstructionParseReq net isSigned tx) = do either throwRosettaError pure work where work :: Either RosettaError ConstructionParseResp @@ -379,7 +379,7 @@ constructionParseH v (ConstructionParseReq net isSigned tx) = constructionCombineH :: ConstructionCombineReq -> Handler ConstructionCombineResp -constructionCombineH (ConstructionCombineReq _ unsignedTx sigs) = +constructionCombineH (ConstructionCombineReq _ unsignedTx sigs) = do either throwRosettaError pure work where work :: Either RosettaError ConstructionCombineResp @@ -398,7 +398,7 @@ constructionCombineH (ConstructionCombineReq _ unsignedTx sigs) = constructionHashH :: ConstructionHashReq -> Handler TransactionIdResp -constructionHashH (ConstructionHashReq _ signedTx) = +constructionHashH (ConstructionHashReq _ signedTx) = do either throwRosetta pure work where work :: Either RosettaFailure TransactionIdResp diff --git a/src/Chainweb/SPV.hs b/src/Chainweb/SPV.hs index 3c58fb1b71..a7ca5c0cb9 100644 --- a/src/Chainweb/SPV.hs +++ b/src/Chainweb/SPV.hs @@ -1,11 +1,14 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE TypeFamilies #-} -- | @@ -19,10 +22,11 @@ -- module Chainweb.SPV ( SpvException(..) +, ProofTarget(..) , TransactionProof(..) , proofChainId , TransactionOutputProof(..) -, outputProofChainId +, outputProofTarget ) where import Control.Applicative @@ -37,6 +41,7 @@ import Data.Aeson import qualified Data.Aeson.Types as Aeson import qualified Data.ByteString as B import Data.MerkleLog hiding (Expected, Actual) +import Data.Text (Text) import qualified Data.Text as T import GHC.Generics (Generic) @@ -60,7 +65,7 @@ data SpvException { _spvExceptionMsg :: !T.Text , _spvExceptionSourceChainId :: !ChainId , _spvExceptionSourceHeight :: !BlockHeight - , _spvExceptionTargetChainId :: !ChainId + , _spvExceptionTargetChainId :: !ProofTarget , _spvExceptionTargetHeight :: !BlockHeight } | SpvExceptionInconsistentPayloadData @@ -88,13 +93,13 @@ instance Exception SpvException -- legacy format for existing endpoints in order to not break existing clients. -- proofProperties - :: forall e kv + :: forall kv e . KeyValue e kv - => ChainId + => ProofTarget -> MerkleProof SHA512t_256 -> [kv] -proofProperties cid p = - [ "chain" .= cid +proofProperties tgt p = + [ "chain" .= tgt , "object" .= obj (_merkleProofObject p) , "subject" .= JsonProofSubject (_getMerkleProofSubject $ _merkleProofSubject p) , "algorithm" .= ("SHA512t_256" :: T.Text) @@ -123,10 +128,10 @@ instance ToJSON JsonProofSubject where parseProof :: String - -> (ChainId -> MerkleProof SHA512t_256 -> a) + -> (ProofTarget -> MerkleProof SHA512t_256 -> Aeson.Parser a) -> Value -> Aeson.Parser a -parseProof name mkProof = withObject name $ \o -> mkProof +parseProof name mkProof = withObject name $ \o -> join $ mkProof <$> o .: "chain" <*> parse o <* (assertJSON ("SHA512t_256" :: T.Text) =<< o .: "algorithm") @@ -169,13 +174,13 @@ data TransactionProof a = TransactionProof deriving (Show, Eq) instance ToJSON (TransactionProof SHA512t_256) where - toJSON (TransactionProof cid p) = object $ proofProperties cid p - toEncoding (TransactionProof cid p) = pairs . mconcat $ proofProperties cid p + toJSON (TransactionProof cid p) = object $ proofProperties (ProofTargetChain cid) p + toEncoding (TransactionProof cid p) = pairs . mconcat $ proofProperties (ProofTargetChain cid) p {-# INLINE toJSON #-} {-# INLINE toEncoding #-} instance FromJSON (TransactionProof SHA512t_256) where - parseJSON = parseProof "TransactionProof" TransactionProof + parseJSON = parseProof "TransactionProof" (\tgt p -> do { ProofTargetChain cid <- return tgt; return (TransactionProof cid p) }) {-# INLINE parseJSON #-} -- | Getter into the chain id of a 'TransactionProof' @@ -185,12 +190,31 @@ proofChainId = to (\(TransactionProof cid _) -> cid) -- -------------------------------------------------------------------------- -- -- Output Proofs +-- +-- | Targets for proofs, usually a chain ID, but in the case of L2, a network +-- and chain identifier. TODO: determine format, if any. +data ProofTarget = ProofTargetChain !ChainId | ProofTargetCrossNetwork !Text + deriving stock (Show, Eq, Ord, Generic) + deriving anyclass NFData + +instance ToJSON ProofTarget where + toJSON (ProofTargetChain cid) = toJSON (toText cid) + toJSON (ProofTargetCrossNetwork subtgt) = toJSON ("crossnet:" <> subtgt) + toEncoding (ProofTargetChain cid) = toEncoding (toText cid) + toEncoding (ProofTargetCrossNetwork subtgt) = toEncoding ("crossnet:" <> subtgt) + +instance FromJSON ProofTarget where + parseJSON = withText "ProofTarget" $ \case + (T.stripPrefix "crossnet:" -> Just tgt) -> return $ ProofTargetCrossNetwork tgt + (chainIdFromText -> Just cid) -> return $ ProofTargetChain cid + _ -> fail "expected numeric chain ID or crossnet:" + -- | Witness that a transaction output is included in the head of a chain in a -- chainweb. -- data TransactionOutputProof a = TransactionOutputProof - !ChainId + !ProofTarget -- ^ the target chain of the proof, i.e the chain which contains -- the root of the proof. !(MerkleProof a) @@ -199,16 +223,16 @@ data TransactionOutputProof a = TransactionOutputProof deriving (Show, Eq) instance ToJSON (TransactionOutputProof SHA512t_256) where - toJSON (TransactionOutputProof cid p) = object $ proofProperties cid p - toEncoding (TransactionOutputProof cid p) = pairs . mconcat $ proofProperties cid p + toJSON (TransactionOutputProof tgt p) = object $ proofProperties tgt p + toEncoding (TransactionOutputProof tgt p) = pairs . mconcat $ proofProperties tgt p {-# INLINE toJSON #-} {-# INLINE toEncoding #-} instance FromJSON (TransactionOutputProof SHA512t_256) where - parseJSON = parseProof "TransactionOutputProof" TransactionOutputProof + parseJSON = parseProof "TransactionOutputProof" (\tgt p -> return (TransactionOutputProof tgt p)) {-# INLINE parseJSON #-} -- | Getter into the chain id of a 'TransactionOutputProof' -- -outputProofChainId :: Getter (TransactionOutputProof a) ChainId -outputProofChainId = to (\(TransactionOutputProof cid _) -> cid) +outputProofTarget :: Getter (TransactionOutputProof a) ProofTarget +outputProofTarget = to (\(TransactionOutputProof tgt _) -> tgt) diff --git a/src/Chainweb/SPV/CreateProof.hs b/src/Chainweb/SPV/CreateProof.hs index 424d570d4b..57b8ce6660 100644 --- a/src/Chainweb/SPV/CreateProof.hs +++ b/src/Chainweb/SPV/CreateProof.hs @@ -22,6 +22,7 @@ module Chainweb.SPV.CreateProof , createTransactionOutputProof , createTransactionOutputProof_ , createTransactionOutputProof' +, createCrossNetworkTransactionOutputProof ) where import Control.Applicative @@ -34,6 +35,7 @@ import Crypto.Hash.Algorithms import qualified Data.ByteString as B import qualified Data.List.NonEmpty as N import Data.MerkleLog +import Data.Text (Text) import GHC.Stack @@ -188,7 +190,6 @@ createTransactionOutputProof cutDb = (view cutDbWebBlockHeaderDb cutDb) (view cutDbPayloadDb cutDb) - -- | Version without CutDb dependency -- createTransactionOutputProof_ @@ -209,7 +210,7 @@ createTransactionOutputProof_ -> IO (TransactionOutputProof SHA512t_256) createTransactionOutputProof_ headerDb payloadDb tcid scid bh i = do trgHeader <- minimumTrgHeader headerDb tcid scid bh - TransactionOutputProof tcid + TransactionOutputProof (ProofTargetChain tcid) <$> createPayloadProof_ outputProofPrefix headerDb payloadDb tcid scid bh i trgHeader @@ -234,7 +235,7 @@ createTransactionOutputProof' -- ^ The index of the transaction in the block -> IO (TransactionOutputProof SHA512t_256) createTransactionOutputProof' cutDb tcid scid bh i - = TransactionOutputProof tcid + = TransactionOutputProof (ProofTargetChain tcid) <$> createPayloadProof outputProofPrefix cutDb tcid scid bh i outputProofPrefix @@ -259,6 +260,27 @@ outputProofPrefix i db payload = do where blockOutputTable = _payloadCacheBlockOutputs $ _payloadCache db +-- TODO: incorporate version into crossnet: syntax? +-- TODO: if and when this is less trivial, incorporate this logic into createPayloadProof +createCrossNetworkTransactionOutputProof :: (CanReadablePayloadCas tbl, HasCallStack) => CutDb tbl -> Text -> ChainId -> BlockHeight -> Int -> IO (TransactionOutputProof SHA512t_256) +createCrossNetworkTransactionOutputProof cutDb tgt scid txHeight txIx = do + tip <- maxEntry headerDb + txHeader <- maybe (throwM headerNotFound) pure =<< seekAncestor headerDb tip (int txHeight) + Just payload <- tableLookup pDb (_blockPayloadHash txHeader) + (subj, prefix) <- outputProofPrefix txIx payloadDb payload + TransactionOutputProof (ProofTargetCrossNetwork tgt) <$> merkleProof_ subj prefix + where + headerDb = cutDb ^?! cutDbWebBlockHeaderDb . ixg scid + payloadDb = view cutDbPayloadDb cutDb + pDb = _transactionDbBlockPayloads $ _transactionDb payloadDb + headerNotFound = SpvExceptionTargetNotReachable + { _spvExceptionMsg = "Target of SPV proof can't be reached from the source transaction" + , _spvExceptionSourceChainId = scid + , _spvExceptionSourceHeight = txHeight + , _spvExceptionTargetChainId = ProofTargetCrossNetwork tgt + , _spvExceptionTargetHeight = txHeight + } + -- -------------------------------------------------------------------------- -- -- Internal Proof Creation @@ -342,7 +364,7 @@ createPayloadProof_ getPrefix headerDb payloadDb tcid scid txHeight txIx trgHead { _spvExceptionMsg = "target chain not reachable. Chainweb instance is too young" , _spvExceptionSourceChainId = scid , _spvExceptionSourceHeight = txHeight - , _spvExceptionTargetChainId = tcid + , _spvExceptionTargetChainId = ProofTargetChain tcid , _spvExceptionTargetHeight = _blockHeight trgHeader } @@ -351,7 +373,7 @@ createPayloadProof_ getPrefix headerDb payloadDb tcid scid txHeight txIx trgHead { _spvExceptionMsg = "Target of SPV proof can't be reached from the source transaction" , _spvExceptionSourceChainId = scid , _spvExceptionSourceHeight = txHeight - , _spvExceptionTargetChainId = tcid + , _spvExceptionTargetChainId = ProofTargetChain tcid , _spvExceptionTargetHeight = _blockHeight trgHeader } @@ -362,7 +384,7 @@ createPayloadProof_ getPrefix headerDb payloadDb tcid scid txHeight txIx trgHead { _spvExceptionMsg = "Target of SPV proof can't be reached from the source transaction" , _spvExceptionSourceChainId = scid , _spvExceptionSourceHeight = txHeight - , _spvExceptionTargetChainId = tcid + , _spvExceptionTargetChainId = ProofTargetChain tcid , _spvExceptionTargetHeight = _blockHeight trgHeader } @@ -430,7 +452,7 @@ crumbsOnChain db trgHeader srcHeight go p (cur : acc) -- | Create a path of bread crumbs from the source chain id to the target header --- along the adjancet parent relation. +-- along the adjacent parent relation. -- -- Returns 'Nothing' if no such path exists. -- @@ -481,7 +503,7 @@ minimumTrgHeader headerDb tcid scid bh = do { _spvExceptionMsg = "target chain not reachable. Chainweb instance is too young" , _spvExceptionSourceChainId = scid , _spvExceptionSourceHeight = bh - , _spvExceptionTargetChainId = tcid + , _spvExceptionTargetChainId = ProofTargetChain tcid , _spvExceptionTargetHeight = int trgHeight } where diff --git a/src/Chainweb/SPV/VerifyProof.hs b/src/Chainweb/SPV/VerifyProof.hs index ee5d3de238..64310675b7 100644 --- a/src/Chainweb/SPV/VerifyProof.hs +++ b/src/Chainweb/SPV/VerifyProof.hs @@ -126,9 +126,12 @@ verifyTransactionOutputProof :: CutDb tbl -> TransactionOutputProof SHA512t_256 -> IO TransactionOutput -verifyTransactionOutputProof cutDb proof@(TransactionOutputProof cid p) = do - unlessM (member cutDb cid h) $ throwM - $ SpvExceptionVerificationFailed "target header is not in the chain" +verifyTransactionOutputProof cutDb proof@(TransactionOutputProof tgt p) = do + case tgt of + ProofTargetChain cid -> + unlessM (member cutDb cid h) $ throwM + $ SpvExceptionVerificationFailed "target header is not in the chain" + ProofTargetCrossNetwork _net -> return () proofSubject p where h = runTransactionOutputProof proof @@ -145,9 +148,12 @@ verifyTransactionOutputProofAt -> TransactionOutputProof SHA512t_256 -> BlockHash -> IO TransactionOutput -verifyTransactionOutputProofAt cutDb proof@(TransactionOutputProof cid p) ctx = do - unlessM (memberOfM cutDb cid h ctx) $ throwM - $ SpvExceptionVerificationFailed "target header is not in the chain" +verifyTransactionOutputProofAt cutDb proof@(TransactionOutputProof tgt p) ctx = do + case tgt of + ProofTargetChain cid -> + unlessM (memberOfM cutDb cid h ctx) $ throwM + $ SpvExceptionVerificationFailed "target header is not in the chain" + ProofTargetCrossNetwork _net -> return () proofSubject p where h = runTransactionOutputProof proof @@ -164,9 +170,12 @@ verifyTransactionOutputProofAt_ -> TransactionOutputProof SHA512t_256 -> BlockHash -> IO TransactionOutput -verifyTransactionOutputProofAt_ bdb proof@(TransactionOutputProof _cid p) ctx = do - unlessM (ancestorOf bdb h ctx) $ throwM - $ SpvExceptionVerificationFailed "target header is not in the chain" +verifyTransactionOutputProofAt_ bdb proof@(TransactionOutputProof tgt p) ctx = do + case tgt of + ProofTargetChain _cid -> + unlessM (ancestorOf bdb h ctx) $ throwM + $ SpvExceptionVerificationFailed "target header is not in the chain" + ProofTargetCrossNetwork _net -> return () proofSubject p where h = runTransactionOutputProof proof diff --git a/test/Chainweb/Test/Orphans/Internal.hs b/test/Chainweb/Test/Orphans/Internal.hs index 3d99ace644..ee4a9ee2de 100644 --- a/test/Chainweb/Test/Orphans/Internal.hs +++ b/test/Chainweb/Test/Orphans/Internal.hs @@ -896,6 +896,12 @@ instance Arbitrary Spv2Request where instance Arbitrary (TransactionProof ChainwebMerkleHashAlgorithm) where arbitrary = TransactionProof <$> arbitrary <*> arbitrary +instance Arbitrary ProofTarget where + arbitrary = oneof + [ ProofTargetChain <$> arbitrary + , ProofTargetCrossNetwork <$> arbitrary + ] + instance Arbitrary (TransactionOutputProof ChainwebMerkleHashAlgorithm) where arbitrary = TransactionOutputProof <$> arbitrary <*> arbitrary diff --git a/test/Chainweb/Test/Roundtrips.hs b/test/Chainweb/Test/Roundtrips.hs index 696b24c870..473cb904a9 100644 --- a/test/Chainweb/Test/Roundtrips.hs +++ b/test/Chainweb/Test/Roundtrips.hs @@ -300,6 +300,7 @@ jsonTestCases f = , testProperty "SpvSubjectIdentifier" $ f @SpvSubjectIdentifier , testProperty "Spv2Request" $ f @Spv2Request , testProperty "TransactionProof" $ f @(TransactionProof ChainwebMerkleHashAlgorithm) + , testProperty "ProofTarget" $ f @ProofTarget , testProperty "TransactionOutputProof" $ f @(TransactionOutputProof ChainwebMerkleHashAlgorithm) , testProperty "PayloadProof" $ f @(PayloadProof ChainwebMerkleHashAlgorithm) , testProperty "SomePayloadProof" $ f @(SomePayloadProof) diff --git a/test/Chainweb/Test/Utils.hs b/test/Chainweb/Test/Utils.hs index 36e6c21c39..5a3303ecaf 100644 --- a/test/Chainweb/Test/Utils.hs +++ b/test/Chainweb/Test/Utils.hs @@ -943,6 +943,7 @@ withNodes = withNodes_ (genericLogger Error (error . T.unpack)) -- anything. A message at log level error means that the test harness itself -- failed and with thus abort the test. + withNodesAtLatestBehavior :: ChainwebVersion -> B.ByteString diff --git a/test/golden/development-block-hashes-expected.txt b/test/golden/development-block-hashes-expected.txt index 79e04e8926..2b2864c50d 100644 --- a/test/golden/development-block-hashes-expected.txt +++ b/test/golden/development-block-hashes-expected.txt @@ -1 +1 @@ -I44qr9WzXAwKaBL_cOdhLC9PKB0Jmo0dIuMXUz3Q4ws=LHOg2z-LlJYKpbPqyPtmmPtt52TsJZw98-8Yqa6z3mY=tMZtszaMwDE8ZBkZ63wbTmuL3R32bH1pVH6BCxO-KTA=KzOGhVdvZrAJnsyd94qVrt2y9JelNFGI36k5qzFPovM=Dgkcz1vTanUkii3ytBTjxospbVctGauWbFITQTf_7RU=QBgdPHASVl5DMiTTkCpo9aYzq5BcuQOAjNNh4ddfOaA=ul5HX4I4gzLgiT5ZIcv6to9vd0NieNiF0gtXV56u9aQ=vcCyL7Q3hrNMdIH3ugomHcKgzkzKIC9-53X_sSiGpm0=dglsXm0bcrHzXSPnAbRGmSMrSxjR8hgecb9tuHmI9o4=Uqb6NvnmsDKUf1nRKNB6ogZVQGT75lebfyHPMgq6IYk=pKCVftcctJ0SM_3h9vTuMKFo-eDnZB9qVnnpgMzW5Hg=3RPSalWuswFQJegbeEvrizAeQC6wxUJ9UtqM3xMkZBE=RpN2i3kNWkh0Dm7gLvhX3YlkruLXA-s4La5W831CRao=KwQ8VlmijrLd8diO5Ipy2H89hKhKDJQ3TC3al7vRrdQ=IfaxAeTGndKZqBb_0emJlkBYt4r5x-h8AFTH-hFjQKk=KMgFuiEt8hVL5FjjXw4pRmjI5FtgZ0W7loGRkOBZP5Y=_agbXYJt3-uklho_gSJBgIxxyHLMy_BtV_cvObxvmUY=C9luSkCJOC6g8lpKzDD56YJuKqQQLXR3PbOaPEgTIwA=ftB18G_4NdWDC6LYulkocXWPAkThii9nvsEDsP9Lzk4=GWe3oNkU1tWHvW_qzJGJ1eS5g-6wZRIIzhj25oF5Tvk= \ No newline at end of file +I44qr9WzXAwKaBL_cOdhLC9PKB0Jmo0dIuMXUz3Q4ws=LHOg2z-LlJYKpbPqyPtmmPtt52TsJZw98-8Yqa6z3mY=tMZtszaMwDE8ZBkZ63wbTmuL3R32bH1pVH6BCxO-KTA=KzOGhVdvZrAJnsyd94qVrt2y9JelNFGI36k5qzFPovM=Dgkcz1vTanUkii3ytBTjxospbVctGauWbFITQTf_7RU=QBgdPHASVl5DMiTTkCpo9aYzq5BcuQOAjNNh4ddfOaA=ul5HX4I4gzLgiT5ZIcv6to9vd0NieNiF0gtXV56u9aQ=vcCyL7Q3hrNMdIH3ugomHcKgzkzKIC9-53X_sSiGpm0=dglsXm0bcrHzXSPnAbRGmSMrSxjR8hgecb9tuHmI9o4=Uqb6NvnmsDKUf1nRKNB6ogZVQGT75lebfyHPMgq6IYk=QH7IwZf9tKCvimg4ixGeIGAyDm8HMDYrUas3jonqvYw=EC8nr6z0h4VUkAXRv5OlbzqEZa2svQZTj1oaJUMwRUg=tTgE2LZFcibxVnv00im0m3V7UYY9-taN615DPc1Y6dY=ezUdXnVjpEleQziJLVWK19n5_LWClh4ya7JRwusFnZQ=VXhjzpyPWl4Qniho1abLTOx2UZ-BFGGF2iWi4v6hTfQ=iNKy0Kw3PPCktOmU5xUhNekzq67al061oYtcHhNJq_E=QDvloZ__EySOGhpx64zGmUkjDvQU-Q1PFb_G7_8cesw=Qt-GUJrJGjjl0r-PWJcTa_VLzVxpCCl6SqaSeEIA274=6ds_b1BAaJHDL5WCdf-8XewDMIzswRvmzhtXtk8KprM=xpupUzKhexojr5gz8HcEkY34VRRfjA4eR5cjxTXmh78= \ No newline at end of file diff --git a/tools/cwtool/TxSimulator.hs b/tools/cwtool/TxSimulator.hs index 0a71654b5a..e775ade0fb 100644 --- a/tools/cwtool/TxSimulator.hs +++ b/tools/cwtool/TxSimulator.hs @@ -241,7 +241,8 @@ spvSim sc bh pwo = do case decodeStrict' t of Nothing -> internalError "unable to decode continuation proof" Just (TransactionOutputProof pcid p :: TransactionOutputProof SHA512t_256) -> do - unless (pcid == scChain sc) $ + -- TODO: crossnetwork pacts + unless (pcid == ProofTargetChain (scChain sc)) $ internalError "cannot redeem continuation proof on wrong target chain" TransactionOutput tout <- proofSubject p case decodeStrict' tout :: Maybe (CommandResult Hash) of