Arguments of type 'object' lead to internal server on invokes.
Given a firefly schema
{
"name": "createVoting",
"description": "Create a vote, using a ballot.",
"params": [
{
"name": "ballot",
"schema": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"id": {
"type": "string"
}
}
}
}
],
"returns": [
{
"name": "",
"schema": {
"type": "string"
}
}
]
},
When called with:
curl -X 'POST' \
'http://127.0.0.1:5000/api/v1/namespaces/general/apis/chaincode/invoke/createVoting' \
-H 'accept: application/json' \
-H 'Request-Timeout: 2m0s' \
-H 'Content-Type: application/json' \
-d '{"input":{"title":"Food preferences - title","ballot":{"id":"00000000-00000000-00000000-00000000","title":"Food preferences."}},"options":{}}'
Firefly returns status code 400 Bad Request:
{
"error": "FF10284: Error from fabconnect: failed to validate argument \"ballot\": - (root): Invalid type. Expected: object, given: string\n"
}
Firefly shows these log lines:
[2023-05-18T17:41:52.790Z] INFO --> POST /api/v1/namespaces/general/apis/chaincode/invoke/createVoting httpreq=hD6T8jaI pid=1 req=ZO0HVzmC
[2023-05-18T17:41:52.790Z] INFO <-- POST /api/v1/namespaces/general/apis/chaincode/invoke/createVoting [400] (0.01ms): invalid character ':' looking for beginning of object key string httpreq=hD6T8jaI pid=1 req=ZO0HVzmC
[2023-05-18T17:42:38.197Z] INFO --> POST /api/v1/namespaces/general/apis/chaincode/invoke/createVoting httpreq=YY3hA6_v pid=1 req=whl_kIeZ
[2023-05-18T17:42:38.221Z] INFO Emitted transaction_submitted event 147457e2-a1e3-4dfb-9c85-c32129e88a56 for general:4af22562-16b3-4ef1-aa89-58ee218bbcca (correlator=,topic=contract_invoke) dbtx=kqV8Ssxn httpreq=YY3hA6_v pid=1 req=whl_kIeZ
[2023-05-18T17:42:38.222Z] INFO Executing blockchain_invoke operation 60b657d9-705d-4e23-800f-36fb4684106d via handler ContractManager httpreq=YY3hA6_v pid=1 req=whl_kIeZ
[2023-05-18T17:42:38.223Z] ERROR <== POST http://fabconnect-0.fabconnect.default:3000/transactions [400] (1.28ms) breq=tSKqVL6u pid=1 proto=fabric
[2023-05-18T17:42:38.242Z] INFO Emitted blockchain_invoke_op_failed event c4937a8c-8a17-4ce7-b7ba-16847f8e1c6d for general:60b657d9-705d-4e23-800f-36fb4684106d (correlator=,topic=) dbtx=W1ImNQtu ns=general pid=1
[2023-05-18T17:42:38.242Z] INFO <-- POST /api/v1/namespaces/general/apis/chaincode/invoke/createVoting [500] (44.83ms): FF10284: Error from fabconnect: failed to validate argument "ballot": - (root): Invalid type. Expected: object, given: string
Fabconnect shows these log lines:
[2023-05-18T17:42:38.223Z] INFO --> POST /transactions
[2023-05-18T17:42:38.223Z] ERROR <-- POST /transactions [400]:
failed to validate argument "ballot": - (root): Invalid type. Expected: object, given: string
It seems that firefly passes the nested object as a string, instead of a nested of an object.
Firefly Version: 1.2.0 Fabconnect v0.9.17
I suspect that the input arguments are always serialized as a seprate string, instead of preserving the structure: https://github.com/hyperledger/firefly/blob/4df24f30508b046fe57def1d386d2fb73a5d1979/internal/blockchain/fabric/fabric.go#L820
I think that json.Marshal is called twice. Once on the nested json-object and once on the body of the request by the rest client.
This is the equivalent of:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var inner = make(map[string]string)
inner["inner"] = "data"
var output, _ = json.Marshal(inner)
var outer = make(map[string]string)
outer["outer"] = string(output)
var output2, _ = json.Marshal(outer)
fmt.Println(string(output2))
}
Which results in:
{"outer":"{\"inner\":\"data\"}"}
While what should happen is:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var inner = make(map[string]string)
inner["inner"] = "data"
var outer = make(map[string]map[string]string)
outer["outer"] = inner
var output2, _ = json.Marshal(outer)
fmt.Println(string(output2))
}
Which results in:
{"outer":{"inner":"data"}}
Because Resty is called using an unmarshalled object, it is marshalled again. I think this line is not required: https://github.com/hyperledger/firefly/blob/4df24f30508b046fe57def1d386d2fb73a5d1979/internal/blockchain/fabric/fabric.go#L712 And the comment is wrong.