diff --git a/.stack-to-nix.cache b/.stack-to-nix.cache index 76f4885e..20476ec9 100644 --- a/.stack-to-nix.cache +++ b/.stack-to-nix.cache @@ -1,19 +1,15 @@ -https://github.com/input-output-hk/cardano-prelude f2802079ba2c07c4d408e3c0aa000fc363792398 . 0wy8sifjmvwjrgmr46rrdy3323bh1fww6wvy4yszhd8azb5z11bn cardano-prelude .stack.nix/cardano-prelude.nix -https://github.com/input-output-hk/cardano-prelude f2802079ba2c07c4d408e3c0aa000fc363792398 test 0wy8sifjmvwjrgmr46rrdy3323bh1fww6wvy4yszhd8azb5z11bn cardano-prelude-test .stack.nix/cardano-prelude-test.nix -https://github.com/well-typed/cborg 80fbe0ee5e67a5622e2cb9eaa9d8594a2214322d cborg 1khd1v9yh6jdkcvzvknvhxpc1qvxvww0pp7c43w4hbvdyhs1q8wh cborg .stack.nix/cborg.nix -https://github.com/nc6/cardano-crypto d46e8a44d85a71f5da03fb6b176e9427c684144b . 0g8ln8k8wx4csdv92bz09pr7v9dp4lcyv1334b09c9rgwdwhqg1b cardano-crypto .stack.nix/cardano-crypto.nix -https://github.com/avieth/plutus-prototype d094be301195fcd8ab864d793f114970426a4478 . 1s932rghn4zn441waansp408b5bwk20rc1wsa5693a2nwnp4dijw plutus-prototype .stack.nix/plutus-prototype.nix -https://github.com/input-output-hk/haskell-hedgehog.git 2e741bb53afb085741807018948ae17d956c53af hedgehog 0l0d1n2b68m0628j4yi214q5fy6pz777qfj1bc1lrra8scs5gcxh hedgehog .stack.nix/hedgehog.nix -http://github.com/nc6/canonical-json a9dc9b893649bc2e2a770ab22d278a780f7e3a3c . 0alwbi9xqaj6fmwzs6lr2drqrnhlnp13d9k2qkl5ga7h4grz9zcr canonical-json .stack.nix/canonical-json.nix -https://github.com/input-output-hk/cardano-prelude db5deaa1780b3a0811aaa4b8941037c5efa17105 . 1r712w8mrkwgznn3v5ynjrizb227krrwykl4ym8kpsbpd6z048yz cardano-prelude .stack.nix/cardano-prelude.nix -https://github.com/input-output-hk/cardano-prelude db5deaa1780b3a0811aaa4b8941037c5efa17105 test 1r712w8mrkwgznn3v5ynjrizb227krrwykl4ym8kpsbpd6z048yz cardano-prelude-test .stack.nix/cardano-prelude-test.nix -https://github.com/input-output-hk/cardano-prelude 7f8544ae9e162b6664f07093227edb148f1c8a5b . 0yywq1m77k2f95pi59pdsk7rq7zlq140d1lsk6gl5qsjrxvyzkb5 cardano-prelude .stack.nix/cardano-prelude.nix -https://github.com/input-output-hk/cardano-prelude 7f8544ae9e162b6664f07093227edb148f1c8a5b test 0yywq1m77k2f95pi59pdsk7rq7zlq140d1lsk6gl5qsjrxvyzkb5 cardano-prelude-test .stack.nix/cardano-prelude-test.nix +https://github.com/input-output-hk/cardano-prelude 7161436bd31195b2ddfa7d359cd99f0fe53c881c . 1vv2x8ihql6fh6kkq07sjx2g7jjhc5g4j55jplwnhh48b5pghrxb cardano-prelude .stack.nix/cardano-prelude.nix +https://github.com/input-output-hk/cardano-prelude 7161436bd31195b2ddfa7d359cd99f0fe53c881c test 1vv2x8ihql6fh6kkq07sjx2g7jjhc5g4j55jplwnhh48b5pghrxb cardano-prelude-test .stack.nix/cardano-prelude-test.nix https://github.com/input-output-hk/cardano-chain 4d9eec080374179bf15bf9c4fca09cc7d73e5f53 binary 15525inprrbapkvisnqgsxzn8vmcdm1inwv1r6nxnv9qczkb7ca5 cardano-binary .stack.nix/cardano-binary.nix https://github.com/input-output-hk/cardano-chain 4d9eec080374179bf15bf9c4fca09cc7d73e5f53 binary/test 15525inprrbapkvisnqgsxzn8vmcdm1inwv1r6nxnv9qczkb7ca5 cardano-binary-test .stack.nix/cardano-binary-test.nix https://github.com/input-output-hk/cardano-chain 4d9eec080374179bf15bf9c4fca09cc7d73e5f53 crypto 15525inprrbapkvisnqgsxzn8vmcdm1inwv1r6nxnv9qczkb7ca5 cardano-crypto-wrapper .stack.nix/cardano-crypto-wrapper.nix https://github.com/input-output-hk/cardano-chain 4d9eec080374179bf15bf9c4fca09cc7d73e5f53 crypto/test 15525inprrbapkvisnqgsxzn8vmcdm1inwv1r6nxnv9qczkb7ca5 cardano-crypto-test .stack.nix/cardano-crypto-test.nix +https://github.com/input-output-hk/fm-ledger-rules bf059d1d593e7ef9f3b983a0c904e7bb81362af9 specs/semantics/hs 0rdyb0bfk69ndb86m91m9fzcfnhaj4q5yw0cgfj0ap4vmirz92cs small-steps .stack.nix/small-steps.nix +https://github.com/input-output-hk/fm-ledger-rules bf059d1d593e7ef9f3b983a0c904e7bb81362af9 specs/ledger/hs 0rdyb0bfk69ndb86m91m9fzcfnhaj4q5yw0cgfj0ap4vmirz92cs cs-ledger .stack.nix/cs-ledger.nix +https://github.com/input-output-hk/fm-ledger-rules bf059d1d593e7ef9f3b983a0c904e7bb81362af9 specs/chain/hs 0rdyb0bfk69ndb86m91m9fzcfnhaj4q5yw0cgfj0ap4vmirz92cs cs-blockchain .stack.nix/cs-blockchain.nix https://github.com/input-output-hk/cardano-mainnet-mirror 74ca63f8ad6b47beba2f565c73592cede63ce4b5 . 0kkgfdw6z2k7wrsjgcs1w3scm9d397nz5nacadw1jpan8l56xa5y cardano-mainnet-mirror .stack.nix/cardano-mainnet-mirror.nix +https://github.com/well-typed/cborg 80fbe0ee5e67a5622e2cb9eaa9d8594a2214322d cborg 1khd1v9yh6jdkcvzvknvhxpc1qvxvww0pp7c43w4hbvdyhs1q8wh cborg .stack.nix/cborg.nix https://github.com/input-output-hk/cardano-crypto 3c707936ba0a665375acf5bd240dc4b6eaa6c0bc . 0g8ln8k8wx4csdv92bz09pr7v9dp4lcyv1334b09c9rgwdwhqg1b cardano-crypto .stack.nix/cardano-crypto.nix -https://github.com/input-output-hk/cardano-prelude 7161436bd31195b2ddfa7d359cd99f0fe53c881c . 1vv2x8ihql6fh6kkq07sjx2g7jjhc5g4j55jplwnhh48b5pghrxb cardano-prelude .stack.nix/cardano-prelude.nix -https://github.com/input-output-hk/cardano-prelude 7161436bd31195b2ddfa7d359cd99f0fe53c881c test 1vv2x8ihql6fh6kkq07sjx2g7jjhc5g4j55jplwnhh48b5pghrxb cardano-prelude-test .stack.nix/cardano-prelude-test.nix +https://github.com/avieth/plutus-prototype d094be301195fcd8ab864d793f114970426a4478 . 1s932rghn4zn441waansp408b5bwk20rc1wsa5693a2nwnp4dijw plutus-prototype .stack.nix/plutus-prototype.nix +https://github.com/input-output-hk/haskell-hedgehog.git 2e741bb53afb085741807018948ae17d956c53af hedgehog 0l0d1n2b68m0628j4yi214q5fy6pz777qfj1bc1lrra8scs5gcxh hedgehog .stack.nix/hedgehog.nix +http://github.com/nc6/canonical-json a9dc9b893649bc2e2a770ab22d278a780f7e3a3c . 0alwbi9xqaj6fmwzs6lr2drqrnhlnp13d9k2qkl5ga7h4grz9zcr canonical-json .stack.nix/canonical-json.nix diff --git a/cabal.project b/cabal.project index 52d84b6b..e2999948 100644 --- a/cabal.project +++ b/cabal.project @@ -1,9 +1,7 @@ -packages: specs/semantics/hs - specs/ledger/hs - specs/chain/hs - binary - crypto - ./ +packages: + binary + crypto + ./ source-repository-package type: git @@ -25,3 +23,21 @@ source-repository-package type: git location: https://github.com/avieth/plutus-prototype tag: d094be301195fcd8ab864d793f114970426a4478 + +source-repository-package + type: git + location: https://github.com/input-output-hk/fm-ledger-rules + tag: bf059d1d593e7ef9f3b983a0c904e7bb81362af9 + subdir: specs/semantics/hs + +source-repository-package + type: git + location: https://github.com/input-output-hk/fm-ledger-rules + tag: bf059d1d593e7ef9f3b983a0c904e7bb81362af9 + subdir: specs/ledger/hs + +source-repository-package + type: git + location: https://github.com/input-output-hk/fm-ledger-rules + tag: bf059d1d593e7ef9f3b983a0c904e7bb81362af9 + subdir: specs/chain/hs diff --git a/default.nix b/default.nix index 1cb62c61..3a61d838 100644 --- a/default.nix +++ b/default.nix @@ -27,9 +27,3 @@ in # We will instantiate the defaul-nix template with the # nix/pkgs.nix file... localLib.nix-tools.default-nix ./nix/pkgs.nix args -# ... and add a few custom packages as well. -// { - byronLedgerSpec = import ./specs/ledger/latex {}; - byronChainSpec = import ./specs/chain/latex {}; - semanticsSpec = import ./specs/semantics/latex {}; -} diff --git a/nix/.stack-pkgs.nix b/nix/.stack-pkgs.nix index 975b3719..621ee866 100644 --- a/nix/.stack-pkgs.nix +++ b/nix/.stack-pkgs.nix @@ -12,15 +12,15 @@ } // { cardano-chain = ./.stack.nix/cardano-chain.nix; cardano-chain-test = ./.stack.nix/cardano-chain-test.nix; - cs-ledger = ./.stack.nix/cs-ledger.nix; - small-steps = ./.stack.nix/small-steps.nix; - cs-blockchain = ./.stack.nix/cs-blockchain.nix; cardano-prelude = ./.stack.nix/cardano-prelude.nix; cardano-prelude-test = ./.stack.nix/cardano-prelude-test.nix; cardano-binary = ./.stack.nix/cardano-binary.nix; cardano-binary-test = ./.stack.nix/cardano-binary-test.nix; cardano-crypto-wrapper = ./.stack.nix/cardano-crypto-wrapper.nix; cardano-crypto-test = ./.stack.nix/cardano-crypto-test.nix; + small-steps = ./.stack.nix/small-steps.nix; + cs-ledger = ./.stack.nix/cs-ledger.nix; + cs-blockchain = ./.stack.nix/cs-blockchain.nix; cardano-mainnet-mirror = ./.stack.nix/cardano-mainnet-mirror.nix; cborg = ./.stack.nix/cborg.nix; cardano-crypto = ./.stack.nix/cardano-crypto.nix; diff --git a/nix/.stack.nix/canonical-json.nix b/nix/.stack.nix/canonical-json.nix index 38aeff6b..b0f8f757 100644 --- a/nix/.stack.nix/canonical-json.nix +++ b/nix/.stack.nix/canonical-json.nix @@ -41,9 +41,9 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "http://github.com/nc6/canonical-json"; rev = "a9dc9b893649bc2e2a770ab22d278a780f7e3a3c"; sha256 = "0alwbi9xqaj6fmwzs6lr2drqrnhlnp13d9k2qkl5ga7h4grz9zcr"; - }; + }); } \ No newline at end of file diff --git a/nix/.stack.nix/cardano-binary-test.nix b/nix/.stack.nix/cardano-binary-test.nix index 7c66e39f..0bbf77ad 100644 --- a/nix/.stack.nix/cardano-binary-test.nix +++ b/nix/.stack.nix/cardano-binary-test.nix @@ -39,10 +39,10 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-chain"; rev = "4d9eec080374179bf15bf9c4fca09cc7d73e5f53"; sha256 = "15525inprrbapkvisnqgsxzn8vmcdm1inwv1r6nxnv9qczkb7ca5"; - }; + }); postUnpack = "sourceRoot+=/binary/test; echo source root reset to \$sourceRoot"; } \ No newline at end of file diff --git a/nix/.stack.nix/cardano-binary.nix b/nix/.stack.nix/cardano-binary.nix index 1163c148..384a70f5 100644 --- a/nix/.stack.nix/cardano-binary.nix +++ b/nix/.stack.nix/cardano-binary.nix @@ -61,10 +61,10 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-chain"; rev = "4d9eec080374179bf15bf9c4fca09cc7d73e5f53"; sha256 = "15525inprrbapkvisnqgsxzn8vmcdm1inwv1r6nxnv9qczkb7ca5"; - }; + }); postUnpack = "sourceRoot+=/binary; echo source root reset to \$sourceRoot"; } \ No newline at end of file diff --git a/nix/.stack.nix/cardano-crypto-test.nix b/nix/.stack.nix/cardano-crypto-test.nix index 05544ee7..8e29402a 100644 --- a/nix/.stack.nix/cardano-crypto-test.nix +++ b/nix/.stack.nix/cardano-crypto-test.nix @@ -35,10 +35,10 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-chain"; rev = "4d9eec080374179bf15bf9c4fca09cc7d73e5f53"; sha256 = "15525inprrbapkvisnqgsxzn8vmcdm1inwv1r6nxnv9qczkb7ca5"; - }; + }); postUnpack = "sourceRoot+=/crypto/test; echo source root reset to \$sourceRoot"; } \ No newline at end of file diff --git a/nix/.stack.nix/cardano-crypto-wrapper.nix b/nix/.stack.nix/cardano-crypto-wrapper.nix index 3591382a..3063eff6 100644 --- a/nix/.stack.nix/cardano-crypto-wrapper.nix +++ b/nix/.stack.nix/cardano-crypto-wrapper.nix @@ -66,10 +66,10 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-chain"; rev = "4d9eec080374179bf15bf9c4fca09cc7d73e5f53"; sha256 = "15525inprrbapkvisnqgsxzn8vmcdm1inwv1r6nxnv9qczkb7ca5"; - }; + }); postUnpack = "sourceRoot+=/crypto; echo source root reset to \$sourceRoot"; } \ No newline at end of file diff --git a/nix/.stack.nix/cardano-crypto.nix b/nix/.stack.nix/cardano-crypto.nix index 6443123b..30bdba93 100644 --- a/nix/.stack.nix/cardano-crypto.nix +++ b/nix/.stack.nix/cardano-crypto.nix @@ -80,9 +80,9 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-crypto"; rev = "3c707936ba0a665375acf5bd240dc4b6eaa6c0bc"; sha256 = "0g8ln8k8wx4csdv92bz09pr7v9dp4lcyv1334b09c9rgwdwhqg1b"; - }; + }); } \ No newline at end of file diff --git a/nix/.stack.nix/cardano-mainnet-mirror.nix b/nix/.stack.nix/cardano-mainnet-mirror.nix index 23acdc93..4ff8e4ff 100644 --- a/nix/.stack.nix/cardano-mainnet-mirror.nix +++ b/nix/.stack.nix/cardano-mainnet-mirror.nix @@ -20,9 +20,9 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-mainnet-mirror"; rev = "74ca63f8ad6b47beba2f565c73592cede63ce4b5"; sha256 = "0kkgfdw6z2k7wrsjgcs1w3scm9d397nz5nacadw1jpan8l56xa5y"; - }; + }); } \ No newline at end of file diff --git a/nix/.stack.nix/cborg.nix b/nix/.stack.nix/cborg.nix index 86e6a1d0..42067fd2 100644 --- a/nix/.stack.nix/cborg.nix +++ b/nix/.stack.nix/cborg.nix @@ -56,10 +56,10 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/well-typed/cborg"; rev = "80fbe0ee5e67a5622e2cb9eaa9d8594a2214322d"; sha256 = "1khd1v9yh6jdkcvzvknvhxpc1qvxvww0pp7c43w4hbvdyhs1q8wh"; - }; + }); postUnpack = "sourceRoot+=/cborg; echo source root reset to \$sourceRoot"; } \ No newline at end of file diff --git a/nix/.stack.nix/cs-blockchain.nix b/nix/.stack.nix/cs-blockchain.nix index ea9a5f5c..58383854 100644 --- a/nix/.stack.nix/cs-blockchain.nix +++ b/nix/.stack.nix/cs-blockchain.nix @@ -44,4 +44,11 @@ }; }; }; - } // rec { src = (pkgs.lib).mkDefault .././../specs/chain/hs; } \ No newline at end of file + } // { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { + url = "https://github.com/input-output-hk/fm-ledger-rules"; + rev = "bf059d1d593e7ef9f3b983a0c904e7bb81362af9"; + sha256 = "0rdyb0bfk69ndb86m91m9fzcfnhaj4q5yw0cgfj0ap4vmirz92cs"; + }); + postUnpack = "sourceRoot+=/specs/chain/hs; echo source root reset to \$sourceRoot"; + } \ No newline at end of file diff --git a/nix/.stack.nix/cs-ledger.nix b/nix/.stack.nix/cs-ledger.nix index c4aa1b00..85eeacc8 100644 --- a/nix/.stack.nix/cs-ledger.nix +++ b/nix/.stack.nix/cs-ledger.nix @@ -44,4 +44,11 @@ }; }; }; - } // rec { src = (pkgs.lib).mkDefault .././../specs/ledger/hs; } \ No newline at end of file + } // { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { + url = "https://github.com/input-output-hk/fm-ledger-rules"; + rev = "bf059d1d593e7ef9f3b983a0c904e7bb81362af9"; + sha256 = "0rdyb0bfk69ndb86m91m9fzcfnhaj4q5yw0cgfj0ap4vmirz92cs"; + }); + postUnpack = "sourceRoot+=/specs/ledger/hs; echo source root reset to \$sourceRoot"; + } \ No newline at end of file diff --git a/nix/.stack.nix/hedgehog.nix b/nix/.stack.nix/hedgehog.nix index 8ee8de97..737eb786 100644 --- a/nix/.stack.nix/hedgehog.nix +++ b/nix/.stack.nix/hedgehog.nix @@ -59,10 +59,10 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/haskell-hedgehog.git"; rev = "2e741bb53afb085741807018948ae17d956c53af"; sha256 = "0l0d1n2b68m0628j4yi214q5fy6pz777qfj1bc1lrra8scs5gcxh"; - }; + }); postUnpack = "sourceRoot+=/hedgehog; echo source root reset to \$sourceRoot"; } \ No newline at end of file diff --git a/nix/.stack.nix/plutus-prototype.nix b/nix/.stack.nix/plutus-prototype.nix index b7ca607a..c0aa3ce5 100644 --- a/nix/.stack.nix/plutus-prototype.nix +++ b/nix/.stack.nix/plutus-prototype.nix @@ -36,9 +36,9 @@ }; }; } // { - src = pkgs.fetchgit { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/avieth/plutus-prototype"; rev = "d094be301195fcd8ab864d793f114970426a4478"; sha256 = "1s932rghn4zn441waansp408b5bwk20rc1wsa5693a2nwnp4dijw"; - }; + }); } \ No newline at end of file diff --git a/nix/.stack.nix/small-steps.nix b/nix/.stack.nix/small-steps.nix index dd20b6ac..5f6e109f 100644 --- a/nix/.stack.nix/small-steps.nix +++ b/nix/.stack.nix/small-steps.nix @@ -40,4 +40,11 @@ }; }; }; - } // rec { src = (pkgs.lib).mkDefault .././../specs/semantics/hs; } \ No newline at end of file + } // { + src = (pkgs.lib).mkDefault (pkgs.fetchgit { + url = "https://github.com/input-output-hk/fm-ledger-rules"; + rev = "bf059d1d593e7ef9f3b983a0c904e7bb81362af9"; + sha256 = "0rdyb0bfk69ndb86m91m9fzcfnhaj4q5yw0cgfj0ap4vmirz92cs"; + }); + postUnpack = "sourceRoot+=/specs/semantics/hs; echo source root reset to \$sourceRoot"; + } \ No newline at end of file diff --git a/nix/pkgs.nix b/nix/pkgs.nix index ab3a35ae..fc63599f 100644 --- a/nix/pkgs.nix +++ b/nix/pkgs.nix @@ -16,7 +16,8 @@ let th-packages = [ "hedgehog" "cardano-crypto-wrapper" "cardano-crypto-test" "cardano-chain" - "small-steps" "cs-ledger" "cs-blockchain" ]; + "small-steps" "cs-ledger" "cs-blockchain" + ]; # Build the packageset with module support. # We can essentially override anything in the modules diff --git a/pkgs.nix b/pkgs.nix deleted file mode 100644 index cd0f4b1a..00000000 --- a/pkgs.nix +++ /dev/null @@ -1,24 +0,0 @@ -let - nixpkgs = builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/38db6fdfb9672a0206a2042447132094bc05a5ea.tar.gz"; -in -import nixpkgs { - config = { - packageOverrides = pkgs: { - haskell = pkgs.haskell // { - packages = pkgs.haskell.packages // { - ghc861 = pkgs.haskell.packages.ghc861.override { - overrides = self: super: { - basement = self.callHackage "basement" "0.0.8" {}; - memory = pkgs.haskell.lib.doJailbreak (self.callHackage "memory" "0.14.18" {}); - small-steps = self.callCabal2nix "small-steps" ./specs/semantics/hs {}; - cs-ledger = pkgs.haskell.lib.overrideCabal (self.callCabal2nix "cs-ledger" ./specs/ledger/hs {}) (old: { - enableParallelBuilding = false; - }); - cs-blockchain = self.callCabal2nix "cs-blockchain" ./specs/chain/hs {}; - }; - }; - }; - }; - }; - }; -} diff --git a/release.nix b/release.nix index b4098f90..db8636a4 100644 --- a/release.nix +++ b/release.nix @@ -6,7 +6,7 @@ localLib.nix-tools.release-nix { # packages from our stack.yaml or plan file (via nix/pkgs.nix) we # are intereted in building on CI via nix-tools. - packages = [ "cardano-chain" "cs-ledger" "small-steps" "cs-blockchain" ]; + packages = [ "cardano-chain" ]; # The set of jobs we consider crutial for each CI run. # if a single one of these fails, the build will be marked @@ -39,32 +39,15 @@ localLib.nix-tools.release-nix { # required-name = "cardano-chain-required-checks"; required-targets = jobs: [ - jobs.byronLedgerSpec - jobs.byronChainSpec - jobs.semanticsSpec - - jobs.nix-tools.libs.cs-blockchain.x86_64-darwin - jobs.nix-tools.libs.cs-blockchain.x86_64-linux - jobs.nix-tools.libs.small-steps.x86_64-darwin - jobs.nix-tools.libs.small-steps.x86_64-linux jobs.nix-tools.libs.cardano-chain.x86_64-darwin jobs.nix-tools.libs.cardano-chain.x86_64-linux jobs.nix-tools.tests.cardano-chain.cardano-chain-test.x86_64-darwin jobs.nix-tools.tests.cardano-chain.cardano-chain-test.x86_64-linux - jobs.nix-tools.libs.cs-ledger.x86_64-darwin - jobs.nix-tools.libs.cs-ledger.x86_64-linux - jobs.nix-tools.tests.cs-ledger.ledger-delegation-test.x86_64-darwin - jobs.nix-tools.tests.cs-ledger.ledger-delegation-test.x86_64-linux - # windows cross compilation targets jobs.nix-tools.libs.x86_64-pc-mingw32-cardano-chain.x86_64-linux - jobs.nix-tools.libs.x86_64-pc-mingw32-cs-blockchain.x86_64-linux - jobs.nix-tools.libs.x86_64-pc-mingw32-cs-ledger.x86_64-linux - jobs.nix-tools.libs.x86_64-pc-mingw32-small-steps.x86_64-linux jobs.nix-tools.tests.x86_64-pc-mingw32-cardano-chain.cardano-chain-test.x86_64-linux - jobs.nix-tools.tests.x86_64-pc-mingw32-cs-ledger.ledger-delegation-test.x86_64-linux ]; } diff --git a/specs/README.md b/specs/README.md deleted file mode 100644 index cf445828..00000000 --- a/specs/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Formal and executable specifications for the cardano chain - -This directory is organized as follows: - -- [`ledger/latex`](ledger/latex) contains the LaTeX specification of Cardano - ledger semantics. -- [`ledger/hs`](ledger/hs) contains an executable specification of Cardano - ledger semantics. -- [`chain/latex`](chain/latex) contains the LaTeX specification of Cardano - chain semantics. -- [`chain/hs`](chain/hs) contains an executable specification of Cardano chain - semantics. - -## Building the documents - -To build the `LaTeX` document run: - -```shell -nix-shell --pure --run make -``` - -For a continuous compilation of the `LaTeX` file run: - -```shell -nix-shell --pure --run "make watch" -``` - -## Building the executable specification - -The executable specifications can be built and tested using -[Nix](https://nixos.org/nix/). - -To build to go to the directory in which the executable specifications are -(e.g. [`ledger/hs`](ledger/hs)) and then run: - -```sh -nix-build -``` - -To start a REPL first make sure to run the configure script: - -```sh -nix-shell --pure --run "runhaskell Setup.hs configure" -``` - -then run: - -```sh -nix-shell --pure --run "runhaskell Setup.hs repl" -``` - -To test run: - -```sh -nix-shell --pure --run "runhaskell Setup.hs test" -``` - -### Development - -For running the tests you can use: - -```sh -nix-shell --pure --command "cabal new-test " -``` - -Example, while on the `specs/ledger/hs` directory one can run: - -```sh -nix-shell --pure --run "cabal new-test ledger-delegation-test" -``` - -To have the warnings not being treated as errors the `development` flag can be -used, e.g.: - -```sh -nix-shell --pure --run "cabal new-test ledger-delegation-test -fdevelopment" -``` diff --git a/specs/cabal.project b/specs/cabal.project deleted file mode 100644 index d1fc58dc..00000000 --- a/specs/cabal.project +++ /dev/null @@ -1,3 +0,0 @@ -packages: semantics/hs - ledger/hs - chain/hs diff --git a/specs/chain/hs/ChangeLog.md b/specs/chain/hs/ChangeLog.md deleted file mode 100644 index 5bd7ea27..00000000 --- a/specs/chain/hs/ChangeLog.md +++ /dev/null @@ -1,5 +0,0 @@ -# Revision history for cs-blockchain - -## 0.1.0.0 -- 2018-11-06 - -* First version. Released on an unsuspecting world. diff --git a/specs/chain/hs/LICENSE b/specs/chain/hs/LICENSE deleted file mode 100644 index 67c2cde3..00000000 --- a/specs/chain/hs/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2018 Input Output HK - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/specs/chain/hs/Setup.hs b/specs/chain/hs/Setup.hs deleted file mode 100644 index 9a994af6..00000000 --- a/specs/chain/hs/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/specs/chain/hs/cs-blockchain.cabal b/specs/chain/hs/cs-blockchain.cabal deleted file mode 100644 index 18b0fc86..00000000 --- a/specs/chain/hs/cs-blockchain.cabal +++ /dev/null @@ -1,67 +0,0 @@ --- Initial cs-blockchain.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/ - -name: cs-blockchain -version: 0.1.0.0 -synopsis: Executable specification of the Cardano blockchain --- description: -homepage: https://github.com/input-output-hk/cardano-chain -license: MIT -license-file: LICENSE -author: IOHK Formal Methods Team -maintainer: formal.methods@iohk.io --- copyright: -category: Testing -build-type: Simple -extra-source-files: ChangeLog.md -cabal-version: >=1.10 - -flag development - description: Disable '-Werror' - default: False - manual: True - -library - exposed-modules: Cardano.Spec.Chain.STS.Block - , Cardano.Spec.Chain.STS.Rule.BBody - , Cardano.Spec.Chain.STS.Rule.BHead - , Cardano.Spec.Chain.STS.Rule.Chain - , Cardano.Spec.Chain.STS.Rule.Epoch - , Cardano.Spec.Chain.STS.Rule.SigCnt - --other-modules: - -- other-extensions: - hs-source-dirs: src - default-language: Haskell2010 - build-depends: base >=4.11 && <5 - , bytestring - , containers - , cryptonite - , cs-ledger - , hedgehog - , lens - , memory - , small-steps - ghc-options: -Wall - -Wcompat - -Wincomplete-record-updates - -Wincomplete-uni-patterns - -Wredundant-constraints - if (!flag(development)) - ghc-options: -Werror - -test-suite chain-spec-test - hs-source-dirs: test - main-is: Main.hs - other-modules: Cardano.Spec.Chain.STS.Properties - type: exitcode-stdio-1.0 - default-language: Haskell2010 - build-depends: base - , data-ordlist - , hedgehog - , lens - , tasty - , tasty-hunit - , tasty-hedgehog - -- local deps - , cs-blockchain - , small-steps diff --git a/specs/chain/hs/default.nix b/specs/chain/hs/default.nix deleted file mode 100644 index 4bdd7ef5..00000000 --- a/specs/chain/hs/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - pkgs = import ../../../pkgs.nix; -in - pkgs.haskell.packages.ghc861.cs-blockchain diff --git a/specs/chain/hs/shell.nix b/specs/chain/hs/shell.nix deleted file mode 100644 index 56b62349..00000000 --- a/specs/chain/hs/shell.nix +++ /dev/null @@ -1,5 +0,0 @@ -let - pkgs = import ../../../pkgs.nix; -in pkgs.lib.overrideDerivation ((import ./.).env) (old: { - nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.cabal-install pkgs.haskell.packages.ghc861.ghcid ]; -}) diff --git a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Block.hs b/specs/chain/hs/src/Cardano/Spec/Chain/STS/Block.hs deleted file mode 100644 index 94ef8a5b..00000000 --- a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Block.hs +++ /dev/null @@ -1,93 +0,0 @@ -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE OverloadedLists #-} -{-# LANGUAGE TemplateHaskell #-} - -module Cardano.Spec.Chain.STS.Block where - -import Control.Lens ((^.), makeLenses, view) -import Crypto.Hash (hashlazy) -import Data.AbstractSize -import Data.ByteString.Lazy.Char8 (pack) -import Data.Sequence ((<|)) -import Data.Typeable (typeOf) -import Numeric.Natural (Natural) -import GHC.Generics (Generic) -import Control.State.Transition.Generator -import Ledger.Core -import Ledger.Delegation -import Ledger.Signatures - -data BlockHeader - = BlockHeader - { _prevHHash :: !Hash - -- ^ Hash of the previous block header, or 'genesisHash' in case of the - -- first block in a chain. - , _bSlot :: !Slot - -- ^ Absolute slot for which the block was generated. - , _bIssuer :: !VKey - -- ^ Block issuer. - , _bSig :: !(Sig VKey) - -- ^ Signature of the block by its issuer. - - -- TODO: BlockVersion – the protocol (block) version that created the block - - -- TODO: SoftwareVersion – the software version that created the block - } deriving (Eq, Show, Generic) - -makeLenses ''BlockHeader - --- We declare a specific instance here to avoid recursing into cardano-crypto -instance HasTypeReps BlockHeader where - typeReps x = typeOf x - <| typeOf (undefined :: Hash) - <| typeReps (x ^. bSlot :: Slot) - <> typeReps (x ^. bIssuer :: VKey) - <> typeReps (x ^. bSig :: Sig VKey) - -data BlockBody - = BlockBody - { _bDCerts :: [DCert] - -- ^ Delegation certificates. - } deriving (Eq, Show, Generic) - -instance HasTypeReps BlockBody -makeLenses ''BlockBody - --- | A block in the chain. The specification only models regular blocks since --- epoch boundary blocks will be largely ignored in the Byron-Shelley bridge. -data Block - = Block - { _bHeader :: BlockHeader - , _bBody :: BlockBody - } deriving (Eq, Show, Generic) - -instance HasTypeReps Block -makeLenses ''Block - --- | Compute the size (in words) that a block takes. -bSize :: Block -> Natural -bSize = fromIntegral . abstractSize acctMap - where - acctMap = [] - --- | Compute the size (in words) that a block header. -bHeaderSize :: BlockHeader -> Natural -bHeaderSize = fromIntegral . abstractSize acctMap - where - acctMap = [] - --- | Computes the hash of a header. -hashHeader :: BlockHeader -> Hash -hashHeader = hashlazy . pack . show --- TODO: we might want to serialize this properly, without using show... - - --- | Compute the epoch for the given _absolute_ slot -sEpoch :: Slot -> Epoch -sEpoch (Slot s) = Epoch $ s `div` slotsPerEpoch - where - -- Hardcoded number of slots per epoch, as per Byron. - slotsPerEpoch = 21600 - -instance HasSizeInfo Block where - isTrivial = null . view (bBody . bDCerts) diff --git a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/BBody.hs b/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/BBody.hs deleted file mode 100644 index 5052f6f4..00000000 --- a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/BBody.hs +++ /dev/null @@ -1,55 +0,0 @@ -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE MultiParamTypeClasses #-} - -module Cardano.Spec.Chain.STS.Rule.BBody where - -import Control.Lens ((^.)) -import Data.Set (Set) - -import Control.State.Transition -import Ledger.Core -import Ledger.Delegation -import Ledger.Update - -import Cardano.Spec.Chain.STS.Block - -data BBODY - -instance STS BBODY where - type Environment BBODY - = ( Epoch - , Slot - , PParams - , Set VKeyGenesis - ) - - type State BBODY = DIState - - type Signal BBODY = Block - - data PredicateFailure BBODY - = InvalidBlockSize - | DelegationFailure (PredicateFailure DELEG) - deriving (Eq, Show) - - initialRules = [] - - transitionRules = - [ do - TRC ((e, s, pps, gks), ds, b) <- judgmentContext - bSize b <= pps ^. maxBkSz ?! InvalidBlockSize - let diEnv - = DSEnv - { _dSEnvAllowedDelegators = gks - , _dSEnvEpoch = e - , _dSEnvSlot = s - , _dSEnvLiveness = pps ^. dLiveness - } - ds' <- trans @DELEG - $ TRC (diEnv, ds, b ^. bBody . bDCerts) - return $! ds' - ] - -instance Embed DELEG BBODY where - wrapFailed = DelegationFailure diff --git a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/BHead.hs b/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/BHead.hs deleted file mode 100644 index 49638180..00000000 --- a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/BHead.hs +++ /dev/null @@ -1,81 +0,0 @@ -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeApplications #-} - -module Cardano.Spec.Chain.STS.Rule.BHead where - -import Control.Lens ((^.)) -import Data.Map.Strict (Map) -import Data.Sequence (Seq) - -import Control.State.Transition -import Ledger.Core -import Ledger.Signatures -import Ledger.Update - -import Cardano.Spec.Chain.STS.Block -import Cardano.Spec.Chain.STS.Rule.Epoch -import Cardano.Spec.Chain.STS.Rule.SigCnt - -data BHEAD - -instance STS BHEAD where - type Environment BHEAD - = ( Slot - , Map VKeyGenesis VKey - ) - type State BHEAD - = ( Epoch - , Slot - , Hash - , Seq VKeyGenesis - , PParams - ) - - type Signal BHEAD = BlockHeader - - data PredicateFailure BHEAD - = HashesDontMatch -- TODO: Add fields so that users know the two hashes that don't match - | HeaderSizeTooBig -- TODO: Add more information here as well. - | SlotDidNotIncrease - -- ^ The block header slot number did not increase w.r.t the last seen slot - | SlotInTheFuture - -- ^ The block header slot number is greater than the current slot (As - -- specified in the environment). - | EpochFailure (PredicateFailure EPOCH) - | SigCntFailure (PredicateFailure SIGCNT) - deriving (Eq, Show) - - initialRules = [] - - transitionRules = - [ do - TRC ( (sNow, dms) - , (eLast, sLast, hLast, sgs, us) - , bh ) <- judgmentContext - -- Check header size - let sMax = us ^. maxHdrSz - bHeaderSize bh <= sMax ?! HeaderSizeTooBig - -- Check that the previous hash matches - bh ^. prevHHash == hLast ?! HashesDontMatch - -- Check sanity of current slot - let sNext = bh ^. bSlot - sLast < sNext ?! SlotDidNotIncrease - sNext <= sNow ?! SlotInTheFuture - -- Perform an epoch transition - eNext <- trans @EPOCH $ TRC (dms, eLast, sNext) - -- Perform a signature count transition - sgs' <- trans @SIGCNT $ TRC ((us, dms), sgs, bh ^. bIssuer) - return $! ( eNext - , sNext - , hashHeader bh - , sgs' - , us - ) - ] - -instance Embed EPOCH BHEAD where - wrapFailed = EpochFailure - -instance Embed SIGCNT BHEAD where - wrapFailed = SigCntFailure diff --git a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/Chain.hs b/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/Chain.hs deleted file mode 100644 index 8d884422..00000000 --- a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/Chain.hs +++ /dev/null @@ -1,170 +0,0 @@ -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE OverloadedLists #-} -{-# LANGUAGE OverloadedStrings #-} - -module Cardano.Spec.Chain.STS.Rule.Chain where - -import Control.Lens ((^.)) -import qualified Crypto.Hash -import Data.ByteString (ByteString) -import qualified Data.Map.Strict as Map -import Data.Set (Set) -import Data.Sequence (Seq) -import qualified Hedgehog.Gen as Gen -import qualified Hedgehog.Range as Range - -import Control.State.Transition -import Control.State.Transition.Generator -import Ledger.Core -import Ledger.Core.Generator -import Ledger.Delegation -import Ledger.Signatures -import Ledger.Update - -import Cardano.Spec.Chain.STS.Block -import Cardano.Spec.Chain.STS.Rule.BHead -import Cardano.Spec.Chain.STS.Rule.BBody - -data CHAIN - -instance STS CHAIN where - type Environment CHAIN = - ( Slot -- Current slot - , Set VKeyGenesis -- Genesis keys - , PParams -- Initial protocol parameters - ) - -- TODO: it can be confusing to have this in the environment. It will be - -- used by the initial rule only, and then we'll have to drag it for - -- eternity. The state contains the up to date protocol parameters. - - type State CHAIN = - ( Epoch - , Slot - , Hash - , Seq VKeyGenesis - , DIState - , PParams - ) - - type Signal CHAIN = Block - - data PredicateFailure CHAIN - = BHeadFailure (PredicateFailure BHEAD) - | BBodyFailure (PredicateFailure BBODY) - | LedgerFailure (PredicateFailure DELEG) - deriving (Eq, Show) - - initialRules = - [ do - IRC (s, gks, pps) <- judgmentContext - let dsenv - = DSEnv - { _dSEnvAllowedDelegators = gks - , _dSEnvEpoch = sEpoch s - , _dSEnvSlot = s - , _dSEnvLiveness = pps ^. dLiveness - } - ds <- trans @DELEG $ IRC dsenv - return $! ( Epoch 0 - , Slot 0 - , genesisHash - , [] - , ds - , pps - ) - ] - - transitionRules = - [ do - TRC - ( (sNow, gks, _) - , (eLast, sLast, hLast, sgs, ds, us) - , b ) <- judgmentContext - - (eNext, sNext, h', sgs', us') <- trans @BHEAD $ TRC ( (sNow, ds ^. dms) - , (eLast, sLast, hLast, sgs, us) - , b ^. bHeader ) - - ds' <- trans @BBODY $ TRC ( (eNext, sNext, us, gks) - , ds - , b ) - - return $! (eNext, sNext, h', sgs', ds', us') - ] - -instance Embed DELEG CHAIN where - wrapFailed = LedgerFailure - -instance Embed BHEAD CHAIN where - wrapFailed = BHeadFailure - -instance Embed BBODY CHAIN where - wrapFailed = BBodyFailure - -genesisHash :: Hash --- Not sure we need a concrete hash in the specs ... -genesisHash = Crypto.Hash.hash ("" :: ByteString) - --------------------------------------------------------------------------------- --- Generators --------------------------------------------------------------------------------- - -instance HasTrace CHAIN where - initEnvGen = - do - -- In mainet the maximum header size is set to 2000000 and the maximum - -- block size is also set to 2000000, so we have to make sure we cover - -- those values here. The upper bound is arbitrary though. - mHSz <- Gen.integral (Range.constant 0 4000000) - mBSz <- Gen.integral (Range.constant 0 4000000) - -- The delegation liveness parameter is arbitrarily determined. - d <- SlotCount <$> Gen.integral (Range.linear 0 10) - -- The size of the rolling widow is arbitrarily determined. - w <- Gen.integral (Range.linear 0 10) - -- The percentage of the slots will typically be between 1/5 and 1/4, - -- however we want to stretch that range a bit for testing purposes. - t <- Gen.double (Range.constant (1/6) (1/3)) - -- The slots per-epoch is arbitrarily determined. - spe <- SlotCount <$> Gen.integral (Range.linear 1 1000) - let initPPs - = PParams - { _maxHdrSz = mHSz - , _maxBkSz = mBSz - , _dLiveness = d - , _bkSgnCntW = w - , _bkSgnCntT = t - , _bkSlotsPerEpoch = spe - } - initGKeys <- Gen.set (Range.constant 1 70) vkgenesisGen - -- If we want to generate large traces, we need to set up the value of the - -- "clock-slot" to a sufficiently large value. - clockSlot <- Slot <$> - Gen.integral (Range.constant 32768 2147483648) - return (clockSlot, initGKeys, initPPs) - - sigGen (_, gks, _) (e, Slot s, h, _sgs, ds, us) = do - -- We'd expect the slot increment to be close to 1, even for large Gen's - -- size numbers. - slotInc <- Gen.integral (Range.exponential 0 10) - -- Get some random issuer from the delegates of the delegation map. - vkI <- Gen.element $ Map.elems (ds ^. dms) - let dsEnv - = DSEnv - { _dSEnvAllowedDelegators = gks - , _dSEnvEpoch = e - , _dSEnvSlot = Slot s - , _dSEnvLiveness = us ^. dLiveness } - dCerts <- dcertsGen dsEnv - let bh - = BlockHeader - { _prevHHash = h - , _bSlot = Slot (s + slotInc) - , _bIssuer = vkI - , _bSig = Sig vkI (owner vkI) - } - bb - = BlockBody - { _bDCerts = dCerts } - return $ Block bh bb diff --git a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/Epoch.hs b/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/Epoch.hs deleted file mode 100644 index 57912120..00000000 --- a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/Epoch.hs +++ /dev/null @@ -1,25 +0,0 @@ -{-# LANGUAGE TypeFamilies #-} - -module Cardano.Spec.Chain.STS.Rule.Epoch where - -import Data.Map.Strict (Map) - -import Control.State.Transition -import Ledger.Core - -import Cardano.Spec.Chain.STS.Block - -data EPOCH - -instance STS EPOCH where - type Environment EPOCH = Map VKeyGenesis VKey - type State EPOCH = Epoch - type Signal EPOCH = Slot - data PredicateFailure EPOCH = X - deriving (Eq, Show) - initialRules = [] - transitionRules = - [ do - TRC (_, _, s) <- judgmentContext - return $! sEpoch s - ] diff --git a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/SigCnt.hs b/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/SigCnt.hs deleted file mode 100644 index 4fd5c4e3..00000000 --- a/specs/chain/hs/src/Cardano/Spec/Chain/STS/Rule/SigCnt.hs +++ /dev/null @@ -1,65 +0,0 @@ -{-# LANGUAGE TypeFamilies #-} - -module Cardano.Spec.Chain.STS.Rule.SigCnt where - -import Control.Lens ((^.)) -import qualified Data.Map.Strict as Map -import Data.Map.Strict (Map) -import Data.Sequence (Seq, (|>)) -import qualified Data.Sequence as S - -import Control.State.Transition - -import Ledger.Core -import Ledger.Update - -data SIGCNT - -instance STS SIGCNT where - type Environment SIGCNT - = ( PParams - , Map VKeyGenesis VKey - ) - - type State SIGCNT = Seq VKeyGenesis - - type Signal SIGCNT = VKey - - data PredicateFailure SIGCNT - = TooManyIssuedBlocks VKeyGenesis -- The given genesis key issued too many blocks. - | NotADelegate - -- ^ The key signing the block is not a delegate of a genesis key. - | NonInjectiveDelegationMap - -- ^ Delegation rules should restrict the delegation map to be injective. - -- - -- Should not be needed once - -- https://github.com/input-output-hk/cardano-chain/issues/257 gets - -- resolved. - - deriving (Eq, Show) - - initialRules = [] - - transitionRules = - [ do - TRC ((pps, dms), sgs, vk) <- judgmentContext - let w = pps ^. bkSgnCntW - t = pps ^. bkSgnCntT - case Map.keys (Map.filter (== vk) dms) of - -- Currently we do not restrict the number of delegators to a given key - -- in the delegation rules. See: https://github.com/input-output-hk/cardano-chain/issues/257 - -- - -- Even we implement the restriction in the delegation rules, we might - -- still want to check this (unless the types forbid such situation). - [vkG] -> do - let sgs' = S.drop (S.length sgs + 1 - w) (sgs |> vkG) - nrSignedBks = fromIntegral (S.length (S.filter (==vkG) sgs')) - nrSignedBks <= fromIntegral w * t ?! TooManyIssuedBlocks vkG - return $! sgs' - [] -> do - failBecause NotADelegate - return sgs -- TODO: this is a quite inconvenient encoding for this transition system! - _ -> do - failBecause NonInjectiveDelegationMap - return sgs - ] diff --git a/specs/chain/hs/test/Cardano/Spec/Chain/STS/Properties.hs b/specs/chain/hs/test/Cardano/Spec/Chain/STS/Properties.hs deleted file mode 100644 index bb09fc09..00000000 --- a/specs/chain/hs/test/Cardano/Spec/Chain/STS/Properties.hs +++ /dev/null @@ -1,27 +0,0 @@ -{-# LANGUAGE TypeFamilies #-} -module Cardano.Spec.Chain.STS.Properties where - -import Control.Lens ((^..)) -import Data.List.Ordered (sort, nub) -import Hedgehog - ( MonadTest - , Property - , assert - , forAll - , property - ) - -import Control.State.Transition.Generator -import Control.State.Transition.Trace - -import Cardano.Spec.Chain.STS.Block -import Cardano.Spec.Chain.STS.Rule.Chain - -slotsIncrease :: Property -slotsIncrease = property $ forAll trace >>= slotsIncreaseInTrace - -slotsIncreaseInTrace :: MonadTest m => Trace CHAIN -> m () -slotsIncreaseInTrace tr = assert $ slots == sortedSlots && nub slots == slots - where blocks = traceSignals NewestFirst tr - slots = blocks ^.. traverse . bHeader . bSlot - sortedSlots = sort slots diff --git a/specs/chain/hs/test/Main.hs b/specs/chain/hs/test/Main.hs deleted file mode 100644 index 78618ad1..00000000 --- a/specs/chain/hs/test/Main.hs +++ /dev/null @@ -1,18 +0,0 @@ - -module Main (main) where - -import Test.Tasty (TestTree, defaultMain, testGroup, localOption) -import Test.Tasty.Hedgehog (testProperty) -import Test.Tasty.Ingredients.ConsoleReporter (UseColor(Auto)) - -import Cardano.Spec.Chain.STS.Properties - -main :: IO () -main = defaultMain tests - where - tests :: TestTree - tests = - testGroup "Chain" - [ testGroup "Properties" - [testProperty "Increasing slots" slotsIncrease] - ] diff --git a/specs/chain/latex/Makefile b/specs/chain/latex/Makefile deleted file mode 100644 index ac903d18..00000000 --- a/specs/chain/latex/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -## -## Makefile for a specification of the blockchain layer, based on: -## -## https://tex.stackexchange.com/questions/40738/how-to-properly-make-a-latex-project -## - -# Document name -DOCNAME = blockchain-spec - -# You want latexmk to *always* run, because make does not have all the info. -# Also, include non-file targets in .PHONY so they are run regardless of any -# file of the given name existing. -.PHONY: $(DOCNAME).pdf all clean - -# The first rule in a Makefile is the one executed by default ("make"). It -# should always be the "all" rule, so that "make" and "make all" are identical. -all: $(DOCNAME).pdf - -## -## CUSTOM BUILD RULES -## - - -## -## MAIN LATEXMK RULE -## - -# -pdf tells latexmk to generate PDF directly (instead of DVI). -# -pdflatex="" tells latexmk to call a specific backend with specific options. -# -use-make tells latexmk to call make for generating missing files. - -# -interaction=nonstopmode keeps the pdflatex backend from stopping at a -# missing file reference and interactively asking you for an alternative. - -$(DOCNAME).pdf: $(DOCNAME).tex - latexmk -pdf -pdflatex="pdflatex -interaction=nonstopmode" -use-make $(DOCNAME).tex - -watch: $(DOCNAME).tex - latexmk -pvc -pdf -pdflatex="pdflatex -interaction=nonstopmode -synctex=1" -use-make $(DOCNAME).tex - -clean: - latexmk -CA - -install: - mkdir -pv ${out}/nix-support/ - cp blockchain-spec.pdf ${out}/ - echo "doc-pdf blockchain-spec ${out}/blockchain-spec.pdf" > ${out}/nix-support/hydra-build-products diff --git a/specs/chain/latex/blockchain-spec.tex b/specs/chain/latex/blockchain-spec.tex deleted file mode 100644 index 4dde5de2..00000000 --- a/specs/chain/latex/blockchain-spec.tex +++ /dev/null @@ -1,1345 +0,0 @@ -\documentclass[11pt,a4paper]{article} -\usepackage{amsmath} -\usepackage{amssymb} -\usepackage{array} -\usepackage{extarrows} -\usepackage{float} -\usepackage[margin=2.5cm]{geometry} -\usepackage[unicode=true,pdftex,pdfa]{hyperref} -\usepackage[capitalise,noabbrev,nameinlink]{cleveref} -\usepackage[utf8]{inputenc} -\usepackage{latexsym} -\usepackage{listings} -\usepackage{mathpazo} % nice fonts -\usepackage{mathtools} -\usepackage{microtype} -\usepackage[colon]{natbib} -\usepackage[toc,page]{appendix} -%% -%% Package `semantic` can be used for writing inference rules. -%% -\usepackage{semantic} -\usepackage{slashed} -\usepackage{stmaryrd} -\usepackage[colorinlistoftodos,prependcaption,textsize=tiny]{todonotes} - -\hypersetup{ - pdftitle={Specification of the Blockchain Layer}, - breaklinks=true, - bookmarks=true, - colorlinks=false, - linkcolor={blue}, - citecolor={blue}, - urlcolor={blue}, - linkbordercolor={white}, - citebordercolor={white}, - urlbordercolor={white} -} -\floatstyle{boxed} -\restylefloat{figure} - -%% Setup for the semantic package -\setpremisesspace{20pt} - -\DeclareMathOperator{\dom}{dom} -\DeclareMathOperator{\range}{range} - -%% -\newcommand{\powerset}[1]{\mathbb{P}~#1} -\newcommand\Set[2]{\left\{\,#1\mid#2\,\right\}} -\newcommand{\restrictdom}{\lhd} -\newcommand{\subtractdom}{\mathbin{\slashed{\restrictdom}}} -\newcommand{\restrictrange}{\rhd} -\newcommand{\union}{\cup} -\newcommand{\unionoverride}{\mathbin{\underrightarrow\cup}} -\newcommand{\uniondistinct}{\uplus} -\newcommand{\var}[1]{\mathit{#1}} -\newcommand{\fun}[1]{\mathsf{#1}} -\newcommand{\type}[1]{\mathsf{#1}} -\newcommand{\pp}[1]{\mathsf{#1}} -\newcommand{\size}[1]{\left| #1 \right|} -\newcommand{\trans}[2]{\xlongrightarrow[\textsc{#1}]{#2}} -\newcommand{\seqof}[1]{#1^{*}} -\newcommand{\serialised}[1]{\llbracket \var{#1} \rrbracket} - -\newcommand{\leteq}{\ensuremath{\mathrel{\mathop:}=}} - -% Partial and total function aliases -\newcommand{\totalf}{\to} -\newcommand{\partialf}{\mapsto} - -%% -%% Types -%% -\newcommand{\Hash}{\type{Hash}} % hashes of various things, including blocks -\newcommand{\Slot}{\type{Slot}} -\newcommand{\SlotCount}{\type{SlotCount}} -\newcommand{\BlockIx}{\type{BlockIx}} -\newcommand{\Block}{\type{Block}} -\newcommand{\DCert}{\type{DCert}} -\newcommand{\Queue}{\type{Q}} - -\newcommand{\VKey}{\type{VKey}} -\newcommand{\VKeyGen}{\type{VKey_G}} -\newcommand{\Sig}{\type{Sig}} -\newcommand{\Data}{\type{Data}} -\newcommand{\DelegState}{\type{DIState}} - -\newcommand{\ProtParams}{\type{PParams}} % protocol parameters -\newcommand{\Nothing}{\Diamond} - -%% -%% Function and relation names -%% -\newcommand{\bsizename}{bSize} -\newcommand{\bhdrsizename}{bHeaderSize} -\newcommand{\verifyname}{verify} - -\newcommand{\isebbname}{bIsEBB} -\newcommand{\bcertsname}{bCerts} -\newcommand{\bhsigname}{bhSig} -\newcommand{\bhissuername}{bhissuer} - -%% -%% Functions and relations -%% -\newcommand{\verify}[3]{\fun{\verifyname} ~ #1 ~ #2 ~ #3} -\newcommand{\bsize}[1]{\fun{\bsizename} ~ #1} -\newcommand{\bhdrsize}[1]{\fun{\bhdrsizename} ~ #1} -\newcommand{\delegation}[2]{\fun{\delegationname} ~ #1 ~ #2} -\newcommand{\signmap}[1]{\fun{\signmapname} ~ #1} -\newcommand{\qrestr}[2]{\fun{\qrestrname} ~ #1 ~ #2} -\newcommand{\trimix}[2]{\fun{\trimixname} ~ #1 ~ #2} -\newcommand{\incixmap}[3]{\fun{\incixmapname} ~ #1 ~ #2 ~ #3} - -\newcommand{\hashofblock}[1]{\fun{\hashofblockname} ~ #1} -\newcommand{\blocksizelimit}[2]{\fun{\blocksizelimitname} ~ #1 ~ #2} -\newcommand{\isebb}[1]{\fun{\isebbname} ~ #1} -\newcommand{\bcerts}[1]{\fun{\bcertsname} ~ #1} -\newcommand{\bhsig}[1]{\fun{\bhsigname} ~ #1} -\newcommand{\bhissuer}[1]{\fun{\bhissuername} ~ #1} - -\newcommand{\qpop}[1]{\fun{\qpopname} ~ #1} -\newcommand{\qhead}[1]{\fun{\qheadname} ~ #1} -\newcommand{\qpush}[1]{\fun{\qpushname} ~ #1} - - -% A type alias for a map from a genesis block verification key to a queue of indices -\newcommand{\mapqueue}{\mathcal{Q}} -% comments -\newcommand{\marko}[1]{\todo[size=\small, color=yellow!40, inline]{Marko: #1}} - -\begin{document} - -\title{Specification of the Blockchain Layer} - -\author{Marko Dimjašević \\ Nicholas Clarke} - -\date{December 13, 2018} - -\maketitle - -\begin{abstract} - This documents defines inference rules for operations on a blockchain as a - specification of the blockchain layer of Cardano in the Byron release and in - a transition to the Shelley release. - % - In particular, a block validity definition is given, which is accompanied by - small-step operational semantics inference rules. -\end{abstract} - -\section*{List of Contributors} -\label{acknowledgements} - -Damian Nadales, Yun Lu. - -\tableofcontents -\listoffigures - -\section{Introduction} -\label{sec:introduction} - -The idea behind this document is to formalise what it means for a new block to -be added to the blockchain to be valid. -% -The scope of the document is the Byron release and a transition phase to the -Shelley release of the Cardano blockchain platform. - - -Unless a new block is valid, it cannot be added to the blockchain and thereby -extend it. -% -This is needed for a system that is subscribed to the blockchain and keeps a -copy of it locally. -% -In particular, this document gives a formalisation that should be -straightforward to implement in a programming language, e.g., in Haskell. - -This document is intended to be read in conjunction with \cite{byron_ledger_spec}, -which covers the payload carried around in the blockchain. Certain of the -underlying systems and types defined will rely on definitions in that document. - -\section{Preliminaries} -\label{sec:preliminaries} - -\begin{description} -\item[Powerset] Given a set $\type{X}$, $\powerset{\type{X}}$ is the set of all - the subsets of $X$. -\item[Sequence] Given a set $\type{X}$, $\seqof{\type{X}}$ is a sequence - having elements taken from $\type{X}$. - % - The empty sequence is denoted by $\epsilon$, and given a sequence $\Lambda$, - $\Lambda; x$ is the sequence that results from appending - $x \in \type{X}$ to $\Lambda$. - % - Furthermore, $\epsilon$ is an identity element for sequence joining: - $\epsilon; x = x; \epsilon = x$. -\item[Dropping on sequences] Given a sequence $\Lambda$, - $\Lambda \shortdownarrow n$ is the sequence that is obtained after removing - (dropping) the first $n$ elements from $\Lambda$. If $n \leq 0$ then - $\Lambda \shortdownarrow n = \Lambda$. -\item[Appending with a moving window] Given a sequence $\Lambda$, we define - $$\Lambda ;_w x \leteq (\Lambda; x) \shortdownarrow (\size{\Lambda} + 1 - w)$$ -\item[Filtering on sequences] Given a sequence $\Lambda$, and a predicate $p$ - on the elements of $\Lambda$, $\fun{filter}~p~\Lambda$ is the sequence that - contains all the elements of $\Lambda$ that satisfy $p$, in the same order - they appear on $\Lambda$. -\item[Option type] An option type in type $A$ is denoted as $A^? = A + \Nothing$. The - $A$ case corresponds to a case when there is a value of type $A$ and the $1$ - case corresponds to a case when there is no value. -\item[Union override] The union override operation is defined in - Figure~\ref{fig:unionoverride}. - % - \begin{figure} - \begin{align*} - \var{K} \restrictdom \var{M} - & = \{ i \mapsto o \mid i \mapsto o \in \var{M}, ~ i \in \var{K} \} - & \text{domain restriction} - \\ - \var{K} \subtractdom \var{M} - & = \{ i \mapsto o \mid i \mapsto o \in \var{M}, ~ i \notin \var{K} \} - & \text{domain exclusion} - \\ - \var{M} \restrictrange \var{V} - & = \{ i \mapsto o \mid i \mapsto o \in \var{M}, ~ o \in \var{V} \} - & \text{range restriction} - \\ - & \unionoverride \in (A \mapsto B) \to (A \mapsto B) \to (A \mapsto B) - & \text{union override}\\ - & d_0 \unionoverride d_1 = d_1 \cup (\dom d_1 \subtractdom d_0) - \end{align*} - \caption{Definition of the Union Override Operation} - \label{fig:unionoverride} - \end{figure} -\end{description} - -\subsection{Sets} -\label{sec:sets} - -There are several standard sets used in the document: -% -\begin{description} -\item[Booleans] The set of booleans is denoted with $\mathbb{B}$ and has two - values, $\mathbb{B} = \{\bot, \top\}$. -\item[Natural numbers] The set of natural numbers is denoted with - $\mathbb{N}$ and defined as $\mathbb{N} = \{0, 1, 2, \dots\}$. -\end{description} - -\section{Update interface} - -\newcommand{\bupdprop}[1]{\fun{bUpdProp}\ #1} -\newcommand{\bupdvotes}[1]{\fun{bUpdVotes}\ #1} -\newcommand{\bprotver}[1]{\fun{bProtVer}\ #1} -\newcommand{\bendorsment}[1]{\fun{bEndorsment}\ #1} - -\newcommand{\Bupisig}{\type{BUPISig}} -% Imported definitions - -\newcommand{\UPIEnv}{\type{UPIEnv}} -\newcommand{\UPIState}{\type{UPIState}} -\newcommand{\UProp}{\type{UProp}} -\newcommand{\Vote}{\ensuremath{\type{Vote}}} -\newcommand{\ProtVer}{\ensuremath{\type{ProtVer}}} - -We define a general update interface to abstract over the various update state -transitions which happen when a new block is processed. Figure -\ref{fig:defs:bupi} defines the type of signals used for this system. Figure -\ref{fig:rules:bupi} defines the rules for this system. The two rules handle the -cases where there is or is not an update proposal contained within the block. - -\begin{figure}[ht] - \emph{Update interface signals} - \begin{equation*} - \Bupisig = - \left( - \begin{array}{r@{~\in~}lr} - \var{mprop} & \UProp^{?} & \text{Possible update proposal}\\ - \var{votes} & \seqof{\Vote} & \text{Votes for update proposals}\\ - \var{end} & (\VKey \times \ProtVer) & \text{Protocol version endorsment} - \end{array} - \right) - \end{equation*} - - \caption{Update interface processing types and functions} - \label{fig:defs:bupi} -\end{figure} - -\begin{figure}[ht] - \emph{Update interface processing transitions} - \begin{equation*} - \_ \vdash \var{\_} \trans{bupi}{\_} \var{\_} \subseteq - \powerset (\UPIEnv \times \UPIState \times \Bupisig \times \UPIState) - \end{equation*} - \caption{Update interface processing transition-system types} - \label{fig:ts-types:bupi} -\end{figure} - -\begin{figure}[ht] - \begin{equation*} - \inference - { \Gamma \vdash \var{us} \trans{upireg}{\var{prop}} \var{us'} - \\ - \Gamma \vdash \var{us'} \trans{upivotes}{\var{votes}} \var{us''} - & - \Gamma \vdash \var{us''} \trans{upiend}{\var{end}} \var{us'''} - } - { - \Gamma \vdash - {\var{us}} - \trans{bupi} - { - \left( - \begin{array}{l} - \var{prop} \\ - \var{votes} \\ - \var{end} - \end{array} - \right) - } - {\var{us'''}} - } - \end{equation*} - \vspace{20pt} - \begin{equation*} - \inference - { \Gamma \vdash \var{us} \trans{upivotes}{\var{votes}} \var{us'} - & - \Gamma \vdash \var{us'} \trans{upiend}{\var{end}} \var{us''} - } - { - \Gamma \vdash \var{us} - \trans{bupi}{ - \left( - \begin{array}{l} - \Nothing \\ - \var{votes} \\ - \var{end} - \end{array} - \right) - } - \var{us''} - } - \end{equation*} - \caption{Update interface processing rules} - \label{fig:rules:bupi} -\end{figure} - -\clearpage - -\section{Epoch transitions} - -\newcommand{\Epoch}{\type{Epoch}} - -\newcommand{\ETState}{\type{ETState}} -\newcommand{\ETEnv}{\type{ETEnv}} - -\newcommand{\sepochname}{sEpoch} -\newcommand{\sepoch}[2]{\fun{\sepochname}\ #1\ #2} - -During each block transition, we must determine whether that block sits on an -epoch boundary and, if so, carry out various actions which are done on that -boundary. In the BFT era, the only computation carried out at the epoch boundary -is the update of protocol versions. - -In figure~\ref{fig:defs:epoch} we give the definition of the $\sepoch$ -function to determine the epoch corresponding to a given slot. This relies on -keeping a map of the length of each epoch. Such a map is also required by the -database layer to find the requisite epoch file to look up a given block, and is -hence maintained by the ledger layer for this purpose. We envision that an -implementation may of course choose a more compact representation for this -partial function that only records the changes in epoch length, rather than -storing a length for each epoch. - -Figure \ref{fig:rules:epoch} determines when an epoch change has occurred and -updates the update state to the correct version. - -\begin{figure}[ht] - \emph{Derived functions} - % - \begin{equation*} - \begin{array}{rlr} - \fun{\sepochname} & \in \Slot \totalf (\Epoch \partialf \SlotCount) \totalf \Epoch & \text{Epoch containing this slot} \\ - \end{array} - \end{equation*} - \begin{equation*} - \fun{\sepochname}~\var{slot}~\fun{elens} = \min \left\{ e \middle| slot < \sum_{i \leq e} \fun{elens}~i \right\} - \end{equation*} - - \emph{Protocol parameters} - \begin{equation*} - \begin{array}{r@{~\partialf~}l!{~\in~\ProtParams~}r} - \pp{slotsPerEpoch} & \SlotCount & \text{Number of slots in the current epoch} \\ - \end{array} - \end{equation*} - - \caption{Epoch transition types and functions} - \label{fig:defs:epoch} -\end{figure} - -\begin{figure}[ht] - - \emph{Epoch transition states} - \begin{equation*} - \ETState = - \left( - \begin{array}{r@{~\in~}lr} - \var{elens} & \Epoch \partialf \SlotCount & \text{Historical epoch lengths} \\ - \var{e_c} & \Epoch & \text{Current epoch} \\ - \var{us} & \UPIState & \text{Update interface state} - \end{array} - \right) - \end{equation*} - - \emph{Epoch transition transitions} - \begin{equation*} - \_ \vdash \var{\_} \trans{epoch}{\_} \var{\_} \subseteq - \powerset ((\VKey \mapsto \VKeyGen) \times \ETState \times \Slot \times \ETState) - \end{equation*} - \caption{Epoch transition transition-system types} - \label{fig:ts-types:epoch} -\end{figure} - -\begin{figure}[ht] - \begin{equation*} - \inference - { - \var{e_c} \geq \sepoch{s}{elens} - } - {\var{dms} \vdash - { - \left( - {\begin{array}{c} - \var{elens} \\ - \var{e_c} \\ - \var{us} - \end{array} - } - \right) - } - \trans{epoch}{s} - { - \left( - {\begin{array}{c} - \var{elens} \\ - \var{e_c} \\ - \var{us} - \end{array} - } - \right) - } - } -\end{equation*} -\vspace{20pt} -\begin{equation*} - \inference - { - \pp{slotsPerEpoch} \mapsto \var{es} \in \fun{pps}~\var{us} & \var{e_n} \leteq \sepoch{s}{elens} \\ - \var{e_c} < \var{e_n} - \\ - {\left( - \begin{array}{l} - \var{\var{e_c}} \\ - \var{s} \\ - \var{dms} - \end{array} - \right) - } - \vdash \var{us} \trans{upiec}{\var{e_n}} \var{us'} - } - { - \var{dms} \vdash - { - \left( - {\begin{array}{c} - \var{elens} \\ - \var{e_c} \\ - \var{us} - \end{array} - } - \right) - } - \trans{epoch}{\var{s}} - { - \left( - {\begin{array}{c} - \var{elens} \unionoverride \{\var{e_n} \mapsto \var{es}\}\\ - \var{e_n} \\ - \var{us'} - \end{array} - } - \right) - } -} -\end{equation*} -\caption{Epoch transition rules} -\label{fig:rules:epoch} -\end{figure} - -\clearpage -\section{Permissive BFT} - -The majority of this specification is concerned with the processing of the -\textit{ledger}; that is, the content (contained in both the block header and -the block body). In addition, however, we must also concern ourselves with the -protocol used to transmit the blocks and whether, according to that protocol, we -may validly extend the chain with a new block (assuming that block forms a valid -extension to the chain under the ledger rules). - -Cardano's planned evolution can be split into roughly three eras: -\begin{description} -\item[Byron/Ouroboros] In the Byron/Ouroboros era, the Ouroboros (\cite{ouroboros}) - protocol is used to control who is eligible to issue a block, using a stake - distribution mediated by heavyweight delegation certificates. The Byron - payload includes such things as VSS and payloads verified by individual - signatures. -\item[Handover] In the handover era, blocks will be issued according to - Ouroboros BFT (\cite{ouroboros_bft}). The Byron payload will be retained, although - parts of will be superfluous. -\item[Shelley/Praos] In the Shelley/Praos era, blocks will be issued according - to the Ouroboros Praos (\cite{ouroboros_praos}) protocol, with stake distribution - determined according to the new delegation design in \cite{delegation_design}. -\end{description} - -During the handover era (as described in this document), while blocks will be -issued according to Ouroboros BFT, they will be validated according to a variant -known as Permissive BFT. This is designed such that it will successfully -validate blocks issued both under Ouroboros and under Ouroboros BFT (with a high -probability - see Appendix \ref{apdx:calculating-t}). - -This section therefore will describe the section of the rules concerned with the -Permissive BFT protocol. Note that all of these are concerned only with the -block header, since the block body is entirely concerned with the ledger. - -\subsection{Counting signed blocks} - -\newcommand{\BSCEnv}{\type{BSCEnv}} -\newcommand{\BSCState}{\type{BSCState}} - -To guard against the compromise of a minority of the genesis keys, -we require that in the rolling window of the last $w$ blocks, the number of -blocks signed by keys that $sk_s$ delegated to is no more than a threshold $w -\cdot t$, where $t$ is a constant that will be picked in the range -$1/5 \leq t \leq 1/4$. Initial research suggests setting $t=0.22$ as a good -value. Specifically, given $K=2160$, we would allow a single genesis key to -issue (via delegates) $475$ blocks, but a $476^{\text{th}}$ block would be -rejected. See Appendix \ref{apdx:calculating-t} for the background on this value. - -\begin{figure}[ht] - \emph{Protocol parameters} - \begin{equation*} - \begin{array}{r@{~\partialf~}l!{~\in~\ProtParams~}r} - \pp{blockSignatureCountWindow} & \mathbb{N} & \text{Block signature count window size} \\ - \pp{blockSignatureCountThreshold} & \left[\frac{1}{5}, \frac{1}{4}\right] & \text{Block signature count threshold} \\ - \end{array} - \end{equation*} - \caption{Blockchain signature count protocol parameters} - \label{fig:defs:sigcnt} -\end{figure} - -Figure \ref{fig:rules:sigcnt} gives the rules for signature counting. We verify -that the key that delegates to the signer of this block has not already signed -more than its allowed threshold of blocks. If there are no delegators for the -given key, or if there is more than one delegator, the rule will fail to trigger. -% -We then update the sequence of signers, and drop those elements that fall -outside the size of the moving window $w$. - -\begin{figure}[ht] - \emph{Block signature count environments} - \begin{equation*} - \BSCEnv = - \left( - \begin{array}{r@{~\in~}lr} - \var{pps} & \ProtParams & \text{Protocol parameters} \\ - \var{ds} & \DelegState & \text{Delegation state} \\ - \end{array} - \right) - \end{equation*} - - \emph{Block signature count transitions} - \begin{equation*} - \_ \vdash \var{\_} \trans{sigcnt}{\_} \var{\_} \subseteq - \powerset (\BSCEnv \times \seqof{\VKeyGen} \times \VKey \times \seqof{\VKeyGen}) - \end{equation*} - \caption{Block signature count transition-system types} - \label{fig:ts-types:sigcnt} -\end{figure} - -\begin{figure}[ht] - \begin{equation*} - \inference - { - \pp{blockSignatureCountWindow} \partialf \var{w} \in pps & \pp{blockSignatureCountThreshold} \partialf \var{t} \in pps \\ - \{\var{vk_g}\} \leteq (\fun{dms} ~ \var{ds}) \restrictrange \{\var{vk_d}\} - & \var{sgs'} \leteq \var{sgs};_w {vk_g} & - \size{\fun{filter}~(=\var{vk_g})~\var{sgs'}} \leq w \cdot t \\ - } - { - \left( - {\begin{array}{c} - \var{pps} \\ - \var{ds} - \end{array}} - \right) - \vdash - {\var{sgs}} - \trans{sigcnt}{\var{vk_d}} - {\var{sgs'}} - } - \label{eq:rule:sigcnt} - \end{equation*} - \caption{Block signature count rules} - \label{fig:rules:sigcnt} -\end{figure} - -\clearpage - -\subsection{Permissive BFT Header Processing} - -\newcommand{\PBFTEnv}{\type{PBFTEnv}} -\newcommand{\PBFTState}{\type{PBFTState}} - -\newcommand{\Bhead}{\type{BlockHeader}} -\newcommand{\Bhtosign}{\type{BHToSign}} - -\newcommand{\bhslotname}{bhSlot} -\newcommand{\bhslot}[1]{\fun{\bhslotname}\ #1} -\newcommand{\bhhashname}{bhHash} -\newcommand{\bhhash}[1]{\fun{\bhhashname}\ #1} -\newcommand{\bhprevhashname}{bhPrevHash} -\newcommand{\bhprevhash}[1]{\fun{\bhprevhashname}\ #1} -\newcommand{\bhtosignname}{bhToSign} -\newcommand{\bhtosign}[1]{\fun{\bhtosignname}\ #1} - -During PBFT processing of the block header, we do the following: -\begin{enumerate} - \item We check that the current block is being issued for a slot later than - that of the last block issued. - \item We check that the current block is being issued for a slot no later than - the current slot (as determined by the system clock). - \item We verify that the block signer is the current delegate of at least one - of the authorised genesis keys. - \item We check that the previous block hash contained in the block header - corresponds to the known hash of the previous block. - \item We check that the header signature correctly verifies the ``signed'' - content of the header. - \item Finally, we verify and update the signature count rules. - \end{enumerate} - \begin{figure}[ht] - \emph{Abstract types} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - bh & \Bhead & \text{Block header} - \end{array} - \end{equation*} - % - \emph{Abstract functions} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \fun{\bhprevhashname} & \Bhead \totalf \Hash & \text{Previous header hash} \\ - \fun{\bhhashname} & \Bhead \totalf \Hash & \text{Header hash} \\ - \fun{\bhsigname} & \Bhead \totalf \Sig & \text{Block signature} \\ - \fun{\bhissuername} & \Bhead \totalf \VKey & \text{Block issuer} \\ - \fun{\bhslotname} & \Bhead \totalf \Slot & \text{Slot for which this block is issued} - \end{array} - \end{equation*} - \caption{Permissive BFT types and functions} - \label{fig:defs:pbft} -\end{figure} - -\begin{figure}[ht] - \emph{Permissive BFT environments} - \begin{equation*} - \PBFTEnv = - \left( - \begin{array}{r@{~\in~}lr} - \var{pps} & \ProtParams & \text{Protocol parameters} \\ - \var{ds} & \DelegState & \text{Delegation state} \\ - \var{s_{last}} & \Slot & \text{Slot for which the last known block was issued} \\ - \var{s_{now}} & \Slot & \text{Current slot} \\ - \end{array} - \right) - \end{equation*} - - \emph{Permissive BFT states} - \begin{equation*} - \PBFTState = - \left( - \begin{array}{r@{~\in~}lr} - \var{h} & \Hash & \text{Tip header hash} \\ - \var{sgs} & \seqof{\VKeyGen} & \text{Last signers} - \end{array} - \right) - \end{equation*} - \emph{Permissive BFT transitions} - \begin{equation*} - \_ \vdash \var{\_} \trans{pbft}{\_} \var{\_} \subseteq - \powerset (\PBFTEnv \times \PBFTState \times \Bhead \times \PBFTState) - \end{equation*} - \caption{Permissive BFT transition-system types} - \label{fig:ts-types:pbft} -\end{figure} - -\begin{figure}[ht] - \begin{equation*} - \inference - { - \var{vk_d} \leteq \bhissuer{bh} & \var{s} \leteq \bhslot{bh} - \\ \var{s} > \var{s_{last}} & \var{s} \leq \var{s_{now}} - \\ \bhprevhash{bh} = \var{h} & \verify{vk_d}{\serialised{\bhtosign{bh}}}{(\bhsig{bh})} - \\ - {\left( - \begin{array}{l} - \var{pps} \\ - ds - \end{array} - \right)} - \vdash - \var{sgs} \trans{sigcnt}{\var{vk_d}} \var{sgs'} - \\ - } - { - \left( - {\begin{array}{c} - \var{pps} \\ - \var{ds} \\ - \var{s_{last}} \\ - \var{s_{now}} \\ - \end{array}} - \right) - \vdash - \left( - {\begin{array}{c} - \var{h} \\ - \var{sgs} - \end{array}} - \right) - \trans{pbft}{\var{bh}} - \left( - {\begin{array}{c} - \bhhash{bh} \\ - \var{sgs}' - \end{array}} - \right) - } -\end{equation*} -\caption{Permissive BFT rules} -\label{fig:rules:pbft} -\end{figure} - - -\clearpage - -\section{Block processing} -\label{sec:block-processing} - -\newcommand{\BHState}{\type{BHState}} - -\newcommand{\BBEnv}{\type{BBEnv}} -\newcommand{\BBState}{\type{BBState}} - -\newcommand{\Bbody}{\type{BlockBody}} - -\newcommand{\bheadname}{bHead} -\newcommand{\bhead}[1]{\fun{\bheadname}\ #1} -\newcommand{\bupdpayloadname}{bUpdPayload} -\newcommand{\bupdpayload}[1]{\fun{\bupdpayloadname}\ #1} - -\newcommand{\bslotname}{bSlot} -\newcommand{\bslot}[1]{\fun{\bslotname}\ #1} - -\newcommand{\butxo}[1]{\fun{bUtxo}\ #1} - -\newcommand{\maxblocksize}{\pp{maxBlockSize}} -\newcommand{\maxheadersize}{\pp{maxHeaderSize}} - -% Imported definitions -\newcommand{\UTxO}{\type{UTxO}} -\newcommand{\DIEnv}{\type{DIEnv}} -\newcommand{\DIState}{\type{DIState}} - -We delineate here between processing the header and body of a block. It's useful -to make this distinction since we may process headers ahead of the -block body, and we have less context available to process headers - in -particular, we must be able to process block headers without the recent history -of block bodies. - -\begin{figure}[ht] - \emph{Abstract types} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - b & \Block & \text{block} \\ - h & \Hash & \text{hash} \\ - \var{data} & \Data & \text{data} - \end{array} - \end{equation*} - % - % - \emph{Abstract functions} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \fun{\bsizename} & \Block \totalf \mathbb{N} & \text{block size in bytes} \\ - \fun{\verifyname} & \VKey \times \Data \times \Sig & \text{verification relation} \\ - \end{array} - \end{equation*} - \emph{Protocol parameters} - \begin{equation*} - \begin{array}{r@{~\partialf~}l!{~\in~\ProtParams~}r} - \maxblocksize & \mathbb{N} & \text{maximum block size} \\ - \end{array} - \end{equation*} - \caption{Basic Block-related Types and Functions} - \label{fig:block-defs} -\end{figure} - -\subsection{Block header processing} - -Figure \ref{fig:ts-types:bhead} gives the transition system types for block -header processing. The header state contains the current update state and -historical epoch length map, which must be updated along the epoch boundary. -Figure \ref{fig:rules:bhead} gives the corresponding transition rules. During -header processing we verify the following things: - -\begin{enumerate} - \item We compute whether this block is the first block in a new epoch. - If so, we apply the epoch transition updates. Unlike other cases, we use the - resulting update state in all downstream verification for this block, since - the epoch transition is not contingent on the block itself, but simply a - recognition that this is a block in a new epoch. - \item We verify that the block header does not exceed the maximum size - specified in the protocol parameters. -\end{enumerate} - -\begin{figure}[ht] - \emph{Abstract types} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - bh & \Bhead & \text{Block header} \\ - bts & \Bhtosign & \text{Part of the block header which must be signed} - \end{array} - \end{equation*} - % - \emph{Abstract functions} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \fun{\bheadname} & \Block \totalf \Bhead & \text{Block header} \\ - \fun{\bhdrsizename} & \Bhead \totalf \mathbb{N} & \text{Block header size in bytes}\\ - \end{array} - \end{equation*} - \emph{Protocol parameters} - \begin{equation*} - \begin{array}{r@{~\partialf~}l!{~\in~\ProtParams~}r} - \maxheadersize & \mathbb{N} & \text{maximum block header size} \\ - \end{array} - \end{equation*} - \caption{Block header processing types and functions} - \label{fig:defs:bhead} -\end{figure} - -\begin{figure}[ht] - - \emph{Block header processing states} - \begin{equation*} - \BHState = - \left( - \begin{array}{r@{~\in~}lr} - \var{us} & \UPIState & \text{Update state} \\ - \var{elens} & \Epoch \partialf \SlotCount & \text{Historical epoch lengths} \\ - \end{array} - \right) - \end{equation*} - \emph{Block header processing transitions} - \begin{equation*} - \var{\_} \vdash \var{\_} \trans{bhead}{\_} \var{\_} \subseteq - \powerset (\Slot \times \BHState \times \Bhead \times \BHState) - \end{equation*} - \caption{Block header processing transition-system types} - \label{fig:ts-types:bhead} -\end{figure} - -\begin{figure}[ht] - \begin{equation*} - \inference - { \fun{pps} ~ us \vdash - {\left( - \begin{array}{l} - \var{elens} \\ - \sepoch{s_{last}}{elens} \\ - us - \end{array} - \right)} - \trans{epoch}{\bslot{b}} - {\left( - \begin{array}{l} - \var{elens'} \\ - \var{e_n} \\ - us' - \end{array} - \right)} - \\ - \\ \maxheadersize \mapsto \var{s_{max}} \in \fun{pps}~\var{us'} & \bhdrsize{bh} \leq \var{s_{max}} - } - { - \var{s_{last}} \vdash - \left( - {\begin{array}{c} - \var{us} \\ - \var{elens} - \end{array}} - \right) - \trans{bhead}{\var{bh}} - \left( - {\begin{array}{c} - \var{us'} \\ - \var{elens'} - \end{array}} - \right) - } -\end{equation*} -\caption{Block header processing rules} -\label{fig:rules:bhead} -\end{figure} - -\clearpage - -\subsection{Block body processing} - -During processing of the block body, we perform two main functions: verification -of the body integrity using the proofs contained in the block header, and update -of the various state components. These rules are given in figure -\ref{fig:rules:bbody}. - -Verification is done independently for the three components of the body payload: -UTxO, delegation and update. Each of these three have a signature in the block -header. Note that Byron-era block payload also has an additional component: the -VSS payload. This part of the block is unnecessary during the BFT era, and hence -we do not verify it. - -In addition to block verification, we also process the three components of the -payload; UTxO, delegation and update. - -\begin{figure}[ht] - \emph{Abstract types} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - bb & \Bbody & \text{Block body} \\ - - \end{array} - \end{equation*} - % - \emph{Abstract functions} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \fun{bUtxo} & \Block \totalf \UTxO & \text{Block UTxO payload} \\ - \fun{\bcertsname} & \Block \totalf \seqof{\DCert} - & \text{block certificates} \\ - \fun{bUpdProp} & \Block \totalf \UProp^{?} & \text{Block update proposal payload} \\ - \fun{bUpdVotes} & \Block \totalf \seqof{\Vote} & \text{Block update votes payload} \\ - \fun{bProtVer} & \Block \totalf \ProtVer & \text{Block protocol version} \\ - \fun{bhUtxoSig} & \Bhead \totalf \Sig & \text{UTxO payload signature} \\ - \fun{bhDlgSig} & \Bhead \totalf \Sig & \text{Delegation payload signature} \\ - \fun{bhUpdSig} & \Bhead \totalf \Sig & \text{Update payload signature} \\ - \end{array} - \end{equation*} - \emph{Derived functions} - \begin{equation*} - \begin{array}{rlr} - \fun{bEndorsment} & \in \Block \to \ProtVer \times \VKey & \text{Protocol version endorsment} \\ - \bendorsment{b} & = (\bprotver{b}, \bhissuer{b}) \\ - \fun{\bslotname} & \in \Block \to \Slot & \text{Slot for which this block is being issued} \\ - \bslot{b} & = (\bhslotname \cdot \bheadname)~b \\ - \fun{\bupdpayloadname} & \in \Block \to (\UProp^{?}\times\seqof{\Vote}) & \text{Block update payload} \\ - \bupdpayload{b} & = (\bupdprop{b},~\bupdvotes{b}) - \end{array} - \end{equation*} - \caption{Block body processing types and functions} - \label{fig:defs:bbody} -\end{figure} - -\begin{figure}[ht] - \emph{Block body processing environments} - \begin{equation*} - \BBEnv = - \left( - \begin{array}{r@{~\in~}lr} - \var{pps} & \ProtParams & \text{Protocol parameters} \\ - \var{e_n} & \Epoch & \text{Epoch we are currently processing blocks for} - \end{array} - \right) - \end{equation*} - - \emph{Block body processing states} - \begin{equation*} - \BBState = - \left( - \begin{array}{r@{~\in~}lr} - \var{utxo} & \UTxO & \text{UTxO} \\ - \var{us} & \UPIState & \text{Update interface state} \\ - \var{ds} & \DIState & \text{Delegation state} - \end{array} - \right) - \end{equation*} - - \emph{Block body processing transitions} - \begin{equation*} - \_ \vdash \var{\_} \trans{bbody}{\_} \var{\_} \subseteq - \powerset (\BBEnv \times \BBState \times \Block \times \BBState) - \end{equation*} - \caption{Block body processing transition-system types} - \label{fig:ts-types:bbody} -\end{figure} - -\begin{figure}[ht] - \begin{equation*} - \inference - { \maxblocksize \mapsto \var{b_{max}} \in \var{pps} && \bsize{b} \leq \var{b_{max}} \\ - \var{bh} \leteq \bhead{b} & \var{vk_d} \leteq \bhissuer{\var{bh}} \\ - \verify{\var{vk_d}}{\serialised{\butxo{b}}}{(\fun{bhUtxoSig}~\var{bh})} & - \verify{\var{vk_d}}{\serialised{\bcerts{b}}}{(\fun{bhDlgSig}~\var{bh})} \\ - \verify{\var{vk_d}}{\serialised{\bupdpayload{b}}}{(\fun{bhUpdSig}~\var{bh})} \\ - {\left( - \begin{array}{l} - \bslot{b} \\ - \var{e_n} \\ - \fun{dms} ~ \var{ds} - \end{array} - \right)} - \vdash \var{us} \trans{bupi}{ - {\left( - \begin{array}{l} - \bupdprop{b} \\ - \bupdvotes{b} \\ - \bendorsment{b} - \end{array} - \right)} - } \var{us'} - \\ - {\left( - \begin{array}{l} - \dom{(\fun{dms}~ ds)} \\ - \var{e_n} \\ - \bslot{b} \\ - \fun{pps} ~ us \\ - \end{array} - \right)} - \vdash \var{ds} \trans{deleg}{\bcerts{b}} \var{ds'} & - \fun{pps} ~ us \vdash \var{utxo} \trans{utxow}{\butxo{b}} \var{utxo'} \\ - } - { - \left( - {\begin{array}{c} - \var{pps} \\ - \var{e_n} - \end{array}} - \right) - \vdash - { - \left( - {\begin{array}{c} - \var{utxo} \\ - \var{ds} \\ - \var{us} - \end{array}} - \right) - } - \trans{bbody}{\var{b}} - { - \left( - {\begin{array}{c} - \var{utxo'} \\ - \var{ds'} \\ - \var{us'} - \end{array}} - \right) - } - } -\end{equation*} -\caption{Block body processing rules} -\label{fig:rules:bbody} -\end{figure} - -\clearpage - -\section{Blockchain Extension} -\label{sec:chain-extension} - -\newcommand{\CEEnv}{\type{CEEnv}} -\newcommand{\CEState}{\type{CEState}} - -Figure \ref{fig:rules:chain-extension} captures the central chain extension -rule. This has two variants, depending on whether the block in question is an -epoch boundary block. Epoch boundary blocks are not required during the BFT era, -but whilst they are not distributed, epoch boundary blocks must still be -processed since their hash forms part of the chain. Since we do not care about -the contents of an epoch boundary block, we check that it does not exceed some -suitably large size, and otherwise simply update the header hash to the block -hash. - -If the block is not an epoch boundary block, then we process both the header and -body according to the rules in figures \ref{fig:rules:bhead} and -\ref{fig:rules:bbody} respectively. - -\begin{figure}[ht] - \emph{Abstract functions} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \fun{\isebbname} & \Block \totalf \mathbb{B} & \text{epoch boundary block check} \\ - \end{array} - \end{equation*} - \caption{Blockchain Extension Types and Functions} - \label{fig:defs:chain-extension} -\end{figure} - -\begin{figure}[ht] - \emph{Chain extension states} - \begin{equation*} - \CEState = - \left( - \begin{array}{r@{~\in~}lr} - \var{s_{last}} & \Slot & \text{Slot of the last seen block} \\ - \var{elens} & \Epoch \partialf \SlotCount & \text{Historical epoch lengths} \\ - \var{sgs} & \seqof{\VKeyGen} & \text{Last signers}\\ - \var{h} & \Hash & \text{Current block hash} \\ - \var{utxo} & \UTxO & \text{UTxO} \\ - \var{us} & \UPIState & \text{Update interface state} \\ - \var{ds} & \DIState & \text{Delegation state} - \end{array} - \right) - \end{equation*} - - \emph{Chain extension transitions} - \begin{equation*} - \_ \vdash \var{\_} \trans{chain}{\_} \var{\_} \subseteq - \powerset (\Slot \times \CEState \times \Block \times \CEState) - \end{equation*} - - \caption{Blockchain extension transition-system types} - \label{fig:ts-types:chain-extension} -\end{figure} - -\begin{figure} - \begin{equation*} - \inference - { \isebb{b} & \bsize{b} \leq 2^{21} & - \var{h'} \leteq \bhhash{(\bhead b)} - } - { - \left( - {\begin{array}{c} - \var{s_{now}} - \end{array}} - \right) - \vdash - \left( - {\begin{array}{c} - \var{s_{last}} \\ - \var{sgs} \\ - \var{h} \\ - \var{utxo} \\ - \var{us} \\ - \var{ds} - \end{array}} - \right) - \trans{chain}{b} - \left( - {\begin{array}{c} - \var{s_{last}} \\ - \var{sgs} \\ - \var{h'} \\ - \var{utxo} \\ - \var{us} \\ - \var{ds} - \end{array}} - \right) - } -\end{equation*} -\vspace{20pt} -\begin{equation*} - \inference - { - \neg\isebb{b} & - \var{s_{last}} - \vdash - \left( - {\begin{array}{c} - \var{us} \\ - \var{elens} \\ - \end{array}} - \right) - \trans{bhead}{\bhead{b}} - \left( - {\begin{array}{c} - \var{us'} \\ - \var{elens'} \\ - \end{array}} - \right) - \\ - \left( - {\begin{array}{c} - \fun{pps} ~ us' \\ - \var{ds} \\ - \var{s_{last}} \\ - \var{s_{now}} \\ - \end{array}} - \right) - \vdash - \left( - {\begin{array}{c} - \var{h} \\ - \var{sgs} - \end{array}} -\right) -\trans{pbft}{\var{bh}} -\left( - {\begin{array}{c} - \var{h'} \\ - \var{sgs}' - \end{array}} -\right) - \\ - {\left( - \begin{array}{l} - \fun{pps} ~ us' \\ - \sepoch{(\bslot{b})}{elens} \\ - \end{array} - \right)} - \vdash - { - \left( - {\begin{array}{c} - \var{utxo} \\ - \var{ds} \\ - \var{us'} - \end{array}} - \right) - } - \trans{bbody}{b} - { - \left( - {\begin{array}{c} - \var{utxo'} \\ - \var{ds'} \\ - \var{us''} - \end{array}} - \right) -} -} -{ - \left( - {\begin{array}{c} - \var{s_{now}} - \end{array}} - \right) - \vdash - \left( - {\begin{array}{c} - \var{s_{last}} \\ - \var{elens} \\ - \var{sgs} \\ - \var{h} \\ - \var{utxo} \\ - \var{us} \\ - \var{ds} - \end{array}} -\right) -\trans{chain}{b} -\left( - {\begin{array}{c} - \var{\bslot{b}} \\ - \var{elens'} \\ - \var{sgs'} \\ - \var{h'} \\ - \var{utxo'} \\ - \var{us''} \\ - \var{ds'} - \end{array}} -\right) -} -\end{equation*} -\caption{Blockchain extension rules} -\label{fig:rules:chain-extension} -\end{figure} -\clearpage -\bibliographystyle{plainnat} -\bibliography{references} -\begin{appendices} - \section{Calculating the $t$ parameter} - \label{apdx:calculating-t} - - We originally give the range of $t$ as between $\frac{1}{5}$ and $\frac{1}{4}$. - The upper bound here is to reduce the possible number of malicious blocks; if - two of the genesis keys are comprimised, the attackers may not be able to - produce a longer chain than the honest participants. The lower bound is required - to prevent a situation in which a chain produced under the initial Ouroboros - setting produces a chain which, according to the new BFT semantics, is invalid. - - In order to determine the best value of $t$, we must consider the likelihood of - such an invalid chain being produced by the old procedure of randomly selecting - the slot leaders for each slot. Given the Cardano chain is still federated, the - likelihood of this happening is the same for each of the 7 stakeholders, and we - may model the number of selected slots within a $w$-slot window $X$ as a binomial - distribution $X \sim \mathrm{B}\left(w, \frac{1}{7}\right)$. - - In each epoch of size $n$ blocks, there are $n-w+1$ such $w$-block windows. - Boole's inequality gives us that the likelihood of exceeding the threshold in - any one of these windows is bounded above by the sum of the likelihoods for each - window. We may thus consider that the probability of a given stakeholder - violating the threshold in an epoch to be bounded by $(n-w+1)\cdot P(X > t*w)$. - Appealing to Boole's inequality again, we may multiply this by the number of - epochs and the number of stakeholders to give a bound for the likelihood of - generating an invalid chain. - - Figure \ref{fig:calculating-t} gives the bound on the likelihood of threshold - violation for $t$ in our plausible range: from this we can see that the - likelihood decreases to a negligible level around $0.21$, and so we choose the - value of $t=0.22$, giving an upper bound on the likelihood around $6e-10$. - Increasing $t$ beyond this point gives no decrease in the likelihood of - violation. - - \begin{figure}[ht] - \begin{center} - \includegraphics[scale=0.5]{calculating-t.png} - \end{center} - \caption{Probability of generating an invalid chain for values of $t\in\left[ - \frac{1}{4}, \frac{1}{5} \right]$.} - \label{fig:calculating-t} - \end{figure} - -\end{appendices} -\end{document} - - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: t -%%% LaTeX-command: "nix-shell --run make" -%%% End: diff --git a/specs/chain/latex/calculating-t.png b/specs/chain/latex/calculating-t.png deleted file mode 100644 index d6f35314..00000000 Binary files a/specs/chain/latex/calculating-t.png and /dev/null differ diff --git a/specs/chain/latex/default.nix b/specs/chain/latex/default.nix deleted file mode 100644 index a724ffb5..00000000 --- a/specs/chain/latex/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ pkgs ? import ../../../pkgs.nix -}: - -with pkgs; - -stdenv.mkDerivation { - name = "docsEnv"; - buildInputs = [ (texlive.combine { - inherit (texlive) - scheme-small - - # libraries - stmaryrd lm-math amsmath extarrows cleveref semantic xcolor appendix - - # bclogo and dependencies - bclogo mdframed xkeyval etoolbox needspace pgf - - # font libraries `mathpazo` seems to depend on palatino - # , but it isn't pulled. - mathpazo palatino microtype - - # libraries for marginal notes - xargs todonotes - - # build tools - latexmk - - ; - }) - ]; - src = ./.; - buildPhase = "make"; - - meta = with lib; { - description = "Byron Blockchain Specification"; - license = licenses.bsd3; - platforms = platforms.linux; - }; -} diff --git a/specs/chain/latex/references.bib b/specs/chain/latex/references.bib deleted file mode 100644 index d3220df5..00000000 --- a/specs/chain/latex/references.bib +++ /dev/null @@ -1,43 +0,0 @@ -@misc{small_step_semantics, - author = {Formal Methods Team, IOHK}, - title = {Small Step Semantics for Cardano}, - year = {2018}, - url = {https://hydra.iohk.io/job/Cardano/cardano-chain/semanticsSpec/latest/download/1/small-steps.pdf} -} - -@misc{byron_ledger_spec, - author = {Damian Nadales, IOHK}, - title = {A Formal Specification of the Cardano Ledger}, - titleaddon = {(for the Byron release)}, - year = {2019}, - url = {https://hydra.iohk.io/jobset/Cardano/cardano-chain/latest/download/1/ledger-spec.pdf} -} - -@misc{ouroboros, - author = {Aggelos Kiayias and Alexander Russell and Bernardo David and Roman Oliynykov}, - title = {Ouroboros: A Provably Secure Proof-of-Stake Blockchain Protocol}, - year = {2017}, - url = {https://eprint.iacr.org/2016/889.pdf} -} - -@misc{ouroboros_praos, - author = {Bernardo David and Peter Gaži and Aggelos Kiayias and Alexander Russell}, - title = {Ouroboros Praos: An adaptively-secure, semi-synchronous proof-of-stake protocol}, - year = {2017}, - url = {https://eprint.iacr.org/2017/573.pdf} -} - -@misc{ouroboros_bft, - author = {Aggelos Kiayias and Alexander Russell}, - title = {Ouroboros-BFT: A Simple Byzantine Fault Tolerant Consensus Protocol}, - year = {2018}, - url = {https://api.zotero.org/groups/478201/items/J6E2Q8L7/file/view?key=Qcjdk4erSuUZ8jvAah59Asef} -} - -@misc{delegation_design, - author = {Philipp Kant and Lars Br\"unjes and Duncan Coutts}, - title = {Design Specification for Delegation and Incentives in -Cardano}, - year = {2018}, - url = {https://github.com/input-output-hk/fm-ledger-rules/tree/master/docs/delegation_design_spec}, -} \ No newline at end of file diff --git a/specs/ledger/hs/CHANGELOG.md b/specs/ledger/hs/CHANGELOG.md deleted file mode 100644 index 5032c2a8..00000000 --- a/specs/ledger/hs/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Revision history for cs-ledger - -## 0.1.0.0 -- YYYY-mm-dd - -* First version. Released on an unsuspecting world. diff --git a/specs/ledger/hs/LICENSE b/specs/ledger/hs/LICENSE deleted file mode 100644 index f7084dc7..00000000 --- a/specs/ledger/hs/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2018 IOHK - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/specs/ledger/hs/Setup.hs b/specs/ledger/hs/Setup.hs deleted file mode 100644 index 9a994af6..00000000 --- a/specs/ledger/hs/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/specs/ledger/hs/cabal.project.local b/specs/ledger/hs/cabal.project.local deleted file mode 100644 index 6112d3c7..00000000 --- a/specs/ledger/hs/cabal.project.local +++ /dev/null @@ -1 +0,0 @@ -with-compiler: ghc-8.6.1 diff --git a/specs/ledger/hs/cs-ledger.cabal b/specs/ledger/hs/cs-ledger.cabal deleted file mode 100644 index 9c4bc2b6..00000000 --- a/specs/ledger/hs/cs-ledger.cabal +++ /dev/null @@ -1,79 +0,0 @@ --- Initial cs-ledger.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/ - -name: cs-ledger -version: 0.1.0.0 -synopsis: Executable specification of Cardano ledger --- description: -homepage: https://github.com/input-output-hk/cardano-chain -license: MIT -license-file: LICENSE -author: IOHK Formal Methods Team -maintainer: formal.methods@iohk.io --- copyright: -category: Testing -build-type: Simple -extra-source-files: CHANGELOG.md -cabal-version: >= 2.0 - -flag development - description: Disable '-Werror' - default: False - manual: True - -library - hs-source-dirs: src - exposed-modules: Ledger.Core - , Ledger.Core.Generator - , Ledger.Delegation - , Ledger.Update - , Ledger.Signatures - , Ledger.UTxO - build-depends: base >=4.11 && <5 - , bytestring - , containers - , cryptonite - , hedgehog - , lens - , memory - , text - -- Local deps - , small-steps - default-language: Haskell2010 - ghc-options: -Wall - -Wcompat - -Wincomplete-record-updates - -Wincomplete-uni-patterns - -Wredundant-constraints - if (!flag(development)) - ghc-options: -Werror - -test-suite ledger-delegation-test - hs-source-dirs: test - main-is: Main.hs - other-modules: Ledger.Delegation.Examples - , Ledger.Delegation.Properties - type: exitcode-stdio-1.0 - default-language: Haskell2010 - build-depends: base - , containers - , lens - , hedgehog - , tasty - , tasty-hunit - , tasty-hedgehog - -- Local deps - , cs-ledger - , small-steps - ghc-options: -Wall - -Wcompat - -Wincomplete-record-updates - -Wincomplete-uni-patterns - -Wredundant-constraints - -- We set a bound here so that we're alerted of potential space - -- leaks in our generators (or test) code. - -- - -- The 50 megabytes heap bound was determined ad-hoc. - "-with-rtsopts=-K1m -M50m" - if (!flag(development)) - ghc-options: -Werror diff --git a/specs/ledger/hs/default.nix b/specs/ledger/hs/default.nix deleted file mode 100644 index 1260fddb..00000000 --- a/specs/ledger/hs/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - pkgs = import ../../../pkgs.nix; -in - pkgs.haskell.packages.ghc861.cs-ledger diff --git a/specs/ledger/hs/shell.nix b/specs/ledger/hs/shell.nix deleted file mode 100644 index 56b62349..00000000 --- a/specs/ledger/hs/shell.nix +++ /dev/null @@ -1,5 +0,0 @@ -let - pkgs = import ../../../pkgs.nix; -in pkgs.lib.overrideDerivation ((import ./.).env) (old: { - nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.cabal-install pkgs.haskell.packages.ghc861.ghcid ]; -}) diff --git a/specs/ledger/hs/src/Ledger/Core.hs b/specs/ledger/hs/src/Ledger/Core.hs deleted file mode 100644 index 2e0edcf8..00000000 --- a/specs/ledger/hs/src/Ledger/Core.hs +++ /dev/null @@ -1,127 +0,0 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE DeriveGeneric #-} -module Ledger.Core where - -import qualified Crypto.Hash as Crypto -import qualified Data.ByteArray as BA -import qualified Data.ByteString.Char8 as BS -import Data.Map.Strict (Map) -import Data.Set (Set) -import qualified Data.Set as Set -import qualified Data.Map.Strict as Map -import GHC.Generics (Generic) -import GHC.Natural (minusNaturalMaybe) -import Numeric.Natural (Natural) - -import Data.AbstractSize -import Ledger.Signatures - --- | Hash part of the ledger paylod -class HasHash a where - hash :: a -> Hash - ---------------------------------------------------------------------------------- --- Signing and verification ---------------------------------------------------------------------------------- - --- |Representation of the owner of key pair. -newtype Owner = Owner Natural deriving (Show, Eq, Ord, HasTypeReps) - -class HasOwner a where - owner :: a -> Owner - --- |Signing Key. -newtype SKey = SKey Owner deriving (Show, Eq, Ord, HasTypeReps) - -instance HasOwner SKey where - owner (SKey o) = o - --- |Verification Key. -newtype VKey = VKey Owner deriving (Show, Eq, Ord, HasTypeReps) - -instance HasHash VKey where - hash = Crypto.hash - -instance BA.ByteArrayAccess VKey where - length = BA.length . BS.pack . show - withByteArray = BA.withByteArray . BS.pack . show - -instance HasOwner VKey where - owner (VKey o) = o - --- | A genesis key is a specialisation of a generic VKey. -newtype VKeyGenesis = VKeyGenesis VKey - deriving (Eq, Ord, Show, HasTypeReps) - -instance HasOwner VKeyGenesis where - owner (VKeyGenesis vk) = owner vk - --- |Key Pair. -data KeyPair = KeyPair - {sKey :: SKey, vKey :: VKey} deriving (Show, Eq, Ord, Generic) - -instance HasTypeReps KeyPair - --- |Return a key pair for a given owner. -keyPair :: Owner -> KeyPair -keyPair o = KeyPair (SKey o) (VKey o) - --- |A digital signature. -data Sig a = Sig a Owner deriving (Show, Eq, Ord, Generic) - -instance HasTypeReps a => HasTypeReps (Sig a) - --- |Produce a digital signature -sign :: SKey -> a -> Sig a -sign (SKey k) d = Sig d k - --- |Verify a digital signature -verify :: Eq a => VKey -> a -> Sig a -> Bool -verify (VKey vk) vd (Sig sd sk) = vk == sk && vd == sd - ---------------------------------------------------------------------------------- --- Slots and Epochs ---------------------------------------------------------------------------------- - -newtype Epoch = Epoch Natural - deriving (Eq, Ord, Show, HasTypeReps) - -newtype Slot = Slot Natural - deriving (Eq, Ord, Show, HasTypeReps) - --- | A number of slots. --- --- We use this newtype to distinguish between a cardinal slot and a relative --- period of slots. -newtype SlotCount = SlotCount Natural - deriving (Eq, Ord, Show) - --- | Add a slot count to a slot. -addSlot :: Slot -> SlotCount -> Slot -addSlot (Slot n) (SlotCount m) = Slot $ m + n - --- | Subtract a slot count from a slot. --- --- This is bounded below by 0. -minusSlot :: Slot -> SlotCount -> Slot -minusSlot (Slot n) (SlotCount m) = case minusNaturalMaybe m n of - Nothing -> Slot 0 - Just k -> Slot k - ---------------------------------------------------------------------------------- --- Domain restriction and exclusion ---------------------------------------------------------------------------------- - --- |Domain restriction --- -(◁) :: Ord a => Set a -> Map a b -> Map a b -s ◁ r = Map.filterWithKey (\k _ -> k `Set.member` s) r - --- |Domain exclusion --- -(⋪) :: Ord a => Set a -> Map a b -> Map a b -s ⋪ r = Map.filterWithKey (\k _ -> k `Set.notMember` s) r - --- | Union Override -(⨃) :: Ord a => Map a b -> Map a b -> Map a b -d0 ⨃ d1 = d1 `Map.union` (Map.keysSet d1 ⋪ d0) diff --git a/specs/ledger/hs/src/Ledger/Core/Generator.hs b/specs/ledger/hs/src/Ledger/Core/Generator.hs deleted file mode 100644 index 3ee0c6f7..00000000 --- a/specs/ledger/hs/src/Ledger/Core/Generator.hs +++ /dev/null @@ -1,22 +0,0 @@ --- | Generators for the 'Ledger.Core' values. -module Ledger.Core.Generator - ( vkGen - , vkgenesisGen - ) -where - -import Hedgehog (Gen) -import Hedgehog.Gen (integral) -import Hedgehog.Range (linear) - -import Ledger.Core - ( Owner(Owner) - , VKey(VKey) - , VKeyGenesis(VKeyGenesis) - ) - -vkGen :: Gen VKey -vkGen = VKey . Owner <$> integral (linear 0 10000) - -vkgenesisGen :: Gen VKeyGenesis -vkgenesisGen = VKeyGenesis <$> vkGen diff --git a/specs/ledger/hs/src/Ledger/Delegation.hs b/specs/ledger/hs/src/Ledger/Delegation.hs deleted file mode 100644 index ef4f2574..00000000 --- a/specs/ledger/hs/src/Ledger/Delegation.hs +++ /dev/null @@ -1,486 +0,0 @@ -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FunctionalDependencies #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE MultiParamTypeClasses #-} - -module Ledger.Delegation - ( -- * Delegation scheduling - SDELEG - , SDELEGS - , DSState(DSState) - , _dSStateScheduledDelegations - , _dSStateKeyEpochDelegations - , DCert(DCert) - , _dbody - , _dwit - , _dwho - , _depoch - , delegator - , delegate - , dbody - , dwit - , dwho - , depoch - -- * Delegation activation - , ADELEG - , ADELEGS - , DSEnv - ( DSEnv - , _dSEnvAllowedDelegators - , _dSEnvEpoch - , _dSEnvSlot - , _dSEnvLiveness - ) - , allowedDelegators - , DState - ( DState - , _dStateDelegationMap - , _dStateLastDelegation - ) - -- * Delegation interface - , DELEG - , DIEnv - , DIState(DIState) - , _dIStateDelegationMap - , _dIStateLastDelegation - , _dIStateScheduledDelegations - , _dIStateKeyEpochDelegations - , PredicateFailure(SDelegSFailure, SDelegFailure, IsAlreadyScheduled) - -- * State lens fields - , slot - , liveness - , delegationMap - -- * State lens type classes - , HasScheduledDelegations - , scheduledDelegations - , dms - -- * Generators - , dcertGen - , dcertsGen - ) -where - -import Data.AbstractSize -import qualified Data.List as List -import Data.Map.Strict (Map) -import qualified Data.Map.Strict as Map -import Data.Set (Set) -import qualified Data.Set as Set -import GHC.Generics (Generic) -import Hedgehog (Gen) -import qualified Hedgehog.Gen as Gen -import Hedgehog.Range (constant, linear) -import Control.Lens - ( Lens' - , (%~) - , (&) - , (.~) - , (<>~) - , (^.) - , _1 - , _2 - , lens - , makeFields - , makeLenses - , to - ) - - -import Control.State.Transition - ( Embed - , Environment - , PredicateFailure - , STS - , Signal - , State - , IRC(IRC) - , TRC(TRC) - , (?!) - , initialRules - , judgmentContext - , trans - , transitionRules - , wrapFailed - ) -import Control.State.Transition.Generator - ( HasTrace - , initEnvGen - , sigGen - ) -import Ledger.Core - ( Epoch(Epoch) - , Sig(Sig) - , Slot(Slot) - , SlotCount(SlotCount) - , VKey - , VKeyGenesis(VKeyGenesis) - , (⨃) - , addSlot - , minusSlot - , owner - , owner - ) -import Ledger.Core.Generator (vkGen, vkgenesisGen) - --------------------------------------------------------------------------------- --- Abstract types --------------------------------------------------------------------------------- - --- | A delegation certificate. -data DCert = DCert - { -- | Body of the delegation certificate - _dbody :: (VKey, Epoch) - -- | Witness for the delegation cerfiticate - , _dwit :: Sig VKeyGenesis - -- | Who delegates to whom - , _dwho :: (VKeyGenesis, VKey) - -- | Certificate epoch - , _depoch :: Epoch - } deriving (Show, Eq, Generic) - -instance HasTypeReps DCert - -makeLenses ''DCert - --- | Key that is delegating. -delegator :: DCert -> VKeyGenesis -delegator c = c ^. dwho . _1 - --- | Key being delegated to. -delegate :: DCert -> VKey -delegate c = c ^. dwho . _2 - --------------------------------------------------------------------------------- --- Derived types --------------------------------------------------------------------------------- - --- | Delegation scheduling environment -data DSEnv = DSEnv - { _dSEnvAllowedDelegators :: Set VKeyGenesis - , _dSEnvEpoch :: Epoch - , _dSEnvSlot :: Slot - , _dSEnvLiveness :: SlotCount - } deriving (Show, Eq) - -makeFields ''DSEnv - --- | Delegation scheduling state -data DSState = DSState - { _dSStateScheduledDelegations :: [(Slot, (VKeyGenesis, VKey))] - , _dSStateKeyEpochDelegations :: Set (Epoch, VKeyGenesis) - } deriving (Show, Eq) - -makeFields ''DSState - --- | Delegation state -data DState = DState - { _dStateDelegationMap :: Map VKeyGenesis VKey - -- | When was the last time each genesis key delegated. - , _dStateLastDelegation :: Map VKeyGenesis Slot - } deriving (Eq, Show) - -makeFields ''DState - --- | Interface environment is the same as scheduling environment. -type DIEnv = DSEnv - -data DIState = DIState - { _dIStateDelegationMap :: Map VKeyGenesis VKey - , _dIStateLastDelegation :: Map VKeyGenesis Slot - , _dIStateScheduledDelegations :: [(Slot, (VKeyGenesis, VKey))] - , _dIStateKeyEpochDelegations :: Set (Epoch, VKeyGenesis) - } deriving (Show, Eq) - -makeFields ''DIState - -dms :: HasDelegationMap a (Map VKeyGenesis VKey) - => Lens' a (Map VKeyGenesis VKey) -dms = delegationMap - -dIStateDSState :: Lens' DIState DSState -dIStateDSState = lens - (\dis -> DSState (dis ^. scheduledDelegations) (dis ^. keyEpochDelegations)) - (\dis dss -> - dis - & scheduledDelegations - .~ dss - ^. scheduledDelegations - & keyEpochDelegations - .~ dss - ^. keyEpochDelegations - ) - -dIStateDState :: Lens' DIState DState -dIStateDState = lens - (\dis -> DState (dis ^. delegationMap) (dis ^. lastDelegation)) - (\dis dss -> - dis - & delegationMap - .~ dss - ^. delegationMap - & lastDelegation - .~ dss - ^. lastDelegation - ) - --------------------------------------------------------------------------------- --- Transition systems --------------------------------------------------------------------------------- - --- | Delegation scheduling rules -data SDELEG - -instance STS SDELEG where - type State SDELEG = DSState - type Signal SDELEG = DCert - type Environment SDELEG = DSEnv - - data PredicateFailure SDELEG - = IsNotGenesisKey - | IsPastEpoch - | HasAlreadyDelegated - | IsAlreadyScheduled - | DoesNotVerify - deriving (Eq, Show) - - initialRules = [ return DSState - { _dSStateScheduledDelegations = [] - , _dSStateKeyEpochDelegations = Set.empty - } - ] - transitionRules = - [ do - TRC (env, st, cert) <- judgmentContext - verify cert ?! DoesNotVerify - notAlreadyDelegated st cert ?! HasAlreadyDelegated - notAlreadyScheduled env st cert ?! IsAlreadyScheduled - Set.member (cert ^. dwho . _1) (env ^. allowedDelegators) ?! IsNotGenesisKey - env ^. epoch <= cert ^. depoch ?! IsPastEpoch - return $ st - & scheduledDelegations <>~ [((env ^. slot) `addSlot` (env ^. liveness) - , cert ^. dwho - )] - & keyEpochDelegations %~ Set.insert (env ^. epoch, cert ^. dwho . _1) - ] - where - verify :: DCert -> Bool - verify = const True - -- Check that this delegator hasn't already delegated this epoch - notAlreadyDelegated :: DSState -> DCert -> Bool - notAlreadyDelegated st cert = - Set.notMember (cert ^. depoch, cert ^. dwho . _1) (st ^. keyEpochDelegations) - -- Check whether there is a scheduled delegation from this key - notAlreadyScheduled :: DSEnv -> DSState -> DCert -> Bool - notAlreadyScheduled env st cert = - List.notElem - ((env ^. slot) `addSlot` (env ^. liveness), cert ^. dwho . _1) - (st ^. scheduledDelegations . to (fmap $ fmap fst)) - --- | Delegation rules -data ADELEG - -instance STS ADELEG where - type State ADELEG = DState - type Signal ADELEG = (Slot, (VKeyGenesis, VKey)) - type Environment ADELEG = Set VKeyGenesis - - data PredicateFailure ADELEG - = BeforeExistingDelegation - -- | Not actually a failure; this should just trigger the other rule. - | NoLastDelegation - -- | Not a failure; this should just pass the other rule - | AfterExistingDelegation - deriving (Eq, Show) - - initialRules = [ do - IRC env <- judgmentContext - return DState - { _dStateDelegationMap = Map.fromSet (\(VKeyGenesis k) -> k) env - , _dStateLastDelegation = Map.fromSet (const (Slot 0)) env - } - ] - transitionRules = - [ do - TRC (_env, st, (slt, (vks, vkd))) <- judgmentContext - case Map.lookup vks (st ^. lastDelegation) of - Nothing -> True ?! BeforeExistingDelegation - Just sp -> sp < slt ?! BeforeExistingDelegation - return $ st - & delegationMap %~ (\sdm -> sdm ⨃ Map.singleton vks vkd) - & lastDelegation %~ (\ldm -> ldm ⨃ Map.singleton vks slt) - , do - (TRC (_env, st, (slt, (vks, _vkd)))) <- judgmentContext - case Map.lookup vks (st ^. lastDelegation) of - Just sp -> sp >= slt ?! AfterExistingDelegation - Nothing -> False ?! NoLastDelegation - return st - ] - --- | Delegation scheduling sequencing -data SDELEGS - -instance STS SDELEGS where - type State SDELEGS = DSState - type Signal SDELEGS = [DCert] - type Environment SDELEGS = DSEnv - - data PredicateFailure SDELEGS - = SDelegFailure (PredicateFailure SDELEG) - deriving (Eq, Show) - - initialRules = [ do - IRC env <- judgmentContext - trans @SDELEG $ IRC env - ] - transitionRules = - [ do - TRC (env, st, sig) <- judgmentContext - case sig of - [] -> return st - (x:xs) -> do - dss' <- trans @SDELEGS $ TRC (env, st, xs) - dss'' <- trans @SDELEG $ TRC (env, dss', x) - return dss'' - ] - -instance Embed SDELEG SDELEGS where - wrapFailed = SDelegFailure - --- | Delegation rules sequencing -data ADELEGS - -instance STS ADELEGS where - type State ADELEGS = DState - type Signal ADELEGS = [(Slot, (VKeyGenesis, VKey))] - type Environment ADELEGS = Set VKeyGenesis - - data PredicateFailure ADELEGS - = ADelegFailure (PredicateFailure ADELEG) - deriving (Eq, Show) - - initialRules = [ do - IRC env <- judgmentContext - trans @ADELEG $ IRC env - ] - transitionRules = - [ do - TRC (env, st, sig) <- judgmentContext - case sig of - [] -> return st - (x:xs) -> do - ds' <- trans @ADELEGS $ TRC (env, st, xs) - ds'' <- trans @ADELEG $ TRC (env, ds', x) - return ds'' - ] - -instance Embed ADELEG ADELEGS where - wrapFailed = ADelegFailure - --- | Delegation interface -data DELEG - -instance STS DELEG where - type State DELEG = DIState - type Signal DELEG = [DCert] - type Environment DELEG = DIEnv - - data PredicateFailure DELEG - = SDelegSFailure (PredicateFailure SDELEGS) - | ADelegSFailure (PredicateFailure ADELEGS) - deriving (Eq, Show) - - initialRules = [ do - IRC env <- judgmentContext - initADelegsState <- trans @ADELEGS $ IRC (env ^. allowedDelegators) - initSDelegsState <- trans @SDELEGS $ IRC env - return DIState - { _dIStateDelegationMap = initADelegsState ^. delegationMap - , _dIStateLastDelegation = initADelegsState ^. lastDelegation - , _dIStateScheduledDelegations = initSDelegsState ^. scheduledDelegations - , _dIStateKeyEpochDelegations = initSDelegsState ^. keyEpochDelegations - } - ] - transitionRules = - [ do - TRC (env, st, sig) <- judgmentContext - sds <- trans @SDELEGS $ TRC (env, st ^. dIStateDSState, sig) - let slots = filter ((<= (env ^. slot)) . fst) $ sds ^. scheduledDelegations - as <- trans @ADELEGS $ TRC (env ^. allowedDelegators, st ^. dIStateDState, slots) - return $ DIState - (as ^. delegationMap) - (as ^. lastDelegation) - (filter (aboutSlot (env ^. slot) (env ^. liveness) . fst) - $ sds ^. scheduledDelegations) - (Set.filter ((<= (env ^. epoch)) . fst) - $ sds ^. keyEpochDelegations) - ] - where - aboutSlot :: Slot -> SlotCount -> (Slot -> Bool) - aboutSlot a b c = c >= (a `minusSlot` b) && c <= (a `addSlot` b) - -instance Embed SDELEGS DELEG where - wrapFailed = SDelegSFailure - -instance Embed ADELEGS DELEG where - wrapFailed = ADelegSFailure - --------------------------------------------------------------------------------- --- Generators --------------------------------------------------------------------------------- - --- | Generate delegation certificates, using the allowed delegators in the --- environment passed as parameter. -dcertGen :: DSEnv -> Gen DCert -dcertGen env = do - -- The generated delegator must be one of the genesis keys in the - -- environment. - vkS <- Gen.element $ Set.toList (env ^. allowedDelegators) - vkD <- vkGen - let Epoch n = env ^. epoch - m <- Gen.integral (linear 0 100) - let epo = Epoch (n + m) - return DCert { _dbody = (vkD, epo) - , _dwit = Sig vkS (owner vkS) - , _dwho = (vkS, vkD) - , _depoch = epo - } - --- | Generate a list of delegation certificates. --- --- At the moment the size of the generated list is severely constrained since --- the longer the list the higher the probability that it will contain --- conflicting delegation certificates (that will be rejected by the --- transition-system-rules). -dcertsGen :: DSEnv -> Gen [DCert] --- NOTE: at the moment we cannot use a linear range that depends on the --- generator size: the problem is that the more delegation certificates in the --- resulting list, the higher the probability that this list will be rejected --- and the generator will have to retry. --- -dcertsGen env = Gen.list (constant 0 n) (dcertGen env) - where n = env ^. allowedDelegators . to length - -instance HasTrace DELEG where - - initEnvGen - = DSEnv - -- We need at least one delegator in the environment to be able to generate - -- delegation certificates. - -- - -- The use of a linear generator and its bound is rather arbitrary. The - -- sizes passed to the `Gen` monad would be around 100~300, so we rather - -- arbitrarily decided that this size times 100 is a reasonable upper - -- bounds for epochs. - -- - -- A similar remark applies to the ranges chosen for slot and slot count - -- generators. - <$> Gen.set (linear 1 7) vkgenesisGen - <*> (Epoch <$> Gen.integral (linear 0 100)) - <*> (Slot <$> Gen.integral (linear 0 10000)) - <*> (SlotCount <$> Gen.integral (linear 0 10)) - - sigGen e _st = dcertsGen e diff --git a/specs/ledger/hs/src/Ledger/Signatures.hs b/specs/ledger/hs/src/Ledger/Signatures.hs deleted file mode 100644 index 74e67b29..00000000 --- a/specs/ledger/hs/src/Ledger/Signatures.hs +++ /dev/null @@ -1,19 +0,0 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE DerivingVia #-} -module Ledger.Signatures where - -import Crypto.Hash (Digest, SHA256) -import Data.Monoid (Sum(..)) -import Numeric.Natural (Natural) - --- | An encoded hash of part of the system. -type Hash = Digest SHA256 - --- | A unit of value held by a UTxO. -newtype Value = Value Natural - deriving (Show, Eq, Ord) - deriving (Semigroup, Monoid) via (Sum Natural) - --- |The address of a transaction output, used to identify the owner. -newtype Addr = Addr Hash - deriving (Show, Eq, Ord) diff --git a/specs/ledger/hs/src/Ledger/UTxO.hs b/specs/ledger/hs/src/Ledger/UTxO.hs deleted file mode 100644 index 29adf704..00000000 --- a/specs/ledger/hs/src/Ledger/UTxO.hs +++ /dev/null @@ -1,185 +0,0 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -module Ledger.UTxO where - -import Control.State.Transition -import qualified Data.ByteArray as BA -import Data.List (find) -import qualified Data.Map.Strict as Map -import Data.Maybe (isJust) -import qualified Data.Set as Set -import Ledger.Core hiding ((◁), (⋪)) -import Ledger.Signatures -import Numeric.Natural (Natural) -import Data.Map.Strict (Map) -import Data.Set (Set) -import qualified Crypto.Hash as Crypto -import qualified Data.ByteString.Char8 as BS - --- |A unique ID of a transaction, which is computable from the transaction. -newtype TxId = TxId { getTxId :: Hash } - deriving (Show, Eq, Ord) - --- |The input of a UTxO. --- --- * __TODO__ - is it okay to use list indices instead of implementing the Ix Type? -data TxIn = TxIn TxId Natural deriving (Show, Eq, Ord) - --- |The output of a UTxO. -data TxOut = TxOut Addr Value deriving (Show, Eq) - --- |The unspent transaction outputs. -newtype UTxO = UTxO (Map TxIn TxOut) deriving (Show, Eq) - --- |A raw transaction -data Tx = Tx { inputs :: Set TxIn - , outputs :: [TxOut] - } deriving (Show, Eq) - --- |Compute the id of a transaction. -txid :: Tx -> TxId -txid = TxId . hash - --- |Compute the UTxO inputs of a transaction. -txins :: Tx -> Set TxIn -txins = inputs - --- |Compute the UTxO outputs of a transaction. -txouts :: Tx -> UTxO -txouts tx = UTxO $ Map.fromList - [ (TxIn transId idx, out) | (out, idx) <- zip (outputs tx) [0 ..] ] - where transId = txid tx - -txfee :: Tx -> Value -txfee = undefined - --- |Domain restriction --- --- * __TODO__ - better symbol? -(◁) :: Set TxIn -> UTxO -> UTxO -ins ◁ (UTxO utxo) = UTxO $ Map.filterWithKey (\k _ -> k `Set.member` ins) utxo - --- |Domain exclusion --- -(⋪) :: Set TxIn -> UTxO -> UTxO -ins ⋪ (UTxO utxo) = - UTxO $ Map.filterWithKey (\k _ -> k `Set.notMember` ins) utxo - --- |Combine two collections of UTxO. --- --- * TODO - Should we return 'Maybe UTxO' so that we can return --- Nothing when the collections are not disjoint? -(∪) :: UTxO -> UTxO -> UTxO -(UTxO a) ∪ (UTxO b) = UTxO $ Map.union a b - --- |Determine the total balance contained in the UTxO. -balance :: UTxO -> Value -balance (UTxO utxo) = Map.foldl' addValues mempty utxo - where addValues b (TxOut _ a) = b <> a - -instance Ledger.Core.HasHash Tx where - hash = Crypto.hash - -instance BA.ByteArrayAccess Tx where - length = BA.length . BS.pack . show - withByteArray = BA.withByteArray . BS.pack . show - ---------------------------------------------------------------------------------- --- UTxO transitions ---------------------------------------------------------------------------------- - -newtype ProtocolConstants = ProtocolConstants - { pcMinFee :: Tx -> Value } - --- | UTXO transition system -data UTXO - -instance STS UTXO where - type State UTXO = UTxO - type Signal UTXO = Tx - type Environment UTXO = ProtocolConstants - data PredicateFailure UTXO - = BadInputs - | FeeTooLow - | IncreasedTotalBalance - deriving (Eq, Show) - - initialRules = - [ return (UTxO Map.empty) ] - transitionRules = [ utxoInductive ] - -utxoInductive :: TransitionRule UTXO -utxoInductive = do - TRC (pc, utxo, tx) <- judgmentContext - balance (txouts tx) - <> txfee tx - == balance (txins tx ◁ utxo) - ?! IncreasedTotalBalance - pcMinFee pc tx <= txfee tx ?! FeeTooLow - let unspentInputs (UTxO aUtxo) = Map.keysSet aUtxo - txins tx `Set.isSubsetOf` unspentInputs utxo ?! BadInputs - return $ (txins tx ⋪ utxo) ∪ txouts tx - ---------------------------------------------------------------------------------- --- UTxO transitions ---------------------------------------------------------------------------------- - --- |Proof/Witness that a transaction is authorized by the given key holder. -data Wit = Wit VKey (Sig Tx) deriving (Show, Eq) - --- |A fully formed transaction. --- --- * __TODO__ - Would it be better to name this type Tx, and rename Tx to TxBody? -data TxWits = TxWits - { body :: Tx - , witneses :: Set Wit - } deriving (Show, Eq) - --- |Create a witness for transaction -makeWitness :: KeyPair -> Tx -> Wit -makeWitness keys tx = Wit (vKey keys) (sign (sKey keys) tx) - --- | UTXO with witnessing -data UTXOW - -instance STS UTXOW where - type State UTXOW = UTxO - type Signal UTXOW = TxWits - type Environment UTXOW = ProtocolConstants - data PredicateFailure UTXOW - = UtxoFailure (PredicateFailure UTXO) - | InsufficientWitnesses - deriving (Eq, Show) - - initialRules = [ return $ UTxO Map.empty ] - transitionRules = - [ do - TRC (pc, utxo, tw) <- judgmentContext - witnessed tw utxo ?! InsufficientWitnesses - res <- trans @UTXO $ TRC (pc, utxo, body tw) - return res - ] - -instance Embed UTXO UTXOW where - wrapFailed = UtxoFailure - --- |Determine if a UTxO input is authorized by a given key. -authTxin :: VKey -> TxIn -> UTxO -> Bool -authTxin key txin (UTxO utxo) = case Map.lookup txin utxo of - Just (TxOut (Addr pay) _) -> hash key == pay - _ -> False - --- |Given a ledger state, determine if the UTxO witnesses in a given --- transaction are sufficient. --- TODO - should we only check for one witness for each unique input address? -witnessed :: TxWits -> UTxO -> Bool -witnessed (TxWits tx wits) utxo = - Set.size wits == Set.size ins && all (hasWitness wits) ins - where - ins = inputs tx - hasWitness witnesses input = - isJust $ find (isWitness tx input utxo) witnesses - isWitness tx' input unspent (Wit key sig) = - verify key tx' sig && authTxin key input unspent diff --git a/specs/ledger/hs/src/Ledger/Update.hs b/specs/ledger/hs/src/Ledger/Update.hs deleted file mode 100644 index fe93e46d..00000000 --- a/specs/ledger/hs/src/Ledger/Update.hs +++ /dev/null @@ -1,29 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} - -module Ledger.Update where - -import Control.Lens (makeLenses) -import Numeric.Natural - -import Ledger.Core (SlotCount) - --- | Protocol parameters. --- -data PParams = PParams -- TODO: this should be a module of @cs-ledger@. - { _maxBkSz :: !Natural - -- ^ Maximum (abstract) block size in words. - , _maxHdrSz :: !Natural - -- ^ Maximum (abstract) block header size in words. - , _dLiveness :: !SlotCount - -- ^ Delegation liveness parameter: number of slots it takes a delegation - -- certificate to take effect. - , _bkSgnCntW :: !Int - -- ^ Size of the moving window to count signatures. - , _bkSgnCntT :: !Double - -- ^ Fraction [0, 1] of the blocks that can be signed by any given key in a - -- window of lenght '_bkSgnCntW'. This value will be typically between 1/5 - -- and 1/4. - , _bkSlotsPerEpoch :: !SlotCount - } deriving (Eq, Show) - -makeLenses ''PParams diff --git a/specs/ledger/hs/test/Ledger/Delegation/Examples.hs b/specs/ledger/hs/test/Ledger/Delegation/Examples.hs deleted file mode 100644 index db1aed4e..00000000 --- a/specs/ledger/hs/test/Ledger/Delegation/Examples.hs +++ /dev/null @@ -1,90 +0,0 @@ -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE OverloadedLists #-} --- | Examples of the application of the delegation rules. -module Ledger.Delegation.Examples - ( deleg - ) -where - -import Data.Set (fromList, Set) -import Numeric.Natural (Natural) -import Test.Tasty (TestTree, testGroup) -import Test.Tasty.HUnit (testCase) - -import Ledger.Core - ( Epoch(Epoch) - , Owner(Owner) - , Sig(Sig) - , Slot(Slot) - , SlotCount(SlotCount) - , VKey(VKey) - , VKeyGenesis(VKeyGenesis) - , owner - ) -import Ledger.Delegation - ( ADELEG - , DCert(DCert) - , DSEnv(DSEnv) - , DSState(DSState) - , DState(DState) - , SDELEG - ) -import Control.State.Transition.Trace ((.-), (.->), checkTrace) - --- | Delegation examples. -deleg :: [TestTree] -deleg = - [ testGroup "Activation" - [ testCase "Example 0" $ checkTrace @ADELEG genKeys $ - - pure (DState [] []) - - .- (s 0, (gk 0, k 10)) .-> DState [(gk 0, k 10)] - [(gk 0, s 0)] - - .- (s 1, (gk 1, k 11)) .-> DState [(gk 0, k 10), (gk 1, k 11)] - [(gk 0, s 0), (gk 1, s 1)] - - .- (s 2, (gk 0, k 11)) .-> DState [(gk 0, k 11), (gk 1, k 11)] - [(gk 0, s 2), (gk 1, s 1)] - - .- (s 3, (gk 2, k 12)) .-> DState [(gk 0, k 11), (gk 1, k 11), (gk 2, k 12)] - [(gk 0, s 2), (gk 1, s 1), (gk 2, s 3)] - ] - - , testGroup "Scheduling" - [ testCase "Example 0" $ checkTrace @SDELEG (DSEnv [gk 0, gk 1, gk 2] (e 8) (s 2) (sc 10)) $ - - pure (DSState [] []) - - .- dc (gk 0) (k 10) (e 8) .-> DSState [(s 12, (gk 0, k 10))] - [(e 8, gk 0)] - - .- dc (gk 1) (k 11) (e 8) .-> DSState [(s 12, (gk 0, k 10)), (s 12, (gk 1, k 11))] - [(e 8, gk 0), (e 8, gk 1)] - - .- dc (gk 2) (k 10) (e 8) .-> DSState [(s 12, (gk 0, k 10)), (s 12, (gk 1, k 11)), (s 12, (gk 2, k 10))] - [(e 8, gk 0), (e 8, gk 1), (e 8, gk 2)] - ] - ] - where - s :: Natural -> Slot - s = Slot - - k :: Natural -> VKey - k = VKey . Owner - - gk :: Natural -> VKeyGenesis - gk = VKeyGenesis . k - - sc :: Natural -> SlotCount - sc = SlotCount - - e :: Natural -> Epoch - e = Epoch - - dc :: VKeyGenesis -> VKey -> Epoch -> DCert - dc vkg vk ep = DCert (vk, ep) (Sig vkg (owner vkg)) (vkg, vk) ep - - genKeys :: Set VKeyGenesis - genKeys = fromList $ map (VKeyGenesis . VKey . Owner) [0 .. 6] diff --git a/specs/ledger/hs/test/Ledger/Delegation/Properties.hs b/specs/ledger/hs/test/Ledger/Delegation/Properties.hs deleted file mode 100644 index 5eac888f..00000000 --- a/specs/ledger/hs/test/Ledger/Delegation/Properties.hs +++ /dev/null @@ -1,284 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE MultiParamTypeClasses #-} --- | Properties of the delegation traces induced by the transition systems --- associated with this aspect of the ledger. -module Ledger.Delegation.Properties - ( dcertsAreTriggered - , rejectDupSchedDelegs - ) -where - -import Control.Arrow ((&&&)) -import Control.Lens ((^.), makeLenses, (&), (.~), view) -import Data.Map.Strict (Map) -import qualified Data.Map.Strict as Map -import qualified Data.Set as Set -import GHC.Natural (minusNaturalMaybe) -import Hedgehog - ( MonadTest - , Property - , (===) - , assert - , forAll - , property - , withTests - ) -import Hedgehog.Gen (integral) -import Hedgehog.Range (constant, linear) - -import Control.State.Transition - ( Environment - , PredicateFailure - , STS - , Signal - , State - , initialRules - , transitionRules - , TRC (TRC) - , judgmentContext - , (?!) - , trans - , Embed - , wrapFailed - , applySTS - ) -import Control.State.Transition.Generator - ( HasSizeInfo - , HasTrace - , initEnvGen - , isTrivial - , nonTrivialTrace - , sigGen - , suchThatLastState - , trace - ) -import Control.State.Transition.Trace - ( Trace - , TraceOrder(NewestFirst) - , lastState - , traceEnv - , traceSignals - ) -import Ledger.Core - ( Epoch(Epoch) - , Owner(Owner) - , Sig(Sig) - , Slot(Slot) - , SlotCount(SlotCount) - , VKey(VKey) - , VKeyGenesis - , VKeyGenesis(VKeyGenesis) - , addSlot - , owner - ) -import Ledger.Delegation - ( DCert - , DCert(DCert) - , DELEG - , DState(DState, _dStateDelegationMap, _dStateLastDelegation) - , DSState(DSState) - , _dSStateScheduledDelegations - , _dSStateKeyEpochDelegations - , DIState(DIState) - , _dIStateDelegationMap - , _dIStateLastDelegation - , _dIStateScheduledDelegations - , _dIStateKeyEpochDelegations - , DSEnv(DSEnv) - , DSEnv - , PredicateFailure(IsAlreadyScheduled, SDelegFailure, SDelegSFailure) - , _dbody - , _depoch - , _dwho - , _dwit - , delegate - , delegationMap - , delegator - , liveness - , scheduledDelegations - , slot - ) -import Ledger.Core.Generator (vkGen) - --------------------------------------------------------------------------------- --- Delegation certification triggering tests --------------------------------------------------------------------------------- - --- | Initial state for the ADELEG and ADELEGS systems -initADelegsState :: DState -initADelegsState = DState - { _dStateDelegationMap = Map.empty - , _dStateLastDelegation = Map.empty - } - --- | Initial state for the ADELEG and ADELEGS systems -initSDelegsState :: DSState -initSDelegsState = DSState - { _dSStateScheduledDelegations = [] - , _dSStateKeyEpochDelegations = Set.empty - } - --- | Initial state for the DELEG system -initialDIState :: DIState -initialDIState = DIState - { _dIStateDelegationMap = _dStateDelegationMap initADelegsState - , _dIStateLastDelegation = _dStateLastDelegation initADelegsState - , _dIStateScheduledDelegations = initSDelegsState ^. scheduledDelegations - , _dIStateKeyEpochDelegations = _dSStateKeyEpochDelegations initSDelegsState - } - --- | Delegation blocks. Simple blockchain to test delegation. -data DBLOCK - --- | A delegation block. -data DBlock - = DBlock - { _blockSlot :: Slot - , _blockCerts :: [DCert] - } - deriving (Show, Eq) - -makeLenses ''DBlock - --- | This corresponds to a state-transition rule where blocks with increasing --- slot-numbers are produced. -instance STS DBLOCK where - type Environment DBLOCK = () - type State DBLOCK = (DSEnv, DIState) - type Signal DBLOCK = DBlock - - data PredicateFailure DBLOCK - = DPF (PredicateFailure DELEG) - | NotIncreasingBlockSlot - deriving (Eq, Show) - - initialRules = [pure (initDSEnv, initialDIState)] - - transitionRules - = [ do - TRC (_, (env, st), dblock) <- judgmentContext - env ^. slot < dblock ^. blockSlot ?! NotIncreasingBlockSlot - stNext <- trans @DELEG $ TRC (env, st, dblock ^. blockCerts) - return (env & slot .~ dblock ^. blockSlot, stNext) - ] - -instance Embed DELEG DBLOCK where - wrapFailed = DPF - --- | Check that all the delegation certificates in the trace were correctly --- applied. -dcertsAreTriggeredInTrace :: MonadTest m => Trace DBLOCK -> m () -dcertsAreTriggeredInTrace tr - = lastDms === trExpectedDms - where - lastDms = st ^. delegationMap - - trExpectedDms - = expectedDms (env ^. slot) (env ^. liveness) (traceSignals NewestFirst tr) - - (env, st) = lastState tr - --- | Compute the expected delegation map after applying the sequence of --- delegation certificates contained in the given blocks. --- --- Delegation certificates are applied in the order they appear in the within a --- block, and blocks are considered in the order they appear on the list passed --- as parameter. -expectedDms - :: Slot - -- ^ Current slot - -> SlotCount - -- ^ Delegation certificate liveness parameter. - -> [DBlock] - -- ^ Delegation certificates to apply. - -> Map VKeyGenesis VKey -expectedDms s d cs = Map.fromList (fmap (delegator &&& delegate) activeCerts) - where - -- | We keep all the blocks whose certificates should be active given the - -- current slot. - activeBlocks :: [DBlock] - activeBlocks = filter (\b -> b ^. blockSlot <= activationSlot) cs - - -- | Slot at which the certificates become active. - activationSlot :: Slot - activationSlot = s `minusSlotCount` d - - -- | Get the active certificates from each block, and concatenate them all - -- together. - activeCerts :: [DCert] - activeCerts = concatMap _blockCerts activeBlocks - -minusSlotCount :: Slot -> SlotCount -> Slot -minusSlotCount (Slot s) (SlotCount c) = case s `minusNaturalMaybe` c of - Nothing -> Slot 0 - Just k -> Slot k - --- | An initial delegation scheduling environment to be used in the traces --- produced by the @DBLOCK@ transition system. -initDSEnv :: DSEnv -initDSEnv - = DSEnv - (Set.fromAscList $ gk <$> [0..6]) - (Epoch 0) - (Slot 0) - (SlotCount 1) - where - gk = VKeyGenesis . k - k n = VKey (Owner n) - -instance HasTrace DBLOCK where - - initEnvGen = return () - - sigGen _ (env, st) = do - c <- integral (constant 1 10) - let newSlot = (env ^.slot) `addSlot` SlotCount c - delegs <- sigGen @DELEG env st - return $ DBlock newSlot delegs - -instance HasSizeInfo DBlock where - isTrivial = null . view blockCerts - -dcertsAreTriggered :: Property -dcertsAreTriggered = withTests 300 $ property $ - -- The number of tests was determined ad-hoc, since the default failed to - -- uncover the presence of errors. - forAll nonTrivialTrace >>= dcertsAreTriggeredInTrace - --------------------------------------------------------------------------------- --- Properties related to the transition rules --------------------------------------------------------------------------------- - --- | Reject delegation certificates where a genesis key tries to delegate in --- the same slot. --- --- This property tries to generate a trace where the last state contains a --- non-empty sequence of scheduled delegations. If such trace cannot be --- generated, then the test will fail when the heap limit is reached, or --- hedgehog gives up. -rejectDupSchedDelegs :: Property -rejectDupSchedDelegs = property $ do - (tr, dcert) <- forAll $ do - tr <- trace @DELEG - `suchThatLastState` (not . null . view scheduledDelegations) - let vkS = - case lastState tr ^. scheduledDelegations of - (_, (res, _)):_ -> res - _ -> error $ "This should not happen: " - ++ "tr is guaranteed to contain a non-empty sequence of scheduled delegations" - vkD <- vkGen - epo <- Epoch <$> integral (linear 0 100) - let dcert - = DCert - { _dbody = (vkD, epo) - , _dwit = Sig vkS (owner vkS) - , _dwho = (vkS, vkD) - , _depoch = epo - } - return (tr, dcert) - let pfs = case applySTS (TRC (tr ^. traceEnv, lastState tr, [dcert])) of - Left res -> res - Right _ -> [] - assert $ SDelegSFailure (SDelegFailure IsAlreadyScheduled) `elem` pfs diff --git a/specs/ledger/hs/test/Main.hs b/specs/ledger/hs/test/Main.hs deleted file mode 100644 index 596baf5a..00000000 --- a/specs/ledger/hs/test/Main.hs +++ /dev/null @@ -1,26 +0,0 @@ -module Main - ( main - ) -where - -import System.Environment (withArgs) - -import Test.Tasty (TestTree, defaultMain, testGroup, localOption) -import Test.Tasty.Hedgehog (testProperty) -import Test.Tasty.Ingredients.ConsoleReporter (UseColor(Auto)) -import Ledger.Delegation.Examples (deleg) -import Ledger.Delegation.Properties (dcertsAreTriggered, rejectDupSchedDelegs) - -main :: IO () -main = withArgs [] $ defaultMain tests - where - tests :: TestTree - tests = localOption Auto $ testGroup - "Ledger" - [ testGroup "Ledger" [testGroup "Delegation Examples" deleg] - , testGroup - "Properties" - [ testProperty "Activation" dcertsAreTriggered - , testProperty "One delegation per-slot per-key" rejectDupSchedDelegs - ] - ] diff --git a/specs/ledger/latex/.dir-locals.el b/specs/ledger/latex/.dir-locals.el deleted file mode 100644 index 83e87a9c..00000000 --- a/specs/ledger/latex/.dir-locals.el +++ /dev/null @@ -1,2 +0,0 @@ -((latex-mode - (TeX-master ."ledger-spec.tex"))) diff --git a/specs/ledger/latex/Makefile b/specs/ledger/latex/Makefile deleted file mode 100644 index 0e7591f0..00000000 --- a/specs/ledger/latex/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -## -## Makefile for the ledger rules, based on: -## -## https://tex.stackexchange.com/questions/40738/how-to-properly-make-a-latex-project -## - -# Document name -DOCNAME = ledger-spec - -# You want latexmk to *always* run, because make does not have all the info. -# Also, include non-file targets in .PHONY so they are run regardless of any -# file of the given name existing. -.PHONY: $(DOCNAME).pdf all clean - -# The first rule in a Makefile is the one executed by default ("make"). It -# should always be the "all" rule, so that "make" and "make all" are identical. -all: $(DOCNAME).pdf - -## -## CUSTOM BUILD RULES -## - -## -## MAIN LATEXMK RULE -## - -# -pdf tells latexmk to generate PDF directly (instead of DVI). -# -pdflatex="" tells latexmk to call a specific backend with specific options. -# -use-make tells latexmk to call make for generating missing files. - -# -interaction=nonstopmode keeps the pdflatex backend from stopping at a -# missing file reference and interactively asking you for an alternative. - -$(DOCNAME).pdf: $(DOCNAME).tex - latexmk -pdf -pdflatex="pdflatex -interaction=nonstopmode" -use-make $(DOCNAME).tex - -watch: $(DOCNAME).tex - latexmk -pvc -pdf -pdflatex="pdflatex -interaction=nonstopmode" -use-make $(DOCNAME).tex - -clean: - latexmk -CA - -install: - mkdir -pv ${out}/nix-support/ - cp ledger-spec.pdf ${out}/ - echo "doc-pdf ledger-spec ${out}/ledger-spec.pdf" > ${out}/nix-support/hydra-build-products diff --git a/specs/ledger/latex/blockchain-interface.tex b/specs/ledger/latex/blockchain-interface.tex deleted file mode 100644 index a683d843..00000000 --- a/specs/ledger/latex/blockchain-interface.tex +++ /dev/null @@ -1,926 +0,0 @@ -\section{Blockchain interface} -\label{sec:blockchain-interface} - -\newcommand{\DIEnv}{\type{DIEnv}} -\newcommand{\DIState}{\type{DIState}} - -\newcommand{\UPIEnv}{\type{UPIEnv}} -\newcommand{\UPIState}{\type{UPIState}} - -\subsection{Delegation interface} -\label{sec:delegation-interface} - -\begin{figure}[htb] - \emph{Delegation interface environments} - \begin{equation*} - \DIEnv = - \left( - \begin{array}{r@{~\in~}lr} - \mathcal{K} & \powerset{\VKeyGen} & \text{allowed delegators}\\ - \var{e} & \Epoch & \text{epoch}\\ - \var{s} & \Slot & \text{slot}\\ - \var{pps} & \PPMMap & \text{Protocol parameters} - \end{array} - \right) - \end{equation*} - - \emph{Delegation interface states} - \begin{equation*} - \DIState - = \left( - \begin{array}{r@{~\in~}lr} - \var{dms} & \VKeyGen \mapsto \VKey & \text{delegation map}\\ - \var{dws} & \VKeyGen \mapsto \Slot & \text{when last delegation occurred}\\ - \var{sds} & \seqof{(\Slot \times (\VKeyGen \times \VKey))} & \text{scheduled delegations}\\ - \var{eks} & \powerset{(\Epoch \times \VKeyGen)} & \text{key-epoch delegations} - \end{array} - \right) - \end{equation*} - - \emph{Delegation transitions} - \begin{equation*} - \_ \vdash \_ \trans{deleg}{\_} \_ \in - \powerset (\DIEnv \times \DIState \times \seqof{\DCert} \times \DIState) - \end{equation*} - \caption{Delegation interface transition-system types} - \label{fig:ts-types:delegation-interface} -\end{figure} - -\subsubsection{Delegation interface rules} -\label{sec:delegation-interface-rules} - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:delegation-interface} - \inference - { - \var{certificateLiveness} \mapsto d \in \var{pps} \\ - {\begin{array}{l} - \mathcal{K} \\ - e\\ - s\\ - d - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{sds}\\ - \var{eks} - \end{array} - \right) - } - \trans{sdelegs}{\Gamma} - { - \left( - \begin{array}{l} - \var{sds'}\\ - \var{eks'} - \end{array} - \right) - } - & - { - \left( - \begin{array}{l} - \var{dms}\\ - \var{dws} - \end{array} - \right) - } - \trans{adelegs}{[.., s] \restrictdom \var{sds'}} - { - \left( - \begin{array}{l} - \var{dms'}\\ - \var{dws'} - \end{array} - \right) - } - } - { - {\begin{array}{l} - \mathcal{K} \\ - e\\ - s\\ - pps - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{dms}\\ - \var{dws}\\ - \var{sds}\\ - \var{eks} - \end{array} - \right) - } - \trans{deleg}{\Gamma} - { - \left( - \begin{array}{l} - \var{dms'}\\ - \var{dws'}\\ - \var{[s-d,~ s+d]} \restrictdom \var{sds'}\\ - \var{[e, ..]} \restrictdom \var{eks'} - \end{array} - \right) - } - } - \end{equation} - \caption{Delegation interface rules} - \label{fig:rules:delegation-interface} -\end{figure} - -\subsubsection{Delegation interface functions} -\label{sec:delegation-interface-functions} - -\begin{figure}[htb] - \begin{align*} - & \fun{delegates} \in \DIState \to (\VKeyGen \times \VKey) \to \Bool & \text{delegation relationship}\\ - & \fun{delegates}~s~(\var{vk_s}, \var{vk_d}) = \var{vk_s} \mapsto \var{vk_d} \in (\var{dms}~s)\\ - \nextdef - & \fun{initialDS} \in \VKeyGen \to \DIState & \text{initial delegation state}\\ - & \fun{initialDS}~\var{ks} = - \left( - \begin{array}{l} - \var{ks} \mapsto \var{ks}\\ - \emptyset\\ - \epsilon\\ - \emptyset\\ - \end{array} - \right) - \end{align*} - \caption{Delegation interface functions} -\end{figure} - -\clearpage - -\subsection{Update-proposals interface} -\label{sec:update-proposals-interface} - -Figure~\ref{fig:ts-types:upi} defines the types of the transition systems -related with the update-proposals interface. The acronyms in the transition -labels have the following meaning: -\begin{description} -\item[UPIREG] Update-proposal-interface registration. -\item[UPIVOTE] Update-proposal-interface vote. -\item[UPIEND] Update-proposal-interface endorsement. -\item[UPIEC] Update-proposal-interface epoch-change. -\end{description} - -\begin{figure}[htb] - \emph{Update-proposals interface environments} - \begin{align*} - & \UPIEnv - = \left( - \begin{array}{r@{~\in~}lr} - \var{e_c} & \Epoch & \text{current epoch}\\ - \var{s_n} & \Slot & \text{current slot number}\\ - \var{dms} & \VKeyGen \mapsto \VKey & \text{delegation map}\\ - \end{array}\right) - \end{align*} - % - \emph{Update-proposals interface states} - \begin{align*} - & \UPIState = \\ - & \left( - \begin{array}{r@{~\in~}lr} - \var{e_p} & \Epoch & \text{previously seen epoch}\\ - (\var{pv}, \var{pps}) & \ProtVer \times \PPMMap - & \text{current protocol information}\\ - \var{fads} & \seqof{(\Slot \times (\ProtVer \times \PPMMap))} - & \text{future protocol version adoptions}\\ - \var{avs} & \ApName \mapsto (\ApVer \times \Slot) - & \text{application versions}\\ - \var{rpus} & \UPropId \mapsto (\ProtVer \times \PPMMap) - & \text{registered protocol update proposals}\\ - \var{raus} & \UPropId \mapsto (\ApName \times \mathbb{N}) - & \text{registered software update proposals}\\ - \var{cps} & \UPropId \mapsto \Slot & \text{confirmed proposals}\\ - \var{vts} & \powerset{(\UPropId \times \VKeyGen)} & \text{proposals votes}\\ - \var{bvs} & \powerset{(\ProtVer \times \VKeyGen)} - & \text{endorsement-key pairs}\\ - \var{pws} & \UPropId \mapsto \Slot & \text{proposal timestamps} - \end{array}\right)\\ - \end{align*} - % - \emph{Update-proposals interface transitions} - \begin{equation*} - \begin{array}{r@{~\in~}l} - \_ \vdash \_ \trans{upireg}{\_} \_ & - \powerset (\UPIEnv \times \UPIState \times \UProp \times \UPIState)\\ - \_ \vdash \_ \trans{upivote}{\_} \_ & - \powerset (\UPIEnv \times \UPIState \times \Vote \times \UPIState)\\ - \_ \vdash \_ \trans{upiend}{\_} \_ & - \powerset (\UPIEnv \times \UPIState - \times (\ProtVer \times \VKey) \times \UPIState)\\ - \_ \vdash \_ \trans{upiec}{\_} \_ & - \powerset (\UPIEnv \times \UPIState \times \Epoch \times \UPIState) - \end{array} - \end{equation*} - \caption{Update-proposals interface transition-system types} - \label{fig:ts-types:upi} -\end{figure} - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:upi-reg-interface} - \inference - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps}\\ - \var{avs}\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus}\\ - \var{raus} - \end{array} - \right) - } - \trans{upreg}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus'}\\ - \var{raus'} - \end{array} - \right) - } - & - pws' = pws \unionoverride \{ \upId{up} \mapsto s_n\} - } - { - { - \begin{array}{l} - e_c\\ - s_n\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{e_p}\\ - (\var{pv}, \var{pps})\\ - \var{fads}\\ - \var{avs}\\ - \var{rpus}\\ - \var{raus}\\ - \var{cps}\\ - \var{vts}\\ - \var{bvs}\\ - \var{pws} - \end{array} - \right) - } - \trans{upireg}{\var{up}} - { - \left( - \begin{array}{l} - \var{e_p}\\ - (\var{pv}, \var{pps})\\ - \var{fads}\\ - \var{avs}\\ - \var{rpus'}\\ - \var{raus'}\\ - \var{cps}\\ - \var{vts}\\ - \var{bvs}\\ - \var{pws'} - \end{array} - \right) - } - } - \end{equation} - \caption{Update-proposals registration rules} - \label{fig:rules:upi-reg-interface} -\end{figure} - -\clearpage - -Rule~\ref{eq:rule:upi-vote} models the effect of voting on an update proposal: -after a vote, a proposal might get confirmed, which means that it will be added -to the set $\var{cps'}$. In such case, the mapping of application names to -their latest version known to the ledger will be updated to include the -information in the confirmed proposal. Note that, unlike protocol updates, -software updates take effect as soon as a proposal is confirmed. In this rule, -we also delete the confirmed proposal id's from the set of registered -application update proposals ($\var{raus}$), since this information is no -longer needed once the application-name to software-version map ($\var{avs}$) is -updated. - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:upi-vote} - \inference - { - { - \begin{array}{l} - s_n\\ - \var{pps}\\ - \var{\dom~pws}\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{cps}\\ - \var{vts} - \end{array} - \right) - } - \trans{upvote}{\var{v}} - { - \left( - \begin{array}{l} - \var{cps'}\\ - \var{vts'} - \end{array} - \right) - }\\ - \var{avs_{new}} = \{ \var{an} \mapsto (\var{av}, \var{s_n}) - \mid \var{pid} \mapsto (\var{an}, \var{av}) \in \var{raus} - ,~ \var{pid} \in \dom~\var{cps'} - \} - } - { - { - \begin{array}{l} - e_c\\ - s_n\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{e_p}\\ - (\var{pv}, \var{pps})\\ - \var{fads}\\ - \var{avs}\\ - \var{rpus}\\ - \var{raus}\\ - \var{cps}\\ - \var{vts}\\ - \var{bvs}\\ - \var{pws} - \end{array} - \right) - } - \trans{upivote}{\var{v}} - { - \left( - \begin{array}{l} - \var{e_p}\\ - (\var{pv}, \var{pps})\\ - \var{fads}\\ - \var{avs} \unionoverride \var{avs_{new}}\\ - \var{rpus}\\ - \dom~ \var{cps} \subtractdom \var{raus}\\ - \var{cps'}\\ - \var{vts'}\\ - \var{bvs}\\ - \var{pws} - \end{array} - \right) - } - } - \end{equation} - \caption{Voting on update-proposals rules} - \label{fig:rules:upi-vote} -\end{figure} - -Figure~\ref{fig:st-diagram-sw-up} shows the different states in which a -software proposal update might be: if valid, a software update proposal becomes -active whenever it is included in a block. If the update proposal gets enough -votes, then the corresponding software update proposal becomes confirmed, and -the ledger state reflects this. If the voting period ends without an update -proposal being confirmed, then the corresponding software update proposal gets -rejected. -% -Protocol updates on the other hand, involve a slightly different logic, and the -state transition diagram for these kind of updates is shown in -Figure~\ref{fig:st-diagram-pt-up}. - -\begin{figure}[ht] - \centering - \begin{tikzpicture}[ align = center - , node distance = 6em and 12em - , text width = 5em - , font = \footnotesize - , >={Latex[width=0.5em, length=0.5em]} - , every node/.style = { rectangle - , rounded corners - , draw = black - , align = center - , minimum height = 4em } - ] - - \node (active) [fill = blue!10] {Active}; - \node (rejected) [below = of active, fill = red!10] {Rejected}; - \node (confirmed) [right = of active, fill = green!30] {Confirmed}; - - \tikzset{every node/.style={align=center, text width=10em, text=brown}} - - \draw[->] (active) - edge node [above] {Software Update proposal\\ gets enough votes} - (confirmed); - - \draw[->] (active) - edge node [left] {Voting period \\ends} - (rejected); - - \end{tikzpicture} - - \caption{State-transition diagram for software-updates} - \label{fig:st-diagram-sw-up} -\end{figure} - -\clearpage - -The interface rule for protocol-version endorsement makes use of the -$\trans{upend}{}$ transition, passing only the portion of the state relevant -to it. In addition, the unconfirmed proposals that are older than $u$ blocks -are removed from the parts of the state that hold: -\begin{itemize} -\item the registered protocol and software update proposals, -\item the votes associated with the proposals, -\item the set of endorsement-key pairs, and -\item the block number in which proposals where added. -\end{itemize} - -In Rule~\ref{eq:rule:upi-pend}, the set of proposal id's $\var{pid_{keep}}$ -contains only those proposals that haven't expired yet or that are confirmed. -Once a proposal $\var{up}$ is confirmed, it is removed from the set of -confirmed proposals ($\var{cps}$) either when it is adopted or when a protocol -version higher than that of $\var{up}$ gets adopted (see -Rule~\ref{eq:rule:upi-ec}). -% -The set of endorsement-key pairs is cleaned here as well as in the epoch change -rule (Rule~\ref{eq:rule:upi-ec}). The reason for this is that this set grows at -each block, and it can get considerably large if no proposal gets adopted at -the end on an epoch. - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:upi-pend} - \inference - { - { - \begin{array}{l} - k\\ - s_n\\ - (\var{pv}, \var{pps})\\ - \var{cps}\\ - \var{rpus} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{fads}\\ - \var{bvs} - \end{array} - \right) - } - \trans{upend}{(\var{bv}, \var{vk})} - { - \left( - \begin{array}{l} - \var{fads'}\\ - \var{bvs'} - \end{array} - \right) - }\\ - \var{chainStability} \mapsto k \in \var{pps} & - \var{upropTTL} \mapsto u \in \var{pps} \\ - { - \begin{array}{r@{~=~}l} - \var{pids_{keep}} & \dom~(pws \restrictrange [s_n - u, ..]) \cup \dom~\var{cps}\\ - \var{vs_{keep}} & \dom~(\range~\var{rpus'})\\ - \var{rpus'} & \var{pids_{keep}} \restrictdom \var{rpus} - \end{array} - } - } - { - { - \begin{array}{l} - e_c\\ - s_n\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{e_p}\\ - (\var{pv}, \var{pps})\\ - \var{fads}\\ - \var{avs}\\ - \var{rpus}\\ - \var{raus}\\ - \var{cps}\\ - \var{vts}\\ - \var{bvs}\\ - \var{pws} - \end{array} - \right) - } - \trans{upiend}{(\var{bv}, \var{vk})} - { - \left( - \begin{array}{l} - \var{e_p}\\ - (\var{pv}, \var{pps})\\ - \var{fads'}\\ - \var{avs}\\ - \var{rpus'}\\ - \var{pids_{keep}} \restrictdom \var{raus}\\ - \var{cps}\\ - \var{pids_{keep}} \restrictdom \var{vts}\\ - \var{vs_{keep}} \restrictdom \var{bvs}\\ - \var{pids_{keep}} \restrictdom \var{pws} - \end{array} - \right) - } - } - \end{equation} - \caption{Proposal endorsement rules} - \label{fig:rules:upi-pend} -\end{figure} - -\clearpage - -Rule~\ref{eq:rule:upi-ec} models how the epoch, protocol-version and its -parameters are changed depending on the epoch in the signal ($e_n$ in this -case). A change in the epoch only occurs if the new epoch is greater than the -previously seen epoch ($e_p$). -% -On an epoch change, this rule will pick a candidate that gathered enough -endorsements at least $2 \cdot k$ slots ago. If a protocol-version candidate -cannot gather enough endorsements $2 \cdot k$ slots before the end of an -epoch, the proposal can only be adopted in the next epoch. -% -Figure~\ref{fig:up-confirmed-too-late} shows an example of a proposal being -confirmed too late in an epoch, where it is not possible to get enough -endorsements in the remaining window. In this Figure we take $k = 2$, and we -assume $5$ endorsements are needed to consider a proposal as candidate for -adoption. -% -Note that, in the final state, we use union override to define the updated -parameters ($\var{pps} \unionoverride \var{pps'}$). This is because candidate -proposal might only update some parameters of the protocol. - -Rule~\ref{eq:rule:upi-ec} performs cleanup of several state variables: -\begin{itemize} -\item We keep only the information of proposals whose proposed - protocol-versions are greater than the newly adopted protocol version - ($\var{pv'}$). This means that active proposals will be discarded even if the - voting period is not over (it makes no sense to vote on a proposal that - proposes to upgrade to an older version of the protocol). -\item The registered software-update proposals need not be cleaned here, since - this is done either when a proposal gets confirmed or when it expires. -\item Rule~\ref{eq:rule:pvbump-change} keeps only those candidates that can be - adopted in future epochs. -\end{itemize} - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:pvbump-change-noop} - \inference - { - e_n \leq e_p - } - { - {\begin{array}{l} - k\\ - s_n - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{e_p}\\ - \var{(\var{pv}, \var{pps})}\\ - \var{fads} - \end{array} - \right) - } - \trans{pvbump}{\var{e_n}} - { - \left( - \begin{array}{l} - \var{e_p}\\ - \var{(\var{pv}, \var{pps})}\\ - \var{fads} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:pvbump-change-epoch-only} - \inference - { - [.., s_n - 2 \cdot k] \restrictdom \var{fads} = \epsilon & e_p < e_n - } - { - {\begin{array}{l} - k\\ - s_n - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{e_p}\\ - \var{(\var{pv}, \var{pps})}\\ - \var{fads} - \end{array} - \right) - } - \trans{pvbump}{\var{e_n}} - { - \left( - \begin{array}{l} - \var{e_n}\\ - \var{(\var{pv}, \var{pps})}\\ - \var{fads} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:pvbump-change} - \inference - { - \wcard ; (\wcard , (\var{pv_c}, \var{pps_c})) \leteq [.., s_n - 2 \cdot k] \restrictdom \var{fads} - & e_p < e_n - } - { - {\begin{array}{l} - k\\ - s_n - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{e_p}\\ - \var{(\var{pv}, \var{pps})}\\ - \var{fads} - \end{array} - \right) - } - \trans{pvbump}{\var{e_n}} - { - \left( - \begin{array}{l} - \var{e_n}\\ - \var{(\var{pv_c}, \var{pps_c})}\\ - {[s_n - 2 \cdot k + 1, ..]} \restrictdom fads - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:upi-ec} - \inference - { - \var{chainStability} \mapsto k \in \var{pps} & - {\begin{array}{l} - k\\ - s_n - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{e_p}\\ - \var{(\var{pv}, \var{pps})}\\ - \var{fads} - \end{array} - \right) - } - \trans{pvbump}{\var{e_n}} - { - \left( - \begin{array}{l} - \var{e'}\\ - \var{(\var{pv'}, \var{pps'})}\\ - \var{fads'} - \end{array} - \right) - }\\ ~ \\ - \var{pids_{keep}} = \{ \var{pid} \mid - \var{pid} \mapsto (\var{pv_i}, \wcard) \in \var{rpus} - ,~ \var{pv'} < \var{pv_i}\} - } - { - { - \begin{array}{l} - e_c\\ - s_n\\ - \var{dms}\\ - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{e_p}\\ - \var{(\var{pv}, \var{pps})}\\ - \var{fads}\\ - \var{avs}\\ - \var{rpus}\\ - \var{raus}\\ - \var{cps}\\ - \var{vts}\\ - \var{bvs}\\ - \var{pws} - \end{array} - \right) - } - \trans{upiec}{\var{e_n}} - { - \left( - \begin{array}{l} - \var{e'}\\ - \var{(\var{pv'}, \var{pps} \unionoverride \var{pps'})}\\ - \var{fads'}\\ - \var{avs}\\ - \var{pids_{keep}} \restrictdom \var{rpus}\\ - \var{raus}\\ - \var{pids_{keep}} \restrictdom \var{cps}\\ - \var{pids_{keep}} \restrictdom \var{vts}\\ - {[\var{pv'}, ..]} \restrictdom \var{bvs}\\ - \var{pids_{keep}} \restrictdom \var{pws} - \end{array} - \right) - } - } - \end{equation} - \caption{Block version adoption on epoch change rules} - \label{fig:rules:upi-ec} -\end{figure} - -\begin{figure}[htb] - \centering - \begin{tikzpicture} - %% - %% Macros used in this picture - %% - % - % Number of slots - \pgfmathsetmacro{\nrSlots}{12} - % Slot in which the proposal gets confirmed - \pgfmathsetmacro{\cSlot}{1} - % Our special K. - \pgfmathsetmacro{\K}{4} - % Epoch end. - \pgfmathsetmacro{\eend}{11} - % Number of positive votes needed - \pgfmathsetmacro{\votes}{5} - - % Draw the horizontal line - \draw[thick, -Triangle] (0,0) -- (\nrSlots,0) - node[font=\scriptsize,below left=3pt and -8pt]{slots}; - - % % draw vertical lines - \foreach \x in {0,1,...,\nrSlots} - \draw (\x cm, 3pt) -- (\x cm, -3pt); - - % Add a label to with the block number in which the proposal got confirmed. - \node at (\cSlot, -.7) {$b_j$}; - - % Update in cps - \node at (\cSlot, -1.5) {$\var{cps'} = \var{cps} \cup \{ \var{pid} \mapsto b_j \}$}; - - % The no-endorsements red bar. - \draw[red, line width=4pt] (\cSlot, .5) -- +(\K, 0); - - % Brace above the no-endorsement window bar. - \draw[thick, red, decorate, decoration={brace, amplitude=5pt}] - (\cSlot, .7) -- +(\K, 0) - node[black!20!red, midway, above=4pt, font=\scriptsize] {No endorsements possible}; - - % The endorsements window. - \coordinate (ewStart) at (\cSlot + \K, .5); - \coordinate (ewEnd) at ($(\eend - \K, .5)$); - \draw[green, line width=4pt] - (ewStart) -- (ewEnd); - - % Brace above the endorsements window - \coordinate (ewStartB) at ($(ewStart) + (0, 0.2)$); - \coordinate (ewEndB) at ($(ewEnd) + (0, 0.2)$); - \draw[thick, green, decorate, decoration={brace, amplitude=5pt}] - (ewStartB) -- (ewEndB) - node[black!50!green, midway, above=18pt, font=\scriptsize] {Endorsements window}; - - % The no-candidates change window. - \coordinate (nccStart) at (\eend - \K, .5); - \coordinate (nccEnd) at ($(\eend, .5)$); - \draw[gray, line width=4pt] - (nccStart) -- (nccEnd); - - % Brace above the no-candidates change window. - \coordinate (nccStartB) at ($(nccStart) + (0, 0.2)$); - \coordinate (nccEndB) at ($(nccEnd) + (0, 0.2)$); - \draw[thick, gray, decorate, decoration={brace, amplitude=5pt}] - (nccStartB) -- (nccEndB) - node[gray, midway, above=5pt, font=\scriptsize] {No candidates change for current epoch}; - - - % The 2k before end-of-epoch window. - \coordinate (beeStart) at (\cSlot + \K, -.5); - \coordinate (beeEnd) at ($(\cSlot + \K + \votes, -.5)$); - \draw[blue, line width=4pt] - (beeStart) -- (beeEnd); - - % Brace on above the 2k before end-of-epoch window. - \coordinate (beeStartB) at ($(beeStart) - (0, 0.2)$); - \coordinate (beeEndB) at ($(beeEnd) - (0, 0.2)$); - \draw[thick, blue, decorate, decoration={brace, amplitude=5pt}] - (beeEndB) -- (beeStartB) - node[black!20!blue, midway, below=5pt, font=\scriptsize] {$\votes$ endorsements needed}; - - \draw[blue, line width=2pt] (\eend, 3pt) -- (\eend, -3pt); - - \draw[<-] (\cSlot, 4pt) -- +(-1, 1) - node [above=2pt, black, font=\scriptsize] - {Proposal with id $\var{pid}$ gets confirmed}; - - \draw[->] (\eend, -4pt) -- +(1, -1) - node[right, blue, font=\scriptsize] {End of epoch}; - \end{tikzpicture} - \caption{An update proposal confirmed too late} - \label{fig:up-confirmed-too-late} -\end{figure} - -Figure~\ref{fig:st-diagram-pt-up} shows the different states a protocol-update -proposal can be in, and what causes the transitions between them. - -\begin{figure}[ht] - \centering - \begin{tikzpicture}[ align = center - , node distance = 8em and 16em - , text width = 5em - , font = \footnotesize - , >={Latex[width=0.5em, length=0.5em]} - , every node/.style = { rectangle - , rounded corners - , draw = black - , align = center - , minimum height = 4em } - ] - - \node (active) [fill = blue!10] {Active}; - \node (rejected) [below = of active, fill = red!10] {Rejected}; - \node (confirmed) [right = of active, fill = green!10] {Confirmed}; - \node (adopted) [below = of confirmed, fill = green!30] {Adopted}; - - \tikzset{every node/.style={align=center, text width=10em, text=brown}} - - \draw[->] (active) - edge node [above] {Protocol update proposal\\ gets enough votes} - (confirmed); - - \draw[->] (active) - edge node [left] {Voting period \\ends} - (rejected); - - \draw[->] (confirmed) - edge node [above left] - {Proposal with higher version adopted} - (rejected); - - \draw[->] (confirmed) - edge node [right, text width=8em] - {Proposal gets enough endorsements $2 \cdot k$ slots before the end of an epoch} - (adopted); - - \end{tikzpicture} - - \caption{State-transition diagram for protocol-updates} - \label{fig:st-diagram-pt-up} -\end{figure} \ No newline at end of file diff --git a/specs/ledger/latex/crypto-primitives.tex b/specs/ledger/latex/crypto-primitives.tex deleted file mode 100644 index 474b0d96..00000000 --- a/specs/ledger/latex/crypto-primitives.tex +++ /dev/null @@ -1,103 +0,0 @@ -\section{Cryptographic primitives} -\label{sec:crypto-primitives} - -Figure~\ref{fig:crypto-defs} introduces the cryptographic abstractions used in -this document. Note that we define a family of serialization functions -$\serialised{\wcard}_\type{A}$, for all types $\type{A}$ for which such -serialization function can be defined. When the context is clear, we omit the -type suffix, and use simply $\serialised{\wcard}$. - -\begin{figure}[htb] - \emph{Abstract types} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \var{vk} & \SKey & \text{signing key}\\ - \var{vk} & \VKey & \text{verifying key}\\ - \var{hk} & \Hash & \text{hash of a key}\\ - \sigma & \Sig & \text{signature}\\ - \var{d} & \Data & \text{data}\\ - \end{array} - \end{equation*} - \emph{Derived types} - \begin{equation*} - \begin{array}{r@{~\in~}lr} - (sk, vk) & \SkVk & \text{signing-verifying key pairs} - \end{array} - \end{equation*} - \emph{Abstract functions} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \hash{} & \VKey \to \Hash - & \text{hash function} \\ - % - \fun{verify} & \VKey \times \Data \times \Sig - & \text{verification relation}\\ - \serialised{\wcard}_\type{A} & \type{A} \to \Data - & \text{serialization function for values of type $\type{A}$}\\ - \fun{sign} & \SKey \to \Data \to \Sig - & \text{signing function} - \end{array} - \end{equation*} - \emph{Constraints} - \begin{align*} - & \forall (sk, vk) \in \SkVk,~ m \in \Data,~ \sigma \in \Sig \cdot - \sign{sk}{m} = \sigma \Rightarrow \verify{vk}{m}{\sigma} - \end{align*} - \emph{Notation} - \begin{align*} - & \mathcal{V}^\sigma_{\var{vk}}~{d} = \verify{vk}{d}{\sigma} - & \text{shorthand notation for } \fun{verify} - \end{align*} - \caption{Cryptographic definitions} - \label{fig:crypto-defs} -\end{figure} - -\subsection{A note on serialization} -\label{sec:a-note-on-serialization} - -\begin{definition}[Distributivity over serialization functions] - For all types $\type{A}$ and $\type{B}$, given a function - $\fun{f} \in \type{A} \to \type{B}$, we say that the serialization function - for values of type $\type{A}$, namely $\serialised{ }_\type{A}$ distributes - over $\fun{f}$ if there exists a function $\fun{f}_{\serialised{ }}$ such - that for all $a \in \type{A}$: - \begin{equation} - \label{eq:distributivity-serialization} - \serialised{\fun{f}~a}_\type{B} = \fun{f}_{\serialised{ }}~\serialised{a}_\type{A} - \end{equation} -\end{definition} -The equality defined in \cref{eq:distributivity-serialization} means that the -following diagram commutes: - -\[ - \begin{tikzcd} - A \arrow{r}{\fun{f}} \arrow{d}{\serialised{ }_\type{A}} - & B \arrow{d}{\serialised{ }_\type{B}} \\ - \Data \arrow{r}{\fun{f}_{\serialised{ }}} & \Data - \end{tikzcd} -\] - -Throughout this specification, whenever we use -$\serialised{\fun{f}~a}_\type{B}$, for some type $\type{B}$ and function -$\fun{f} \in \type{A} \to \type{B}$, we assume that $\serialised{ }_\type{A}$ -distributes over $\fun{f}$ (see for example -Rule~\ref{eq:utxo-witness-inductive}). This property is what allow us to -extract a component of the serialized data (if it is available) without -deserializing it in the cases in which the deserialization function -($\serialised{\wcard}^{-1}_\type{A}$) doesn't behave as an inverse of -serialization: - -\begin{equation*} - \serialised{\wcard}^{-1}_\type{A} \cdot \serialised{\wcard}_\type{A} \neq \fun{id}_\type{A} -\end{equation*} - -For the cases in which such an inverse exists, given a function $\fun{f}$, we -can readily define $\fun{f}_{\serialised{ }}$ as: - -\begin{equation*} - \fun{f}_{\serialised{ }} \dot{=} \serialised{\wcard}_\type{B} - . \fun{f} - . \serialised{\wcard}^{-1}_\type{A} -\end{equation*} diff --git a/specs/ledger/latex/default.nix b/specs/ledger/latex/default.nix deleted file mode 100644 index cb7c05dc..00000000 --- a/specs/ledger/latex/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ pkgs ? import ../../../pkgs.nix -}: - -with pkgs; - -stdenv.mkDerivation { - name = "docsEnv"; - buildInputs = [ (texlive.combine { - inherit (texlive) - scheme-small - - # libraries - stmaryrd lm-math amsmath extarrows cleveref semantic tikz-cd xcolor - - # bclogo and dependencies - bclogo mdframed xkeyval etoolbox needspace pgf - - # font libraries `mathpazo` seems to depend on palatino - # , but it isn't pulled. - mathpazo palatino microtype - - # libraries for marginal notes - xargs todonotes - - # build tools - latexmk - ; - }) - - ]; - src = ./.; - buildPhase = "make"; - - meta = with lib; { - description = "Byron Ledger Specification"; - license = licenses.bsd3; - platforms = platforms.linux; - }; -} diff --git a/specs/ledger/latex/delegation.tex b/specs/ledger/latex/delegation.tex deleted file mode 100644 index 82910092..00000000 --- a/specs/ledger/latex/delegation.tex +++ /dev/null @@ -1,578 +0,0 @@ -\section{Delegation} -\label{sec:delegation} - -\newcommand{\DEnv}{\type{DEnv}} -\newcommand{\DSEnv}{\type{DSEnv}} -\newcommand{\DSState}{\type{DSState}} -\newcommand{\DCert}{\type{DCert}} -\newcommand{\DState}{\type{DState}} -\newcommand{\DEState}{\type{DEState}} - -An agent owning a key that can sign new blocks can delegate its signing rights -to another key by means of \textit{delegation certificates}. These certificates -are included in the ledger, and therefore also included in the body of the -blocks in the blockchain. - -There are several restrictions on a certificate posted on the blockchain: -\begin{enumerate} -\item Only genesis keys can delegate. -\item Certificates must be properly signed by the delegator. -\item Any given key can delegate at most once per-epoch. -\item Any given key can issue at most one certificate in a given slot. -\item The epochs in certificates cannot refer to past epochs. This mechanism - prevents replay attacks. -\item Certificates do not become active immediately, but they require a certain - number of slots till they become stable in all the nodes. -\end{enumerate} -These conditions are formalized in \cref{fig:rules:delegation-scheduling}. -Rule~\ref{eq:rule:delegation-scheduling} determines when a certificate can -become ``scheduled''. The definitions used in this rules are presented in -\cref{fig:defs:delegation-scheduling}, and the types of the system induced by -$\trans{sdeleg}{\wcard}$ are presented in -\cref{fig:ts-types:delegation-scheduling}. - -\begin{figure}[htb] - \emph{Abstract types} - \begin{equation*} - \begin{array}{r@{~\in~}lr} - c & \DCert & \text{delegation certificate}\\ - \var{vk_g} & \VKeyGen & \text{genesis verification key}\\ - \end{array} - \end{equation*} - - \emph{Derived types} - \begin{equation*} - \begin{array}{r@{~\in~}l@{\qquad=\qquad}r@{~\in~}lr} - \var{e} & \Epoch & n & \mathbb{N} & \text{epoch}\\ - \var{s} & \Slot & s & \mathbb{N} & \text{slot}\\ - \var{d} & \SlotCount & s & \mathbb{N} & \text{slot} - \end{array} - \end{equation*} - - \emph{Constraints} - \begin{align*} - \VKeyGen \subseteq \VKey - \end{align*} - - \emph{Abstract functions} - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \fun{dbody} & \DCert \to (\VKey \times \Epoch) - & \text{body of the delegation certificate}\\ - \fun{dwit} & \DCert \to (\VKeyGen \times \Sig) - & \text{witness for the delegation certificate}\\ - \fun{dwho} & \DCert \mapsto (\VKeyGen \times \VKey) - & \text{who delegates to whom in the certificate}\\ - \fun{depoch} & \DCert \mapsto \Epoch - & \text{certificate epoch} - \end{array} - \end{equation*} - \caption{Delegation scheduling definitions} - \label{fig:defs:delegation-scheduling} -\end{figure} - -\begin{figure}[htb] - \emph{Delegation scheduling environments} - \begin{equation*} - \DSEnv = - \left( - \begin{array}{r@{~\in~}lr} - \mathcal{K} & \powerset{\VKeyGen} & \text{allowed delegators}\\ - \var{e} & \Epoch & \text{epoch}\\ - \var{s} & \Slot & \text{slot}\\ - \var{d} & \SlotCount & \text{certificate liveness parameter} - \end{array} - \right) - \end{equation*} - - \emph{Delegation scheduling states} - \begin{equation*} - \DSState - = \left( - \begin{array}{r@{~\in~}lr} - \var{sds} & \seqof{(\Slot \times (\VKeyGen \times \VKey))} & \text{scheduled delegations}\\ - \var{eks} & \powerset{(\Epoch \times \VKeyGen)} & \text{key-epoch delegations} - \end{array} - \right) - \end{equation*} - - \emph{Delegation scheduling transitions} - \begin{equation*} - \var{\_} \vdash - \var{\_} \trans{sdeleg}{\_} \var{\_} - \subseteq \powerset (\DSEnv \times \DSState \times \DCert \times \DSState) - \end{equation*} - \caption{Delegation scheduling transition-system types} - \label{fig:ts-types:delegation-scheduling} -\end{figure} - -\begin{figure}[htb] - \begin{equation} - \inference - { - } - { - {\begin{array}{l} - \mathcal{K}\\ - e\\ - s\\ - d - \end{array}} - \vdash - \left( - \begin{array}{l} - \epsilon\\ - \emptyset - \end{array} - \right) - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:delegation-scheduling} - \inference - { - (\var{vk_s},~ \sigma) = \dwit{c} - & \verify{vk_s}{\serialised{\dbody{c}}}{\sigma} & vk_s \in \mathcal{K}\\ ~ \\ - (\var{vk_s},~ \var{vk_d}) = \dwho{c} & e_d = \depoch{c} - & (e_d,~ \var{vk_s}) \notin \var{eks} & e \leq e_d \\ ~ \\ - (s + d,~ (\var{vk_s},~ \wcard)) \notin \var{sds}\\ - } - { - {\begin{array}{l} - \mathcal{K}\\ - e\\ - s\\ - d - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{sds}\\ - \var{eks} - \end{array} - \right) - } - \trans{sdeleg}{c} - { - \left( - \begin{array}{l} - \var{sds}; (s + d,~ (\var{vk_s},~ \var{vk_d}))\\ - \var{eks} \cup \{(e_d,~ \var{vk_s})\} - \end{array} - \right) - } - } - \end{equation} - \caption{Delegation scheduling rules} - \label{fig:rules:delegation-scheduling} -\end{figure} - -\clearpage - -The rules in Figure~\ref{fig:rules:delegation} model the activation of -delegation certificates. Once a scheduled certificate becomes active -(see~\cref{sec:delegation-interface-rules}), the delegation map is changed by -it only if: -\begin{itemize} -\item The delegating key ($\var{vk_s}$) did not activate a delegation - certificate in a slot greater or equal than the certificate slot ($s$). This - check is performed to avoid having the constraint that the delegation - certificates have to be activated in slot order. -\item The key being delegated to ($\var{vk_d}$) has not been delegated by - another key (injectivity constraint). -\end{itemize} -The reason why we check that the delegation map is injective is to avoid a -potential risk (during the OBFT era) in which a malicious node gets control of -a genesis key $\var{vk_m}$ that issued the maximum number of blocks in a given -window. By delegating to another key $\var{vk_d}$, which was already delegated to -by some other key $\var{vk_g}$, the malicious node could prevent $\var{vk_g}$ -from issuing blocks. Even though the delegation certificates take several slots -to become effective, the malicious node could calculate when the certificate -would become active, and issue a delegation certificate at the right time. - -As an additional advantage, by having an injective delegation map, we are able -to simplify our specification when it comes to counting the blocks issued by -(delegates of) genesis keys. - -Note also, that we could not impose the injectivity constraint in -Rule~\ref{eq:rule:delegation-scheduling} since we do not have information about -the delegations that will become effective. We could of course detect a -violation in the injectivity constraint when scheduling a delegation -certificate, but this will lead to a complex computation and larger state in -said rule. - -Finally, note that we do not want to reject a scheduled delegation that would -violate the injectivity constraint (since delegation might not have been -scheduled by the node issuing the block). Instead, we simply ignore the -delegation certificate (Rule~\ref{eq:rule:delegation-nop}). - -\begin{figure}[htb] - \begin{align*} - & \unionoverride \in (A \mapsto B) \to (A \mapsto B) \to (A \mapsto B) - & \text{union override}\\ - & d_0 \unionoverride d_1 = d_1 \cup (\dom d_1 \subtractdom d_0) - \end{align*} - \caption{Functions used in delegation rules} - \label{fig:funcs:delegation} -\end{figure} - -\begin{figure}[htb] - \emph{Delegation environments} - \begin{equation*} - \DEnv = - \left( - \begin{array}{r@{~\in~}lr} - \mathcal{K} & \powerset{\VKeyGen} & \text{allowed delegators} - \end{array} - \right) - \end{equation*} - - \emph{Delegation states} - \begin{align*} - & \DState - = \left( - \begin{array}{r@{~\in~}lr} - \var{dms} & \VKeyGen \mapsto \VKey & \text{delegation map}\\ - \var{dws} & \VKeyGen \mapsto \Slot & \text{when last delegation occurred}\\ - \end{array}\right) - \end{align*} - \emph{Delegation transitions} - \begin{equation*} - \_ \vdash \_ \trans{adeleg}{\_} \_ \in - \powerset (\DEnv \times \DState \times (\Slot \times (\VKeyGen \times \VKey)) \times \DState) - \end{equation*} - \caption{Delegation transition-system types} - \label{fig:ts-types:delegation} -\end{figure} - -\begin{figure}[htb] - \begin{equation} - \inference - { - \var{dms_0} = \Set{k \mapsto k}{k \in \mathcal{K}} & - \var{dws_0} = \Set{k \mapsto 0}{k \in \mathcal{K}} - } - { - \mathcal{K} - \vdash - \left( - \begin{array}{l} - \var{dms_0}\\ - \var{dws_0} - \end{array} - \right) - } - \end{equation} - \nextdef - \begin{equation}\label{eq:rule:delegation-change} - \inference - { - \var{vk_d} \notin \range~\var{dms} & (\var{vk_s} \mapsto s_p \in \var{dws} \Rightarrow s_p < s) - } - { - \mathcal{K} - \vdash - \left( - \begin{array}{r} - \var{dms}\\ - \var{dws} - \end{array} - \right) - \trans{adeleg}{(s,~ (vk_s,~ vk_d))} - \left( - \begin{array}{lcl} - \var{dms} & \unionoverride & \{\var{vk_s} \mapsto \var{vk_d}\}\\ - \var{dws} & \unionoverride & \{\var{vk_s} \mapsto s \} - \end{array} - \right) - } - \end{equation} - \nextdef - \begin{equation}\label{eq:rule:delegation-nop} - \inference - {\var{vk_d} \in \range~\var{dms} \vee (\var{vk_s} \mapsto s_p \in \var{dws} \wedge s \leq s_p) - } - { - \mathcal{K} - \vdash - \left( - \begin{array}{r} - \var{dms}\\ - \var{dws} - \end{array} - \right) - \trans{adeleg}{(s,~ (\var{vk_s},~ \var{vk_d}))} - \left( - \begin{array}{lcl} - \var{dms}\\ - \var{dws} - \end{array} - \right) - } - \end{equation} - \caption{Delegation inference rules} - \label{fig:rules:delegation} -\end{figure} - -\clearpage - -\subsection{Delegation sequences} -\label{sec:delegation-sequences} - -This section presents the rules that model the effect that sequences of -delegations have on the ledger. - -\begin{figure}[htb] - \begin{equation} - \inference[Initial-SDELEGS] - { - } - { - {\begin{array}{l} - \mathcal{K}\\ - e\\ - s\\ - d - \end{array}} - \vdash - \left( - \begin{array}{l} - \epsilon\\ - \emptyset - \end{array} - \right) - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:delegation-scheduling-seq-base} - \inference - { - } - { - {\begin{array}{l} - \mathcal{K} \\ - e\\ - s\\ - d - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{sds}\\ - \var{eks} - \end{array} - \right) - } - \trans{sdelegs}{\epsilon} - { - \left( - \begin{array}{l} - \var{sds}\\ - \var{eks} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:delegation-scheduling-seq-ind} - \inference - { - {\begin{array}{l} - \mathcal{K} \\ - e\\ - s\\ - d - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{sds}\\ - \var{eks} - \end{array} - \right) - } - \trans{sdelegs}{\Gamma} - { - \left( - \begin{array}{l} - \var{sds'}\\ - \var{eks'} - \end{array} - \right) - } - & - {\begin{array}{l} - \mathcal{K} \\ - e\\ - s\\ - d - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{sds'}\\ - \var{eks'} - \end{array} - \right) - } - \trans{sdeleg}{c} - { - \left( - \begin{array}{l} - \var{sds''}\\ - \var{eks''} - \end{array} - \right) - } - } - { - {\begin{array}{l} - \mathcal{K} \\ - e\\ - s\\ - d - \end{array}} - \vdash - { - \left( - \begin{array}{l} - \var{sds}\\ - \var{eks} - \end{array} - \right) - } - \trans{sdelegs}{\Gamma; c} - { - \left( - \begin{array}{l} - \var{sds''}\\ - \var{eks''} - \end{array} - \right) - } - } - \end{equation} - \caption{Delegation scheduling sequence rules} - \label{fig:rules:delegation-scheduling-seq} -\end{figure} - -\begin{figure} - \begin{equation} - \inference[Initial-ADELEGS] - { - \var{dms_0} = \Set{k \mapsto k}{k \in \mathcal{K}} & - \var{dws_0} = \Set{k \mapsto 0}{k \in \mathcal{K}} - } - { - \mathcal{K} - \vdash - \left( - \begin{array}{l} - \var{dms_0}\\ - \var{dws_0} - \end{array} - \right) - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:delegation-seq-base} - \inference - { - } - { - \mathcal{K} - \vdash - { - \left( - \begin{array}{l} - \var{dms}\\ - \var{dws} - \end{array} - \right) - } - \trans{adelegs}{\epsilon} - { - \left( - \begin{array}{l} - \var{dms}\\ - \var{dws} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:delegation-seq-ind} - \inference - { - { - \left( - \begin{array}{l} - \var{dms}\\ - \var{dws} - \end{array} - \right) - } - \trans{adelegs}{\Gamma} - { - \left( - \begin{array}{l} - \var{dms'}\\ - \var{dws'} - \end{array} - \right) - } - & - { - \left( - \begin{array}{l} - \var{dms'}\\ - \var{dws'} - \end{array} - \right) - } - \trans{adeleg}{c} - { - \left( - \begin{array}{l} - \var{dms''}\\ - \var{dws''} - \end{array} - \right) - } - } - { - \mathcal{K} - \vdash - { - \left( - \begin{array}{l} - \var{dms}\\ - \var{dws} - \end{array} - \right) - } - \trans{adelegs}{\Gamma; c} - { - \left( - \begin{array}{l} - \var{dms''}\\ - \var{dws''} - \end{array} - \right) - } - } - \end{equation} - \caption{Delegations sequence rules } - \label{fig:rules:delegation-seq} -\end{figure} diff --git a/specs/ledger/latex/frontmatter.tex b/specs/ledger/latex/frontmatter.tex deleted file mode 100644 index 149bbe88..00000000 --- a/specs/ledger/latex/frontmatter.tex +++ /dev/null @@ -1,38 +0,0 @@ -\hypersetup{ - pdftitle={A Simplified Formal Specification of a UTxO Ledger}, - breaklinks=true, - bookmarks=true, - colorlinks=false, - linkcolor={blue}, - citecolor={blue}, - urlcolor={blue}, - linkbordercolor={white}, - citebordercolor={white}, - urlbordercolor={white} -} - -\title{ - A Formal Specification of the Cardano Ledger\\ - \small{(for the Byron release)} -} - -\author{Damian Nadales \\ - {\small \texttt{damian.nadales@iohk.io}}\\ -} - -\date{\today} - -\maketitle - -\begin{abstract} - This documents defines the rules for extending a ledger with transactions, as - implemented in the Byron release of the Cardano Ledger. It is intended to - serve as the specification for random generators of transactions which adhere - to the rules presented here. -\end{abstract} - -\section*{List of Contributors} -\label{acknowledgements} - -Jared Corduan, Nicholas Clarke, Marko Dimjašević, Duncan Coutts, Ru Horlick, -Michael Hueschen. diff --git a/specs/ledger/latex/gitinfo2.mk b/specs/ledger/latex/gitinfo2.mk deleted file mode 100644 index 0a73e9d7..00000000 --- a/specs/ledger/latex/gitinfo2.mk +++ /dev/null @@ -1,24 +0,0 @@ -# Get info on current git status for gitinfo2 -# That package recommends creating the appropriate file via git hooks; however, -# that would require everyone working on the repository to install the hooks. -# Creating the auxiliary file in the Makefile instead assures that it's always -# there when the document is compiled. -FIRSTTAG := $(shell git describe --tags --always --dirty='-*' 2>/dev/null) -RELTAG := $(shell git describe --tags --long --always --dirty='-*' --match '[0-9]*.*' 2>/dev/null) -gitHeadLocal.gin: - git --no-pager log -1 --date=short --decorate=short --pretty=format:"\usepackage[shash={%h}\ -, lhash={%H}\ -, authname={%an}\ -, authemail={%ae}\ -, authsdate={%ad}\ -, authidate={%ai}\ -, authudate={%at}\ -, commname={%cn}\ -, commemail={%ce}\ -, commsdate={%cd}\ -, commidate={%ci}\ -, commudate={%ct}\ -, refnames={%d}\ -, firsttagdescribe={$(FIRSTTAG)}\ -, reltag={$(RELTAG)}\ -]{gitexinfo} " HEAD > gitHeadLocal.gin diff --git a/specs/ledger/latex/intro.tex b/specs/ledger/latex/intro.tex deleted file mode 100644 index a99a6518..00000000 --- a/specs/ledger/latex/intro.tex +++ /dev/null @@ -1,25 +0,0 @@ -\section{Introduction} -\label{sec:introduction} - -This specification models the \textit{conditions} that the different parts of a -transaction have to fulfill so that they can extend a ledger, which is -represented here as a list of transactions. In particular, we model the -following aspects: - -\begin{description} -\item[Preservation of value] relationship between the total value of input and - outputs in a new transaction, and the unspent outputs. -\item[Witnesses] authentication of parts of the transaction data by means of - cryptographic entities (such as signatures and private keys) contained in - these transactions. -\item[Delegation] validity of delegation certificates, which delegate - block-signing rights. -\item[Update validation] voting mechanism which captures the identification of - the voters, and the participants that can post update proposals. -\end{description} - -The following aspects will not be modeled (since they are not part of the Byron -release): -\begin{description} -\item[Stake] staking rights associated to an addresses. -\end{description} diff --git a/specs/ledger/latex/iohk.sty b/specs/ledger/latex/iohk.sty deleted file mode 100644 index 7d7f2086..00000000 --- a/specs/ledger/latex/iohk.sty +++ /dev/null @@ -1,41 +0,0 @@ -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{iohk}[2018/10/18] - -\RequirePackage{amssymb} -\RequirePackage{extarrows} -\RequirePackage{slashed} -\RequirePackage[tikz]{bclogo} -\RequirePackage{stmaryrd} - -\DeclareMathOperator{\dom}{dom} -\DeclareMathOperator{\range}{range} - -\newcommand{\powerset}[1]{\mathbb{P}~#1} -\newcommand{\restrictdom}{\lhd} -\newcommand{\subtractdom}{\mathbin{\slashed{\restrictdom}}} -\newcommand{\restrictrange}{\rhd} -\newcommand{\subtractrange}{\mathbin{\slashed{\restrictrange}}} -\newcommand{\union}{\cup} -\newcommand{\unionoverride}{\mathbin{\underrightarrow\cup}} -\newcommand{\uniondistinct}{\uplus} -\newcommand{\var}[1]{\mathit{#1}} -\newcommand{\fun}[1]{\mathsf{#1}} -\newcommand{\type}[1]{\mathsf{#1}} -\newcommand{\signed}[2]{\llbracket #1 \rrbracket_{#2}} -\newcommand{\size}[1]{\left| #1 \right|} -\newcommand{\trans}[2]{\xlongrightarrow[\textsc{#1}]{#2}} -\newcommand{\seqof}[1]{#1^{*}} -\newcommand{\nextdef}{\\[1em]} -\newcommand{\where}{~ ~ \mathbf{where}~ ~ } - -\newenvironment{question} - {\begin{bclogo}[logo=\bcquestion, couleur=orange!10, arrondi=0.2]{ QUESTION}} - {\end{bclogo}} -\newenvironment{todo} - {\begin{bclogo}[logo=\bcoutil, couleur=red!5, couleurBarre=red, arrondi=0.2]{ TODO}} - {\end{bclogo}} -\newenvironment{note} - {\begin{bclogo}[logo=\bcattention, couleur=orange!10, arrondi=0.2]{ NOTE}} - {\end{bclogo}} - -\endinput diff --git a/specs/ledger/latex/ledger-spec.tex b/specs/ledger/latex/ledger-spec.tex deleted file mode 100644 index 34b7a21e..00000000 --- a/specs/ledger/latex/ledger-spec.tex +++ /dev/null @@ -1,152 +0,0 @@ -\documentclass[11pt,a4paper]{article} -\usepackage[margin=2.5cm]{geometry} -\usepackage{iohk} -\usepackage{microtype} -\usepackage{mathpazo} % nice fonts -\usepackage{amsmath} -\usepackage{amssymb} -\usepackage{latexsym} -\usepackage{mathtools} -\usepackage{stmaryrd} -\usepackage{extarrows} -\usepackage{slashed} -\usepackage[colon]{natbib} -\usepackage[unicode=true,pdftex,pdfa,colorlinks=true]{hyperref} -\usepackage{xcolor} -\usepackage[capitalise,noabbrev,nameinlink]{cleveref} -\usepackage{float} -\floatstyle{boxed} -\restylefloat{figure} -\usepackage{listings} % for code blocks. -%% -%% Package `semantic` can be used for writing inference rules. -%% -\usepackage{semantic} -%% Setup for the semantic package -\setpremisesspace{20pt} -\usepackage{tikz} -\usetikzlibrary{decorations.pathreplacing, positioning, arrows.meta, calc} -% For drawing simple diagrams involving arrows between LaTeX symbols -\usepackage{tikz-cd} - -%% -%% Types -%% -\newcommand{\Bool}{\type{Bool}} -\newcommand{\Tx}{\type{Tx}} -\newcommand{\Ix}{\type{Ix}} -\newcommand{\TxId}{\type{TxId}} -\newcommand{\Addr}{\type{Addr}} -\newcommand{\UTxO}{\type{UTxO}} -\newcommand{\Value}{\type{Value}} -\newcommand{\Lovelace}{\type{Lovelace}} -%% Adding witnesses -\newcommand{\TxIn}{\type{TxIn}} -\newcommand{\TxOut}{\type{TxOut}} -\newcommand{\VKey}{\type{VKey}} -\newcommand{\SKey}{\type{SKey}} -\newcommand{\Hash}{\type{Hash}} -\newcommand{\SkVk}{\type{SkVk}} -\newcommand{\Sig}{\type{Sig}} -\newcommand{\Data}{\type{Data}} -%% Adding delegation -\newcommand{\Epoch}{\type{Epoch}} -\newcommand{\VKeyGen}{\type{VKey_G}} -%% Blockchain -\newcommand{\Gkeys}{\var{G_{keys}}} -\newcommand{\Block}{\type{Block}} -\newcommand{\CEEnv}{\type{CEEnv}} -\newcommand{\CEState}{\type{CEState}} -\newcommand{\BDEnv}{\type{BDEnv}} -\newcommand{\BDState}{\type{BDState}} -\newcommand{\Slot}{\type{Slot}} -\newcommand{\SlotCount}{\type{SlotCount}} - -%% -%% Functions -%% -\newcommand{\txins}[1]{\fun{txins}~ \var{#1}} -\newcommand{\txid}[1]{\fun{txid}~ \var{#1}} -\newcommand{\txouts}[1]{\fun{txouts}~ \var{#1}} -\newcommand{\values}[1]{\fun{values}~ #1} -\newcommand{\balance}[1]{\fun{balance}~ \var{#1}} -%% UTxO witnesses -\newcommand{\inputs}[1]{\fun{inputs}~ \var{#1}} -\newcommand{\wits}[1]{\fun{wits}~ \var{#1}} -\newcommand{\verify}[3]{\fun{verify} ~ #1 ~ #2 ~ #3} -\newcommand{\sign}[2]{\fun{sign} ~ #1 ~ #2} -\newcommand{\serialised}[1]{\llbracket \var{#1} \rrbracket} -\newcommand{\addr}[1]{\fun{addr}~ \var{#1}} -\newcommand{\hash}[1]{\fun{hash}~ \var{#1}} -\newcommand{\txbody}[1]{\fun{txbody}~ \var{#1}} -\newcommand{\txfee}[1]{\fun{txfee}~ \var{#1}} -\newcommand{\minfee}[2]{\fun{minfee}~ \var{#1}~ \var{#2}} -% wildcard parameter -\newcommand{\wcard}[0]{\underline{\phantom{a}}} -%% Adding ledgers... -\newcommand{\utxo}[1]{\fun{utxo}~ #1} -%% Delegation -\newcommand{\delegatesName}{\fun{delegates}} -\newcommand{\delegates}[3]{\delegatesName~#1~#2~#3} -\newcommand{\dwho}[1]{\fun{dwho}~\var{#1}} -\newcommand{\depoch}[1]{\fun{depoch}~\var{#1}} -%% Delegation witnesses -\newcommand{\dbody}[1]{\fun{dbody}~\var{#1}} -\newcommand{\dwit}[1]{\fun{dwit}~\var{#1}} -%% Blockchain -\newcommand{\bwit}[1]{\fun{bwit}~\var{#1}} -\newcommand{\bslot}[1]{\fun{bslot}~\var{#1}} -\newcommand{\bbody}[1]{\fun{bbody}~\var{#1}} -\newcommand{\bdlgs}[1]{\fun{bdlgs}~\var{#1}} -%% Set notation -\newcommand\Set[2]{\{\,#1\mid#2\,\}} -%% Let bindings -\newcommand{\leteq}{\ensuremath{\mathrel{\mathop:}=}} - -%% For properties -\newcommand{\txs}{\ensuremath{\mathcal{T}}} -\newcommand{\transtar}[2]{\xlongrightarrow[\textsc{#1}]{#2}\negthickspace^{*}} -\newcommand{\biguo}[1]{\ensuremath{\underset{#1}{\underrightarrow\bigcup}}} - -%\includeonly{update-mechanism, delegation, blockchain-interface} - -%% Parameters that control floats placement. See https://robjhyndman.com/hyndsight/latex-floats/ -\setcounter{topnumber}{2} -\setcounter{bottomnumber}{2} -\setcounter{totalnumber}{4} -\renewcommand{\topfraction}{0.85} -\renewcommand{\bottomfraction}{0.85} -\renewcommand{\textfraction}{0.15} -\renewcommand{\floatpagefraction}{0.7} - -\newtheorem{definition}{Definition} -\newtheorem{prop}{Property} - -\begin{document} - -\input{frontmatter.tex} - -\tableofcontents -\listoffigures - -\include{intro} - -\include{notation} - -\include{crypto-primitives} - -\include{utxo} - -\include{delegation} - -\include{update-mechanism} - -\include{blockchain-interface} - -\include{properties} - -\addcontentsline{toc}{section}{References} -\bibliographystyle{plainnat} -\bibliography{references} - -\end{document} diff --git a/specs/ledger/latex/notation.tex b/specs/ledger/latex/notation.tex deleted file mode 100644 index 48ce50f4..00000000 --- a/specs/ledger/latex/notation.tex +++ /dev/null @@ -1,79 +0,0 @@ -\section{Notation}\label{sec:notation} - -\begin{description} -\item[Natural Numbers] The set $\mathbb{N}$ refers to the set of all natural - numbers $\{0, 1, 2, \ldots\}$. -\item[Powerset] Given a set $\type{X}$, $\powerset{\type{X}}$ is the set of all - the subsets of $X$. -\item[Sequences] Given a set $\type{X}$, $\seqof{\type{X}}$ is the set of - sequences having elements taken from $\type{X}$. The empty sequence is - denoted by $\epsilon$, and given a sequence $\Lambda$, $\Lambda; \type{x}$ is - the sequence that results from appending $\type{x} \in \type{X}$ to - $\Lambda$. -\item[Functions] $A \to B$ denotes a \textbf{total function} from $A$ to $B$. - Given a function $f$ we write $f~a$ for the application of $f$ to argument - $a$. -\item[Fibre] Given a function $f: A \to B$ and $b\in B$, we write - $f^{-1}~b$ for the \textbf{fibre} of $f$ at $b$, which is defined by - $\{a \mid\ f~ a = b\}$. -\item[Maps and partial functions] $A \mapsto B$ denotes a \textbf{partial - function} from $A$ to $B$, which can be seen as a map (dictionary) with - keys in $A$ and values in $B$. Given a map $m \in A \mapsto B$, notation - $a \mapsto b \in m$ is equivalent to $m~ a = b$. Given a set $A$, - $A \mapsto A$ represents the identity map on $A$: - $\{a \mapsto a \mid a \in A\}$. The $\emptyset$ symbol is also used to - represent the empty map as well. -\item[Domain and range] Given a relation $R \in \powerset{(A \times B)}$, - $\dom~R \in \powerset{A}$ refers to the domain of $R$, and - $\range~R \in \powerset{B}$ refers to the range of $R$. Note that (partial) - functions (and hence maps) are also relations, so we will be using $\dom$ and - $\range$ on functions. -\item[Domain and range operations] Given a relation - $R \in \powerset{(A \times B)}$ we make use of the \textit{domain-restriction}, - \textit{domain-exclusion}, and \textit{range-restriction} operators, which - are defined in \cref{fig:domain-and-range-ops}. Note that a map $A \mapsto B$ - can be seen as a relation, which means that these operators can be - applied to maps as well. -\item[Integer ranges] Given $a, b \in \mathbb{Z}$, $[a, b]$ denotes the - sequence $[i \mid a \leq i \leq b]$ . Ranges can have open ends: $[.., b]$ - denotes sequence $[i \mid i \leq b]$, whereas $[a, ..]$ denotes sequence - $[i \mid a \leq i]$. Furthermore, sometimes we use $[a, b]$ to denote a set - instead of a sequence. The context in which it is used should provide enough - information about the specific type. -\item[Domain and range operations on sequences] We overload the $\restrictdom$, - $\subtractdom$, and $\restrictrange$ to operate over sequences. So for - instance given $S \in \seqof{A}$, and $R \in \seqof{(A \times B)}$: - $S \restrictdom R$ denotes the sequence - $[ (a, b) \mid (a, b) \in R, a \in S]$. -\item[Wildcard variables] When a variable is not needed in a term, we replace - it by $\wcard$ to make it explicit that we do not use this variable in the - scope of the given term. -\item[Implicit existential quantifications] Given a predicate - $P \in X \to Bool$, we use $P \wcard$ as a shorthand notation for - $\exists x \cdot P~x$. -% TODO: use leteq -\item[Pattern matching in premises] In the inference-rules premises use - $\var{patt} = \var{exp}$ to pattern-match an expression $\var{exp} $ with a - certain pattern $\var{patt}$. For instance, we use $\Lambda'; x = \Lambda$ to - be able to deconstruct a sequence $\Lambda$ in its last element, and prefix. - If an expression does not match the given pattern, then the premise does not - hold, and the rule cannot trigger. -\end{description} - -\begin{figure}[htb] - \begin{align*} - \var{S} \restrictdom \var{R} - & = \{ (a, b) \mid (a, b) \in R, ~ a \in S \} - & \text{domain restriction} - \\ - S \subtractdom R - & = \{ (a, b) \mid (a, b) \in R, ~ a \notin S \} - & \text{domain exclusion} - \\ - R \restrictrange S - & = \{ (a, b) \mid (a, b) \in R, ~ b \in S \} - & \text{range restriction} - \end{align*} - \caption{Domain and range operations} - \label{fig:domain-and-range-ops} -\end{figure} \ No newline at end of file diff --git a/specs/ledger/latex/properties.tex b/specs/ledger/latex/properties.tex deleted file mode 100644 index 589576e4..00000000 --- a/specs/ledger/latex/properties.tex +++ /dev/null @@ -1,158 +0,0 @@ -\section{Transition System Properties} -\label{sec:ts-properties} - - -\subsection{Transition-system traces} -\label{sec:ts-traces} - -This section introduces the notion of traces induced by the transition systems -described in \cite{small_step_semantics}. - -\begin{definition}[Traces] - Given a state transition system $L=(S,T,\Sigma, R, \Gamma)$, the set of - traces of $L$, denoted as $\fun{traces}_L$ is defined as: - $$ - \{ (e, s, \txs, s') \mid e \in \Gamma,~ s \in S,~ \txs \in \seqof{\Sigma},~ s' \in S\} - $$ - -\end{definition} - - -\begin{definition}[Valid traces] - Given a state transition system $L=(S,T,\Sigma, R, \Gamma)$, we define the - notion of valid traces inductively: - - \begin{itemize} - \item For all $e \in \Gamma$, $s \in S$, $(e, s, \epsilon, s)$ is a valid - trace of $L$. - - \item If $(e, s, \txs s')$ is a valid trace, and - $e \vdash s' \trans{}{\var{t}} s''$ is a valid transition according to the - rules of $L$, then $(e, s, \txs; t, s'')$ is also a valid trace. - \end{itemize} - -\end{definition} - -We denote the set of valid traces of $L$ as $\transtar{L}{}$, and we write -$e \vdash s \transtar{L}{\txs} s'$ as a shorthand for -$(e, s, \txs, s') \in \transtar{L}{}$. Furthermore, when the transition system -name is clear from the context we will omit it from the transition arrow label. - -\subsection{Additional notation} -\label{sec:additional-notation} - -We describe next additional notation needed in the properties of the transition -systems specified in this document. - -\subsubsection{Sequence indexing} -\label{sec:seq-indexing} - -Given a sequence $\mathcal{A} \in \seqof{\type{A}}$, and a natural number $i$ -such that $0 \leq i < \size{\mathcal{A}}$, $\mathcal{A}_i$ refers to the -$i^{\text{th}}$ element of $\mathcal{A}$. - - -Given a sequence $\mathcal{A}$, a quantification symbol $\bigoplus$, e.g. -$\forall$ or $\exists$, a range predicate $R$, and a quantification term $T$ -(both of which depend on an element of $\mathcal{A}$) we write: -% -$$ -\bigoplus \mathcal{A}_i \cdot R~\mathcal{A}_i \cdot T~\mathcal{A}_i -$$ -% -as a shorthand notation for: -% -$$ -\bigoplus i \cdot 0 \leq i < \size{\mathcal{A}} \wedge R~\mathcal{A}_i \cdot T~\mathcal{A}_i -$$ - -For instance: -% -$$ -\forall \txs_i \cdot \txins{\txs_i} \neq \emptyset -$$ -is a shorthand notation for: -$$ -\forall i \cdot 0 \leq i < \size{\txs} \Rightarrow \txins{\txs_i} \neq \emptyset -$$ -Remember that the range of a universal quantification can be expressed by an -implication, and the range of an existential qualification by a conjunction. - -\subsubsection{Quantifying over set operations} -\label{sec:quantifying-over-set-operators} - -Given a sequence $\mathcal{A} \in \seqof{A}$, a set $B$, a set operation -$\bigoplus$, e.g. $\cup$ or $\unionoverride$, and a function -$\fun{f} \in \type{A} \to \type{B}$, the term: -% -$$ -\underset{\fun{f}}{\bigoplus} \mathcal{A} -$$ -is a shorthand notation for: -% -$$ -\underset{0 \leq i < \size{\mathcal{A}}}{\bigoplus} \mathcal{A}_i -$$ - -For instance: -$$ -\bigcup_{\txins{}} \txs -$$ -denotes the sequence of unions: -$$ -\bigcup_{0 \leq i < \size{\txs}} \txins{\txs_i} -$$ - -In a set operation quantification over a sequence $\mathcal{A}$, the operation -is applied to the elements the order in which they appear in $\mathcal{A}$. -This is crucial in the case of non-commutative operations, such as union -override ($\unionoverride$). - -\subsection{UTxO Properties} -\label{sec:utxo-properties} - -Property~\ref{prop:no-double-spending} expresses the fact that transaction -inputs cannot be used more than once. This property requires that the starting -UTxO does not contain any future outputs, which is a reasonable constraint. - -\begin{prop}[No double spending]\label{prop:no-double-spending} - For all - - $$\var{utxo_0} \transtar{UTXO}{\txs} \var{utxo}$$ - - such that - - $$ - \forall \txs_i \cdot \dom~(\txouts{\txs_i}) \cap \dom~(\var{utxo_0}) = \emptyset - $$ - - we have - - $$ - \forall \txs_i,~\txs_j \cdot i < j \Rightarrow \txins{\txs_i} \cap \txins{\txs_j} = \emptyset - $$ -\end{prop} - -Property~\ref{prop:utxo-out-min-in} expresses the fact that all inputs and -outputs are accounted for, in such a way that we can reconstruct the final -(UTxO) state by adding all the outputs to the initial state, and removing the -spent outputs. - -\begin{prop}[UTxO is outputs minus inputs]\label{prop:utxo-out-min-in} - For all - - $$\var{utxo_0} \transtar{UTXO}{\txs} \var{utxo}$$ - - such that - - $$ - \forall \txs_i \cdot \dom~(\txouts{\txs_i}) \cap \dom~(\var{utxo_0}) = \emptyset - $$ - - we have: - - $$ - \bigcup_{\txins{}} \txs \subtractdom (\var{utxo_0} \cup \bigcup_{\txouts{}} \txs) = \var{utxo} - $$ - -\end{prop} diff --git a/specs/ledger/latex/references.bib b/specs/ledger/latex/references.bib deleted file mode 100644 index 94bdc613..00000000 --- a/specs/ledger/latex/references.bib +++ /dev/null @@ -1,6 +0,0 @@ -@misc{small_step_semantics, - author = {Formal Methods Team, IOHK}, - title = {Small Step Semantics for Cardano}, - year = {2018}, - url = {https://hydra.iohk.io/job/Cardano/cardano-chain/semanticsSpec/latest/download/1/small-steps.pdf} -} diff --git a/specs/ledger/latex/update-mechanism.tex b/specs/ledger/latex/update-mechanism.tex deleted file mode 100644 index 81bb1dda..00000000 --- a/specs/ledger/latex/update-mechanism.tex +++ /dev/null @@ -1,1380 +0,0 @@ -\newcommand{\UProp}{\ensuremath{\type{UProp}}} -\newcommand{\UPropId}{\ensuremath{\type{UpId}}} -\newcommand{\UPropSD}{\ensuremath{\type{UpSD}}} -\newcommand{\ProtVer}{\ensuremath{\type{ProtVer}}} -\newcommand{\ProtPm}{\ensuremath{\type{Ppm}}} -\newcommand{\Rpus}{\ensuremath{\type{Rpus}}} -\newcommand{\UPVEnv}{\ensuremath{\type{UPVEnv}}} -\newcommand{\UPVState}{\ensuremath{\type{UPVState}}} -\newcommand{\UPLEnv}{\ensuremath{\type{UPLEnv}}} -\newcommand{\UPLState}{\ensuremath{\type{UPLState}}} -\newcommand{\UPREnv}{\ensuremath{\type{UPREnv}}} -\newcommand{\UPRState}{\ensuremath{\type{UPRState}}} -\newcommand{\Vote}{\ensuremath{\type{Vote}}} -\newcommand{\VEnv}{\ensuremath{\type{VEnv}}} -\newcommand{\VState}{\ensuremath{\type{VState}}} -\newcommand{\BVREnv}{\ensuremath{\type{BVREnv}}} -\newcommand{\BVRState}{\ensuremath{\type{BVRState}}} -\newcommand{\ApName}{\ensuremath{\type{ApName}}} -\newcommand{\SWVer}{\ensuremath{\type{SWVer}}} -\newcommand{\ApVer}{\ensuremath{\type{ApVer}}} - -\newcommand{\upSize}[1]{\ensuremath{\fun{upSize}~\var{#1}}} -\newcommand{\upPV}[1]{\ensuremath{\fun{upPV}~\var{#1}}} -\newcommand{\upId}[1]{\ensuremath{\fun{upId}~\var{#1}}} -\newcommand{\upSig}[1]{\ensuremath{\fun{upSig}~\var{#1}}} -\newcommand{\upSigData}[1]{\ensuremath{\fun{upSigData}~\var{#1}}} -\newcommand{\upIssuer}[1]{\ensuremath{\fun{upIssuer}~\var{#1}}} -\newcommand{\upParams}[1]{\ensuremath{\fun{upParams}~\var{#1}}} -\newcommand{\upSwVer}[1]{\ensuremath{\fun{upSwVer}~\var{#1}}} -\newcommand{\vCaster}[1]{\ensuremath{\fun{vCaster}~\var{#1}}} -\newcommand{\vPropId}[1]{\ensuremath{\fun{vPropId}~\var{#1}}} -\newcommand{\vSig}[1]{\ensuremath{\fun{vSig}~\var{#1}}} - -\lstset{ frame=tb, - , language=Haskell - , basicstyle=\footnotesize\ttfamily, - , keywordstyle=\color{blue!80}, - , commentstyle=\itshape\color{purple!40!black}, - , identifierstyle=\bfseries\color{green!40!black}, - , stringstyle=\color{orange}, - } - -\lstMakeShortInline[columns=fixed]` - -\section{Update mechanism} -\label{sec:update} - -This section formalizes the update mechanism by which the protocol parameters -get updated. This formalization is a simplification of the current update -mechanism implemented in -\href{https://github.com/input-output-hk/cardano-sl/}{\texttt{cardano-sl}}, and -partially documented in: -\begin{itemize} -\item \href{https://cardanodocs.com/technical/updater/}{Updater implementation} -\item \href{https://cardanodocs.com/cardano/update-mechanism/}{Update mechanism} -\item \href{https://github.com/input-output-hk/cardano-sl/blob/develop/wallet-new/docs/updates.md}{Updates technical documentation} -\item - \href{https://github.com/input-output-hk/cardano-sl/blob/develop/docs/block-processing/us.md}{Update - system consensus rules} -\end{itemize} - -The reason for formalizing a simplified version of the current implementation -is that research work on blockchain update mechanisms is needed before -introducing a more complex update logic. Since this specification is to be -implemented in a federated setting, some of the constraints put in place in the -current implementation are no longer relevant. Once the research work is ready, -this specification can be extended to incorporate the research results. - -\subsection{Update proposals} -\label{sec:update-proposals} - -\begin{figure}[htb] - \emph{Abstract types} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \var{up} & \UProp & \text{update proposal}\\ - \var{p} & \ProtPm & \text{protocol parameter}\\ - \var{upd} & \type{UpdData} & \text{update data}\\ - \var{upa} & \type{UpdAttrs} & \text{update attributes}\\ - \var{an} & \ApName & \text{application name} - \end{array} - \end{equation*} - % - \emph{Derived types} - \begin{equation*} - \begin{array}{r@{~\in~}l@{~=~}r@{~\in~}lr} - \var{s_n} & \Slot & n & \mathbb{N} & \text{slot number}\\ - \var{pv} & \ProtVer & (\var{maj}, \var{min}, \var{alt}) - & (\mathbb{N}, \mathbb{N}, \mathbb{N}) & \text{protocol version}\\ - \var{pps} & \PPMMap & \var{pps} & \ProtPm \mapsto \Value - & \text{protocol parameters map}\\ - \var{apv} & \ApVer & n & \mathbb{N}\\ - \var{swv} & \SWVer - & (\var{an}, \var{av}) & \ApName \times \ApVer - & \text{software version}\\ - \var{pb} & \UPropSD - & - {\left(\begin{array}{r l} - \var{pv}\\ - \var{pps}\\ - \var{swv}\\ - \var{upd}\\ - \var{upa}\\ - \end{array}\right)} - & { - \left( - \begin{array}{l} - \ProtVer\\ - \PPMMap\\ - \type{SWVer}\\ - \type{UpdData}\\ - \type{UpdAttrs}\\ - \end{array} - \right) - } - & \text{protocol update signed data} - \end{array} - \end{equation*} - \emph{Abstract functions} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \fun{upIssuer} & \UProp \to \VKey & \text{update proposal issuer (delegate)}\\ - \fun{upSize} & \UProp \to \mathbb{N} & \text{update proposal size}\\ - \fun{upPV} & \UProp \to \ProtVer & \text{update proposal protocol version}\\ - \fun{upId} & \UProp \to \UPropId & \text{update proposal id}\\ - \fun{upParams} & \UProp \to \mathbb{\PPMMap} - & \text{proposed parameters update}\\ - \fun{upSwVer} & \UProp \to \SWVer & \text{software-version update proposal}\\ - \fun{upSig} & \UProp \to \Sig & \text{update proposal signature}\\ - \fun{upSigdata} & \UProp \to \UPropSD & \text{update proposal signed data}\\ - \end{array} - \end{equation*} - \caption{Update proposals definitions} - \label{fig:defs:update-proposals} -\end{figure} - -The set of protocol parameters ($\ProtPm$) is assumed to contain the following keys, which -correspond with fields of the current `BlockVersionData` structure: -\begin{itemize} -\item Slot duration: $\var{slotDuration}$ -\item Maximum block size: $\var{maxBlockSize}$ -\item Maximum transaction size: $\var{maxTxSize}$ -\item Maximum header size: $\var{maxHeaderSize}$ -\item Maximum transaction size: $\var{maxTxSize}$ -\item Maximum proposal size: $\var{maxProposalSize}$ -\item Transaction fee policy: $\var{txFeePolicy}$ -\item Script version: $\var{scriptVersion}$ -\item Update adoption threshold: $\var{upAdptThd}$. This would correspond with - `srInitThd` in `SoftForkRule`, if we set `srMinThd` to `srInitThd` and - `srThdDecrement` to $0$. -\item Chain stability parameter: $\var{chainStabilityParameter}$. -\item Update proposal time-to-live: $\var{upropTTL}$. -\item Certificate liveness: $\var{certificateLiveness}$. -\end{itemize} -In addition we make use of the $\var{cfmThd}$ key, which determines the portion -of the stakeholders that have to vote for a proposal to consider it confirmed. -This key does not seem to have a corresponding field in `BlockVersionData`, so -to be consistent with the existing chain the value corresponding to -$\var{cfmThd}$ can be set to $4$, which represents the majority of the $7$ -genesis keys. - -\subsection{Update proposals registration} -\label{sec:update-proposals-registration} - -\begin{figure}[htb] - \emph{Update proposals validity environments} - \begin{equation*} - \UPVEnv = - \left( - \begin{array}{r@{~\in~}lr} - \var{pv} & \ProtVer & \text{adopted (current) protocol version}\\ - \var{pps} & \PPMMap & \text{adopted protocol parameters map}\\ - \var{avs} & \ApName \mapsto (\ApVer \times \Slot) - & \text{application versions}\\ - \end{array} - \right) - \end{equation*} - % - \emph{Update proposals validity states} - \begin{equation*} - \UPVState - = \left( - \begin{array}{r@{~\in~}lr} - \var{rpus} & \UPropId \mapsto (\ProtVer \times \PPMMap) - & \text{registered protocol update proposals}\\ - \var{raus} & \UPropId \mapsto (\ApName \times \ApVer) - & \text{registered software update proposals}\\ - \end{array} - \right) - \end{equation*} - % - \emph{Update proposals validity transitions} - \begin{equation*} - \var{\_} \vdash - \var{\_} \trans{upv}{\_} \var{\_} - \subseteq \powerset (\UPVEnv \times \UPVState \times \UProp \times \UPVState) - \end{equation*} - \caption{Update proposals validity transition-system types} - \label{fig:ts-types:up-validity} -\end{figure} - -The rules in Figure~\ref{fig:rules:up-validity} model the validity of a proposal: -\begin{itemize} -\item if an update proposal proposes a change in the protocol version, it must - do so in a consistent manner: - \begin{itemize} - \item The proposed version must be lexicographically bigger than the - current version. - \item The major versions of the proposed and current version must differ in - at most one. - \item If the proposed major version is equal to the current major - version, then the proposed minor version must be incremented by one. - \item If the proposed major version is larger than the current major version, - then the proposed minor version must be zero. - \item must be consistent with the current protocol parameters: - \begin{itemize} - \item the proposal size must not exceed the maximum size specified by - the current protocol parameters, - \item the proposed new maximum block size should be not greater than twice - current maximum block size, - \item the maximum transaction size must be smaller than the maximum block - size (this requirement is \textbf{crucial} for having every transaction - fitting in a block \footnote{TODO: we should discuss if this is enough, - since a block might contain other data that contributes to its total - size}), and - \item the proposed new script version can be incremented by at most 1. - \end{itemize} - \item must have a unique version among the current active proposals. This - implies that a proposal is uniquely determined by the protocol version it - proposes. - \end{itemize} -\item if an update proposal proposes to increase the application version - version ($\var{av}$) for a given application ($\var{an}$), then there should - not be an active update proposal that proposes the same update. -\end{itemize} -Note that the rules in Figure~\ref{fig:rules:up-validity} allow for an update -that does not propose changes in the protocol version, or does not propose -changes the software version. However the update proposal must contain a change -proposal in any of these two aspects. -% - -Also note that we do not allow for updating the protocol parameters without -updating the protocol version. If an update in the protocol parameters does not -cause a soft-fork we might use the alt version for that purpose. - -\begin{figure}[htb] - \begin{equation} - \label{eq:func:pv-can-follow} - \begin{array}{r c l} - \fun{pvCanFollow}~(\var{mj_n}, \var{mi_n}, \var{a_n})~(\var{mj_p}, \var{mi_p}, \var{a_p}) - & = & (\var{mj_p}, \var{mi_p}, \var{a_p}) < (\var{mj_n}, \var{mi_n}, \var{a_n})\\ - & \wedge & 0 \leq \var{mj_n} - \var{mj_p} \leq 1\\ - & \wedge & (\var{mj_p} = \var{mj_n} \Rightarrow \var{mi_p} + 1 = \var{mi_n}))\\ - & \wedge & (\var{mj_p} + 1 = \var{mj_n} \Rightarrow \var{mi_n} = 0) - \end{array} - \end{equation} - \nextdef - \begin{equation} - \label{eq:func:can-update} - \begin{array}{l} - \fun{canUpdate}~\var{pps}~\var{up}\\ - {\begin{array}{r c l} - & = & \var{maxProposalSize} \mapsto \var{mus} \in \var{pps}\\ - & \wedge & \upSize{up} \leq \var{mus}\\ - & \wedge & (\var{maxBlockSize} \mapsto \var{bszm_{up}} \in (\upParams{up})\\ - & & \Rightarrow \var{maxBlockSize} \mapsto \var{bszm} \in \var{pps} - \wedge \var{bszm_{up}} \leq 2*\var{bszm})\\ - & \wedge & (\var{maxBlockSize} \mapsto \var{bszm_{up}} \in (\upParams{up}) - \wedge \var{maxTxSize} \mapsto \var{txzm_{up}} \in (\upParams{up})\\ - & & \Rightarrow \var{txzm_{up}} < \var{bszm_{up}})\\ - & \wedge & (\var{scriptVersion} \mapsto \var{sv_{up}} \in (\upParams{up}) \\ - & & \Rightarrow \var{scriptVersion} \mapsto \var{sv} \in \var{pps} - \wedge 0 \leq \var{sv_{up}} - \var{sv} \leq 1) - \end{array}} - \end{array} - \end{equation} - \nextdef - \begin{equation} - \label{eq:func:av-can-follow} - \begin{array}{r c l} - \fun{svCanFollow}~\var{avs}~(\var{an}, \var{av}) & = - & (\var{an} \mapsto (\var{av_c}, \wcard) \in \var{avs} - \Rightarrow \var{av} = \var{av_c} + 1)\\ - & \wedge & (\var{an} \notin \dom~\var{avs} \Rightarrow \var{av} = 0) - \end{array} - \end{equation} - \caption{Update validity functions} -\end{figure} - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:up-av-validity} - \inference - { - (\var{an}, \var{av}) = \upSwVer{up} - & \fun{svCanFollow}~\var{avs}~(\var{an}, \var{av}) - & (\var{an}, \var{av}) \notin \range~\var{raus} - } - { - { - \begin{array}{l} - \var{avs} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{raus} - \end{array} - \right) - } - \trans{upsvv}{up} - { - \left( - \begin{array}{l} - \var{raus} \unionoverride \{ \upId{up} \mapsto (\var{an}, \var{av})\} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:up-pv-validity} - \inference - { - \var{pid} = \upId{up} - & \var{nv} = \upPV{up} - & \var{pps_n} = \upParams{up}\\ - & \fun{pvCanFollow}~\var{nv}~\var{pv} - & \fun{canUpdate}~\var{pps}~\var{up} - & \var{nv} \notin \dom~(\range~\var{rpus}) - } - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus} - \end{array} - \right) - } - \trans{uppvv}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus} \unionoverride \{ \var{pid} \mapsto (\var{nv}, \var{pps_n}) \} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:up-validity-pu-nosu} - \inference - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus} - \end{array} - \right) - } - \trans{uppvv}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus'} - \end{array} - \right) - } - & - (\var{an}, \var{av}) = \upSwVer{up} & \var{an} \mapsto \var{av} \in \var{avs} - } - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps}\\ - \var{avs} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus}\\ - \var{raus} - \end{array} - \right) - } - \trans{upv}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus'}\\ - \var{raus} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:up-validity-nopu-no} - \inference - { - \var{pv} = \upPV{up} & \upParams{up} = \emptyset & - { - \begin{array}{l} - \var{avs} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{raus} - \end{array} - \right) - } - \trans{upsvv}{up} - { - \left( - \begin{array}{l} - \var{raus'} - \end{array} - \right) - } - } - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps}\\ - \var{avs} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus}\\ - \var{raus} - \end{array} - \right) - } - \trans{upv}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus}\\ - \var{raus'} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:up-validity-pu-su} - \inference - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus} - \end{array} - \right) - } - \trans{uppvv}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus'} - \end{array} - \right) - } - & - { - \begin{array}{l} - \var{avs} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{raus} - \end{array} - \right) - } - \trans{upsvv}{up} - { - \left( - \begin{array}{l} - \var{raus'} - \end{array} - \right) - } - } - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps}\\ - \var{avs} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus}\\ - \var{raus} - \end{array} - \right) - } - \trans{upv}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus'}\\ - \var{raus'} - \end{array} - \right) - } - } - \end{equation} - \caption{Update proposals validity rules} - \label{fig:rules:up-validity} -\end{figure} - -\clearpage - -The rule of Figure~\ref{fig:rules:up-registration} models the registration of -an update proposal: -\begin{itemize} -\item We consider the update proposal issuers to be the delegators of the key - ($\var{vk}$) that is associated with the proposal under consideration - ($\var{up}$). -\item We check that the issuer of a proposal was delegated by a genesis key - (which are in the domain of $\var{dms}$). -\item the update proposal data (see the definition of $\fun{upSigdata}$) must - be signed by the proposal issuer. -\end{itemize} - -\begin{figure}[htb] - \emph{Update proposals registration environments} - \begin{equation*} - \UPREnv = - \left( - \begin{array}{r@{~\in~}lr} - \var{pv} & \ProtVer & \text{adopted (current) protocol version}\\ - \var{pps} & \PPMMap & \text{adopted protocol parameters map}\\ - \var{avs} & \ApName \mapsto (\ApVer \times \Slot) - & \text{application versions}\\ - \var{dms} & \VKeyGen \mapsto \VKey & \text{delegation map}\\ - \end{array} - \right) - \end{equation*} - % - \emph{Update proposals registration states} - \begin{align*} - & \UPRState = \\ - & \left( - \begin{array}{r@{~\in~}lr} - \var{rpus} & \UPropId \mapsto (\ProtVer \times \PPMMap) - & \text{registered update proposals}\\ - \var{raus} & \UPropId \mapsto (\ApName \times \ApVer) - & \text{registered software update proposals} - \end{array} - \right) - \end{align*} - % - \emph{Update proposals registration transitions} - \begin{equation*} - \var{\_} \vdash - \var{\_} \trans{upreg}{\_} \var{\_} - \subseteq \powerset (\UPREnv \times \UPRState \times \UProp \times \UPRState) - \end{equation*} - \caption{Update proposals registration transition-system types} - \label{fig:ts-types:up-registration} -\end{figure} - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:up-registration} - \inference - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps}\\ - \var{avs} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus}\\ - \var{raus}\\ - \end{array} - \right) - } - \trans{upv}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus'}\\ - \var{raus'}\\ - \end{array} - \right) - } - & - \var{dms} \restrictrange \{\var{vk}\} \neq \emptyset\\ - \var{vk} = \upIssuer{up} & - \mathcal{V}_{\var{vk}}\serialised{\upSigData{up}}_{(\upSig{up})} - } - { - { - \begin{array}{l} - \var{pv}\\ - \var{pps}\\ - \var{avs}\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{rpus}\\ - \var{raus} - \end{array} - \right) - } - \trans{upreg}{\var{up}} - { - \left( - \begin{array}{l} - \var{rpus'}\\ - \var{raus'} - \end{array} - \right) - } - } - \end{equation} - \caption{Update registration rules} - \label{fig:rules:up-registration} -\end{figure} - -\clearpage - -\subsection{Voting on update proposals} -\label{sec:voting-on-update-proposals} - -\begin{figure}[htb] - \emph{Abstract types} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \var{v} & \Vote & \text{vote on an update proposal} - \end{array} - \end{equation*} - % - \emph{Abstract functions} - \begin{align*} - & \fun{vCaster} \in \Vote \to \VKey & \text{caster of a vote}\\ - & \fun{vPropId} \in \Vote \to \UPropId & \text{proposal id that is being voted}\\ - & \fun{vSig} \in \Vote \to \Sig & \text{vote signature} - \end{align*} - \caption{Voting definitions} - \label{fig:defs:voting} -\end{figure} - -\begin{figure}[htb] - \emph{Voting environments} - \begin{align*} - & \VEnv - = \left( - \begin{array}{r@{~\in~}lr} - \var{rups} & \powerset{\UPropId} - & \text{registered update proposals}\\ - \var{dms} & \VKeyGen \mapsto \VKey & \text{delegation map} - \end{array}\right) - \end{align*} - % - \emph{Voting states} - \begin{align*} - & \VState - = \left( - \begin{array}{r@{~\in~}lr} - \var{vts} & \powerset{(\UPropId \times \VKeyGen)} & \text{votes} - \end{array}\right) - \end{align*} - % - \emph{Voting transitions} - \begin{equation*} - \_ \vdash \_ \trans{addvote}{\_} \_ \in - \powerset (\VEnv \times \VState \times \Vote \times \VState) - \end{equation*} - \caption{Voting transition-system types} - \label{fig:ts-types:voting} -\end{figure} - -In Rule~\ref{eq:rule:voting}: -\begin{itemize} -\item Only genesis keys can vote on an update proposal, although votes can be - cast by delegates of these genesis keys. -\item We count one vote per genesis key that delegated to the key that is - casting the vote. -\item The vote must refer to a registered update proposal. -\item The proposal id must be signed by the key that is casting the vote. -\item It is possible for the same genesis key to vote multiple times for - the same proposal, however this vote will be counted once (note that we're - taking the union of the key-proposal-id pairs). -\end{itemize} - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:voting} - \inference - { - \var{pid} = \vPropId{v} & \var{vk} = \vCaster{v} & - \var{vts}_{\var{pid}} = - \{ (\var{pid}, \var{vk_s}) \mid \var{vk_s} \mapsto \var{vk} \in \var{dms} \}\\ - & \var{pid} \in \var{rups} & - \mathcal{V}_{\var{vk}}\serialised{\var{pid}}_{(\vSig{v})}\\ - } - { - { - \begin{array}{l} - \var{rups}\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{vts} - \end{array} - \right) - } - \trans{addvote}{\var{v}} - { - \left( - \begin{array}{l} - \var{vts} \cup \var{vts}_{\var{pid}}\\ - \end{array} - \right) - } - } - \end{equation} - \caption{Update voting rules} - \label{fig:rules:voting} -\end{figure} - -\clearpage - -\begin{figure}[htb] - \emph{Vote registration environments} - \begin{align*} - & \VEnv - = \left( - \begin{array}{r@{~\in~}lr} - \var{s_n} & \Slot & \text{current slot number}\\ - \var{pps} & \PPMMap & \text{current protocol parameters map}\\ - \var{rups} & \powerset{\UPropId} - & \text{registered update proposals}\\ - \var{dms} & \VKeyGen \mapsto \VKey & \text{delegation map} - \end{array}\right) - \end{align*} - % - \emph{Vote registration states} - \begin{align*} - & \VState - = \left( - \begin{array}{r@{~\in~}lr} - \var{cps} & \UPropId \mapsto \Slot & \text{confirmed proposals}\\ - \var{vts} & \powerset{(\UPropId \times \VKeyGen)} & \text{votes} - \end{array}\right) - \end{align*} - % - \emph{Vote registration transitions} - \begin{equation*} - \_ \vdash \_ \trans{UPVOTE}{\_} \_ \in - \powerset (\VEnv \times \VState \times \Vote \times \VState) - \end{equation*} - \caption{Vote registration transition-system types} - \label{fig:ts-types:vote-reg} -\end{figure} - -The rules in Figure~\ref{fig:rules:up-vote-reg} model the registration of a vote: -\begin{itemize} -\item The vote gets added to the list set of votes per-proposal ($\var{vts}$), - via transition $\trans{addvote}{}$. -\item If the number of votes for the proposal $v$ refers to exceeds the - confirmation threshold and this proposal was not confirmed already, then the - proposal gets added to the set of confirmed proposals ($\var{cps}$). The - reason why we check that the proposal was not already confirmed, is that we - want to keep in $\var{cps}$ the earliest block number in which the proposal - was confirmed. -\end{itemize} - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:up-no-confirmation} - \inference - { - { - \begin{array}{l} - \var{rups}\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{vts} - \end{array} - \right) - } - \trans{addvote}{\var{v}} - { - \left( - \begin{array}{l} - \var{vts'} - \end{array} - \right) - }\\ - \var{pid} = \vPropId{v} - & \var{cfmThd} \mapsto t \in \var{pps} - & (\size{\{\var{pid}\} \restrictdom \var{vts'}} < t - \vee \var{pid} \in \dom~\var{cps} - ) - } - { - { - \begin{array}{l} - s_n\\ - \var{pps}\\ - \var{rups}\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{cps}\\ - \var{vts} - \end{array} - \right) - } - \trans{upvote}{\var{v}} - { - \left( - \begin{array}{l} - \var{cps}\\ - \var{vts'} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:up-vote-reg} - \inference - { - { - \begin{array}{l} - \var{rups}\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{vts} - \end{array} - \right) - } - \trans{addvote}{\var{v}} - { - \left( - \begin{array}{l} - \var{vts'} - \end{array} - \right) - }\\ - \var{pid} = \vPropId{v} - & \var{cfmThd} \mapsto t \in \var{pps} - & t \leq \size{\{\var{pid}\} \restrictdom \var{vts'}} - & \var{pid} \notin \dom~\var{cps} - } - { - { - \begin{array}{l} - \var{s_n}\\ - \var{pps}\\ - \var{rups}\\ - \var{dms} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{cps}\\ - \var{vts} - \end{array} - \right) - } - \trans{upvote}{\var{v}} - { - \left( - \begin{array}{l} - \var{cps} \unionoverride \{\var{pid} \mapsto s_n\} \\ - \var{vts'} - \end{array} - \right) - } - } - \end{equation} - \caption{Vote registration rules} - \label{fig:rules:up-vote-reg} -\end{figure} - -\clearpage - -\subsection{Update-proposal endorsement} -\label{sec:proposal-endorsement} - -Figure~\ref{fig:ts-types:up-end} shows the types of the transition system -associated with the registration of candidate protocol versions present in -blocks. Some clarifications are in order: -\begin{itemize} -\item The $k$ parameter is used to determined when a confirmed proposal is - stable. Given we are in a current slot $s_n$, all update proposals confirmed - at or before slot $s_n - 2 \cdot k$ are deemed stable. -\item For the sake of conciseness, we omit the types associated to the - transitions $\trans{fads}{}$, since they can be inferred from the types of - the $\trans{upend}{}$ transitions. -\end{itemize} - -\begin{figure}[htb] - \emph{Update-proposal endorsement environments} - \begin{align*} - & \BVREnv - = \left( - \begin{array}{r@{~\in~}lr} - \var{k} & \mathbb{N} & \text{chain stability parameter}\\ - \var{s_n} & \Slot & \text{current block number}\\ - (\var{pv}, \var{pps}) & \ProtVer \times \PPMMap - & \text{current protocol parameters map}\\ - \var{cps} & \UPropId \mapsto \Slot & \text{confirmed proposals}\\ - \var{rpus} & \UPropId \mapsto (\ProtVer \times \PPMMap) - & \text{registered update proposals}\\ - \end{array}\right) - \end{align*} - % - \emph{Update-proposal endorsement states} - \begin{align*} - & \BVRState - = \left( - \begin{array}{r@{~\in~}lr} - \var{fads} & \seqof{(\Slot \times (\ProtVer \times \PPMMap))} - & \text{future protocol-version adoptions}\\ - \var{bvs} & \powerset{(\ProtVer \times \VKeyGen)} - & \text{endorsement-key pairs} - \end{array}\right) - \end{align*} - % - \emph{Update-proposal endorsement transitions} - \begin{equation*} - \_ \vdash \_ \trans{upend}{\_} \_ \in - \powerset (\BVREnv \times \BVRState - \times (\ProtVer \times \VKey) \times \BVRState) - \end{equation*} - \caption{Update-proposal endorsement transition-system types} - \label{fig:ts-types:up-end} -\end{figure} - -Rules in \cref{fig:rules:up-end} specify what happens when a block issuer -signals that it is ready to upgrade to a new protocol version, given in the -rule by $\var{bv}$: -\begin{itemize} -\item The set $\var{bvs}$, containing which block issuers are ready to adopt a - given protocol version, is updated to reflect that the block issuer - (identified by its verifying key $\var{vk}$) is ready to upgrade to - $\var{bv}$. Given a pair $(\var{pv}, ~\var{vk}) \in \var{bvs}$, we say that - (the owner of) key $\var{vk}$ endorses the (proposed) protocol version - $\var{pv}$. -\item If there are a significant number of blocks signed with $\var{bv}$ - (condition formalized in \cref{eq:predicate:canadopt}), there is a registered - proposal (which are contained in $\var{rpus}$) which proposes to upgrade the - protocol to version $\var{bv}$, and this update proposal was confirmed at - least $2 \cdot k$ slots ago (to ensure stability of the confirmation), then - we update the sequence of future protocol-version adoptions ($\var{fads}$). -\item An element $(s_c, (\var{pv_c}, \var{pps_c})$ of $\var{fads}$ represents - the fact that protocol version $\var{pv_c}$ got enough endorsements at slot - $s_c$. An invariant that this sequence should maintain is that it is sorted - in ascending order on slots and on protocol versions. This means that if we - want to know what is the next candidate to adopt at a slot $s_k$ we only need - to look at the last element of $[.., s_k] \restrictdom \var{fads}$. Since the - list is sorted in ascending order on protocol versions, we know that this - last element will contain the highest version to be adopted in the slot range - $[.., s_k]$. The $\trans{fads}{}$ transition rules take care of maintaining - the aforementioned invariant. If a given protocol-version $\var{bv}$ got - enough endorsements, but there is an adoption candidate as last element of - $\var{fads}$ with a higher version, we simply discard $\var{bv}$. -\item If a registered proposal cannot be adopted, we only register the - endorsement. -\item If a block version does not correspond to a registered or confirmed - proposal, we just ignore the endorsement. -\end{itemize} - -\begin{figure}[htb] - \begin{equation} - \label{eq:predicate:canadopt} - \begin{array}{r c l} - \fun{canAdopt}~\var{pps}~\var{bvs}~\var{bv} - & = - & \var{upAdptThd} \mapsto t \in pps \wedge - t \leq \size{\{\var{bv}\} \restrictdom \var{bvs}}\\ - \end{array} - \end{equation} - \caption{Update-proposal endorsement functions} -\end{figure} - -\begin{figure}[htb] - \begin{equation} - \label{eq:rule:fads-add} - \inference - { - (\wcard ; (s_c, (\var{pv_c}, \wcard)) \leteq \var{fads} - \wedge \var{pv_c} < bv) \vee \epsilon = fads - } - { - { - \left( - \begin{array}{l} - \var{fads} - \end{array} - \right) - } - \trans{fads}{(s_n, (\var{bv}, \var{pps_c}))} - { - \left( - \begin{array}{l} - \var{fads}; (s_n, (\var{bv}, \var{pps_c})) - \end{array} - \right) - } - } - \end{equation} - % - \nextdef - \begin{equation} - \label{eq:rule:fads-noop} - \inference - { - \wcard ; (\wcard, (\var{pv_c}, \wcard)) \leteq \var{fads} & \var{bv} \leq \var{pv_c} - } - { - { - \left( - \begin{array}{l} - \var{fads} - \end{array} - \right) - } - \trans{fads}{(s_n, (\var{bv}, \var{pps_c}))} - { - \left( - \begin{array}{l} - \var{fads} - \end{array} - \right) - } - } - \end{equation} - \nextdef - \begin{equation} - \label{eq:rule:up-up-invalid} - \inference - { - \var{pid} \mapsto (\var{bv}, \wcard) \notin \var{rpus} - \vee \var{pid} \notin \dom~(\var{cps} \restrictrange [.., s_n - 2 \cdot k]) - } - { - { - \begin{array}{l} - k\\ - s_n\\ - (\var{pv}, \var{pps})\\ - \var{cps}\\ - \var{rpus} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{fads}\\ - \var{bvs} - \end{array} - \right) - } - \trans{upend}{(\var{bv}, \var{vk})} - { - \left( - \begin{array}{l} - \var{fads}\\ - \var{bvs} - \end{array} - \right) - } - } - \end{equation} - \nextdef - % - \begin{equation} - \label{eq:rule:up-cant-adopt} - \inference - { - \var{bvs'} \leteq \var{bvs} \cup \{(\var{bv}, \var{vk})\} - & \neg (\fun{canAdopt}~\var{pps}~\var{bvs'}~\var{bv}) \\ - \var{pid} \mapsto (\var{bv}, \wcard) \in \var{rpus} - & \var{pid} \in \dom~(\var{cps} \restrictrange [.., s_n - 2 \cdot k]) - } - { - { - \begin{array}{l} - k\\ - s_n\\ - (\var{pv}, \var{pps})\\ - \var{cps}\\ - \var{rpus} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{fads}\\ - \var{bvs} - \end{array} - \right) - } - \trans{upend}{(\var{bv}, \var{vk})} - { - \left( - \begin{array}{l} - \var{fads}\\ - \var{bvs'} - \end{array} - \right) - } - } - \end{equation} - % - \nextdef - % - \begin{equation} - \label{eq:rule:up-canadopt} - \inference - { - \var{bvs'} = \var{bvs} \cup \{(\var{bv}, \var{vk})\} - & \fun{canAdopt}~\var{pps}~\var{bvs'}~\var{bv} \\ - \var{pid} \mapsto (\var{bv}, \var{pps_c}) \in \var{rpus} - & \var{pid} \in \dom~(\var{cps} \restrictrange [.., s_n - 2 \cdot k])\\ - (\var{fads}) \trans{fads}{(s_n, (\var{bv}, \var{pps_c}))} (\var{fads'}) - } - { - { - \begin{array}{l} - k\\ - s_n\\ - (\var{pv}, \var{pps})\\ - \var{dms}\\ - \var{cps}\\ - \var{rpus} - \end{array} - } - \vdash - { - \left( - \begin{array}{l} - \var{fads}\\ - \var{bvs} - \end{array} - \right) - } - \trans{upend}{(\var{bv}, \var{vk})} - { - \left( - \begin{array}{l} - \var{fads'}\\ - \var{bvs'} - \end{array} - \right) - } - } - \end{equation} - \caption{Update-proposal endorsement rules} - \label{fig:rules:up-end} -\end{figure} - -\clearpage - -\subsection{Deviations from the actual implementation} -\label{sec:deviation-actual-impl} - -The current specification of the voting mechanism deviates from the actual -implementation, although it should be backwards compatible with the latter. -These deviations are required to simplify the voting and update mechanism -removing unnecessary features for a simplified setting, which will use the OBFT -consensus protocol with federated genesis key holders. This in turn, enables us -to remove any accidental complexity that might have been introduced in the -current implementation. The following subsections highlight the differences -between the this specification and the current implementation. - -\subsubsection{Positive votes} -\label{sec:only-positive-votes} - -Genesis keys can only vote (positively) for an update proposal. In the current -implementation stakeholders can vote for or against a proposal, which makes the -voting logic more complex: -\begin{itemize} -\item there are more cases to consider -\item the current voting validation rules allow voters to change their minds - (by flipping their vote) at most once, which requires to keep track how a - stake holder voted and how many times. Contrast this with - Rule~\ref{eq:rule:voting} where we only need to keep track of the set of - key-proposal-id's pairs. -\end{itemize} - -\subsubsection{Alternative version numbers} -\label{sec:alt-version-numbers-constraints} - -Alternative version numbers are only lexicographically constrained. The current -implementation seems to be dependent on the order in which the update proposals -arrive: given a new update proposal $\var{up}$, if a set $X$ of update -proposals with the same minor and major versions than $\var{up}$ exist, then -the alternative version of $\var{up}$ has to be one more than the maximum -alternative number of $X$. Not only this logic seems to be brittle since it -depends on the order of arrival of the update proposals, but it requires a more -complex check (which depends on state) to determine if a proposed version can -follow the current one. By being more lenient on the alternative versions of -update proposals we can simplify the version checking logic considerably. - -\subsubsection{No implicit agreement} -\label{sec:no-implicit-agreement} - -We do not model the implicit agreement rule. If a proposal does not get enough -votes before the end of the voting period, then we simply discard it. At the -moment it is not clear whether the implicit agreement rule is needed. - -\subsubsection{Adoption threshold} -\label{sec:adoption-threshold} - -The current implementation adopts a proposal with version $\var{pv}$ if the -portion of block issuers' stakes, which issued blocks with this version, is -greater than the threshold given by: - -\begin{lstlisting} -max spMinThd (spInitThd - (t - s) * spThdDecrement) -\end{lstlisting} - -where: -\begin{itemize} -\item \lstinline{spMinThd} is a minimum threshold required for adoption. -\item \lstinline{spInitThd} is an initial threshold. -\item \lstinline{spThdDecrement} is the decrement constant of the initial - threshold. -\end{itemize} - -In this specification we only make use of a minimum adoption threshold, -represented by the protocol parameter $\var{upAdptThd}$ until it becomes clear -why a dynamic alternative is needed. - -\subsubsection{No checks on unlock-stake-epoch parameter} -\label{sec:no-unlock-stake-epoch-check} - -The rule of Figure~\ref{eq:rule:up-pv-validity} does not check the -\lstinline{bvdUnlockStakeEpoch} parameter, since it will have a different -meaning in the handover phase: its use will be reserved for unlocking the -Ouroboros-BFT logic in the software. - -\subsubsection{No grouping of proposals per-application name} -\label{sec:no-app-up-grouping} - -It is unclear at this moment whether we need to model the applications names -and versions, so this aspect is not modeled in the present rules. - -\subsubsection{Ignored attributes of proposals} - -In Figure~\ref{fig:defs:update-proposals} the types -$\type{UpdData}$, and $\type{UpdAttrs}$ are only needed to model the fact that -an update proposal must sign such data, however, we do not use them for any -other purpose in this formalization. - -\subsubsection{No limits on update proposals per-key per-epoch} -\label{sec:no-up-limits} - -In the current system a given genesis key can submit only one proposal per -epoch. At the moment, it is not clear what are the advantages of such -constraint: -\begin{itemize} -\item Genesis keys are controlled by the Cardano foundation. -\item Even if a genesis key falls in the hands of the adversary, only one - update proposal can be submitted per-block, and proposals have an time to - live of $u$ blocks. So in the worst case scenario we are looking at an - increase in the state size of the ledger proportional to $u$. -\end{itemize} -On the other hand, having that constraint in place brings some extra complexity -in the specification, and therefore in the code that will implement it. -Furthermore, in the current system, if an error is made in an update proposal, -then if an amendment must be made within the current epoch, then a new update -proposal must be submitted with a different key, which adds extra complexity -for devops. In light of the preceding discussion, unless there is a benefit for -restricting the number of times a genesis key can submit an update proposal, we -opted for removing such constraint in the current specification. - -\subsubsection{Protocol only or software only updates allowed} -\label{sec:ptonly-or-swonly-allowed} - -We allow for updates in the protocol version without requiring a software -version update, and conversely, we allow for a software update without -requiring an update in the protocol. - -\subsubsection{Acceptance of blocks endorsing unconfirmed proposal updates} -\label{sec:acceptance-of-uncofirmed-up-endorsements} - -A consequence of enforcing the update rules in \cref{fig:rules:up-end} is that -a block that is endorsing an unconfirmed proposal gets accepted, although it -will not have any effect on the update mechanism. It is not clear at this stage -whether such block should be rejected, therefore we have chosen to be lenient. - -\subsection{Questions} -\label{sec:up-questions} - -This temporary section contains unanswered questions about the formalization of -update mechanism: - -\begin{itemize} -\item Do we need to model the $\var{scriptVersion}$? -\item Do we allow an update proposal that proposes no update? -\end{itemize} diff --git a/specs/ledger/latex/utxo.tex b/specs/ledger/latex/utxo.tex deleted file mode 100644 index 1ead33a1..00000000 --- a/specs/ledger/latex/utxo.tex +++ /dev/null @@ -1,226 +0,0 @@ -\newcommand{\PPMMap}{\ensuremath{\type{PParams}}} -\newcommand{\Lmax}{\ensuremath{\mathbb{L}_{\var{max}}}} -\section{UTxO} -\label{sec:state-trans-utxo-1} - -The transition rules for unspent outputs are presented in -Figure~\ref{fig:rules:utxo}. The states of the UTxO transition system, along -with their types are defined in Figure~\ref{fig:defs:utxo}, here we define the -protocol parameters as an abstract type, this type is made concrete in -Section~\ref{sec:update}, where the update mechanism is discussed. Functions on -these types are defined in Figure~\ref{fig:derived-defs:utxo}. In particular, -note that in function $\fun{minfee}$ we make use of the fact that the -$\Lovelace$ type is an alias for the set of the integers numbers -($\mathbb{Z}$). - -\begin{figure*}[htb] - \emph{Abstract types} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \var{tx} & \Tx & \text{transaction}\\ - % - \var{txid} & \TxId & \text{transaction id}\\ - % - ix & \Ix & \text{transaction index}\\ - % - \var{addr} & \Addr & \text{address}\\ - % - \var{pps} & \PPMMap & \text{protocol parameters} - \end{array} - \end{equation*} - % - \emph{Derived types} - % - \begin{equation*} - \begin{array}{r@{~\in~}l@{\qquad=\qquad}r@{~\in~}lr} - \ell & \Lovelace - & n & \mathbb{Z} - & \text{currency value} - \\ - \var{txin} - & \TxIn - & (\var{txid}, \var{ix}) - & \TxId \times \Ix - & \text{transaction input} - \\ - \var{txout} - & \type{TxOut} - & (\var{addr}, c) - & \Addr \times \Lovelace - & \text{transaction output} - \\ - \var{utxo} - & \UTxO - & m - & \TxIn \mapsto \TxOut - & \text{unspent tx outputs} - \end{array} - \end{equation*} - % - \emph{Abstract Functions} - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \txid{} & \Tx \to \TxId & \text{compute transaction id}\\ - % - \fun{txbody} & \Tx \to \powerset{\TxIn} \times (\Ix \mapsto \TxOut) - & \text{transaction body}\\ - % - \fun{a} & \PPMMap \to \mathbb{Z} & \text{minumum fee factor}\\ - % - \fun{b} & \PPMMap \to \mathbb{Z} & \text{minumum fee constant}\\ - % - \fun{txSize} & \Tx \to \mathbb{Z} & \text{abstract size of a transaction} - \end{array} - \end{equation*} - % - \emph{Constraints} - \begin{equation} - \label{eq:txid-injective} - \forall \var{tx_i}, \var{tx_j} \cdot - \txid{\var{tx_i}} = \txid{\var{tx_j}} \Rightarrow \var{tx_i} = \var{tx_j} - \end{equation} - \caption{Definitions used in the UTxO transition system} - \label{fig:defs:utxo} -\end{figure*} - -\begin{figure} - \begin{align*} - & \fun{txins} \in \Tx \to \powerset{\TxIn} - & \text{transaction inputs} \\ - & \txins{tx} = \var{inputs} \where \txbody{tx} = (\var{inputs}, ~\wcard) - \nextdef - & \fun{txouts} \in \Tx \to \UTxO - & \text{transaction outputs as UTxO} \\ - & \fun{txouts} ~ \var{tx} = - \left\{ (\fun{txid} ~ \var{tx}, \var{ix}) \mapsto \var{txout} ~ - \middle| \begin{array}{l@{~}c@{~}l} - (\_, \var{outputs}) & = & \txbody{tx} \\ - \var{ix} \mapsto \var{txout} & \in & \var{outputs} - \end{array} - \right\} - \nextdef - & \fun{balance} \in \UTxO \to \mathbb{Z} - & \text{UTxO balance} \\ - & \fun{balance} ~ utxo = \sum_{(~\wcard ~ \mapsto (\wcard, ~c)) \in \var{utxo}} c\\ - \nextdef - % - & \fun{minfee} \in \PPMMap \to \Tx \to \mathbb{Z} & \text{minimum fee}\\ - & \fun{minfee}~\var{pps}~\var{tx} = - \fun{a}~\var{pps} * \fun{txSize}~\var{tx} + \fun{b}~\var{pps} - \end{align*} - \caption{Functions used in UTxO rules} - \label{fig:derived-defs:utxo} -\end{figure} - -\begin{figure} - \emph{UTxO transitions} - \begin{equation*} - \_ \vdash - \var{\_} \trans{utxo}{\_} \var{\_} - \subseteq \powerset (\PPMMap \times \UTxO \times \Tx \times \UTxO) - \end{equation*} - \caption{UTxO transition-system types} - \label{fig:ts-types:utxo} -\end{figure} - -\begin{figure} - \begin{equation}\label{eq:utxo-inductive} - \inference - { \txins{tx} \subseteq \dom \var{utxo} - & \minfee{pps}{tx} \leq \balance{(\txouts{tx})} - \balance{(\txins{tx} \restrictdom \var{utxo})}\\ - \txins{tx} \neq \emptyset - } - {\var{pps} \vdash \var{utxo} \trans{utxo}{tx} - (\txins{tx} \subtractdom \var{utxo}) \cup \txouts{tx} - } - \end{equation} - \caption{UTxO inference rules} - \label{fig:rules:utxo} -\end{figure} - -Rule~\ref{eq:utxo-inductive} specifies under which conditions a transaction can -be applied to a set of unspent outputs, and how the set of unspent output -changes with a transaction: -\begin{itemize} -\item Each input spent in the transaction must be in the set of unspent - outputs. -\item The minimum fee, which depends on the transaction and the protocol - parameters, must be less or equal than the difference between the balance of - the unspent outputs in a transaction (i.e. the total amount paid in a - transaction) and the amount of spent inputs. -\item The set of inputs must not be empty. -\item If the above conditions hold, then the new state will not have the inputs - spent in transaction $\var{tx}$ and it will have the new outputs in - $\var{tx}$. -\end{itemize} - -\clearpage - -\subsection{Witnesses} -\label{sec:witnesses} - -The rules for witnesses are presented in Figure~\ref{fig:rules:utxow}. -The definitions used in Rule~\ref{eq:utxo-witness-inductive} are given in -Figure~\ref{fig:defs:utxow}. Note that -Rule~\ref{eq:utxo-witness-inductive} uses the transition relation defined in -Figure~\ref{fig:rules:utxo}. The main reason for doing this is to define -the rules incrementally, modeling different aspects in isolation to keep the -rules as simple as possible. Also note that the $\trans{utxo}{}$ relation could -have been defined in terms of $\trans{utxow}{}$ (thus composing the rules in a -different order). The choice here is arbitrary. - -\begin{figure}[htb] - \emph{Abstract functions} - % - \begin{equation*} - \begin{array}{r@{~\in~}lr} - \fun{wits} & \Tx \to \powerset{(\VKey \times \Sig)} - & \text{witnesses of a transaction}\\ - \fun{hash_{spend}} & \Addr \mapsto \Hash - & \text{hash of a spending key in an address}\\ - \end{array} - \end{equation*} - \caption{Definitions used in the UTxO transition system with witnesses} - \label{fig:defs:utxow} -\end{figure} - -\begin{figure}[htb] - \begin{align*} - & \addr{}{} \in \UTxO \to \TxIn \mapsto \Addr & \text{address of an input}\\ - & \addr{utxo} = \{ i \mapsto a \mid i \mapsto (a, \wcard) \in \var{utxo} \} \\ - \nextdef - & \fun{addr_h} \in \UTxO \to \TxIn \mapsto \Hash & \text{hash of an input address}\\ - & \fun{addr_h}~utxo = \{ i \mapsto h \mid i \mapsto (a, \wcard) \in \var{utxo} - \wedge a \mapsto h \in \fun{hash_{spend}} \} - \end{align*} - \caption{Functions used in rules witnesses} - \label{fig:derived-defs:utxow} -\end{figure} - -\begin{figure} - \emph{UTxO with witness transitions} - \begin{equation*} - \var{\_} \vdash - \var{\_} \trans{utxow}{\_} \var{\_} - \subseteq \powerset (\PPMMap \times \UTxO \times \Tx \times \UTxO) - \end{equation*} - \caption{UTxO with witness transition-system types} - \label{fig:ts-types:utxow} -\end{figure} - -\begin{figure} - \begin{equation} - \label{eq:utxo-witness-inductive} - \inference - { \var{pps} \vdash \var{utxo} \trans{utxo}{tx} \var{utxo'}\\ ~ \\ - & \forall i \in \txins{tx} \cdot \exists (\var{vk}, \sigma) \in \wits{\var{tx}} - \cdot - \mathcal{V}^\sigma_{\var{vk}}~{\serialised{\txbody{tx}}} - \wedge \fun{addr_h}~{utxo}~i = \hash{vk}\\ - } - {\var{pps} \vdash \var{utxo} \trans{utxow}{tx} \var{utxo'}} - \end{equation} - \caption{UTxO with witnesses inference rules} - \label{fig:rules:utxow} -\end{figure} diff --git a/specs/semantics/hs/CHANGELOG.md b/specs/semantics/hs/CHANGELOG.md deleted file mode 100644 index 3cb19a1b..00000000 --- a/specs/semantics/hs/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Revision history for small-steps - -## 0.1.0.0 -- YYYY-mm-dd - -* First version. Released on an unsuspecting world. diff --git a/specs/semantics/hs/LICENSE b/specs/semantics/hs/LICENSE deleted file mode 100644 index ab72bf03..00000000 --- a/specs/semantics/hs/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -Copyright (c) 2018, IOHK Formal Methods Team - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of IOHK Formal Methods Team nor the names of other - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/specs/semantics/hs/Setup.hs b/specs/semantics/hs/Setup.hs deleted file mode 100644 index 9a994af6..00000000 --- a/specs/semantics/hs/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/specs/semantics/hs/default.nix b/specs/semantics/hs/default.nix deleted file mode 100644 index 99fe943b..00000000 --- a/specs/semantics/hs/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -let - pkgs = import ../../../pkgs.nix; -in - pkgs.haskell.packages.ghc861.small-steps diff --git a/specs/semantics/hs/shell.nix b/specs/semantics/hs/shell.nix deleted file mode 100644 index 56b62349..00000000 --- a/specs/semantics/hs/shell.nix +++ /dev/null @@ -1,5 +0,0 @@ -let - pkgs = import ../../../pkgs.nix; -in pkgs.lib.overrideDerivation ((import ./.).env) (old: { - nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.cabal-install pkgs.haskell.packages.ghc861.ghcid ]; -}) diff --git a/specs/semantics/hs/small-steps.cabal b/specs/semantics/hs/small-steps.cabal deleted file mode 100644 index dbd2628a..00000000 --- a/specs/semantics/hs/small-steps.cabal +++ /dev/null @@ -1,69 +0,0 @@ --- Initial small-steps.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/ - -name: small-steps -version: 0.1.0.0 -synopsis: Small step semantics --- description: -homepage: https://github.com/input-output-hk/cardano-chain -license: BSD3 -license-file: LICENSE -author: IOHK Formal Methods Team -maintainer: formal.methods@iohk.io --- copyright: -category: Control -build-type: Simple -extra-source-files: CHANGELOG.md -cabal-version: >=1.10 - -flag development - description: Disable '-Werror' - default: False - manual: True - -library - exposed-modules: Control.State.Transition - , Control.State.Transition.Generator - , Control.State.Transition.Trace - , Data.AbstractSize - -- other-modules: - -- other-extensions: - build-depends: base >=4.11 && <5 - , containers - , data-default - , free - , hedgehog - , tasty-hunit - , lens - , mtl - , sequence - , transformers >= 0.5 - hs-source-dirs: src - default-language: Haskell2010 - ghc-options: -Wall - -Wcompat - -Wincomplete-record-updates - -Wincomplete-uni-patterns - -Wredundant-constraints - if (!flag(development)) - ghc-options: -Werror - -test-suite doctests - hs-source-dirs: test - main-is: DoctestDiscover.hs - type: exitcode-stdio-1.0 - default-language: Haskell2010 - build-depends: base - , doctest - , doctest-discover - -- - , small-steps - ghc-options: -Wall - -Wcompat - -Wincomplete-record-updates - -Wincomplete-uni-patterns - -Wredundant-constraints - -threaded - - if (!flag(development)) - ghc-options: -Werror diff --git a/specs/semantics/hs/src/Control/State/Transition.hs b/specs/semantics/hs/src/Control/State/Transition.hs deleted file mode 100644 index 71808808..00000000 --- a/specs/semantics/hs/src/Control/State/Transition.hs +++ /dev/null @@ -1,178 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveFunctor #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE KindSignatures #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeFamilyDependencies #-} -{-# LANGUAGE UndecidableInstances #-} - --- | Small step state transition systems. -module Control.State.Transition where - -import Control.Monad (unless) -import Control.Monad.Free.Church -import Control.Monad.Trans.State.Strict (modify, runState) -import qualified Control.Monad.Trans.State.Strict as MonadState -import Data.Foldable (find, traverse_) -import Data.Maybe (fromMaybe) -import Data.Kind (Type) - -data RuleType - = Initial - | Transition - --- | Singleton instances. --- --- Since our case is so small we don't bother with the singletons library. -data SRuleType a where - SInitial :: SRuleType 'Initial - STransition :: SRuleType 'Transition - -class RuleTypeRep t where - rTypeRep :: SRuleType t - -instance RuleTypeRep 'Initial where - rTypeRep = SInitial - -instance RuleTypeRep 'Transition where - rTypeRep = STransition - --- | Context available to initial rules. -newtype IRC sts = IRC (Environment sts) - --- | Context available to transition rules. -newtype TRC sts = TRC (Environment sts, State sts, Signal sts) - -type family RuleContext (t :: RuleType) = (ctx :: Type -> Type) | ctx -> t where - RuleContext 'Initial = IRC - RuleContext 'Transition = TRC - -type InitialRule sts = Rule sts 'Initial (State sts) -type TransitionRule sts = Rule sts 'Transition (State sts) - --- | State transition system. -class ( Eq (PredicateFailure a) - , Show (PredicateFailure a) - ) - => STS a where - -- | Type of the state which the system transitions between. - type State a :: * - -- | Signal triggering a state change. - type Signal a :: * - -- | Environment type. - type Environment a :: * - - -- | Descriptive type for the possible failures which might cause a transition - -- to fail. - data PredicateFailure a :: * - - -- | Rules governing transition under this system. - initialRules :: [InitialRule a] - transitionRules :: [TransitionRule a] - --- | Embed one STS within another. -class (STS sub, STS super) => Embed sub super where - -- | Wrap a predicate failure of the subsystem in a failure of the super-system. - wrapFailed :: PredicateFailure sub -> PredicateFailure super - -instance STS sts => Embed sts sts where - wrapFailed = id - -data Clause sts (rtype :: RuleType) a where - GetCtx :: (RuleContext rtype sts -> a) - -> Clause sts rtype a - SubTrans :: Embed sub sts - => RuleContext rtype sub - -- Subsequent computation with state introduced - -> (State sub -> a) - -> Clause sts rtype a - Predicate :: Bool - -- Type of failure to return if the predicate fails - -> PredicateFailure sts - -> a - -> Clause sts rtype a - -deriving instance Functor (Clause sts rtype) - -type Rule sts rtype = F (Clause sts rtype) - --- | Oh noes! --- --- This takes a condition (a boolean expression) and a failure and results in --- a clause which will throw that failure if the condition fails. -(?!) :: Bool -> PredicateFailure sts -> Rule sts ctx () -cond ?! orElse = wrap $ Predicate cond orElse (pure ()) - -infix 1 ?! - -failBecause :: PredicateFailure sts -> Rule sts ctx () -failBecause = (False ?!) - -trans - :: Embed sub super => RuleContext rtype sub -> Rule super rtype (State sub) -trans ctx = wrap $ SubTrans ctx pure - --- | Get the judgment context -judgmentContext :: Rule sts rtype (RuleContext rtype sts) -judgmentContext = wrap $ GetCtx pure - --- | Apply a rule even if its predicates fail. --- --- If the rule successfully applied, the list of predicate failures will be --- empty. -applyRuleIndifferently - :: forall s rtype - . (RuleTypeRep rtype) - => RuleContext rtype s - -> Rule s rtype (State s) - -> (State s, [PredicateFailure s]) -applyRuleIndifferently jc r = flip runState [] $ foldF runClause r - where - runClause :: Clause s rtype a -> MonadState.State [PredicateFailure s] a - runClause (GetCtx next ) = next <$> pure jc - runClause (Predicate cond orElse val) = do - unless cond $ modify (orElse :) - pure val - runClause (SubTrans subCtx next) = do - let (ss, sfails) = applySTSIndifferently subCtx - traverse_ (\a -> modify (a :)) $ wrapFailed <$> sfails - next <$> pure ss - -applySTSIndifferently - :: forall s rtype - . (STS s, RuleTypeRep rtype) - => RuleContext rtype s - -> (State s, [PredicateFailure s]) -applySTSIndifferently ctx = - successOrFirstFailure $ applySTSIndifferently' @s @rtype rTypeRep ctx - where - successOrFirstFailure xs = fromMaybe (headOrError xs) $ find (null . snd) xs - applySTSIndifferently' - :: forall s' rtype' - . STS s' - => SRuleType rtype' - -> RuleContext rtype' s' - -> [(State s', [PredicateFailure s'])] - applySTSIndifferently' SInitial env = - map (applyRuleIndifferently env) initialRules - applySTSIndifferently' STransition jc = - map (applyRuleIndifferently jc) transitionRules - headOrError [] = error "applySTSIndifferently was called with an empty set of rules" - headOrError (x:_) = x - -applySTS :: forall s rtype - . (STS s, RuleTypeRep rtype) - => RuleContext rtype s - -> Either [PredicateFailure s] (State s) -applySTS ctx = case applySTSIndifferently ctx of - (st, []) -> Right st - (_, pfs) -> Left pfs diff --git a/specs/semantics/hs/src/Control/State/Transition/Generator.hs b/specs/semantics/hs/src/Control/State/Transition/Generator.hs deleted file mode 100644 index 029eb896..00000000 --- a/specs/semantics/hs/src/Control/State/Transition/Generator.hs +++ /dev/null @@ -1,173 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DerivingVia #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeInType #-} -{-# LANGUAGE UndecidableInstances #-} --- | Generators for transition systems. --- --- How should these work? --- - We start with some initial environment. --- - We start with some initial base state. --- - We generate a stream of signals. These might be influenced by some running state --- - We run each signal through --- -module Control.State.Transition.Generator - ( HasTrace - , initEnvGen - , sigGen - , trace - , traceSuchThat - , suchThatLastState - , nonTrivialTrace - , HasSizeInfo - , isTrivial - , sampleMaxTraceSize - ) -where - -import Control.Monad (forM) -import Hedgehog (Gen) -import qualified Hedgehog.Gen as Gen -import Hedgehog.Range (Size(Size), unSize) - -import Control.State.Transition - ( Environment - , IRC(IRC) - , STS - , Signal - , State - , TRC(TRC) - , applySTS - ) -import Control.State.Transition.Trace - ( Trace - , TraceOrder(OldestFirst) - , lastState - , mkTrace - , traceLength - , traceSignals - ) - -class STS s => HasTrace s where - initEnvGen :: Gen (Environment s) - - sigGen :: Environment s -> State s -> Gen (Signal s) - - trace :: Gen (Trace s) - trace = do - env <- initEnvGen @s - case applySTS @s (IRC env) of - -- Hedgehog will give up if the generators fail to produce any valid - -- initial state, hence we don't have a risk of entering an infinite - -- recursion. - Left _pf -> trace - -- Applying an initial rule with an environment and state will simply - -- validate that state, so we do not care which state 'applySTS' returns. - Right st -> genTrace env st (sigGen @s) - --- | Return a (valid) trace generator given an initial state, environment, and --- signal generator. -genTrace - :: forall s - . STS s - => Environment s - -> State s - -> (Environment s -> State s -> Gen (Signal s)) - -> Gen (Trace s) -genTrace env st aSigGen = Gen.sized $ \d -> mkTrace env st <$> go d st [] - where - go d sti acc = - Gen.frequency [ (5, return acc) - -- The probability of continue with the recursion depends - -- on the size parameter of the generator. Here the - -- constant factor is determined ad-hoc. - , (unSize d * 2, do - mStSig <- genSigSt @s env sti aSigGen - case mStSig of - Nothing -> - go d sti acc - Just (stNext, sig) -> - go d stNext ((stNext, sig): acc) - ) - ] - -- An alternate way to generate a trace of the size of the generator might - -- be: - -- - -- >>> go 0 _ acc = return acc - -- >>> go d sti acc = do - -- >>> mStSig <- genSigSt @s env sti aSigGen - -- >>> case mStSig of - -- >>> Nothing -> - -- >>> go (d - 1) sti acc - -- >>> Just (stNext, sig) -> - -- >>> go (d - 1) stNext ((stNext, sig): acc) - -- - --- | Return a signal-and-ensuing-state generator, given an initial state, --- environment and signal generator. -genSigSt - :: forall s - . STS s - => Environment s - -> State s - -> (Environment s -> State s -> Gen (Signal s)) - -> Gen (Maybe (State s, Signal s)) -genSigSt env st aSigGen = do - sig <- aSigGen env st - -- TODO: we might want to know why are we getting a given failure... - case applySTS @s (TRC(env, st, sig)) of - Left _ -> pure Nothing - Right nextSt -> pure $ Just (nextSt, sig) - -traceSuchThat - :: forall s - . HasTrace s - => (Trace s -> Bool) - -> Gen (Trace s) -traceSuchThat cond = Gen.filter cond (trace @s) - -suchThatLastState - :: forall s - . Gen (Trace s) - -> (State s -> Bool) - -> Gen (Trace s) -suchThatLastState traceGen cond = Gen.filter (cond . lastState) traceGen - --- | Generate a trace that contains at least one non-trivial signal. See --- 'HasSizeInfo'. -nonTrivialTrace - :: forall s - . (HasTrace s, HasSizeInfo (Signal s)) - => Gen (Trace s) -nonTrivialTrace = - Gen.filter (any (not . isTrivial) . traceSignals OldestFirst) trace - -class HasSizeInfo sig where - isTrivial :: sig -> Bool - -instance HasSizeInfo [a] where - isTrivial = null - --------------------------------------------------------------------------------- --- Trace sampling utilities --------------------------------------------------------------------------------- - --- | Sample the maximum trace size, given the generator size and number of --- samples. -sampleMaxTraceSize - :: forall s - . HasTrace s - => Int - -- ^ Generator size - -> Int - -- ^ Number of samples to take - -> IO Int -sampleMaxTraceSize d n = - maximum <$> - forM [0..n] (const $ traceLength <$> Gen.sample (Gen.resize (Size d) (trace @s))) diff --git a/specs/semantics/hs/src/Control/State/Transition/Trace.hs b/specs/semantics/hs/src/Control/State/Transition/Trace.hs deleted file mode 100644 index e178b78c..00000000 --- a/specs/semantics/hs/src/Control/State/Transition/Trace.hs +++ /dev/null @@ -1,132 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE UndecidableInstances #-} --- | Traces of transition systems and associated operators. --- --- This module also includes a minimal domain-specific-language to specify --- expectations on traces. -module Control.State.Transition.Trace - ( (.-) - , (.->) - , checkTrace - , Trace - , TraceOrder (NewestFirst, OldestFirst) - , mkTrace - , traceEnv - , traceSignals - , traceStates - , traceLength - , lastState - ) -where - -import Control.Lens (makeLenses, (^.), (^..), _1, _2, to) -import Control.Monad (void) -import Control.Monad.IO.Class (MonadIO, liftIO) -import Control.Monad.Reader (MonadReader, ReaderT, ask, runReaderT) -import Test.Tasty.HUnit ((@?=), assertFailure) - -import Control.State.Transition - ( Environment - , STS - , Signal - , State - , TRC(TRC) - , applySTS - , PredicateFailure - ) - --- | A successful trace of a transition system. --- -data Trace s - = Trace - { _traceEnv :: Environment s - -- ^ Environment under which the trace was run. - , _traceInitState :: State s - -- ^ Initial state in the trace - , _traceTrans :: [(State s, Signal s)] - -- ^ Signals and resulting states observed in the trace. New elements are - -- put in front of the list. - } - -makeLenses ''Trace - -deriving instance - (Eq (State s), Eq (Signal s), Eq (Environment s)) => (Eq (Trace s)) - -deriving instance - (Show (State s), Show (Signal s), Show (Environment s)) => (Show (Trace s)) - --- | Make a trace given an environment and initial state. -mkTrace :: Environment s -> State s -> [(State s, Signal s)] -> Trace s -mkTrace = Trace - --- | Extract the last state of a trace. Since a trace has at least an initial --- state, the last state of a trace is always defined. -lastState :: Trace s -> State s -lastState tr = case tr ^. traceTrans of - (st, _):_ -> st - _ -> tr ^. traceInitState - -data TraceOrder = NewestFirst | OldestFirst deriving (Eq) - -fromOldestFirst :: TraceOrder -> [a] -> [a] -fromOldestFirst NewestFirst = reverse -fromOldestFirst OldestFirst = id - --- | Retrieve all the signals in the trace, in the order specified. -traceSignals :: TraceOrder -> Trace s -> [Signal s] -traceSignals order tr = fromOldestFirst order (tr ^.. traceTrans . traverse . _2) - --- | Retrieve all the states in the trace, in the order specified. -traceStates :: TraceOrder -> Trace s -> [State s] -traceStates order tr = fromOldestFirst order (tr ^.. traceTrans . traverse . _1) - -traceLength :: Trace s -> Int -traceLength tr = tr ^. traceTrans . to length - --------------------------------------------------------------------------------- --- Minimal DSL to specify expectations on traces --------------------------------------------------------------------------------- - --- | Bind the state inside the first argument, and apply the transition --- function in the @Reader@ environment to that state and given signal, --- obtaining the resulting state, or an assertion failure if the transition --- function fails. -(.-) - :: forall m st sig err - . ( MonadIO m - , MonadReader (st -> sig -> Either err st) m - , Show err - ) - => m st -> sig -> m st -mSt .- sig = do - st <- mSt - validate <- ask -- Get the validation function from the environment - case validate st sig of - Left pfs -> liftIO . assertFailure . show $ pfs - Right st' -> pure st' - --- | Bind the state inside the first argument, and check whether it is equal to --- the expected state, given in the second argument. -(.->) - :: forall m st - . (MonadIO m, Eq st, Show st) - => m st -> st -> m st -mSt .-> stExpected = do - stActual <- mSt - liftIO $ stActual @?= stExpected - return stActual - -checkTrace - :: forall s - . (STS s) - => Environment s - -> ReaderT (State s -> Signal s -> Either [PredicateFailure s] (State s)) IO (State s) - -> IO () -checkTrace env act = - void $ runReaderT act (\st sig -> applySTS (TRC(env, st, sig))) diff --git a/specs/semantics/hs/src/Data/AbstractSize.hs b/specs/semantics/hs/src/Data/AbstractSize.hs deleted file mode 100644 index 1d8f0a63..00000000 --- a/specs/semantics/hs/src/Data/AbstractSize.hs +++ /dev/null @@ -1,149 +0,0 @@ -{-# LANGUAGE DefaultSignatures #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE OverloadedLists #-} -{-# LANGUAGE TypeOperators #-} - --- | An approach to computing the abstract size of data using 'TypeRep'. --- -module Data.AbstractSize - ( HasTypeReps - , typeReps - , abstractSize - , AccountingMap - , Size - ) where - -import Data.Map.Strict (Map) -import qualified Data.Map.Strict as Map -import Data.Sequence (Seq, (<|), (><), empty) -import Data.Typeable (TypeRep, Typeable, typeOf) -import GHC.Generics - ( (:*:)((:*:)) - , (:+:)(L1, R1) - , Generic - , K1(K1) - , M1(M1) - , Rep - , U1(U1) - , from - ) -import GHC.Natural - --- | @abstractSize m a@ computes the abstract size of @a@, using the accounting --- map @m@. The map @m@ determines the abstract size of each 'TypeRep' --- contained in @a@, and this function simply adds all the individual abstract --- sizes. To be able to extract the type representations ('TypeRep's) inside --- @a@, we require it to be an instance of 'HasTypeReps'. --- --- Examples: --- --- >>> :set -XOverloadedLists --- >>> abstractSize [(typeOf (undefined:: Char), 10)] 'a' --- 10 --- --- >>> abstractSize [(typeOf 'x', 10)] "hello" --- 50 --- --- >>> abstractSize [(typeOf 'x', 10), (typeOf True, 100)] ("hello", False) --- 150 --- --- >>> abstractSize [(typeOf (undefined :: [Int]), 6), (typeOf (1 :: Int), 1)] ([0, 1, 2, 3] :: [Int]) --- 10 --- --- >>> abstractSize [(typeOf (undefined :: [Int]), 3), (typeOf (1 :: Int), -1)] ([0, 1, 2] :: [Int]) --- 0 --- -abstractSize :: HasTypeReps a => AccountingMap -> a -> Size -abstractSize m a = sum $ fmap cost trs - where - trs = typeReps a - cost t = Map.findWithDefault 0 t m - -type Size = Int -type AccountingMap = Map TypeRep Size - --------------------------------------------------------------------------------- --- HasTypeReps class --------------------------------------------------------------------------------- - --- | The 'typeReps' function retrieves all the type representations found while --- traversing the data given as parameter. --- --- If you custom data type in an instance of 'Generics', a default --- implementation is provided for you. --- --- Examples: --- --- >>> typeReps "a" --- fromList [[Char],Char] --- --- >>> typeReps "ab" --- fromList [[Char],Char,Char] --- --- >>> typeReps ([] :: [Int]) --- fromList [[Int]] --- --- >>> :set -XDeriveGeneric --- >>> data Foo = Foo [Int] (Char, Char) deriving (Generic) --- >>> instance HasTypeReps Foo --- >>> typeReps $ Foo [1, 2] ('a', 'b') --- fromList [Foo,[Int],Int,Int,(Char,Char),Char,Char] --- -class Typeable a => HasTypeReps a where - typeReps :: a -> Seq TypeRep - - default typeReps :: (Generic a, GHasTypeReps (Rep a)) => a -> Seq TypeRep - typeReps a = typeOf a <| gTypeReps (from a) - -class GHasTypeReps f where - gTypeReps :: f a -> Seq TypeRep - --------------------------------------------------------------------------------- --- GHasTypeReps instances --------------------------------------------------------------------------------- - --- | No types to report for a constructor without arguments. -instance GHasTypeReps U1 where - gTypeReps U1 = empty - --- | The types in a product is the concatenation of the types found in the --- values of the product terms. -instance (GHasTypeReps a, GHasTypeReps b) => GHasTypeReps (a :*: b) where - gTypeReps (a :*: b) = gTypeReps a >< gTypeReps b - -instance (GHasTypeReps a, GHasTypeReps b) => GHasTypeReps (a :+: b) where - gTypeReps (L1 a) = gTypeReps a - gTypeReps (R1 b) = gTypeReps b - --- | We do need to do anything for the metadata. -instance (GHasTypeReps a) => GHasTypeReps (M1 i c a) where - gTypeReps (M1 x) = gTypeReps x - --- | And the only interesting case, get the type of a type constructor -instance (HasTypeReps a) => GHasTypeReps (K1 i a) where - gTypeReps (K1 x) = typeReps x - --------------------------------------------------------------------------------- --- HasTypeReps instances --------------------------------------------------------------------------------- - -instance HasTypeReps a => HasTypeReps [a] where - typeReps xs = typeOf xs <| foldMap typeReps xs - -instance (HasTypeReps a, HasTypeReps b) => HasTypeReps (a, b) where - typeReps t@(a, b) = typeOf t <| (typeReps a >< typeReps b) - -instance HasTypeReps Bool where - typeReps x = [typeOf x] - -instance HasTypeReps Char where - typeReps x = [typeOf x] - -instance HasTypeReps Int where - typeReps x = [typeOf x] - -instance HasTypeReps Double where - typeReps x = [typeOf x] - -instance HasTypeReps Natural where - typeReps x = [typeOf x] diff --git a/specs/semantics/hs/test/DoctestDiscover.hs b/specs/semantics/hs/test/DoctestDiscover.hs deleted file mode 100644 index 5e8562d1..00000000 --- a/specs/semantics/hs/test/DoctestDiscover.hs +++ /dev/null @@ -1 +0,0 @@ -{-# OPTIONS_GHC -F -pgmF doctest-discover #-} diff --git a/specs/semantics/latex/Makefile b/specs/semantics/latex/Makefile deleted file mode 100644 index 3fe9d8d6..00000000 --- a/specs/semantics/latex/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -## -## Makefile for the ledger rules, based on: -## -## https://tex.stackexchange.com/questions/40738/how-to-properly-make-a-latex-project -## - -# Document name -DOCNAME = small-step-semantics - -# You want latexmk to *always* run, because make does not have all the info. -# Also, include non-file targets in .PHONY so they are run regardless of any -# file of the given name existing. -.PHONY: $(DOCNAME).pdf all clean - -# The first rule in a Makefile is the one executed by default ("make"). It -# should always be the "all" rule, so that "make" and "make all" are identical. -all: $(DOCNAME).pdf - -## -## CUSTOM BUILD RULES -## - - -## -## MAIN LATEXMK RULE -## - -# -pdf tells latexmk to generate PDF directly (instead of DVI). -# -pdflatex="" tells latexmk to call a specific backend with specific options. -# -use-make tells latexmk to call make for generating missing files. - -# -interaction=nonstopmode keeps the pdflatex backend from stopping at a -# missing file reference and interactively asking you for an alternative. - -$(DOCNAME).pdf: $(DOCNAME).tex - latexmk -pdf -pdflatex="pdflatex -interaction=nonstopmode" -use-make $(DOCNAME).tex - -watch: $(DOCNAME).tex - latexmk -pvc -pdf -pdflatex="pdflatex -interaction=nonstopmode" -use-make $(DOCNAME).tex - -clean: - latexmk -CA - -install: - mkdir -pv ${out}/nix-support/ - cp small-step-semantics.pdf ${out}/ - echo "doc-pdf semantics-spec ${out}/small-step-semantics.pdf" > ${out}/nix-support/hydra-build-products diff --git a/specs/semantics/latex/default.nix b/specs/semantics/latex/default.nix deleted file mode 100644 index cb900afb..00000000 --- a/specs/semantics/latex/default.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ pkgs ? import ../../../pkgs.nix -}: - -with pkgs; - -stdenv.mkDerivation { - name = "docsEnv"; - buildInputs = [ (texlive.combine { - inherit (texlive) - scheme-small - - # libraries - stmaryrd lm-math amsmath extarrows cleveref semantic tikz-cd xcolor - - # bclogo and dependencies - bclogo mdframed xkeyval etoolbox needspace pgf - - # font libraries `mathpazo` seems to depend on palatino, but it isn't pulled. - mathpazo palatino microtype - - # libraries for marginal notes - xargs todonotes - - # build tools - latexmk - - ; - }) - ]; - src = ./.; - buildPhase = "make"; - - meta = with lib; { - description = "Small Steps Semantics Specification"; - license = licenses.bsd3; - platforms = platforms.linux; - }; -} diff --git a/specs/semantics/latex/small-step-semantics.tex b/specs/semantics/latex/small-step-semantics.tex deleted file mode 100644 index 34e75b6b..00000000 --- a/specs/semantics/latex/small-step-semantics.tex +++ /dev/null @@ -1,293 +0,0 @@ -\documentclass[11pt,a4paper]{article} -\usepackage[margin=2.5cm]{geometry} -\usepackage{microtype} -\usepackage{mathpazo} % nice fonts -\usepackage{amsmath} -\usepackage{amssymb} -\usepackage{amsthm} -\usepackage{latexsym} -\usepackage{mathtools} -\usepackage{stmaryrd} -\usepackage{extarrows} -\usepackage{slashed} -\usepackage[colon]{natbib} -\usepackage[unicode=true,pdftex,pdfa]{hyperref} -\usepackage{xcolor} -\usepackage{xparse} -\usepackage[capitalise,noabbrev,nameinlink]{cleveref} -\hypersetup{ - pdftitle={Small Step Semantics for Cardano}, - breaklinks=true, - bookmarks=true, - colorlinks=false, - linkcolor={blue}, - citecolor={blue}, - urlcolor={blue}, - linkbordercolor={white}, - citebordercolor={white}, - urlbordercolor={white} -} -\usepackage{tikz-cd} -\usepackage{float} -\floatstyle{boxed} -\restylefloat{figure} -% For notes containing warnings, questions, etc. -\usepackage[tikz]{bclogo} -\newenvironment{question} - {\begin{bclogo}[logo=\bcquestion, couleur=orange!10, arrondi=0.2]{ QUESTION}} - {\end{bclogo}} -\newenvironment{todo} - {\begin{bclogo}[logo=\bcoutil, couleur=red!5, couleurBarre=red, arrondi=0.2]{ TODO}} - {\end{bclogo}} -%% -%% Package `semantic` can be used for writing inference rules. -%% -\usepackage{semantic} -%% Setup for the semantic package -\setpremisesspace{20pt} - -\DeclareMathOperator{\dom}{dom} -\DeclareMathOperator{\range}{range} - -%% -%% TODO: we should package this -%% -\newcommand{\powerset}[1]{\mathbb{P}~#1} -\newcommand{\restrictdom}{\lhd} -\newcommand{\subtractdom}{\mathbin{\slashed{\restrictdom}}} -\newcommand{\restrictrange}{\rhd} -\newcommand{\union}{\cup} -\newcommand{\unionoverride}{\mathbin{\underrightarrow\cup}} -\newcommand{\uniondistinct}{\uplus} -\newcommand{\var}[1]{\mathit{#1}} -\newcommand{\fun}[1]{\mathsf{#1}} -\newcommand{\type}[1]{\mathsf{#1}} -\newcommand{\signed}[2]{\llbracket #1 \rrbracket_{#2}} -\newcommand{\size}[1]{\left| #1 \right|} -\newcommand{\trans}[2]{\xlongrightarrow[\textsc{#1}]{#2}} -\newcommand{\seqof}[1]{#1^{*}} -\newcommand{\nextdef}{\\[1em]} -\newcommand{\bytes}{\textbf{Bytes}} - -\NewDocumentCommand{\tion}{o m m m m}{ - \IfNoValueF{#1}{\var{#1}\vdash} \var{#3} \trans{#2}{#4} \var{#5} -} - -\theoremstyle{definition} -\newtheorem{definition}{Definition}[section] - -\theoremstyle{remark} -\newtheorem{remark}{Remark}[section] - -\begin{document} -\title{Small Step Semantics for Cardano} -\author{} -\date{October 17, 2018} - -\maketitle - -\begin{abstract} -We define the basis for our version of ``small-step semantics'' as applied to -defining components of the Cardano cryptocurrency. -\end{abstract} - -\section{Introduction} -\label{sec:introduction} - -In defining Cardano, we are concerned with the means to construct inductive -datatypes satisfying some validity conditions. For example, we wish to consider -when a sequence of transactions forms a valid \textit{ledger}, or a sequence of -blocks forms a valid \textit{chain}. - -This document describes the semi-formal methods we use to describe such validity -conditions and how they result in the construction of valid states. - -\section{Preliminaries and Notation} - -In this section, we define some preliminaries and some notation common to -Cardano specifications. - -\begin{description} -\item [Functions and partial functions] We denote the set of functions from $A$ - to $B$ as $A \to B$, and a function from $A$ to $B$ as $f \in A \to B$ or $f : - A \to B$. We - denote the set of partial functions from $A$ to $B$ as $A \mapsto B$, and an - equivalent partial function as $g \in A \mapsto B$ or $g : A \mapsto B$. \\ - Analogously to Haskell, we use spacing for function application. So $f ~ a$ - represents the application of $a$ to the function $f$. - -\end{description} - - -\section{Transition Systems} -\label{sec:preliminaries} - -In describing the semantics for a system $L$ we are principally concerned with -five things: - -\begin{description} -\item [States] The underlying datatype of our system, whose validity we are - required to prove. -\item [Transitions] The means by which we might move from one (valid) state to - another. -\item [Signals] The means by which transitions are triggered. -\item [Rules] Formulae describing how to derive valid states or transitions. A - rule has an \textit{anteccedent} (sometimes called \textit{premise}) and a - \textit{consequent} (sometimes called \textit{conclusion}), such that if the - conditions in the antecedent hold, the consequent is assumed to be a valid - state or transition. -\item [Environment] Sometimes we may implicitly rely on some additional - information being present in the system to evaluate the rules. An environment - does not have to exist (or, equivalently, we may have an empty environment), - but crucially an environment is not modified by transitions. -\end{description} - -\begin{definition}[State transition system] -A \textit{state transition system} $L$ is given by a 5-tuple $(S, T, \Sigma, R, \Gamma)$ -where: -\begin{description} -\item[$S$] is a set of (not necessarily valid) states. -\item[$\Sigma$] is a set of signals. -\item[$\Gamma$] is a set of environment values. -\item[$T$] is a set of (not necessarily valid) transitions. We have - that \[T\subseteq\powerset{(\Gamma\times S\times\Sigma\times S)}\] -\item[$R$] is a set of derivation rules. A derivation rule is given by two - parts: its antecedent is a logical formula in $S\cup\Sigma\cup\Gamma$. Its - consequent is either: - \begin{itemize} - \item A state $s\in S$, or - \item A transition $t\in T$. - \end{itemize} -\end{description} -\end{definition} -\begin{remark} - The above definition is somewhat redundant, since the transition set $T$ - implicitly defines the state, signal and environment sets. We use the above - definition for clarity, since we often wish to refer to states and signals directly. -\end{remark} -\begin{definition}[Validity] - For a transition system $(S, T, \Sigma, R, \Gamma)$ and environment $\gamma\in\Gamma$, we say that a state $s\in - S$ is valid if either: -\begin{itemize} -\item It appears as a consequent of a rule $r\in R$ whose antecedent has no - variables in $S\cup\Sigma$ and which is true as evaluated at $\gamma$, or -\item There exists a tuple $(s', \sigma, r, t)\in S\times\Sigma\times R \times - T$ such that $s'$ is valid, the antecedent of $r$ is true as evaluated at $(\gamma, s', - \sigma)$ and where $t=(\gamma, s', \sigma, s)$. -\end{itemize} -\end{definition} - -\begin{figure}[h] - \label{fig:notation} - For a state transition system $L=(S,T,\Sigma, R, \Gamma)$, we use the - following notation to represent transitions and rules. \\ - - \textit{Transitions} - \[ \_ \vdash \_ \trans{L}{\_} \_ \in T \] - - \textit{Rules} - \[ \inference[Rule-name] - {\textit{antecedent}} - {\textit{consequent}} - \in R - \] - \caption{Notation for a state transition system.} -\end{figure} -Figure \ref{fig:notation} gives the notation for transitions and rules. For -notational convenience, we allow for some additional constructions in the -antecedent: -\begin{itemize} - \item Rather than a single logical predicate in the antecedent, we allow - multiple predicate formulae. All predicates defined in the antecedent must be - true; that is, the antecedent is treated as the conjunction of all predicates defined - there. - \item The antecedent may contain variable definitions of the form $z=f(s)$, - where $z$ is an additional binding to be introduced. We will refer to these - as ``let-bindings'' in analogy with their use in programming languages. - \end{itemize} -We can give an example of such a rule: - \[ \inference[Example] - {P(A) & z = f ~ s & B = g(A,z)} - {\tion[E1]{S2}{A}{s}{B}} - \] -To read such a rule, we proceed as follows: -\begin{enumerate} - \item Firstly, we look at the LHS of the consequent. This introduces the basic - environment, initial state and signal. - \item We then expand our set of variables using let bindings in the - antecedent. - \item We evaluate all predicates in the antecedent ($P(A)$ in the example above), which should now be - defined in terms of $S\cup\Sigma\cup\Gamma$ and the variables introduced in - step 2. - \item If all predicates evaluate to true, then we may assume a valid - transition to the RHS of the consequent. -\end{enumerate} -\section{Composition of Transition Systems} - -Part of the benefit of this approach is that it allows us to define systems -which themselves rely on other state transition systems. To do this, we allow -for an additional construction in the antecedent. - -\begin{itemize} -\item The antecedent may contain a transition of the form $\tion[ENV1]{SYS}{A}{s}{B}$. - This may either act as a predicate (if $B$ is already bound) or as an - introduction of $B$ as per the state transition rules for system $\var{SYS}$. -\end{itemize} - -We then allow a construction as follows: - -\[ - \inference[Example] - {P(A) & z = f ~ s & \tion[E1]{S1}{A}{z}{B}} - {\tion[E1]{S2}{A}{s}{B}} -\] - -The transition in the antecedent acts as a predicate requiring that $A$ -transitions to $B$ under the system $S1$, and, assuming $B$ is otherwise free -(has not been bound by the LHS of the consequent or by another let binding), -acts as an introduction rule for $B$ as determined by the transition rules for -system $S1$. - -\section{Serialisation} -Various of our specifications will rely on a serialisation function which -encodes a variety of types to a binary format. - -\begin{figure}[h] - \label{fig:serialisation} - \begin{align*} - & \llbracket\_\rrbracket \in \textbf{Hask}\mapsto\_\to\bytes - & \text{serialisation} \\ - & \llbracket\_\rrbracket_{A} \in \var{A}\to\bytes - \end{align*} - \caption{Serialisation functions} -\end{figure} - -Figure \ref{fig:serialisation} gives the definition of a serialisation function. -We define this as a partial function since it is defined only on a subset of -Haskell types. As an abuse of notation, we drop the subscript $A$ for the -serialisation function on type $A$, since it is unambiguously determined by its -first argument. - -We require our serialisation function to satisfy the following property: -\begin{definition}[Distributivity over injective functions] - Let $s:\mathcal{C}\mapsto\_\to\var{D}$ be a function defined over a subset of - objects in $\mathcal{C}$, such that $s_A:A\to\var{D}$ for all $A\in\dom{s}$. - We say that $s$ \textit{distributes over injective functions} if, for all - injective functions $f:A\to B$ where $A,B\in\dom{s}$, there exists a function - $f_s:\var{D}\to\var{D}$ such that the following diagram commutes: - \[ - \begin{tikzcd} - A \arrow{r}{f} \arrow{d}{s_A} & B \arrow{d}{s_B} \\ - D \arrow{r}{f_s} & D - \end{tikzcd} - \] -\end{definition} - -This property allows us to extract specific subparts of our serialised form. Our -specifications will rely in places on functions defined over the serialisesation -of a value. If we have a type $A=(B,C,D,E)$, for example, and we need to extract -$\llbracket\var{B}\rrbracket$ from $\llbracket\var{A}\rrbracket$, it is this -property which guarantees we may do so without rounnd-tripping through $A$, -since $\llbracket \pi_1 ~ A\rrbracket = (\pi_1)_{\llbracket\rrbracket} ~ \llbracket A -\rrbracket$ (where $\pi_1$ is the projection onto the first component of the tuple). -\end{document} diff --git a/specs/stack.yaml b/specs/stack.yaml deleted file mode 100644 index 386283e2..00000000 --- a/specs/stack.yaml +++ /dev/null @@ -1,9 +0,0 @@ -resolver: https://raw.githubusercontent.com/input-output-hk/cardano-prelude/f2802079ba2c07c4d408e3c0aa000fc363792398/snapshot.yaml - -packages: -- chain/hs -- ledger/hs -- semantics/hs - -extra-deps: -- sequence-0.9.8 diff --git a/stack.yaml b/stack.yaml index 96c2e00e..c40a7974 100644 --- a/stack.yaml +++ b/stack.yaml @@ -3,8 +3,6 @@ resolver: https://raw.githubusercontent.com/input-output-hk/cardano-prelude/7f85 packages: - . - test - - specs/ledger/hs - - specs/semantics/hs extra-deps: - git: https://github.com/input-output-hk/cardano-prelude @@ -25,6 +23,13 @@ extra-deps: - crypto - crypto/test + - git: https://github.com/input-output-hk/fm-ledger-rules + commit: bf059d1d593e7ef9f3b983a0c904e7bb81362af9 + subdirs: + - specs/semantics/hs + - specs/ledger/hs + - specs/chain/hs + - git: https://github.com/input-output-hk/cardano-mainnet-mirror commit: 74ca63f8ad6b47beba2f565c73592cede63ce4b5