ergo
ergo copied to clipboard
Can't emit an array of obligations formed from an array of values
Bug Report 🐛
I need to emit multiple events based on the list of vendors, specified in my contract.
Here is how I envision that:
My grammar.tem.md
:
[...]
{{#ulist vendors}}
{{businessName}}
{{/ulist}}
[...]
My model.cto
:
event VendorNotification {
o String code
o String description
o Vendor vendor
}
transaction NotifyVendorsReq extends Request {
o String detectionCode
o String description
}
transaction NotifyVendorsRes extends Response {
o String output
}
participant Vendor identified by businessName {
o String businessName
}
asset MyContract extends Contract {
o Vendor[] vendors
}
And logic.ergo
:
contract MyContractLogic over MyContract state State {
//Iterate through an array of vendors and emit an event for each of them
clause notifyVendors(request : NotifyVendorsReq) : NotifyVendorsRes emits VendorNotification[] {
emit foreach vendor in contract.vendors
return VendorNotification {
code: request.notificationCode,
description: request.description,
vendor: vendor
};
return NotifyVendorsRes{ output: "Received " ++ request.notificationCode ++ " " ++ request.description ++ " and sent notification to vendors " ++ toString(contract.vendors) }
}
}
cicero trigger
throws “ERROR: Cannot read property ‘$coll’ of undefined”
Expected Behavior
The contract should emit an array of events
Current Behavior
Throws an error: “ERROR: Cannot read property ‘$coll’ of undefined”
Possible Solution
Would be good to make emit
function compatible with an array of events.
Steps to Reproduce
Please see the bug report section.
Context (Environment)
Desktop
- OS: macOS
- Browser: NodeJS v10.18.1
- Version: "cicero": "^0.22.1"
Detailed Description
The emit
function can receive an array of events and emit them one-by-one to address the situation when multiple events need to be emitted in one go.
Possible Implementation
@frbrkoala Thanks for the bug report / feature request.
Just a quick update:
-
I was able to reproduce the issue. See the archive attached based on your example. [email protected]
-
The
$coll
exception is a runtime error which comes from an inconsistency between the Ergo type checker and the compiler. I think the intended behavior is for the suggested logic to fail type checking (with an error that the emit should be a singleton object). -
This is a perfectly valid and useful requirement imho. I think there might be two ways to support this. First being your suggestion i.e., allow
emit
to take either a single item or an array (which would make it polymorphic). Second might be to keep emit over single items but generalize whereemit
is allowed and notably allow it use insideforeach
. This would look something as follows (both options probably need work):
contract MyContractLogic over MyContract state State {
//Iterate through an array of vendors and emit an event for each of them
clause notifyVendors(request : NotifyVendorsReq) : NotifyVendorsRes emits VendorNotification[] {
foreach vendor in contract.vendors
return
emit VendorNotification {
code: request.notificationCode,
description: request.description,
vendor: vendor
};
return NotifyVendorsRes{ output: "Received " ++ request.notificationCode ++ " " ++ request.description ++ " and sent notification to vendors " ++ toString(contract.vendors) }
}
}