Contract signatures

Can we think about this in terms of migration paths?

I feels like the simplest solution to implement is one where handles are passed around and point to a structure that’s global to the execution of the transaction across multiple operations, with opcodes to read and write from that table. I would suggest no deallocation, just a seal on each value that can be intact or broken (or a counter).

It’s not as elegant as passing values around, but…

Can we think of a way to implement the pointer approach, that would be transparently upgradable to the fancier version?

Or do both version require an equal amount if sweat to integrate in Michelson?

That is the preliminary conclusion I am reaching in the previous message.

Do you mean this user-wise or implementation-wise?

If both variants are equally painful to implement, that doesn’t matter and one what might as well start with the cleanest version.

Still working on that cleanest version. It is essentially about making a more local state monad in script_interpreter.ml . A more local error monad will also naturally follow.

Just so you know I think Raphaël C is taking a crack at it as well… the variant where the stamped values can be duped but the transaction fails if a sealed value is passed more than once or to more than one contract in the list of transaction returned. This was the solution suggested by François and consensus seems to be forming around it. There is already a runtime check to ensure that operations are not duped, it’s a somewhat reasonable extension to ensure that duped stamped values aren’t passed either. The static benefit that we would get from making stamped values into linear types can be easily replicated by running a static analyzer on the code.

Dan Robinson pointed out a hackish way you could get this without a protocol change.

A contract could store a large table of “contract signatures”. Any contract can call it and write a message on it, and pass around a handle to that message. It’s clunky and requires a bunch of callbacks but it works.

To be clear, I don’t recommend this approach, just good to know it’s a possibility.

Had a long talk with the Agoric team, this made sense as contract signatures is very ocap-ish.

They pointed out that these “contract signatures” can do a lot more than what I described above. For instance, the pattern I’ve described for a token contract went as follow:

  • The contract registered as the owner of some amount of XYZcoin in the XYZ token contract creates a “signed” message asking for the transfer of n XYZ coins to a dex.
  • This message is passed to the dex which then uses it to retrieve n XYZ coins.

Here’s a far better pattern:

  • A contract (or some account) asks the XYZcoin contract to create an account for it, the XYZcoin contract creates an account entry, signs it, and sends it to the contract. This storable value is now a key that represents the right to access the XYZcoin contract. It can be kept as is, passed to another contract, etc.

  • The contract calls XYZcoin, and passes its account key as a parameter… there is no need to rely on the SENDER opcode.

  • The contract requests that XYZcoin gives it a sign receipt for “n XYZ coins”. The XYZ contract debits n coins from the balance of the requester and returns a “signed” receipt for n coins. This is now a portable representation of the coins that can be passed around between contracts.

  • The contract sends the receipt to the dex, which can store it, cash it out, send it to another account, etc.

This basically replicates the experience of having assets as first class. Coins from token contracts can be sent just like tez, without expensive callbacks.

In fact, some (maybe not all) token contracts can completely dispense with the notion of mapping accounts to balances, and simply issue signed notes, stored by other contracts on the network, as well as a service to convert a list of notes into a list of other notes with the same sum of balances. As is, this would clash with implicit accounts, but there’s likely some way around it.

In the limit, it starts looking like the asset model that was (once) part of the code-base, where an asset is just a pair between a nat and a contract address, and can be automatically cut up, etc.

1 Like

Why would it “clash with implicit accounts” ?

Because this part?

Why not limit it to KT1 contracts then?

The MR implementing tickets.
You can see the more technical details there:

2 Likes

Me and my prof. Cesar Sanchez have been looking into Tickets and we think using them may jeopardize scalability:
Since the ticket type in Michelson represents a handle to a ticket stored in an internal table shared by all contracts, the effect of the tickets operations modify the blockchain global state.
As we understand, the operations PUNCH and OWN must have immediately visible effect on other contracts, therefore if two contracts try to PUNCH the same ticket there will be a race condition, preventing independence of execution among remote smart contracts which does not seem to be compatible with sharding.

2 Likes

The current implementation is meant to approximate a linear type. Using a linear type would not cause trouble with sharding if I’m not mistaken. I think if or when that happens, better tickets can be introduced.

I agree that tickets can be implemented correctly with sharding using linear types to model the necessary concurrency control (they could also be modelled correctly with other concurrency control mechanisms). I think that the point mcapretto wants to raise is that since operations now have global effects (beyond storage changes and further oprations) due to ticket operations, one must be forced to serialize contract calls.

My point is that it would be relatively straightforward to deprecate the old ticket system and introduce one based on linear types if and when sharding happens. Old style tickets would still be usable but only when no cross shard calls are involved.

I see. Linear types is a way to statically determine which operations are independent of which other operations (and can therefore be run in parallel). That is what I mean by "Ideally, if one knew the effects of all sub-operation generated by a contract many call sequences (whose semantics are sequential) could be run in parallel." in Concurrency, BFS vs DFS (and a proposal)

What I propose in that thread is to be optimistic and run in parallel, check after the execution whether there are concurrency conflicts, and re-run if necessary. This technique is simple and works both for BFS and DFS.