How do I assert a contract is inactive (archived) in a scenario? - daml

If I wanted to validate that a contract is active, I could simply fetch it in a Scenario:
template Something
with
party : Party
where
signatory party
nonconsuming choice DoStuff : ()
controller party
do
return ()
myTest = scenario do
someone <- getParty "Someone"
submit someone do
cid <- create Something with party = someone
exercise cid DoStuff
fetch cid -- would fail if the DoStuff choice was consuming
How do I assert the opposite?
template Something
with
party : Party
where
signatory party
choice DoStuff : ()
controller party
do
return ()
myTest = scenario do
someone <- getParty "Someone"
submit someone do
cid <- create Something with party = someone
exercise cid DoStuff
fetch cid -- fails the scenario, as it should, but that's what I want to check for

This code shows that you can chain the cid into an appropriate scope to allow a submitMustFail to operate in the way intended:
myTest = scenario do
someone <- getParty "Someone"
cid <- submit someone do
create Something with party = someone
submit someone do
exercise cid DoStuff
submitMustFail someone do
fetch cid -- would fail if the DoStuff choice was consuming

Related

Exercising multiple updates within DAML choice

Is it possible in DAML to use a map-like function to iterate over of list of contractids, retrieve them and execute a choice on each? This appears to be limited in DAML by the way everything needs to be wrapped in a single Update when executing a choice.
Here's an example of what I've attempted (noting the issues):
exerciseChoice: ContractId ContractB -> Update (ContractId ContractB)
exerciseChoice contractB = do (exercise contractB UpdateB with newText = "test")
template ContractA
with
party : Party
contracts: [ContractId ContractB]
where
signatory party
controller party can
nonconsuming UpdateA : [Update (ContractId ContractB)]
with newText : Text
do
-- a <- create ContractB with party = party; text = newText
-- a2 <- exerciseChoice a
-- return [a2] #these lines work fine
return map exerciseChoice contracts
-- #this doesn't work due to DAML implicitly adding Update before return definition
-- i.e. DAML expects type 'Update [Update (ContractId ContractB)]' based on this signature
-- we need a function which converts something like:
-- '[Update (ContractId ContractB)] -> Update [ContractId ContractB]'
template ContractB
with
party : Party
text: Text
where
signatory party
controller party can
UpdateB: ContractId ContractB
with newText: Text
do create this with text = newText
If this can be solved, can you also explain why when returning multiple tuples in DAML they seem to implicitly cast from (Update (ContractId A), Update (ContractId B)) to Update (ContractId A, ContractId B)?
The function map has type (a -> b) -> [a] -> [b] so map exerciseChoice contracts will have type [Update (ContractId ContractB)]. Turning a list of actions into a single action is conceptually simple. The resulting action is the action of performing each action in the list in sequence. And indeed, there is a function for that: sequence : (Applicative m) => [m a] -> m [a]. Update is an applicative so you could write sequence (map exerciseChoice contracts). However, this is such a common task that there is a specialised function mapA : (Applicative m) => (a -> m b) -> [a] -> m [b].
mapA exerciseChoice contracts should do the trick.

DAML LookupByKey and FetchByKey require different permission to run

I have a contract with multiple signatories. Is there an example on how to do LookupBykey the contract? I am having trouble working out how to get all parties' authorization for LookupBykey to work.
Also is there anyone can explain to me that why LookupByKey requires more permission to run than FetchByKey?
Put up some codes to get the same contract using LookupByKey and FetchByKey. For the same party, FetchByKey works but LookupByKey doesn't.
LookupByKey got
Scenario execution failed on commit at Main:38:3:
#1: lookup by key of Sample:Sample at DA.Internal.Prelude:365:26
failed due to a missing authorization from 'partyA'
run = scenario do
a <- getParty "partyA"
b <- getParty "partyB"
sample <- submit a do create Sample with sig = a, obs = b, content = "some text here"
caller <-submit b do create Caller with sig = b, obs = a
submit b do exercise caller FetchByKey with company="test", text = "fetch by key sample"
pure()
run2 = scenario do
a <- getParty "partyA"
b <- getParty "partyB"
sample <- submit a do create Sample with sig = a, obs = b, content = "some text here"
caller <-submit b do create Caller with sig = b, obs = a
submit b do exercise caller LookupByKey with company="test", text = "look up by key sample"
pure()
-- choices
controller sig can
FetchByKey : Bool
with
company : Text
text : Text
do
re <- fetchByKey #Sample (company, obs)
cid_tr <- exercise (fst re) Operate with text = text
return True
controller sig can
LookupByKey : Bool
with
company : Text
text : Text
do
re <- lookupByKey #Sample (company, obs)
cid <- fetch (fromSome re)
res <- exercise (fromSome re) Operate with text = text
return True
Let's take a look at both fetchByKey and lookupByKey in the context of a generic Sample template:
template Sample
with
maints : [Party]
extraSigs : [Party]
obs : [Party]
where
signatory maints ++ extraSigs
observer obs
key this : Sample
maintainer key.maints
The key is the whole contract, maintained by a specified subset of the signatories. A simple proposal workflow can be used to instantiate such a contract:
template SampleProposal
with
sample : Sample
sigs : [Party]
where
signatory sigs
observer (signatory sample)
choice Sign
: ContractId SampleProposal
with
sig : Party
controller sig
do
assert (sig `elem` signatory sample)
assert (sig `notElem` sigs)
create this with sigs = sig :: sigs
choice Accept
: ContractId Sample
with
sig : Party
controller sig
do
assert (sig `elem` signatory sample)
create sample
makeSample = scenario do
maints <- mapA getParty ["main1", "main2", "maint3"]
extraSigs <- mapA getParty ["sig1", "sig2", "sig3"]
obs <- mapA getParty ["obs1", "obs2", "obs3"]
let sample = Sample with ..
prop <- submit (head maints) do
create SampleProposal with
sample
sigs = [head maints]
signedProp <- foldlA
(\p sig -> submit sig do exercise p Sign with sig)
prop
(tail maints ++ tail extraSigs)
submit (head extraSigs) do
exercise signedProp Accept with sig = head extraSigs
Now, who can fetchByKey and who can lookupByKey this sample?
The first condition for either is that the submitting party has to know of the contract. Ie they must be an stakeholder (ie signatory or observer), or the contract must have been divulged to them.
Secondly, the operation has to be authorised correctly. fetchByKey is authorised like fetch, meaning you have to have the authority of at least one stakeholder. Thus, an observer of Sample can divulge the contract and delegate a fetchByKey.
template FetchByKeyDelegation
with
sampleObserver : Party
agent : Party
where
signatory sampleObserver, agent
nonconsuming choice FetchSampleByKey
: (ContractId Sample, Sample)
with
ctl : Party
sample : Sample
controller ctl
do
fetchByKey #Sample sample
template FetchByKeyDelegationInvite
with
fbkd : FetchByKeyDelegation
where
signatory fbkd.sampleObserver
controller fbkd.agent can
AcceptFBKDI
: ContractId FetchByKeyDelegation
do
create fbkd
delegateFetch = scenario do
sample <- makeSample
let obs = head sample.obs
agent <- getParty "Agent"
prop <- submit obs do
create FetchByKeyDelegationInvite with
fbkd = FetchByKeyDelegation with
sampleObserver = obs
agent
fbkd <- submit agent do
exercise prop AcceptFBKDI
-- By calling FetchSampleByKey, `obs` divulges the contract to `agent`
submit obs do
exercise fbkd FetchSampleByKey with
ctl = obs
sample
-- Now `agent` can use the authority of `obs` to `fetchByKey`
submit agent do
exercise fbkd FetchSampleByKey with
ctl = agent
sample
lookupByKey has stricter authorization rules. Rather than one stakeholder, you need the authority of all maintainers. Other than that, delegation works the same:
template LookupByKeyDelegation
with
maints : [Party]
agent : Party
where
signatory maints, agent
nonconsuming choice LookupSampleByKey
: Optional (ContractId Sample)
with
ctl : Party
sample : Sample
controller ctl
do
lookupByKey #Sample sample
template LookupByKeyDelegationInvite
with
lbkd : LookupByKeyDelegation
sigs : [Party]
where
signatory sigs
observer (signatory lbkd)
choice SignLBKDI
: ContractId LookupByKeyDelegationInvite
with
sig : Party
controller sig
do
assert (sig `elem` signatory lbkd)
assert (sig `notElem` sigs)
create this with sigs = sig :: sigs
controller lbkd.agent can
AcceptLBKDI
: ContractId LookupByKeyDelegation
do
create lbkd
delegateLookup = scenario do
sample <- makeSample
let maints = sample.maints
agent <- getParty "agent"
lbkdi <- submit (head maints) do
create LookupByKeyDelegationInvite with
lbkd = LookupByKeyDelegation with
maints
agent
sigs = [head maints]
signedlbkdi <- foldlA
(\p sig -> submit sig do exercise p SignLBKDI with sig)
lbkdi
(tail maints)
lbkd <- submit agent do
exercise signedlbkdi AcceptLBKDI
-- By calling LookupSampleByKey, a maintainer divulges the contract to `agent`
submit (head maints) do
exercise lbkd LookupSampleByKey with
ctl = head maints
sample
-- Now `agent` can use the authority of `obs` to `lookupByKey`
submit agent do
exercise lbkd LookupSampleByKey with
ctl = agent
sample
In your specific model, it seems that partyB is an observer, but not a maintainer. Thus, they know the contract (the first conditions), and their actions are authorised by a stakeholder (the second condition for fetchByKey). However, the lookupByKey is not authorised by the maintainers so it fails.
The reason the for the difference in authorisation is the behaviour in case of negative lookups. fetchByKey fails on the submitter node so negative lookups never hit the network. lookupByKey allows negative lookups so they do hit the network.
DAML is designed around the principle that no party should ever have to do work unless they signed something. Validating key lookups is work so you should never have to do it unless you signed a contract. With fetchByKey this is true. Unless you signed a contract on which you are maintainer, no honest node will ever submit a fetchByKey on which you are a maintainer.
However, with lookupByKey this is not true. First of all, if you have a negative lookup, the only information you have is who the maintainers are, as only those are part of the key. Thus to run an authorisation check on the submitter node, the authorisation rule has to be about maintainers, not stakeholders.
Now suppose the authority of one maintainer, rather than all of them, was enough. Then the following would be a perfectly legal thing to do:
badLookup = scenario do
frankie <- getParty "Frankie"
spammer <- getParty "spammer"
let
sample = Sample with
maints = [frankie, spammer]
extraSigs = []
obs = []
forA [1..1000] (\_ -> do
submit spammer do
lookupByKey #Sample sample
)
Ie a malicious party could legitimately spam you with expensive operations. This goes against DAMLs core principles so the authorisation rule has to be that all maintainers are needed.
The key take away is that one should consider very carefully whether lookupByKey is actually needed. It's often advisable to design workflows so that all key lookups are positive.

pycparser retrieving function call hierarchy

is there a way to get the function call stack with pycparser ?
for example if i have code like this:
static int Func_1(int *val)
{
unsigned int data_1 = 0;
int result;
result = Func_2(val,
data_1
);
result = Func_3(val,
result
);
return result;
}
so with FuncDefVisitor i can retrieve Func_1 and with FuncCallVisitor i could retrieve Func_2 and Func_3
but how can i retrieve the information that e.g. Func_2 is called from within Func_1 ?
You can write a visitor that finds FuncDef nodes and runs another visitor on them that finds all FuncCall nodes. For example:
class FuncDefVisitor(c_ast.NodeVisitor):
def visit_FuncDef(self, node):
# Here node is a FuncDef node for the function definition.
v = FuncCallVisitor()
v.visit(node)
class FuncCallVisitor(c_ast.NodeVisitor):
def visit_FuncCall(self, node):
# do something
In visit_FuncDef, we create a new call visitor and run it on node, which means it only runs within the AST node for the function definition. It will find Func_2 and Func_3 in your code, but not func calls in other functions.
That said, note that you will only get the static call graph from this. In C functions can call others via function pointers and that's not something you can know statically in the general case.

Elm Json request not working?

In Elm, you can use the Json.decode and Http package to request json data. My attempt was to work out a periodic lookup for emails ( from this url ). The timer operation does work (i tried it with with a simple counter).
I have used this example and this SO question as reference.
Now the types:
type alias Email = { title: String, ... }
type Action =
NoAction
| TickCounter -- TODO rem
| AddEmails (List Email)
Then the main + state + actions ...
main: Signal Html
main = Signal.map (view actions.address) state
state: Signal Model
state = Signal.foldp update makeEmptyModel input
-- handle inputs (merging signals)
input : Signal Action
input =
Signal.mergeMany
[ actions.signal
-- , other actions
, Signal.map checkForNewMails (Time.every (Time.minute / 6.0) ) -- TODO precise timer (quick test)
]
actions: Signal.Mailbox Action
actions = Signal.mailbox NoAction
update: Action -> Model -> Model
update action model =
case action of
NoAction -> model
TickCounter -> { model | count = model.count + 1 }
AddEmails newMails -> { model | emails = newMails }
checkForNewMails: Time -> Action
checkForNewMails t =
let mails = startGettingEmailData
in TickCounter -- TODO replace with AddEmails using mails
The TickCounter is an Action, which i have used to test my timing operation. But the problem is startGettingEmailData. It uses the next snippet, but it doesn't fire any JSON request (i have checked it through the console). Once that has been resolved, i can convert mails to an action so that i can add the emails in the model.
-- url to json
jsonUrl = "https://dl.dropboxusercontent.com/u/14070433/temp.json"
-- get emails
startGettingEmailData: Task Http.Error (List Email)
startGettingEmailData = Http.get emailJsonDecoder jsonUrl
emailJsonDecoder: Json.Decoder (List Email)
emailJsonDecoder =
let makeEmail = Json.object4
(\ti fr da bo -> makeNewEmail -1 ti fr da bo )
("title" := Json.string)
("from" := Json.string)
("date" := Json.string)
("body" := Json.string)
in
"emails" := Json.list makeEmail
Is there a problem with my code ? If not, then is there a way to check the Http.Error content ? (Maybe the problem lies not in my code, but in the network, but i can access the dropbox file by browser...)
Your code for checkForNewMails doesn't actually do anything with mails, so it never gets invoked. The let statement doesn't make any calls, it only lets you define one-off functions within the body of a larger function. Since the in portion merely returns TickCounter, then it means this function only ever returns TickCounter and does nothing else.
Furthermore, startGettingEmailData is returning a Task, which means it only gets invoked when in a port. You can't use it in a function that only returns an Action, because it would never get run.
You'll instead want to write a port that triggers on a timer, then creates a Task which polls your url, then maps the response of that GET request to an Action, calling the actions mailbox. You can use Task.onError to write a simple error handler, which could forward an error message to your view by creating an Error String constructor on your Action type.
Here's an example:
getEmailData _ =
let
request =
Http.get emailJsonDecoder jsonUrl
|> Task.map AddEmails
in
request
`Task.onError` (\err -> Task.succeed (Error (toString err)))
`Task.andThen` (\action -> Signal.send actions.address action)
port getEmails : Signal (Task a ())
port getEmails =
Signal.map getEmailData (Time.every (Time.minute / 6.0) )
The above code will cause the URL to be retrieved, parsed, then, on success, it will trigger you actions mailbox and cause an update of the view. If there is an error, it will send the new action of Error with a message, which you should handle in the view. (You'll have to add Error String to the Action union type and handle it in the model, update, and view functions).

Debugging ErlyDB and MySQL

I am experimenting with ErlyDB in a non-erlyweb environment and I am not having much luck.
I have a 'Thing' table for testing, and a corresponding Thing module:
-module(thing).
-export([table/0, fields/0]).
table() ->
thing.
fields() ->
[name, value].
The module itself works - I can query the database fine using ([Thing] = thing:find({name, '=', "test"})).
When I try and save a new record, however things aren't so good.
I consistently see the following error:
mysql_conn:426: fetch <<"BEGIN">> (id <0.97.0>)
mysql_conn:426: fetch <<"INSERT INTO thing(value,name) VALUES ('vtha','blah')">> (id <0.97.0>)
mysql_conn:426: fetch <<"ROLLBACK">> (id <0.97.0>)
** exception exit: {{'EXIT',{badarg,[{erlang,hd,[[]]},
{erlydb_base,'-do_save/1-fun-0-',4},
{mysql_conn,do_transaction,2},
{mysql_conn,loop,1}]}},
{rollback_result,{updated,{mysql_result,[],[],0,[]}}}}
in function erlydb_base:do_save/1
in call from erlydb_base:hook/4
in call from test_thing:test/0
called as test_thing:test()
The table exists, the credentials work, and the SQL itself is fine, as I can execute the command directly on the database.
The code I am using to save is:
erlydb:start(mysql, Database),
Thing = thing:new(<<"hello">>, <<"world">>),
thing:save(Thing),
Is there something I am missing?
Is there some way of viewing some more helpful error messages from the database?
Looking at the source of erlydb_base, the exception happens when erlydb calls your thing module's db_pk_fields() function. That function should return a list, but apparently it doesn't.
I can confirm that altering the code in erlydb.erl fixes this problem (from this reference on the mailing list).
Change Line 561 of erlydb.erl from
lists:map(fun({_Name, _Atts} = F) -> F;
(Name) -> {Name, []}
end, lists:usort(DefinedFields)),
To:
lists:map(fun({_Name, _Atts} = F) -> F;
(Name) -> {Name, []}
end, DefinedFields),