Skip to content
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

Arguments of type 'object' lead to internal server on invokes. #1307

Open
Tillaert opened this issue May 18, 2023 · 2 comments
Open

Arguments of type 'object' lead to internal server on invokes. #1307

Tillaert opened this issue May 18, 2023 · 2 comments

Comments

@Tillaert
Copy link

Tillaert commented May 18, 2023

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

@Tillaert
Copy link
Author

I suspect that the input arguments are always serialized as a seprate string, instead of preserving the structure:

output[field] = string(encodedValue)

@Tillaert
Copy link
Author

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:

args, err := jsonEncodeInput(input)
And the comment is wrong.

@Tillaert Tillaert changed the title Internal server error on Invoke with nested object as argument. Arguments of type 'object' lead to internal server on invokes. May 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant