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

Extract Http-Bridge specifics into a dedicated package #212

Merged
merged 6 commits into from
May 3, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 1 addition & 5 deletions lib/core/src/Cardano/Wallet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ module Cardano.Wallet

import Prelude

import Cardano.Wallet.Binary
( encodeSignedTx, toByteString )
import Cardano.Wallet.CoinSelection
( CoinSelection (..)
, CoinSelectionError (..)
Expand Down Expand Up @@ -81,7 +79,6 @@ import Cardano.Wallet.Primitive.Types
( Block (..)
, Coin (..)
, Direction (..)
, SignedTx (..)
, SlotId (..)
, Tx
, TxId (..)
Expand Down Expand Up @@ -319,8 +316,7 @@ mkWalletLayer db nw tl = WalletLayer
throwE $ ErrSignTx e

, submitTx = \wid (tx, meta, wit) -> do
let signed = SignedTx $ toByteString $ encodeSignedTx (tx, wit)
withExceptT ErrSubmitTxNetwork $ postTx nw signed
withExceptT ErrSubmitTxNetwork $ postTx nw (tx, wit)
DB.withLock db $ withExceptT ErrSubmitTxNoSuchWallet $ do
(w, _) <- _readWallet wid
let history = Map.fromList [(txId @t tx, (tx, meta))]
Expand Down
21 changes: 19 additions & 2 deletions lib/core/src/Cardano/Wallet/Api.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ import Cardano.Wallet.Api.Types
)
import Cardano.Wallet.Primitive.Types
( AddressState, WalletId )
import Data.List.NonEmpty
( NonEmpty ((:|)) )
import Network.HTTP.Media
( (//), (/:) )
import Servant.API
( (:<|>)
, (:>)
, Accept (..)
, Capture
, DeleteNoContent
, Get
Expand All @@ -28,8 +33,6 @@ import Servant.API
, QueryParam
, ReqBody
)
import Servant.Extra.ContentTypes
( Any )

type Api = Addresses :<|> Wallets :<|> Transactions

Expand Down Expand Up @@ -109,3 +112,17 @@ type CreateTransaction = "wallets"
:> "transactions"
:> ReqBody '[JSON] PostTransactionData
:> PostAccepted '[JSON] ApiTransaction

{-------------------------------------------------------------------------------
Internals
-------------------------------------------------------------------------------}

-- | Any media type
data Any

instance Accept Any where
contentTypes _ = ("*" // "*") :|
-- We also 'conveniently' accept JSON format
[ "application" // "json"
, "application" // "json" /: ("charset", "utf-8")
]
4 changes: 2 additions & 2 deletions lib/core/src/Cardano/Wallet/Network.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module Cardano.Wallet.Network
import Prelude

import Cardano.Wallet.Primitive.Types
( Block (..), BlockHeader (..), Hash (..), SignedTx, SlotId (..) )
( Block (..), BlockHeader (..), Hash (..), SlotId (..), Tx, TxWitness )
import Control.Exception
( Exception )
import Control.Monad.Trans.Except
Expand All @@ -40,7 +40,7 @@ data NetworkLayer m = NetworkLayer
-- ^ Get the current network tip from the chain producer

, postTx
:: SignedTx -> ExceptT ErrPostTx m ()
:: (Tx, [TxWitness]) -> ExceptT ErrPostTx m ()
-- ^ Broadcast a transaction to the chain producer
}

Expand Down
5 changes: 0 additions & 5 deletions lib/core/src/Cardano/Wallet/Primitive/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ module Cardano.Wallet.Primitive.Types
, TxMeta(..)
, Direction(..)
, TxStatus(..)
, SignedTx (..)
, TxWitness (..)
, txIns

Expand Down Expand Up @@ -412,10 +411,6 @@ instance Buildable Direction where
Outgoing -> "outgoing"
Incoming -> "incoming"

-- | Wrapper around the final CBOR representation of a signed tx
newtype SignedTx = SignedTx { signedTx :: ByteString }
deriving (Show, Eq, Generic)

data TxWitness
= PublicKeyWitness ByteString (Hash "signature")
| ScriptWitness ByteString
Expand Down
4 changes: 2 additions & 2 deletions lib/http-bridge/src/Cardano/Wallet/Network/HttpBridge.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import Cardano.Wallet.Network
import Cardano.Wallet.Network.HttpBridge.Api
( ApiT (..), EpochIndex (..), NetworkName (..), api )
import Cardano.Wallet.Primitive.Types
( Block (..), BlockHeader (..), Hash (..), SignedTx, SlotId (..) )
( Block (..), BlockHeader (..), Hash (..), SlotId (..), Tx, TxWitness )
import Control.Arrow
( left )
import Control.Monad
Expand Down Expand Up @@ -160,7 +160,7 @@ data HttpBridge m = HttpBridge
, getNetworkTip
:: ExceptT ErrNetworkTip m (Hash "BlockHeader", BlockHeader)
, postSignedTx
:: SignedTx -> ExceptT ErrPostTx m ()
:: (Tx, [TxWitness]) -> ExceptT ErrPostTx m ()
}

-- | Construct a new network layer
Expand Down
42 changes: 27 additions & 15 deletions lib/http-bridge/src/Cardano/Wallet/Network/HttpBridge/Api.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ module Cardano.Wallet.Network.HttpBridge.Api

import Prelude

import Cardano.Wallet.Binary
( decodeBlock, decodeBlockHeader )
import Cardano.Wallet.Binary.HttpBridge
( decodeBlock
, decodeBlockHeader
, decodeSignedTx
, encodeSignedTx
, toByteString
)
import Cardano.Wallet.Primitive.Types
( Block, BlockHeader, SignedTx (..) )
( Block, BlockHeader, Tx, TxWitness )
import Crypto.Hash.Algorithms
( Blake2b_256 )
import Data.Aeson
Expand All @@ -29,7 +34,6 @@ import Data.ByteArray.Encoding
( Base (Base64), convertFromBase, convertToBase )
import Data.ByteString
( ByteString )
import qualified Data.ByteString.Char8 as B8
import Data.Proxy
( Proxy (..) )
import Data.Text
Expand All @@ -50,6 +54,10 @@ import Servant.API
import Servant.Extra.ContentTypes
( CBOR, ComputeHash, FromCBOR (..), Hash, Packed, WithHash )

import qualified Codec.CBOR.Read as CBOR
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy as BL


api :: Proxy Api
api = Proxy
Expand Down Expand Up @@ -85,7 +93,7 @@ type PostSignedTx
= Capture "networkName" NetworkName
:> "txs"
:> "signed"
:> ReqBody '[JSON] (ApiT SignedTx)
:> ReqBody '[JSON] (ApiT (Tx, [TxWitness]))
:> Post '[NoContent] NoContent

newtype ApiT a = ApiT { getApiT :: a } deriving (Show)
Expand All @@ -112,17 +120,21 @@ newtype NetworkName = NetworkName
instance ToHttpApiData NetworkName where
toUrlPiece = getNetworkName

instance ToJSON (ApiT SignedTx) where
toJSON (ApiT (SignedTx bs))= object ["signedTx" .= c bs]
instance ToJSON (ApiT (Tx, [TxWitness])) where
toJSON (ApiT (tx, wit))= object ["signedTx" .= base64 bytes]
where
c :: ByteString -> String
c = B8.unpack . convertToBase Base64
bytes :: ByteString
bytes = toByteString $ encodeSignedTx (tx, wit)
base64 :: ByteString -> String
base64 = B8.unpack . convertToBase Base64

instance FromJSON (ApiT SignedTx) where
instance FromJSON (ApiT (Tx, [TxWitness])) where
parseJSON = withObject "SignedTx" $ \p -> do
base64 <- p .: "signedTx"
bs <- either fail return $ c base64
return $ ApiT . SignedTx $ bs
bs <- (base64 <$> (p .: "signedTx"))
>>= either fail return
tx <- pure (CBOR.deserialiseFromBytes decodeSignedTx (BL.fromStrict bs))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this change compatible with "old data" - if tx witness is stored on a blockchain

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aha - in fact I see it didn't change at all. You have just moved some code bits here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. The code is the same, but now done within the http-bridge package (rather than in the core), because it uses some cbor-specific encoding. So, before that, the core was sending a 'SignedTx ByteString, where the ByteStringwas supposedly the serialized tx, and it now sends a(Tx, [TxWitness])` and the network layer takes care of serializing it. This keeps the network layer agnostic to the binary format.

>>= either (fail . show) (return . snd)
return $ ApiT tx
where
c :: String -> Either String ByteString
c bs = convertFromBase Base64 (B8.pack bs)
base64 :: String -> Either String ByteString
base64 bs = convertFromBase Base64 (B8.pack bs)
19 changes: 3 additions & 16 deletions lib/http-bridge/src/Servant/Extra/ContentTypes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,24 @@ module Servant.Extra.ContentTypes
, Hash (..)
, Packed
, WithHash (..)
, Any
) where

import Prelude

import Cardano.Wallet.Binary.Packfile
( decodePackfile )
import Crypto.Hash
( Digest, hashWith )
import Crypto.Hash.IO
( HashAlgorithm (..) )
import Data.ByteArray.Encoding
( Base (Base16), convertToBase )
import Data.List.NonEmpty
( NonEmpty (..) )
import Data.Packfile
( decodePackfile )
import Data.Proxy
( Proxy (..) )
import Data.Text.Encoding
( decodeUtf8 )
import Network.HTTP.Media
( (//), (/:) )
( (//) )
import Servant.API
( Accept (..), MimeUnrender (..), ToHttpApiData (..) )

Expand Down Expand Up @@ -99,13 +96,3 @@ instance forall a b . MimeUnrender a b => MimeUnrender (Packed a) [b] where
(Left . show)
(traverse $ mimeUnrender (Proxy :: Proxy a) . BL.fromStrict)
(decodePackfile bs)

-- | Any media type
data Any

instance Accept Any where
contentTypes _ = ("*" // "*") :|
-- We also 'conveniently' accept JSON format
[ "application" // "json"
, "application" // "json" /: ("charset", "utf-8")
]