I think that in general, when we create Daml models, we encourage a separation between what is active and historical data. The ACS reflects exactly that and if one wants to see historical data, and how it changed, access it via the transaction API.
But what if we want to explicitly enable the ability to go back to a previous state? I could think of a way to do that via off-ledger actions with appropriate request/response mechanism. Or we could try to do it on ledger. What do y’all think about:
type Business = Text
template Historical
with
p : Party
created : Time
archived : Time -- What would be a better name?
previous : Optional (ContractId Historical)
business : Business
where
signatory p
ensure archived >= created
template Current
with
p : Party
created : Time
previous : Optional (ContractId Historical)
business : Business
where
signatory p
controller p can
New : ContractId Current
with
newBusiness : Business
do
now <- getTime
h <- create Historical with
archived = now
..
create Current with
created = now
previous = Some h
..
nonconsuming Unwind : Optional (ContractId Current)
with
to : Time
do
if created <= to then do
return $ Some self
else do
archive self
case previous of
None -> return None
Some hId -> do
-- A bit sneaky but now the context has the correct state.
Historical {..} <- fetch hId
archive hId
createAndExercise (Current with ..) (Unwind with ..)
DoWork : Business
do
when <- getTime
return $ "We did " <> show business <> " at " <> show when
t : Script ()
t = do
p <- allocateParty "p"
created <- getTime
c1 <- p `submit` do
createCmd Current with
p
created
previous = None
business = "work 1"
passTime $ days 2
c2 <- p `submit` do
exerciseCmd c1 New with
newBusiness = "work 2"
passTime $ days 2
c3 <- p `submit` do
exerciseCmd c2 New with
newBusiness = "work 3"
passTime $ days 2
c4 <- p `submit` do
exerciseCmd c3 New with
newBusiness = "work 4"
Some c5 <- p `submit` do
exerciseCmd c4 Unwind with
to = addRelTime created (days 5)
w <- p `submit` do
exerciseCmd c5 DoWork
debug $ w
- I think that we need to split the state into a
Historical
andCurrent
state, or at least I was not able to come up with a way of enforcing the separation via anensure
. - Should I even separate the historical data to a different template or store it as a list on the current one? My thinking here is that a
ContractId
is simpler to fetch and probably better to avoid loading largeBusiness
data records. The time when you need the actual historical data are rarer. - This approach would need to be replicated for each template that I want to have this feature, which isn’t great but probably manageable. The hard part is that, is that one would have to have a custom
Unwind
when two contracts with history are linked that respects the business logic that drives that link. - Any suggestions or thoughts?