Skip to content
This repository has been archived by the owner on Sep 7, 2023. It is now read-only.

Dispatching requests to contracts: requirements and semantics! #550

Open
18 tasks
jeromesimeon opened this issue Feb 15, 2019 · 4 comments
Open
18 tasks

Dispatching requests to contracts: requirements and semantics! #550

jeromesimeon opened this issue Feb 15, 2019 · 4 comments

Comments

@jeromesimeon
Copy link
Member

jeromesimeon commented Feb 15, 2019

What should the semantics be for dispatching requests to their corresponding smart clause?

Currently most of this logic is in Cicero and checks for requests types using simple equality, but this does not take into account a couple of important aspects:

  • What if more than one Clause expects a certain request?
  • What if the request is a subclass of the expected request?

For instance, consider the following contract model:

namespace org.accordproject.dispatchtest

transaction Request1 {
}
transaction Request2 extends Request1 {
}
transaction Request3 extends Request1 {
}
transaction Request4 extends Request1 {
}

transaction Response {
  o String message
}

/**
 * The template model
 */
@AccordTemplateModel("dispatchtest")
concept TemplateModel {
}

and the logic:

namespace org.accordproject.dispatchtest

contract DispatchTest over TemplateModel {
  clause clause1(request : Request1) : Response {
		return Response{ message: "I am a request1" }
  }

  clause clause3(request : Request3) : Response {
		return Response{ message: "I am a request3" }
  }

  clause clause4(request : Request4) : Response {
		return Response{ message: "I am a request4" }
  }

  clause clause4b(request : Request4) : Response {
		return Response{ message: "I am also a request4!" }
  }

}

What should happen if one sends a Request1 to the contract?

  • Error
  • Trigger clause1
  • Something else?

What should happen if one sends a Request2 to the contract?

  • Error
  • Trigger clause1
  • Something else?

What should happen if one sends a Request3 to the contract?

  • Error
  • Trigger clause1
  • Trigger clause3
  • Trigger clause1 and clause 3
  • Something else?

What should happen if one send a Request4 to the contract?

  • Error
  • Trigger clause1
  • Trigger clause4
  • Trigger clause4b
  • Trigger clause4 and clause4b
  • Trigger clause1 and clause4 and clause4b
  • Something else?
@jeromesimeon
Copy link
Member Author

jeromesimeon commented Feb 15, 2019

For reference, here is the current behavior of ergorun:

bash-3.2$ ergorun model.cto logic.ergo --contractName org.accordproject.dispatchtest.DispatchTest --state state.json --contract contract.json --request request1.json 
09:04:03 - info:
{
  "response": {
    "message": "I am a request1",
    "$class": "org.accordproject.dispatchtest.Response"
  },
  "state": {
    "$class": "org.accordproject.cicero.contract.AccordContractState",
    "stateId": "1"
  },
  "emit": []
}
bash-3.2$ ergorun model.cto logic.ergo --contractName org.accordproject.dispatchtest.DispatchTest --state state.json --contract contract.json --request request2.json 
09:04:08 - info:
{
  "response": {
    "message": "I am a request1",
    "$class": "org.accordproject.dispatchtest.Response"
  },
  "state": {
    "$class": "org.accordproject.cicero.contract.AccordContractState",
    "stateId": "1"
  },
  "emit": []
}
bash-3.2$ ergorun model.cto logic.ergo --contractName org.accordproject.dispatchtest.DispatchTest --state state.json --contract contract.json --request request3.json 
09:04:15 - info:
{
  "response": {
    "message": "I am a request3",
    "$class": "org.accordproject.dispatchtest.Response"
  },
  "state": {
    "$class": "org.accordproject.cicero.contract.AccordContractState",
    "stateId": "1"
  },
  "emit": []
}
bash-3.2$ ergorun model.cto logic.ergo --contractName org.accordproject.dispatchtest.DispatchTest --state state.json --contract contract.json --request request4.json 
09:04:24 - info:
{
  "response": {
    "message": "I am also a request4!",
    "$class": "org.accordproject.dispatchtest.Response"
  },
  "state": {
    "$class": "org.accordproject.cicero.contract.AccordContractState",
    "stateId": "1"
  },
  "emit": []
}
bash-3.2$ 

What should happen if one sends a Request1 to the contract?

  • Error
  • Trigger clause1
  • Something else?

What should happen if one sends a Request2 to the contract?

  • Error
  • Trigger clause1
  • Something else?

What should happen if one sends a Request3 to the contract?

  • Error
  • Trigger clause1
  • Trigger clause3
  • Trigger clause1 and clause 3
  • Something else?

What should happen if one send a Request4 to the contract?

  • Error
  • Trigger clause1
  • Trigger clause4
  • Trigger clause4b
  • Trigger clause4 and clause4b
  • Trigger clause1 and clause4 and clause4b
  • Something else?

@jeromesimeon jeromesimeon changed the title Dispatching requests in contracts: requirements and semantics! Dispatching requests to contracts: requirements and semantics! Feb 15, 2019
@jeromesimeon jeromesimeon added Type: Question ❓ Further information is requested Range: Semantics labels Feb 15, 2019
@jeromesimeon
Copy link
Member Author

The semantics that was agreed (as a starting point):

  • The clause which handles the nearest super type of the request is chosen
  • There can be at most one clause handling a given request (compile error if two clauses handle the same request)
  • No other clause is being triggered

@jeromesimeon
Copy link
Member Author

This is completed in PR #555

@otawakkil
Copy link

otawakkil commented Mar 3, 2019

Regarding the routing, what about this ?
(I've have no knowledge yet about the technical limitations)

the logic here is to add a routing directive in the clause declaration to indicate what clause to invoke.

the syntax would be something like this (EBNF):

'clause' identifier '(' identifier: typeName ')' ':' typeName ('emits' typeName)? ('route' identifier)? clauseBody

Here's an example

contract SomeContract {
	clause clause1(request: Request) : Response  emits SomeOblig route 1  {}
	clause clause2(request: Request) : Response route 2 {}
	clause clause3(request: Request) : Response {}
}

if the route directive is not mentioned, the route matches the "clause" 's name. In the example, for clause3 the equivalent form would be:
clause clause3(request: Request) : Response route clause3 {}
As for the route resolver, instead taking the request type, would use the route clause for that.

In this case I used a route id. It could be something else like an attribute/decorator if easier.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants