-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: multiple named tuple result from contract #1333
fix: multiple named tuple result from contract #1333
Conversation
Signed-off-by: Enrique Lacal <enrique.lacal@kaleido.io>
Codecov Report
@@ Coverage Diff @@
## main #1333 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 314 314
Lines 21447 21447
=========================================
Hits 21447 21447
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EnriqueL8 / @nguyer - this seems to be a fundamental change/enhancement to the API surface area of FireFly core. Think we need to be really clear in what the behavior is today, what this change means, and where this is/should-be documented in the FireFly docs.
Would you mind adding some commentary to that effect?
if err = json.Unmarshal(res.Body(), output); err != nil { | ||
|
||
queryOutput := make(map[string]interface{}) | ||
if err = json.Unmarshal(res.Body(), &queryOutput); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly, the proposal here is:
- If the ABI has a single unnamed parameter, then we return
output: {whatever}
- If the ABI has a single named parameter, then we return
output: {name1: {whatever}}
- If the ABI has multiple unnamed parameters, then we return
output: {output: {whatever1}, output1: {whatever2}}
- If the ABI has multiple named parameters, then we return
output: {name1: {whatever1}, name2: {whatever2}}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there just this one is different:
- If the ABI has multiple unnamed parameters, then we return
output: {whatever1}, output1: {whatever2}
instead of it being nested.
Discussed this one with @Chengxuan and thought it would be better as above but happy to change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, so the logic is "if any of the data comes back from the connector contains output
as a field, return the whole output unchanged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... otherwise, nest whatever came back from the connector under an output
parent object
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That Fabric doc must be out of date then!
It's still the same problem I believe. We are decoding to an object that expects a key "Result"
firefly/internal/blockchain/fabric/fabric.go
Line 102 in e2f00f0
Result interface{} `json:"result"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will amend this PR to proxy the direct output for ethereum connector and we can discuss the fabric one as well and decide in a future PR - need to look at the fabric connector code as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fabric construct that object after serialisation https://github.com/hyperledger/firefly-fabconnect/blob/b46951bb6613a2981b89c3ea2e69048441ec41ed/internal/rest/sync/syncdispatcher.go#L200-L203 completely different to ethereum where we add a custom name generator to override the serialisation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so the fabric connector needs to return that
Yes, I agree result
is where Fabric connector returns it. But that's just an interface{}
.
e.g. - in Ethereum today which is broken:
- The connector returns the result at the top level of the JSON, and the result must have exactly one object we care about called
output
In Fabric today:
- The connector returns the result in a sub-field of the JSON called
result
, and can specify anything it likes there which we will return at the top level of the JSON to the end user
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I think if you change Ethereum as follows, it will be very consistent with Fabric:
var output interface{}
if err = json.Unmarshal(res.Body(), &output); err != nil {
return nil, err
}
return output, nil // note UNLIKE fabric this is just `output`, not `output.Result` - but either way the top level of what we return to the end user, is whatever the Connector sent us
This PR changes the contract between Firefly core and the ethereum blockchain connector (EVMConnect and ETHConnect) by relaxing the schema validation when reading the result of a contract query operation. Before this PR, FF core relied on the result being in the format |
Signed-off-by: Enrique Lacal <enrique.lacal@kaleido.io>
output := &queryOutput{} | ||
if err = json.Unmarshal(res.Body(), output); err != nil { | ||
|
||
output := make(map[string]interface{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EnriqueL8 - I believe this should just be interface{}
(not a map)
arbitrary map of string to any (interface{}
I agree that's what EVMConnect is configured to return today. But in firefly-signer
there are other options (possibly not exposed in config on EVMConnect yet).
For example, you can make it work just like Fabric where it returns an array (not an object) of the values.
I don't see any reason why we'd want to make a change now in Core that precludes EVMConnect being configured by someone to do that in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! Amending
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working through the approach in the conversation.
Very pleased with where we are landing to simply proxy through for Ethereum what comes from the connector, and I believe it's very consistent with Fabric where the core<->FabConnect contract is just interface{}
.
Small request above is to just use interface{}
(like Fabric does) rather than map[string]interface{}
, so we can support Array returns from Ethereum connectors in the future.
Signed-off-by: Nicko Guyer <nicko.guyer@kaleido.io>
Resolves #1304 |
Signed-off-by: Nicko Guyer <nicko.guyer@kaleido.io>
Signed-off-by: Enrique Lacal <enrique.lacal@kaleido.io>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Fixes EVM queries for:
Functions with multiple return values
Result of JSON will become:
Functions with named return values
Functions with multiple named return values