Skip to content

Commit 4fffe13

Browse files
committed
FFI library
1 parent fb6cacc commit 4fffe13

File tree

5 files changed

+260
-144
lines changed

5 files changed

+260
-144
lines changed

ouroboros-consensus-cardano/app/snapshot-converter.hs

Lines changed: 3 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,21 @@ import Cardano.Crypto.Init (cryptoInit)
1515
import Cardano.Tools.DBAnalyser.Block.Cardano (configFile)
1616
import Cardano.Tools.DBAnalyser.HasAnalysis (mkProtocolInfo)
1717
import Control.Concurrent
18-
import Control.Exception
1918
import Control.Monad (forever, void)
2019
import Control.Monad.Except
2120
import DBAnalyser.Parsers
22-
import qualified Data.Aeson as Aeson
2321
import qualified Data.List as L
24-
import qualified Data.Text as Text
25-
import qualified Debug.Trace as Debug
26-
import GHC.TypeLits (Symbol)
2722
import Main.Utf8
2823
import Options.Applicative
2924
import Options.Applicative.Help (Doc, line)
3025
import Ouroboros.Consensus.Cardano.SnapshotConversion
26+
import Ouroboros.Consensus.Config
27+
import Ouroboros.Consensus.Node.ProtocolInfo
3128
import Ouroboros.Consensus.Storage.LedgerDB.Snapshots
3229
import System.Exit
3330
import System.FSNotify
3431
import System.FilePath
3532

36-
-- | FilePaths annotated with the purpose
37-
newtype FilePath' (s :: Symbol) = FP {rawFilePath :: FilePath}
38-
39-
instance Show (FilePath' s) where
40-
show = rawFilePath
41-
4233
data Config
4334
= -- | Run in daemon mode, with an output directory
4435
DaemonConfig (FilePath' "OutDir")
@@ -49,19 +40,11 @@ data Config
4940
-- | Which format the output snapshot must be in
5041
Format
5142

52-
-- | Information inferred from the config file
53-
data FromConfigFile
54-
= FromConfigFile
55-
-- | The input format once supplied with a particular snapshot
56-
(FilePath' "Snapshot" -> Format)
57-
-- | The directory of snapshots, to be watched by inotify
58-
(FilePath' "Snapshots")
59-
6043
main :: IO ()
6144
main = withStdTerminalHandles $ do
6245
cryptoInit
6346
(conf, args) <- getCommandLineConfig
64-
pInfo <- mkProtocolInfo args
47+
pInfo <- configCodec . pInfoConfig <$> mkProtocolInfo args
6548
FromConfigFile inFormat ledgerDbPath <- getFormatFromConfig (FP $ configFile args)
6649
case conf of
6750
NoDaemonConfig f t -> do
@@ -219,115 +202,3 @@ parsePath optName strHelp =
219202
, metavar "PATH"
220203
]
221204
)
222-
223-
{-------------------------------------------------------------------------------
224-
Parsing the configuration file
225-
-------------------------------------------------------------------------------}
226-
227-
instance Aeson.FromJSON FromConfigFile where
228-
parseJSON = Aeson.withObject "CardanoConfigFile" $ \o -> do
229-
DBPaths imm vol <- Aeson.parseJSON (Aeson.Object o)
230-
inFmt <- ($ vol) <$> Aeson.parseJSON (Aeson.Object o)
231-
pure $ FromConfigFile inFmt imm
232-
233-
data DBPaths = DBPaths (FilePath' "Snapshots") (FilePath' "Volatile")
234-
235-
-- | Possible database locations:
236-
--
237-
-- (1) Provided as flag: we would need to receive that same flag. For simplicity we will ban this scenario for now, requiring users to put the path in the config file.
238-
--
239-
-- (2) Not provided: we default to "mainnet"
240-
--
241-
-- (3) Provided in the config file:
242-
--
243-
-- (1) One database path: we use that one
244-
--
245-
-- @@
246-
-- "DatabasePath": "some/path"
247-
-- @@
248-
--
249-
-- (2) Multiple databases paths: we use the immutable one
250-
--
251-
-- @@
252-
-- "DatabasePath": {
253-
-- "ImmutableDbPath": "some/path",
254-
-- "VolatileDbPath": "some/other/path",
255-
-- }
256-
-- @@
257-
instance Aeson.FromJSON DBPaths where
258-
parseJSON = Aeson.withObject "CardanoConfigFile" $ \o -> do
259-
pncDatabase <- o Aeson..:? "DatabasePath"
260-
(imm, vol) <- case pncDatabase of
261-
Nothing -> pure ("mainnet", "mainnet") -- (2)
262-
Just p@(Aeson.Object{}) ->
263-
Aeson.withObject
264-
"NodeDatabasePaths"
265-
(\o' -> (,) <$> o' Aeson..: "ImmutableDbPath" <*> o' Aeson..: "VolatileDbPath") -- (3.2)
266-
p
267-
Just (Aeson.String s) ->
268-
let
269-
s' = Text.unpack s
270-
in
271-
pure (s', s') -- (3.1)
272-
_ -> fail "NodeDatabasePaths must be an object or a string"
273-
pure $ DBPaths (FP $ imm </> "ledger") (FP vol)
274-
275-
-- | Possible formats
276-
--
277-
-- (1) Nothing provided: we use InMemory
278-
--
279-
-- (2) Provided in config file:
280-
--
281-
-- (1) "V2InMem": we use InMemory
282-
--
283-
-- @@
284-
-- "LedgerDB": {
285-
-- "Backend": "V2InMem"
286-
-- }
287-
-- @@
288-
--
289-
-- (2) "V1LMDB": we use LMDB
290-
--
291-
-- @@
292-
-- "LedgerDB": {
293-
-- "Backend": "V1LMDB"
294-
-- }
295-
-- @@
296-
--
297-
-- (3) "V2LSM"
298-
-- LSM database locations:
299-
-- (1) Nothing provided: we use "lsm" in the volatile directory
300-
--
301-
-- @@
302-
-- "LedgerDB": {
303-
-- "Backend": "V2LSM"
304-
-- }
305-
-- @@
306-
--
307-
-- (2) Provided in file: we use that one
308-
--
309-
-- @@
310-
-- "LedgerDB": {
311-
-- "Backend": "V2LSM",
312-
-- "LSMDatabasePath": "some/path"
313-
-- }
314-
-- @@
315-
instance Aeson.FromJSON (FilePath' "Volatile" -> FilePath' "Snapshot" -> Format) where
316-
parseJSON = Aeson.withObject "CardanoConfigFile" $ \o -> do
317-
ldb <- Debug.traceShowId <$> o Aeson..:? "LedgerDB"
318-
case ldb of
319-
Nothing -> pure $ const $ Mem . rawFilePath -- (1)
320-
Just ldb' -> do
321-
bkd <- ldb' Aeson..:? "Backend"
322-
case bkd :: Maybe String of
323-
Just "V1LMDB" -> pure $ const $ LMDB . rawFilePath -- (2.2)
324-
Just "V2LSM" -> do
325-
mDbPath <- ldb' Aeson..:? "LSMDatabasePath"
326-
case mDbPath of
327-
Nothing -> pure $ \v -> flip LSM (rawFilePath v </> "lsm") . rawFilePath -- (2.3.1)
328-
Just dbPath -> pure $ const $ flip LSM dbPath . rawFilePath -- (2.3.2)
329-
_ -> pure $ const $ Mem . rawFilePath -- (2.1)
330-
331-
getFormatFromConfig :: FilePath' "ConfigFile" -> IO FromConfigFile
332-
getFormatFromConfig (FP configPath) =
333-
either (throwIO . userError) pure =<< Aeson.eitherDecodeFileStrict' configPath
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{-# LANGUAGE DataKinds #-}
2+
{-# LANGUAGE ForeignFunctionInterface #-}
3+
{-# LANGUAGE TypeApplications #-}
4+
5+
module Ouroboros.Consensus.Cardano.SnapshotConversion.External () where
6+
7+
import Cardano.Chain.Slotting
8+
import Control.Monad.Except
9+
import Data.SOP.Strict
10+
import Foreign.C.String
11+
import Ouroboros.Consensus.Byron.Ledger.Config
12+
import qualified Ouroboros.Consensus.Cardano.SnapshotConversion as Impl
13+
import Ouroboros.Consensus.HardFork.Combinator.AcrossEras
14+
import Ouroboros.Consensus.HardFork.Combinator.Basics
15+
import Ouroboros.Consensus.Shelley.Ledger.Config
16+
import System.FilePath
17+
18+
foreign export ccall ffiConvertSnapshot :: CString -> CString -> CString -> IO ()
19+
20+
ffiConvertSnapshot :: CString -> CString -> CString -> IO ()
21+
ffiConvertSnapshot cfgFileC outDirC snapNameC = do
22+
[cfgFile, outDir, snapName] <- mapM peekCString [cfgFileC, outDirC, snapNameC]
23+
Impl.FromConfigFile inFmt lgrPath <- Impl.getFormatFromConfig $ Impl.FP cfgFile
24+
25+
res <-
26+
runExceptT $
27+
Impl.convertSnapshot
28+
False
29+
( HardForkCodecConfig $
30+
PerEraCodecConfig $
31+
ByronCodecConfig (EpochSlots $ 2160 * 10)
32+
:* ShelleyCodecConfig
33+
:* ShelleyCodecConfig
34+
:* ShelleyCodecConfig
35+
:* ShelleyCodecConfig
36+
:* ShelleyCodecConfig
37+
:* ShelleyCodecConfig
38+
:* ShelleyCodecConfig
39+
:* Nil
40+
)
41+
(inFmt (Impl.FP @"Snapshot" $ Impl.rawFilePath lgrPath </> snapName))
42+
(Impl.Mem $ outDir </> snapName)
43+
case res of
44+
Left err -> putStrLn $ show err
45+
Right () -> pure ()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <stdlib.h>
2+
#include "HsFFI.h"
3+
4+
HsBool mylib_init(void){
5+
int argc = 1;
6+
char *argv[] = { "snapshot-conversion", NULL };
7+
char **pargv = argv;
8+
9+
// Initialize Haskell runtime
10+
hs_init(&argc, &pargv);
11+
12+
// do any other initialization here and
13+
// return false if there was a problem
14+
return HS_BOOL_TRUE;
15+
}
16+
17+
void mylib_end(void){
18+
hs_exit();
19+
}

ouroboros-consensus-cardano/ouroboros-consensus-cardano.cabal

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,28 @@ flag asserts
3636
manual: False
3737
default: False
3838

39+
flag fat-foreign-dylib
40+
description:
41+
Enable foreign library compilation.
42+
Notice this requires a GHC compiled with fPIC.
43+
44+
```
45+
git clone [email protected]:ghc/ghc
46+
cd ghc
47+
git submodule update --init --recursive
48+
./boot
49+
CFLAGS=-fPIC ./configure
50+
CFLAGS=-fPIC ./hadrian/build -j --docs=none binary-dist "*.*.ghc.hs.opts += -fPIC \
51+
*.*.ghc.c.opts += -fPIC \
52+
*.*.cc.c.opts += -fPIC"
53+
ghcup install ghc -u "file:///.../ghc/_build/bindist/ghc-x.y.z-x86_64-unknown-linux.tar.xz" x.y.z-fpic
54+
echo "package *\n ghc-options: -fPIC" >> cabal.project.local
55+
cabal build -w ghc-x.y.z-fpic -ffat-foreign-dylib ...
56+
```
57+
58+
manual: True
59+
default: False
60+
3961
common common-lib
4062
default-language: Haskell2010
4163
ghc-options:
@@ -185,9 +207,12 @@ library snapshot-conversion
185207
hs-source-dirs: src/snapshot-conversion
186208
other-modules:
187209
Ouroboros.Consensus.Cardano.StreamingLedgerTables
210+
188211
exposed-modules:
189212
Ouroboros.Consensus.Cardano.SnapshotConversion
213+
190214
build-depends:
215+
aeson,
191216
ansi-terminal,
192217
base,
193218
cardano-ledger-binary,
@@ -211,6 +236,32 @@ library snapshot-conversion
211236
terminal-progress-bar,
212237
text,
213238

239+
foreign-library snapshot-conversion-ffi
240+
import: common-lib
241+
type: native-shared
242+
hs-source-dirs: external
243+
c-sources:
244+
external/entry.c
245+
external/fini_array_shim.c
246+
247+
other-modules: Ouroboros.Consensus.Cardano.SnapshotConversion.External
248+
ghc-options:
249+
-static
250+
-threaded
251+
-fPIC
252+
253+
build-depends:
254+
base,
255+
cardano-ledger-byron,
256+
filepath,
257+
mtl,
258+
ouroboros-consensus,
259+
ouroboros-consensus-cardano,
260+
snapshot-conversion,
261+
strict-sop-core,
262+
263+
if !flag(fat-foreign-dylib)
264+
buildable: False
214265

215266
library unstable-byronspec
216267
import: common-lib
@@ -727,20 +778,17 @@ executable immdb-server
727778
executable snapshot-converter
728779
import: common-exe
729780
hs-source-dirs: app
730-
731781
main-is: snapshot-converter.hs
732782
build-depends:
733-
fsnotify,
734783
base,
735784
cardano-crypto-class,
785+
filepath,
786+
fsnotify,
736787
mtl,
737788
optparse-applicative,
738789
ouroboros-consensus,
739-
ouroboros-consensus-cardano:{unstable-cardano-tools, ouroboros-consensus-cardano, snapshot-conversion},
740-
text,
790+
ouroboros-consensus-cardano:{ouroboros-consensus-cardano, snapshot-conversion, unstable-cardano-tools},
741791
with-utf8,
742-
filepath,
743-
aeson
744792

745793
other-modules:
746794
DBAnalyser.Parsers

0 commit comments

Comments
 (0)