Skip to content

Commit 383a845

Browse files
committed
Add transaction validity by slot
1 parent f5ef7c0 commit 383a845

File tree

8 files changed

+147
-61
lines changed

8 files changed

+147
-61
lines changed

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
version: "3.5"
22
services:
33
cardano-node:
4-
image: inputoutput/cardano-node:${CARDANO_NODE_VERSION:-1.35.0}
4+
image: inputoutput/cardano-node:${CARDANO_NODE_VERSION:-1.35.3}
55
environment:
66
NETWORK: ${NETWORK:-testnet}
77
volumes:
@@ -13,7 +13,7 @@ services:
1313
max-size: "200k"
1414
max-file: "10"
1515
kuber:
16-
image: dquadrant/kuber:${KUBER_VERSION:-2.0.0}
16+
image: dquadrant/kuber:${KUBER_VERSION:-2.1.0}
1717
environment:
1818
NETWORK: ${NETWORK:- testnet}
1919
volumes:

docs/json-api-reference.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@ Kuber Json Api Reference
88
- [**selections**](#1-selections---string--object--array-of-utxos-that-can-be-used-to-balance-the-transaction) : List of utxos/addresses that can be used for balancing transaction
99
- [**inputs**](#2-inputs---string--object---inputs-utxos-being-spent-in-the-transaction) : List inputs in transactions
1010
- [**referenceInputs**](#3-referenceinputs--string--referenceinputs-transction-field) : Reference Inputs
11-
- [**outputs**](#4-outputs--object--outputs-created-in--the-transaction) : List Output utxos in the transaction
11+
- [**outputs**](#4-outputs--object--outputs-created-in-the-transaction) : List Output utxos in the transaction
1212
- [**collaterals**](#5-collaterals-string-optional--collateral-inputs-in-the-transaction) : [optional] List of collaterals in the transaction (It is automatically selected if missing)
13-
- **validityStart** : [Integer: UnixTimestamp millisecond] Transaction validFrom
14-
- **validityEnd** : [Integer : UnixTimestamp millisecond] Transaction validUntil
13+
- **validityStart** : [Integer: PosixTimestamp seconds] (convinence field for usage instead of `validityStartSlot`) Transaction validFrom
14+
- **validityStartSlot** : [Integer: Slot Number] Transaction validFrom
15+
- **validityEnd** : [Integer : PosixTimestamp seconds] (convinence field for usage instead of `validityEndSlot`) Transaction validUntil
16+
- **validityEndSlot** : [Integer : Slot Numbers] Transaction validUntil
17+
1518
- [**mint**](#6-mint--object--minting-script-and-amount-in-the-transaction) : Minting Scripts and value in the transaction
16-
- [**signatures**](#7 -)
19+
- [**signatures**](#7-signatures-string)
1720
- **fee** : [Integer : Lovelace] Fee is calculated automatically, but setting this will set transaction fee explicitly.
1821
- **changeAddress** [Optional ] : Default change address. If it's missing, it's selected from one of the selection address. Setting `addChange` in any one output will disable this option
19-
- [**metadata**](#7-metadata--object--transaction-metadata) : Transaction metadata
22+
- [**metadata**](#8-metadata--object--transaction-metadata) : Transaction metadata
2023

2124
### 1. `selections` : [ string | object ] Array of utxos that can be used to balance the transaction
2225

@@ -274,8 +277,12 @@ Each object in the mint list must have following keys
274277
"scripts": [ BasicScript | MultiScript ] : when required number of script condition is met, token can be minted.
275278
}
276279

280+
### 7. Signatures: "String"
281+
PubKey Signatures required for usage by Plutus Contract. It must be set when `txSignedBy` function constraint is used in Plutus script.
282+
283+
It can be either bench32 or cborHex format Address.
277284

278-
### 7. metadata : Object : Transaction Metadata
285+
### 8. metadata : Object : Transaction Metadata
279286
Transaction metadata must be a json object with top level integer key label.
280287

281288
Keys in the json shouldn't be longer than 64 bytes length. If the string value in the metadata is longer than 64 bytes length, Kuber will split the string and replace it with array of smaller chunks of the string.

kuber.cabal

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 2.4
22
name: kuber
3-
version: 2.0.0.0
3+
version: 2.1.0.0
44

55
-- A short (one-line) description of the package.
66
-- synopsis:
@@ -66,9 +66,12 @@ library
6666
-- , shelley-spec-ledger
6767
, plutus-ledger-api
6868
, plutus-tx
69+
, ouroboros-consensus
6970
, ouroboros-network
7071
, vector
72+
, transformers
7173
, unordered-containers
74+
, time
7275

7376
test-suite test
7477
default-language: Haskell2010

server/kuber-server.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 2.4
22
name: kuber-server
3-
version: 2.0.0.0
3+
version: 2.1.0.0
44

55
-- A short (one-line) description of the package.
66
-- synopsis:

src/Cardano/Kuber/Api.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ module Cardano.Kuber.Api(
3838
, txSign
3939

4040
-- transaction validity
41-
, txValidFromPosixMs
42-
, txValidUntilPosixMs
43-
, txValidPosixTimeRangeMs
44-
41+
, txValidFromPosix
42+
, txValidUntilPosix
43+
, txValidPosixTimeRange
44+
, txValidFromSlot
45+
, txValidUntilSlot
46+
, txValidSlotRange
4547
-- Core Tx builder object and it's transformation functions
4648
, TxBuilder
4749
, txBuilderToTxBody

src/Cardano/Kuber/Core/TxBuilder.hs

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
{-# LANGUAGE DeriveGeneric #-}
77
{-# LANGUAGE DeriveAnyClass #-}
88
{-# LANGUAGE FlexibleInstances #-}
9+
{-# LANGUAGE TypeApplications #-}
910
module Cardano.Kuber.Core.TxBuilder
1011

1112
where
@@ -19,6 +20,7 @@ import Cardano.Slotting.Time
1920
import qualified Cardano.Ledger.Alonzo.TxBody as LedgerBody
2021
import qualified Data.Map as Map
2122
import qualified Data.Set as Set
23+
import Data.Time.Clock
2224
import Data.Map (Map)
2325
import Control.Exception
2426
import Data.Either
@@ -52,6 +54,8 @@ import qualified Data.HashMap.Internal.Strict as H
5254
import Data.Bifunctor
5355
import Cardano.Kuber.Utility.ScriptUtil ( fromPlutusV2Script)
5456
import GHC.Generics (Generic)
57+
import Data.Time.Clock.POSIX
58+
import Foreign.C (CTime)
5559

5660

5761
data TxSimpleScript = TxSimpleScriptV1 (SimpleScript SimpleScriptV1 )
@@ -139,6 +143,33 @@ data TxMintingScriptSource =
139143

140144
data TxMintData s = TxMintData s [(AssetName ,Quantity)] (Map Word64 (Map AssetName Aeson.Value)) deriving (Show)
141145

146+
data ValidityTimestamp = NoValidityTime
147+
| ValidityPosixTime POSIXTime
148+
| ValiditySlot SlotNo deriving (Show,Eq)
149+
150+
instance Semigroup ValidityTimestamp where
151+
(<>) = maxValidity
152+
153+
instance Monoid ValidityTimestamp where
154+
mempty = NoValidityTime
155+
156+
minValidity :: ValidityTimestamp -> ValidityTimestamp -> ValidityTimestamp
157+
minValidity NoValidityTime v2 = v2
158+
minValidity v1 NoValidityTime = v1
159+
minValidity (ValidityPosixTime t1) (ValidityPosixTime t2) = ValidityPosixTime (min t1 t2)
160+
minValidity (ValiditySlot s1) (ValiditySlot s2) = ValiditySlot (min s1 s2)
161+
minValidity v1@(ValiditySlot _) _ = v1
162+
minValidity _ v2 = v2
163+
164+
165+
maxValidity :: ValidityTimestamp -> ValidityTimestamp -> ValidityTimestamp
166+
maxValidity NoValidityTime v2 = v2
167+
maxValidity v1 NoValidityTime = v1
168+
maxValidity (ValidityPosixTime t1) (ValidityPosixTime t2) = ValidityPosixTime (max t1 t2)
169+
maxValidity (ValiditySlot s1) (ValiditySlot s2) = ValiditySlot (max s1 s2)
170+
maxValidity v1@(ValiditySlot _) _ = v1
171+
maxValidity _ v2 = v2
172+
142173
-- TxBuilder object
143174
-- It is a semigroup and monoid instance, so it can be constructed using helper function
144175
-- and merged to construct a transaction specification
@@ -148,8 +179,8 @@ data TxBuilder=TxBuilder{
148179
txInputReferences:: [TxInputReference],
149180
txOutputs :: [TxOutput TxOutputContent],
150181
txCollaterals :: [TxCollateral], -- collateral for the transaction
151-
txValidityStart :: Maybe Integer,
152-
txValidityEnd :: Maybe Integer,
182+
txValidityStart :: ValidityTimestamp,
183+
txValidityEnd :: ValidityTimestamp,
153184
txMintData :: [TxMintData TxMintingScriptSource],
154185
txSignatures :: [TxSignature],
155186
txFee :: Maybe Integer,
@@ -158,7 +189,7 @@ data TxBuilder=TxBuilder{
158189
} deriving (Show)
159190

160191
instance Monoid TxBuilder where
161-
mempty = TxBuilder [] [] [] [] [] Nothing Nothing [] [] Nothing Nothing Map.empty
192+
mempty = TxBuilder [] [] [] [] [] mempty mempty [] [] Nothing Nothing Map.empty
162193

163194
instance Semigroup TxBuilder where
164195
(<>) txb1 txb2 =TxBuilder{
@@ -167,16 +198,8 @@ instance Semigroup TxBuilder where
167198
txInputReferences = txInputReferences txb1 ++ txInputReferences txb2,
168199
txOutputs = txOutputs txb1 ++ txOutputs txb2,
169200
txCollaterals = txCollaterals txb1 ++ txCollaterals txb2, -- collateral for the transaction
170-
txValidityStart = case txValidityStart txb1 of
171-
Just v1 -> case txValidityStart txb2 of
172-
Just v2 -> Just $ min v1 v2
173-
Nothing -> Just v1
174-
Nothing -> txValidityStart txb2,
175-
txValidityEnd = case txValidityEnd txb1 of
176-
Just v1 -> case txValidityEnd txb2 of
177-
Just v2 -> Just $ max v1 v2
178-
_ -> Just v1
179-
_ -> txValidityEnd txb2,
201+
txValidityStart = minValidity (txValidityStart txb1) (txValidityStart txb2),
202+
txValidityEnd = maxValidity (txValidityStart txb1) (txValidityStart txb2),
180203
txMintData = txMintData txb1 <> txMintData txb2,
181204
txSignatures = txSignatures txb1 ++ txSignatures txb2,
182205
txFee = case txFee txb1 of
@@ -190,50 +213,61 @@ instance Semigroup TxBuilder where
190213
txMetadata = txMetadata txb1 <> txMetadata txb2
191214
}
192215

193-
194216
data TxContext = TxContext {
195217
ctxAvailableUtxo :: UTxO BabbageEra,
196218
ctxBuiler :: [TxBuilder]
197219
}
198220

199221
txSelection :: TxInputSelection -> TxBuilder
200-
txSelection v = TxBuilder [v] [] [] [] [] Nothing Nothing [] [] Nothing Nothing Map.empty
222+
txSelection v = TxBuilder [v] [] [] [] [] mempty mempty [] [] Nothing Nothing Map.empty
201223

202224
txInput :: TxInput -> TxBuilder
203-
txInput v = TxBuilder [] [v] [] [] [] Nothing Nothing [] [] Nothing Nothing Map.empty
225+
txInput v = TxBuilder [] [v] [] [] [] mempty mempty [] [] Nothing Nothing Map.empty
204226

205227
txInputReference :: TxInputReference -> TxBuilder
206-
txInputReference v = TxBuilder [] [] [v] [] [] Nothing Nothing [] [] Nothing Nothing Map.empty
228+
txInputReference v = TxBuilder [] [] [v] [] [] mempty mempty [] [] Nothing Nothing Map.empty
207229

208230

209231
txMints :: [TxMintData TxMintingScriptSource] -> TxBuilder
210-
txMints md= TxBuilder [] [] [] [] [] Nothing Nothing md [] Nothing Nothing Map.empty
232+
txMints md= TxBuilder [] [] [] [] [] mempty mempty md [] Nothing Nothing Map.empty
211233

212234

213235
txOutput :: TxOutput TxOutputContent -> TxBuilder
214-
txOutput v = TxBuilder [] [] [] [v] [] Nothing Nothing [] [] Nothing Nothing Map.empty
236+
txOutput v = TxBuilder [] [] [] [v] [] mempty mempty [] [] Nothing Nothing Map.empty
215237

216238
txCollateral :: TxCollateral -> TxBuilder
217-
txCollateral v = TxBuilder [] [] [] [] [v] Nothing Nothing [] [] Nothing Nothing Map.empty
239+
txCollateral v = TxBuilder [] [] [] [] [v] mempty mempty [] [] Nothing Nothing Map.empty
218240

219241
txSignature :: TxSignature -> TxBuilder
220-
txSignature v = TxBuilder [] [] [] [] [] Nothing Nothing [] [v] Nothing Nothing Map.empty
242+
txSignature v = TxBuilder [] [] [] [] [] mempty mempty [] [v] Nothing Nothing Map.empty
221243

222244

223245

224246
-- Transaction validity
225247

226-
-- Set validity Start and end time in posixMilliseconds
227-
txValidPosixTimeRangeMs :: Integer -> Integer -> TxBuilder
228-
txValidPosixTimeRangeMs start end = TxBuilder [] [] [] [] [] (Just start) (Just end) [] [] Nothing Nothing Map.empty
248+
-- Set validity Start and end time in posix seconds
249+
txValidPosixTimeRange :: POSIXTime -> POSIXTime -> TxBuilder
250+
txValidPosixTimeRange start end = TxBuilder [] [] [] [] [] (ValidityPosixTime start ) (ValidityPosixTime end) [] [] Nothing Nothing Map.empty
251+
252+
-- set validity statart time in posix seconds
253+
txValidFromPosix:: POSIXTime -> TxBuilder
254+
txValidFromPosix start = TxBuilder [] [] [] [] [] (ValidityPosixTime start) mempty [] [] Nothing Nothing Map.empty
255+
256+
-- set transaction validity end time in posix seconds
257+
txValidUntilPosix :: POSIXTime -> TxBuilder
258+
txValidUntilPosix end = TxBuilder [] [] [] [] [] mempty (ValidityPosixTime end) [] [] Nothing Nothing Map.empty
259+
260+
-- Set validity Start and end slot
261+
txValidSlotRange :: SlotNo -> SlotNo -> TxBuilder
262+
txValidSlotRange start end = TxBuilder [] [] [] [] [] (ValiditySlot start ) (ValiditySlot end) [] [] Nothing Nothing Map.empty
229263

230-
-- set validity statart time in posixMilliseconds
231-
txValidFromPosixMs:: Integer -> TxBuilder
232-
txValidFromPosixMs start = TxBuilder [] [] [] [] [] (Just start) Nothing [] [] Nothing Nothing Map.empty
264+
-- set validity statart time in posix seconds
265+
txValidFromSlot:: SlotNo -> TxBuilder
266+
txValidFromSlot start = TxBuilder [] [] [] [] [] (ValiditySlot start) mempty [] [] Nothing Nothing Map.empty
233267

234-
-- set transaction validity end time in posixMilliseconds
235-
txValidUntilPosixMs :: Integer -> TxBuilder
236-
txValidUntilPosixMs end = TxBuilder [] [] [] [] [] Nothing (Just end) [] [] Nothing Nothing Map.empty
268+
-- set transaction validity end time in posix seconds
269+
txValidUntilSlot :: SlotNo -> TxBuilder
270+
txValidUntilSlot end = TxBuilder [] [] [] [] [] mempty (ValiditySlot end) [] [] Nothing Nothing Map.empty
237271

238272
--- minting
239273
_txMint v = txMints [v]

src/Cardano/Kuber/Core/TxFramework.hs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ import Cardano.Ledger.Coin (Coin(Coin))
7171
import qualified Data.Aeson.KeyMap as A
7272
import qualified Data.Aeson.Key as A
7373
import qualified Data.HashMap.Lazy as HMap
74+
import Data.Time (nominalDiffTimeToSeconds)
75+
import Cardano.Ledger.Alonzo.TxInfo (slotToPOSIXTime)
76+
import qualified Data.Text as Text
77+
import Cardano.Ledger.Slot (EpochInfo, epochInfoFirst)
78+
import Cardano.Slotting.EpochInfo (hoistEpochInfo, epochInfoSlotToUTCTime)
79+
import Ouroboros.Consensus.HardFork.History.EpochInfo (interpreterToEpochInfo)
80+
import Control.Monad.Trans.Except(runExcept)
81+
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)
7482

7583
type BoolChange = Bool
7684
type BoolFee = Bool
@@ -161,6 +169,12 @@ txBuilderToTxBody' dCinfo@(DetailedChainInfo cpw conn pParam ledgerPParam syste
161169
(UTxO availableUtxo)
162170
(TxBuilder selections _inputs _inputRefs _outputs _collaterals validityStart validityEnd mintData extraSignatures explicitFee mChangeAddr metadata )
163171
= do
172+
-- (toLedgerPParams era pparams)
173+
-- tx
174+
-- (toLedgerUTxO era utxo)
175+
-- (toLedgerEpochInfo history)
176+
-- systemstart
177+
-- cModelArray
164178
let network = getNetworkId dCinfo
165179
(resolvedMints, unresolvedMints) <- classifyMints (UTxO availableUtxo) mintData <&> partitionEithers
166180
let mergedMetadata = foldl injectMetadataPolicy (foldl injectMetadataPolicy metadata resolvedMints) unresolvedMints
@@ -242,7 +256,7 @@ txBuilderToTxBody' dCinfo@(DetailedChainInfo cpw conn pParam ledgerPParam syste
242256
in iteratedBalancing 10 txBody1 fee1
243257
)
244258
)
245-
259+
246260
respond finalBody finalSignatories
247261
where
248262
applyMintExUnits :: Map PolicyId ExecutionUnits
@@ -757,11 +771,14 @@ txBuilderToTxBody' dCinfo@(DetailedChainInfo cpw conn pParam ledgerPParam syste
757771

758772
txOutValue_ txout= case txout of { TxOut aie tov tod _-> txOutValueToValue tov }
759773
txLowerBound = case validityStart of
760-
Nothing -> TxValidityNoLowerBound
761-
Just v -> TxValidityLowerBound ValidityLowerBoundInBabbageEra (toSlot v)
774+
NoValidityTime -> TxValidityNoLowerBound
775+
ValidityPosixTime ndt -> TxValidityLowerBound ValidityLowerBoundInBabbageEra (toSlot ndt)
776+
ValiditySlot sn -> TxValidityLowerBound ValidityLowerBoundInBabbageEra sn
762777
txUpperBound = case validityEnd of
763-
Nothing -> TxValidityNoUpperBound ValidityNoUpperBoundInBabbageEra
764-
Just n -> TxValidityUpperBound ValidityUpperBoundInBabbageEra (toSlot n)
778+
NoValidityTime -> TxValidityNoUpperBound ValidityNoUpperBoundInBabbageEra
779+
ValidityPosixTime ndt -> TxValidityUpperBound ValidityUpperBoundInBabbageEra (toSlot ndt)
780+
ValiditySlot sn -> TxValidityUpperBound ValidityUpperBoundInBabbageEra sn
781+
765782
plutusWitness script _data redeemer exUnits = PlutusScriptWitness PlutusScriptV2InBabbage
766783
PlutusScriptV2
767784
script
@@ -781,11 +798,11 @@ txBuilderToTxBody' dCinfo@(DetailedChainInfo cpw conn pParam ledgerPParam syste
781798
-- case x of
782799
-- Left tbe -> throw $ SomeError $ "First Balance :" ++ show tbe
783800
-- Right res -> pure res
784-
toSlot tStamp= case getNetworkId dCinfo of
785-
Mainnet -> SlotNo $ fromIntegral $ mainnetSlot tStamp
786-
Testnet nm -> SlotNo $ fromIntegral $ testnetSlot tStamp
787-
testnetSlot timestamp= ((timestamp -1607199617000) `div` 1000 )+ 12830401 -- using epoch 100 as refrence
788-
mainnetSlot timestamp = ((timestamp -1596491091000 ) `div` 1000 )+ 4924800 -- using epoch 209 as reference
801+
toSlot tStamp = case getNetworkId dCinfo of
802+
Mainnet -> SlotNo $ fromIntegral $ mainnetSlot $ round tStamp
803+
Testnet nm -> SlotNo $ fromIntegral $ testnetSlot $ round tStamp
804+
testnetSlot timestamp= (timestamp -1607199617 )+ 12830401 -- using epoch 100 as refrence
805+
mainnetSlot timestamp = (timestamp -1596491091 )+ 4924800 -- using epoch 209 as reference
789806

790807
-- mkBalancedBody :: ProtocolParameters
791808
-- -> UTxO BabbageEra
@@ -954,3 +971,8 @@ txBuilderToTxBody' dCinfo@(DetailedChainInfo cpw conn pParam ledgerPParam syste
954971
-- gatherInfo cInfo txBuilder@TxBuilder{txSelections, txInputs} = do
955972
-- error "sad"
956973
-- where
974+
975+
toLedgerEpochInfo :: EraHistory mode -> EpochInfo (Either Text.Text)
976+
toLedgerEpochInfo (EraHistory _ interpreter) =
977+
hoistEpochInfo (first (Text.pack . show) . runExcept) $
978+
interpreterToEpochInfo interpreter

0 commit comments

Comments
 (0)