-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
New Opcode ASYNC_CALL #118
Comments
+1 Nice approach. |
I think this is a fairly clean change. I was just imagining doing this at the solidity level, but more cleanly makes for a nice opcode. Worth note that this does not handle the case of re-entrancy when you need a return value from the call A couple things that should be explicitly stated in the async case:
seems like the change in computational cost is minimal. you get to free up some memory bc the call stack is empty but we dont set the gasfee of CALL's by stack depth anyways. gas price should be approximately the same as a standard CALL
since the params are different I think it will be easiest to just define a new opcode when we're ready for cross-shard comms curious if theres a way to modify this without muddying it up such that you can get return values as well async.series([
doX,
doY,
], getResults) |
Yeah I really want to build up to being able to do something like this. I image async call going into a queue (FIFO). So if contract A was running and contract B & C both made async calls to it there would be 2 message in contract A's message queue. In this proposal once A is done running the next message in the queue is ran. Now to facilitate callbacks we could give the contract access to the queue. So instead of the kernel shifting the queue the contract it self could do it. I image something like
It would need one extra parameter but it would essentially work the same. Ideally there won't be explicit shards. Just ports that contract sends message throught that allow it to communicate to sub-contracts or parent contracts.
I think you right but If we introduce a concurrency model (add that has to happen with sharding at some level) the difference will grow
yep they will remain the same. |
all the more reason to let the cross-shard async call just be a different opcode and not worry about defining that now |
yep, lets cross that bridge when we get there. But where I'm coming from, all shards are invisible to the contract. |
Sorry, I am rather ignorant about the low-level details of the EVM's opcodes and execution model, but over in the solidity github I was wondering whether the message-passing Actor model from Erlang (and/or the improved Agent model from Clojure), could solve all of the reentrancy issues. After chatting in the solidity gitter I got the impression that it can. So my question is whether this info is at all relevant or useful or related to (in any way) to the creation of such an |
I'm not inherently opposed to this, if it's useful, but I don't think it's hard to get the requested functionality with the existing opcodes. There is nothing saying that you must make an EVM call at the moment your high-level language has the word |
@PeterBorah you can almost get the same functionality as current. But if you build the queue inside the contract the gas costs will be off since the first call to the contract will have to pay for the anyother calls that may be in the queue. Likewise if we had strictly actor model approach you could accomplish the multiple instance writing to the same storage by breaking storage off into a contract it self. So its more about "what is the sanest default" I would like to try to argue here that a singleton/actor model for contracts make more sense. Using only async calls contracts would act like a singleton instances. @taoeffect yes exactly this is the first step needed to move fully to a actor model/ singleton instance for contracts |
I don't think I understand the distinction you're trying to draw. In the current model, each call pays for itself and any subcalls it creates. I believe that the same will be true in an async model, except that in the async model all the calls are bunched at the end rather being interspersed throughout the code. Can you give me an example where the gas would be different? |
@PeterBorah lets walk through an example and see if we can figure out there is a misunderstand in either of our knowledge.
Now how would you duplicate that functionality currently? I have several answers in mind but I'm curious what you will come up with. |
That's not how I understood the original suggestion. Given this line:
I would expect it to go like this:
(etc.) That's how it will work if we're just moving execution of calls to the end of the parent execution. And if you model that in the normal EVM, the gas semantics will be the same, since you're still making the calls from the right context, just at a different time. If instead all calls are going into a global FIFO queue, then you need all contracts to be aware of that queue. Modeled on the current EVM, that would look like:
This does indeed have different gas semantics, since calls don't need to pay for their subcalls. You could model the old semantics by having the queue contract keep track of the tree of calls, and refuse to pass more gas than its parent had available. |
In the pure actor model each actor has a FIFO queue which allows multiple writers and one reader. So contract A sends a message to contract B and it goes on contract B's queue and A keeps running. Eventually A's message gets to B and B runs. B can asynchronously send messages to A and keep on running itself. I haven't thought about a global queue, though it seems it would be a bottleneck. I haven't thought about gas. I have wondered about synchronous calls, which I think require a second, higher priority queue to (mostly) maintain present semantics for present calls. @wanderer @PeterBorah |
Yep that is almost correct... There are a few edges cases when putting all the calls at the end.
One of the additional goals here is to eventually move to a concurrent model, then
For now |
So here is a possible Actor model for ASYNC_CALL as I see it right now.
This model ensures that contract calls within transactions remain distinct from messages in the Actor model, and since calls already occur only within transactions the other restrictions on Actors come for free. No call for receiving messages is needed - this is simply the entry point of the contract. Note that the current CALL opcodes allow for recursion. The #116, #117, and #119 proposals aim to prevent some of the dangers this implies. |
Some background I dug up on the Actor Model. A few references:
As the third paper puts it: (broken into bullet points by me)
Assuming a new behavior can be as simple as storing a value that affects a branch in the next execution of the contract, or as fancy as creating a new contract with generated code and storing its address as the new behavior. |
I'd especially appreciate one of our mathematicians explaining Agha's typed pi calculus for dummies like me. |
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review. |
This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment. |
Update the EIP to the working version from https://github.com/eth-infinitism/account-abstraction/blob/develop/eip/EIPS/eip-4337.md Changes: AA-94 update keccak rules. AA-93 Adding debug RPC APIs for the Bundler to use (ethereum#153) AA 92 simulate execution (ethereum#152) AA 73 unify reputation (ethereum#144) AA-68 rpc calls (ethereum#132) AA-61 rename wallet to account (ethereum#134) AA-69 wallet support for simulation without signing (ethereum#133) AA-70 rename requestId to userOpHash (ethereum#138) AA-67 relax storage rules in opcode banning (ethereum#121) AA-63 remove paymaster stake value from EntryPoint (ethereum#119) AA-51 simpler simulation api, including aggregation AA-60 validate timestamp (ethereum#117) Clarify wallet factory behavior when the wallet already exists (ethereum#118)
Update the EIP to the working version from https://github.com/eth-infinitism/account-abstraction/blob/develop/eip/EIPS/eip-4337.md Changes: AA-94 update keccak rules. AA-93 Adding debug RPC APIs for the Bundler to use (ethereum#153) AA 92 simulate execution (ethereum#152) AA 73 unify reputation (ethereum#144) AA-68 rpc calls (ethereum#132) AA-61 rename wallet to account (ethereum#134) AA-69 wallet support for simulation without signing (ethereum#133) AA-70 rename requestId to userOpHash (ethereum#138) AA-67 relax storage rules in opcode banning (ethereum#121) AA-63 remove paymaster stake value from EntryPoint (ethereum#119) AA-51 simpler simulation api, including aggregation AA-60 validate timestamp (ethereum#117) Clarify wallet factory behavior when the wallet already exists (ethereum#118)
Update the EIP to the working version from https://github.com/eth-infinitism/account-abstraction/blob/develop/eip/EIPS/eip-4337.md Changes: AA-94 update keccak rules. AA-93 Adding debug RPC APIs for the Bundler to use (ethereum#153) AA 92 simulate execution (ethereum#152) AA 73 unify reputation (ethereum#144) AA-68 rpc calls (ethereum#132) AA-61 rename wallet to account (ethereum#134) AA-69 wallet support for simulation without signing (ethereum#133) AA-70 rename requestId to userOpHash (ethereum#138) AA-67 relax storage rules in opcode banning (ethereum#121) AA-63 remove paymaster stake value from EntryPoint (ethereum#119) AA-51 simpler simulation api, including aggregation AA-60 validate timestamp (ethereum#117) Clarify wallet factory behavior when the wallet already exists (ethereum#118)
* Update to latest working version Update the EIP to the working version from https://github.com/eth-infinitism/account-abstraction/blob/develop/eip/EIPS/eip-4337.md Changes: AA-94 update keccak rules. AA-93 Adding debug RPC APIs for the Bundler to use (#153) AA 92 simulate execution (#152) AA 73 unify reputation (#144) AA-68 rpc calls (#132) AA-61 rename wallet to account (#134) AA-69 wallet support for simulation without signing (#133) AA-70 rename requestId to userOpHash (#138) AA-67 relax storage rules in opcode banning (#121) AA-63 remove paymaster stake value from EntryPoint (#119) AA-51 simpler simulation api, including aggregation AA-60 validate timestamp (#117) Clarify wallet factory behavior when the wallet already exists (#118) * lint fixes
DESCRIPTION
If block.number >= METROPOLIS_FORK_BLKNUM, then opcode 0xfa functions equivalently to a CALL, except it takes 6 arguments not including value, and makes an ASYNC calls the child. No Items are PUSHED on to the stack. Normal Calls made after an Async call work as normal.
In the current execution model, async calls are executed after the parent execution is finished. If more than one Async calls (ac₀, ac₁ .... acₙ) happened during a given execution then after the parent execution has stopped then the async calls are ran in the order that they were generated (ac₀, ac₁ .... acₙ).
Here is a Sequence Diagram of the current model
The first instance of A (A₀) Make a call to contract B which then make a call back to A which creates a new instance of A (A₁)
Here is how Async calls would look
Only one instance of A is every created. All calls are run sequential.
In the future we maybe able to loosen the restriction on running calls sequentially. In a Concurrent Model Async calls could run in parallel. It is assumed that contracts running concurrently would be running at the same "speed" (gas Per clock cycles).
REVERTS
Reverting also work that same way as the current model. If the parent execution run out of gas the child async calls will not be executed. (although a future improvement could this restriction optional)
GAS PRICE
The gas price should be half that of CALL (20 gas) since you could view an async call as one half of a sync call.
RATIONALE
By using async calls a contract programmer can guarantees about the state of storage and contract re-entry.
The async call can also be used in the future for cross shard communications. In this scenario async call would have to be modified to accept a port (which parent shard to call). It would work similar to
ETHLOG
except there would be no need for a get log.Last async calls can be used to recall a contract if recursive calling is disable (in an actor model where contracts are actors or It can also be thought of as contracts being singleton instances). See here
REFERENCES
ALTERNATIVES
The text was updated successfully, but these errors were encountered: