Skip to content

Commit

Permalink
Hyperlane fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Evgenii Akentev committed Apr 25, 2024
1 parent ebe2edf commit 1186195
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 142 deletions.
4 changes: 2 additions & 2 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ package yet-another-logger
source-repository-package
type: git
location: https://github.com/kadena-io/pact.git
tag: 85301eff5b66d2733d4213f16271d91128689d4b
--sha256: sha256-3ARA5apBLK+urukjLZjOZF9dP1lDN5E1dkFC58sTcBE=
tag: acfeaa3960ef4e9095d4a80f5e20155e9ac72b60
--sha256: sha256-09+lahu93XZBikKp3diwIJG5EVSLNnd9G6zzwH0Hy5g=

source-repository-package
type: git
Expand Down
2 changes: 1 addition & 1 deletion src/Chainweb/VerifierPlugin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ runVerifierPlugins chainContext logger allVerifiers gasRemaining tx = try $ do
tryAny (hoist stToIO (runVerifierPlugin verifierPlugin chainContext proof caps gasRef)) >>= \case
Left ex -> do
liftIO $ logFunctionText logger Warn ("Uncaught exception in verifier: " <> sshow ex)
throwError $ VerifierError "Uncaught exception in verifier"
throwError $ VerifierError $ "Uncaught exception in verifier" <> sshow ex
Right () -> return ()
verifierDoneGasRemaining <- lift $ stToIO $ readSTRef gasRef
if verifierDoneGasRemaining > verifierGasRemaining
Expand Down
9 changes: 5 additions & 4 deletions src/Chainweb/VerifierPlugin/Hyperlane/Binary.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module Chainweb.VerifierPlugin.Hyperlane.Binary
, putMerkleRootMultisigIsmMetadata
, getMerkleRootMultisigIsmMetadata

, padLeft
, ethereumAddressSize
) where

Expand Down Expand Up @@ -48,9 +49,9 @@ putHyperlaneMessage (HyperlaneMessage {..}) = do
putWord8 hmVersion
putWord32be hmNonce
putWord32be hmOriginDomain
putRawByteString (padLeft hmSender)
putRawByteString hmSender
putWord32be hmDestinationDomain
putRawByteString (padLeft hmRecipient)
putRawByteString hmRecipient

putRawByteString hmMessageBody

Expand All @@ -59,9 +60,9 @@ getHyperlaneMessage = do
hmVersion <- getWord8
hmNonce <- getWord32be
hmOriginDomain <- getWord32be
hmSender <- BS.takeEnd ethereumAddressSize <$> getByteString 32
hmSender <- getByteString 32
hmDestinationDomain <- getWord32be
hmRecipient <- BS.dropWhile (== 0) <$> getByteString 32
hmRecipient <- getByteString 32
hmMessageBody <- BL.toStrict <$> getRemainingLazyByteString

return $ HyperlaneMessage {..}
Expand Down
43 changes: 30 additions & 13 deletions src/Chainweb/VerifierPlugin/Hyperlane/Message/After224.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import Control.Monad (unless)
import Control.Monad.Except
import Control.Monad.ST

import qualified Data.Text.Encoding as Text
import Data.Traversable (forM)
import qualified Data.Vector as V
import qualified Data.Set as Set
import qualified Data.Map.Strict as M
Expand Down Expand Up @@ -50,9 +50,13 @@ runPlugin proof caps gasRef = do
[cap] -> return cap
_ -> throwError $ VerifierError "Expected one capability."

(capMessageId, capMessage, capSigners) <- case _scArgs of
[mid, mb, sigs] -> return (mid, mb, sigs)
_ -> throwError $ VerifierError $ "Incorrect number of capability arguments. Expected: messageId, message, signers."
(capMessageId, capMessage, capSigners, capThreshold) <- case _scArgs of
[mid, mb, PList sigs, PLiteral (LInteger threshold)] -> do
parsedSigners <- forM sigs $ \case
(PLiteral (LString v)) -> pure v
_ -> throwError $ VerifierError "Only string signers are supported"
return (mid, mb, parsedSigners, fromIntegral threshold)
_ -> throwError $ VerifierError $ "Incorrect number of capability arguments. Expected: messageId, message, signers, threshold."

-- extract proof object values
(hyperlaneMessageBase64, metadataBase64) <- case proof of
Expand Down Expand Up @@ -87,8 +91,8 @@ runPlugin proof caps gasRef = do
hmNoncePactValue = PLiteral $ LInteger $ fromIntegral hmNonce
hmOriginDomainPactValue = PLiteral $ LInteger $ fromIntegral hmOriginDomain
hmDestinationDomainPactValue = PLiteral $ LInteger $ fromIntegral hmDestinationDomain
hmSenderPactValue = PLiteral $ LString $ encodeHex hmSender
hmRecipientPactValue = PLiteral $ LString $ Text.decodeUtf8 hmRecipient
hmSenderPactValue = PLiteral $ LString $ encodeB64UrlNoPaddingText hmSender
hmRecipientPactValue = PLiteral $ LString $ encodeB64UrlNoPaddingText hmRecipient

hmMessageBodyPactValue = PLiteral $ LString $ encodeB64UrlNoPaddingText hmMessageBody
hmMessagePactValue = PObject . ObjectMap . M.fromList $
Expand Down Expand Up @@ -128,11 +132,24 @@ runPlugin proof caps gasRef = do
putWord32be mrmimSignedCheckpointIndex
putRawByteString mrmimSignedCheckpointMessageId

addresses <- catMaybes <$> mapM (\sig -> chargeGas gasRef 16250 >> recoverAddress digest sig) mrmimSignatures
let addressesVals = PList $ V.fromList $ map (PLiteral . LString . encodeHex) addresses
-- Requires that m-of-n validators verify a merkle root, and verifies a merkle proof of message against that root.
--
-- The signature addresses and validator addresses should be in the same order.
--
-- The original algorithm in hyperlane.
-- https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/v3/solidity/contracts/isms/multisig/AbstractMultisigIsm.sol#L67
unless (capThreshold > 0) $ throwError $ VerifierError $ "Threshold should be greater than 0"

-- Note, that we check the signers for the full equality including their order and amount.
-- Hyperlane's ISM uses a threshold and inclusion check.
unless (addressesVals == capSigners) $
throwError $ VerifierError $
"Signers don't match. Expected: " <> sshow addressesVals <> " but got " <> sshow capSigners
unless (length mrmimSignatures >= capThreshold) $ throwError $ VerifierError $ "The number of signatures can't be less than threshold"

let
verify [] _ = pure ()
verify (sig:sigs) validators =
chargeGas gasRef 16250 >> recoverAddress digest sig >>= \case
Just addr -> do
case V.elemIndex (encodeHex addr) validators of
Just i -> verify sigs (V.drop (i + 1) validators)
Nothing -> throwError $ VerifierError "Verification failed"
Nothing -> throwError $ VerifierError $ "Failed to recover an address: incorrect signature"

verify (take capThreshold mrmimSignatures) capSigners
3 changes: 2 additions & 1 deletion src/Chainweb/VerifierPlugin/Hyperlane/Message/Before224.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Control.Monad (unless)
import Control.Monad.Except
import Control.Monad.ST

import qualified Data.ByteString as BS
import qualified Data.Text.Encoding as Text
import qualified Data.Vector as V
import qualified Data.Set as Set
Expand Down Expand Up @@ -72,7 +73,7 @@ runPlugin proof caps gasRef = do
runGetS getMessageIdMultisigIsmMetadata metadata

-- validate recipient
let hmRecipientPactValue = PLiteral $ LString $ Text.decodeUtf8 hmRecipient
let hmRecipientPactValue = PLiteral $ LString $ Text.decodeUtf8 $ BS.dropWhile (== 0) hmRecipient
unless (hmRecipientPactValue == capRecipient) $
throwError $ VerifierError $
"Recipients don't match. Expected: " <> sshow hmRecipientPactValue <> " but got " <> sshow capRecipient
Expand Down
Loading

0 comments on commit 1186195

Please sign in to comment.