Skip to content

Commit 334d604

Browse files
committed
Implement InitialGasModel
1 parent 4d51b78 commit 334d604

12 files changed

Lines changed: 137 additions & 28 deletions

File tree

chainweb.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ library
343343
, Chainweb.Pact5.TransactionExec
344344
, Chainweb.Pact5.Types
345345
, Chainweb.Pact5.Validations
346+
, Chainweb.Pact5.InitialGasModel
346347
, Chainweb.Pact.Transactions.FungibleV2Transactions
347348
, Chainweb.Pact.Transactions.CoinV3Transactions
348349
, Chainweb.Pact.Transactions.CoinV4Transactions

src/Chainweb/Pact/PactService.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ execLocal cwtx preflight sigVerify rdepth = pactLabel "execLocal" $ do
918918
lift (Pact5.liftPactServiceM (Pact5.assertPreflightMetadata (view Pact5.payloadObj <$> pact5Cmd) txCtx sigVerify)) >>= \case
919919
Left err -> earlyReturn $ review _MetadataValidationFailure err
920920
Right () -> return ()
921-
let initialGas = Pact5.initialGasOf v cid (Pact5.ctxCurrentBlockHeight txCtx) $ Pact5._cmdPayload pact5Cmd
921+
let initialGas = Pact5.initialGasOf v cid (Pact5.ctxCurrentBlockHeight txCtx) (Pact5.ctxParentForkNumber txCtx) pact5Cmd
922922
applyCmdResult <- lift $ Pact5.pactTransaction Nothing (\dbEnv ->
923923
Pact5.applyCmd
924924
_psLogger _psGasLogger dbEnv

src/Chainweb/Pact/PactService/Pact5/ExecBlock.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,8 @@ applyPactCmd env miner txIdxInBlock tx = StateT $ \(blockHandle, blockGasRemaini
359359
(unsafeApplyPactCmd blockHandle
360360
(initialGasOf (_chainwebVersion env) (Chainweb.Version._chainId env)
361361
(env ^. psParentHeader . parentHeader . blockHeight)
362-
(tx ^. Pact5.cmdPayload))
362+
(env ^. psParentHeader . parentHeader . blockForkNumber)
363+
tx)
363364
alteredTx)
364365
env
365366
case resultOrGasError of
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
{-# LANGUAGE LambdaCase #-}
2+
{-# LANGUAGE TemplateHaskell #-}
3+
{-# LANGUAGE BangPatterns #-}
4+
5+
module Chainweb.Pact5.InitialGasModel
6+
( InitialGasModel(..)
7+
, pre31GasModel
8+
, post31GasModel
9+
, post32GasModel
10+
-- Lenses
11+
, feePerByte
12+
, rawPayloadSizeFactor
13+
, proofSizeFactor
14+
, signatureSizeFactor
15+
, sizePenalty
16+
, signatureCost
17+
) where
18+
19+
import Control.DeepSeq
20+
import Pact.Core.Scheme
21+
import Control.Lens
22+
23+
24+
data InitialGasModel = InitialGasModel
25+
{ _feePerByte :: Rational
26+
-- ^ Base Price charged per byte
27+
, _rawPayloadSizeFactor :: Rational
28+
-- ^ Multiplier for the raw payload (without continuation proof) size
29+
, _proofSizeFactor :: Rational
30+
-- ^ Multiplier for the proof size
31+
, _signatureSizeFactor :: Rational
32+
-- ^ Multiplier for signatures size
33+
, _sizePenalty :: Rational -> Rational
34+
-- ^ Function used to compute a penalty for big transactions
35+
, _signatureCost :: PPKScheme -> Rational
36+
-- ^ Function used to compute a fixed amount of gas per signature
37+
}
38+
39+
-- Required to be used as a rule
40+
instance NFData InitialGasModel where
41+
rnf (InitialGasModel {}) = ()
42+
43+
makeLenses ''InitialGasModel
44+
45+
pre31GasModel :: InitialGasModel
46+
pre31GasModel = InitialGasModel
47+
{ _feePerByte = 0.01
48+
, _rawPayloadSizeFactor = 1.0
49+
, _proofSizeFactor = 0.0
50+
, _signatureSizeFactor = 0.0
51+
, _sizePenalty = \x -> (x / 512) ^ (7 :: Integer)
52+
, _signatureCost = const 0.0
53+
}
54+
55+
56+
post31GasModel :: InitialGasModel
57+
post31GasModel = InitialGasModel
58+
{ _feePerByte = 0.01
59+
, _rawPayloadSizeFactor = 1.0
60+
, _proofSizeFactor = 1.0
61+
, _signatureSizeFactor = 0.0
62+
, _sizePenalty = \x -> (x / 512) ^ (7 :: Integer)
63+
, _signatureCost = const 0.0
64+
}
65+
66+
67+
post32GasModel :: InitialGasModel
68+
post32GasModel = InitialGasModel
69+
{ _feePerByte = 0.01
70+
, _rawPayloadSizeFactor = 1.0
71+
, _proofSizeFactor = 1.0
72+
, _signatureSizeFactor = 1.0
73+
, _sizePenalty = \x -> (x / 512) ^ (7 :: Integer)
74+
, _signatureCost = \case
75+
ED25519 -> 10.0 -- | TODO => Needs to be benchmarked
76+
WebAuthn -> 10.0 -- |
77+
}

src/Chainweb/Pact5/TransactionExec.hs

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ import Pact.Core.Hash
8686
import Pact.Core.Info
8787
import Pact.Core.Names
8888
import Pact.Core.Namespace
89+
import Pact.Core.Scheme (defPPKScheme)
8990
import Pact.Core.PactValue
9091
import Pact.Core.Persistence.Types hiding (GasM(..))
9192
import Pact.Core.Persistence.Utils (ignoreGas)
@@ -103,11 +104,13 @@ import Chainweb.BlockCreationTime
103104
import Chainweb.BlockHash
104105
import Chainweb.BlockHeader
105106
import Chainweb.BlockHeight
107+
import Chainweb.ForkState
106108
import Chainweb.Logger
107109
import Chainweb.Miner.Pact
108110
import Chainweb.Pact.Types
109111
import Chainweb.Pact5.Templates
110112
import Chainweb.Pact5.Types
113+
import Chainweb.Pact5.InitialGasModel
111114

112115
import Chainweb.Time
113116
import Chainweb.Pact5.Transaction
@@ -977,33 +980,25 @@ redeemGas logger db txCtx gasUsed maybeFundTxPactId cmd
977980
-- -- Utilities
978981

979982
-- | Initial gas charged for transaction size
980-
-- ignoring the size of a continuation proof, if present
981-
--
982-
initialGasOf :: ChainwebVersion -> V.ChainId -> BlockHeight -> PayloadWithText meta ParsedCode -> Gas
983-
initialGasOf v cid bh payload = Gas gasFee
984-
where
985-
feePerByte :: Rational = 0.01
986-
987-
contProofSize =
988-
case payload ^. payloadObj . pPayload of
989-
Continuation (ContMsg _ _ _ _ (Just (ContProof p))) -> B.length p
990-
_ -> 0
991-
txSize
992-
| chainweb31 v cid bh = SB.length (payload ^. payloadBytes)
993-
| otherwise = SB.length (payload ^. payloadBytes) - contProofSize
994-
995-
costPerByte = fromIntegral txSize * feePerByte
996-
sizePenalty = txSizeAccelerationFee costPerByte
997-
gasFee = ceiling (costPerByte + sizePenalty)
998-
{-# INLINE initialGasOf #-}
999-
1000-
txSizeAccelerationFee :: Rational -> Rational
1001-
txSizeAccelerationFee costPerByte = total
983+
initialGasOf :: ChainwebVersion -> V.ChainId -> BlockHeight -> ForkNumber -> Transaction -> Gas
984+
initialGasOf v cid bh fn tx = Gas $ ceiling $ sizeCost + sizePenaltyCost + sigsCost
1002985
where
1003-
total = (costPerByte / bytePenalty) ^ power
1004-
bytePenalty = 512
1005-
power :: Integer = 7
1006-
{-# INLINE txSizeAccelerationFee #-}
986+
model = activeInitialGasModel v cid fn bh
987+
proofSize = case tx ^. cmdPayload . payloadObj . pPayload of
988+
Continuation (ContMsg _ _ _ _ (Just (ContProof p))) -> B.length p
989+
_ -> 0
990+
991+
rawSize = SB.length (tx ^. cmdPayload . payloadBytes) - proofSize
992+
sigsSize = sum $ map (B.length . J.encodeStrict) $ tx ^. cmdSigs
993+
994+
sizeCost = model ^. feePerByte * ( model ^. rawPayloadSizeFactor * fromIntegral rawSize
995+
+ model ^. proofSizeFactor * fromIntegral proofSize
996+
+ model ^. signatureSizeFactor * fromIntegral sigsSize)
997+
sizePenaltyCost = (model ^. sizePenalty) sizeCost
998+
999+
sigsCost = sum $ map ((model ^. signatureCost) . fromMaybe defPPKScheme . view siScheme)
1000+
$ tx ^. cmdPayload . payloadObj . pSigners
1001+
10071002

10081003
-- | Chainweb's namespace policy for ordinary transactions.
10091004
-- Doesn't allow installing modules in the root namespace.

src/Chainweb/Version.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ module Chainweb.Version
7070
, versionGraphs
7171
, versionHeaderBaseSizeBytes
7272
, versionMaxBlockGasLimit
73+
, versionInitialGasModel
7374
, versionSpvProofRootValidWindow
7475
, versionName
7576
, versionWindow
@@ -184,6 +185,7 @@ import Chainweb.MerkleUniverse
184185
import Chainweb.Payload
185186
import Chainweb.Pact4.Transaction qualified as Pact4
186187
import Chainweb.Pact5.Transaction qualified as Pact5
188+
import Chainweb.Pact5.InitialGasModel
187189
import Chainweb.ForkState
188190
import Chainweb.Utils
189191
import Chainweb.Utils.Rule
@@ -539,6 +541,8 @@ data ChainwebVersion
539541
, _versionSpvProofRootValidWindow :: Rule ForkHeight (Maybe Word64)
540542
-- ^ The minimum number of block headers a chainweb node should
541543
-- retain in its history at all times.
544+
, _versionInitialGasModel :: ChainMap (Rule ForkHeight (InitialGasModel))
545+
-- ^ The initial gas model used for Pact 5 transactions processing
542546
, _versionBootstraps :: [PeerInfo]
543547
-- ^ The locations of the bootstrap peers.
544548
, _versionGenesis :: VersionGenesis

src/Chainweb/Version/Development.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import qualified Data.Set as Set
1212
import Chainweb.BlockCreationTime
1313
import Chainweb.ChainId
1414
import Chainweb.Difficulty
15+
import Chainweb.Pact5.InitialGasModel
1516
import Chainweb.Graph
1617
import Chainweb.Time
1718
import Chainweb.Utils
@@ -52,6 +53,7 @@ devnet = ChainwebVersion
5253
-- defaultChainwebConfiguration._configBlockGasLimit
5354
, _versionMaxBlockGasLimit = Bottom (minBound, Nothing)
5455
, _versionSpvProofRootValidWindow = Bottom (minBound, Nothing)
56+
, _versionInitialGasModel = AllChains $ Bottom (minBound, post32GasModel)
5557
, _versionCheats = VersionCheats
5658
{ _disablePow = True
5759
, _fakeFirstEpochStart = True

src/Chainweb/Version/Guards.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ module Chainweb.Version.Guards
5757
, pact4ParserVersion
5858
, maxBlockGasLimit
5959
, minimumBlockHeaderHistory
60+
, activeInitialGasModel
6061
, validPPKSchemes
6162
, isWebAuthnPrefixLegal
6263
, validKeyFormats
@@ -75,6 +76,7 @@ import Chainweb.Pact4.Transaction qualified as Pact4
7576
import Chainweb.Utils.Rule
7677
import Chainweb.ForkState
7778
import Chainweb.Version
79+
import Chainweb.Pact5.InitialGasModel
7880
import Control.Lens
7981
import Data.Word (Word64)
8082
import Numeric.Natural
@@ -348,6 +350,12 @@ minimumBlockHeaderHistory v fn bh = snd $ ruleZipperHere $ snd
348350
where
349351
searchKey = ForkAtBlockHeight bh `max` ForkAtForkNumber fn
350352

353+
activeInitialGasModel :: ChainwebVersion -> ChainId -> ForkNumber -> BlockHeight -> InitialGasModel
354+
activeInitialGasModel v cid fn bh = snd $ ruleZipperHere $ snd
355+
$ ruleSeek (\h _ -> searchKey >= h) $ v ^?! versionInitialGasModel . atChain cid
356+
where
357+
searchKey = ForkAtBlockHeight bh `max` ForkAtForkNumber fn
358+
351359
-- | Different versions of Chainweb allow different PPKSchemes.
352360
--
353361
validPPKSchemes :: ChainwebVersion -> ChainId -> BlockHeight -> [PPKScheme]

src/Chainweb/Version/Mainnet.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Chainweb.BlockHeight
1616
import Chainweb.ChainId
1717
import Chainweb.Difficulty
1818
import Chainweb.Graph
19+
import Chainweb.Pact5.InitialGasModel
1920
import Chainweb.Time
2021
import Chainweb.Utils
2122
import Chainweb.Utils.Rule
@@ -166,6 +167,10 @@ mainnet = ChainwebVersion
166167
, _versionMaxBlockGasLimit =
167168
(succByHeight $ mainnet ^?! versionForks . at Chainweb216Pact . _Just . atChain (unsafeChainId 0), Just 180_000) `Above`
168169
Bottom (minBound, Nothing)
170+
, _versionInitialGasModel = AllChains $
171+
(ForkNever, post32GasModel) `Above`
172+
(succByHeight $ mainnet ^?! versionForks . at Chainweb231Pact . _Just . atChain (unsafeChainId 0), post31GasModel) `Above`
173+
Bottom (minBound, pre31GasModel)
169174
, _versionSpvProofRootValidWindow =
170175
(succByHeight $ mainnet ^?! versionForks . at Chainweb31 . _Just . atChain (unsafeChainId 0), Nothing) `Above`
171176
(succByHeight $ mainnet ^?! versionForks . at Chainweb231Pact . _Just . atChain (unsafeChainId 0) , Just 20_000) `Above`

src/Chainweb/Version/RecapDevelopment.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ module Chainweb.Version.RecapDevelopment(recapDevnet, pattern RecapDevelopment)
99

1010
import qualified Data.HashMap.Strict as HM
1111
import qualified Data.Set as Set
12+
import Control.Lens
1213

1314
import Chainweb.BlockCreationTime
1415
import Chainweb.BlockHeight
1516
import Chainweb.ChainId
17+
import Chainweb.Pact5.InitialGasModel
1618
import Chainweb.Difficulty
1719
import Chainweb.Graph
1820
import Chainweb.Time
@@ -113,6 +115,11 @@ recapDevnet = ChainwebVersion
113115
}
114116

115117
, _versionMaxBlockGasLimit = Bottom (minBound, Just 180_000)
118+
, _versionInitialGasModel = AllChains $
119+
(ForkNever, post32GasModel) `Above`
120+
(succByHeight $ recapDevnet ^?! versionForks . at Chainweb231Pact . _Just . atChain (unsafeChainId 0), post31GasModel) `Above`
121+
Bottom (minBound, pre31GasModel)
122+
116123
, _versionSpvProofRootValidWindow = Bottom (minBound, Nothing)
117124
, _versionCheats = VersionCheats
118125
{ _disablePow = False

0 commit comments

Comments
 (0)