-
Notifications
You must be signed in to change notification settings - Fork 125
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
Serenity async proposal (discussion) #185
Comments
What function on the callee is invoked when the caller does a More questions: does each contract have its own logic for tracking pending requests, and fulfilled requests/response objects? Or does the sharding protocol ensure guaranteed once in-order delivery of requests and responses? If not, then how are response objects validated (to prevent spoofing)? and so on. |
Also note that async calls to another contract on the same shard are another use case. The difference between same-shard-async and cross-shard-async is that with same-shard-async, the contract module memory can persist, and multiple requests/responses happen in the same transaction. With cross-shard-async, the module memory doesn't persist (only contract storage). Each request is one transaction, the response is another transaction, and so on. |
I was actually thinking about this and somehow concluded the above, with reference to the request is good enough. Probably it isn't. A better option is
Based on the discussion that is my impression.
Based on the discussions it seems to me no such guarantees are provided.
The proposal to have |
I was trying to find some information about the questions you've posed, here's what I've found from here: Identifier
According to this, receipts have a unique id, it should be possible to return it to caller:
Request guarantee
I think the only guarantee might be that a "receipt" has been "spent" (not necessarily in order):
Executing tx on destination shard
I remember reading about a gas mechanism for this somewhere, but couldn't find it now. This only specifies a contract that handles receipts, but I didn't understand who calls this contract on the destination shard.
About the One simplification would be to only have Asking because I feel many more things can go wrong in a cross-shard call, which takes a few blocks, and it seems complicated to prepare a response for all of the cases. One option for contracts that absolutely would need to know the result (or need to to atomic stuff) might be to use yanking.
Without |
serenity asynchronous execution
(Some of these details are based on asking @vbuterin questions and my interpretation of the answers. I'm not 100% familiar with the entire Serenity specification.)
Based on my limited understanding, asynchronous communication on Serenity shards operate in the following manner:
Note, cross-shard data exchange takes place between 1-2 and 2-3. This may take non-insignificant amount of time.
relevant primitives on the execution engine
A contract may issue multiple async calls in a single execution. Issuing these calls will not stop execution.
It is not clear whether it is possible or would be beneficial at all to batch incoming async response and whether that batching should be separated by shard origins.
execution dependency on async calls
Another question is whether the given account should be in a locked state until responses to its async calls are available.
Without aiming to have a complete list, here are some potential avenues to take:
hide all this complexity from contracts and expose a synchronous interface. This means it won't be possible to execute the contract by any other means before the receipt from the other shard arrives. The main drawback here is the contract is blocked potentially for a long amount of time. Potentially in this case contracts cannot batch multiple async calls and their execution would stop after the first one.
only expose a very low-level async interface and let contract developers to decide whether the contract should be in a locked state after a certain async call or not. By this I mean the contract can just set a locked flag in its regular storage - no need for any additional specific feature provided by the VM.
ewasm background
The current ewasm design is only considering synchronous execution within a single address space. It also makes heavy use of wasm's imports and exports to do effective FFI.
Methods for retrieving external data exists in the form of
calldata
andreturndata
. Additionally current contract's code and any contract's code can be retrieved. All these in practice access a buffer and it may make more sense to abstract buffers away to reduce the number of methods listed here. See #181 for more detail.Execution starts with the
main()
function which receives no arguments.async on ewasm
As we can see in order to accomplish this we need to introduce two features:
issuing calls
The simplest approach for issuing calls is to follow what ewasm does with synch calls. It has a
call(gasLimit, address, value, data) -> result_code
method exposed to contracts.Proposal:
callShard(gasLimit, shard_number, address, data)
receiving answers
The simplest way is to expose a new exported method, for example
fromShard(shard_number, sender, data)
some questions
main()
or have two more consistently named exports:fromRemoteShard()
andfromCurrentShard()
callShard
and the same returned byfromShard
so that the contract can account for the transaction if it wishes soresult
flag infromShard
?async on ewasm v2
If execution speed (aka the overhead of imported methods in wasm) is not an object, one of the more cleaner approaches would be the following.
Define a
request
object. It has a request kind/flags (read-only or read-write), origin shard, origin address, destination shard, destination address and a data buffer.Define a
response
object. It has a flag forstatus
, origin shard, origin address and a data buffer. It also has a reference to therequest
object.Execution of a contract starts with
main(response)
which has a reference to the response object. Thestatus
field would indicate whether this is an external user-submitted transaction or a successful or failing async response.To make calls two primitives exists:
callSync(request) -> response
andcallAsync(request)
.Alternative proposal:
call(request)
andcallResult(request) -> response
.Note, this design may resemble Primea as it is a logical step in abstractions. This design also strongly depends on the success of "contract-linking" or code-merklization which would eliminate the need for the workaround of
delegatecall
to achieve libraries and code-deduplication.The text was updated successfully, but these errors were encountered: