Conversation
joshuahannan
left a comment
There was a problem hiding this comment.
Well thought out and well written. I just have a few questions and comments
|
|
||
| ```go | ||
| type EVMScheduler interface { | ||
|
|
There was a problem hiding this comment.
Is getStatus included here or is that just querying the status on the EVM side?
There was a problem hiding this comment.
We can just use the EVM side to query. This way we could even introduce failed status.
| Scheduling involves coordination between all the above components and should be initiated from EOA using the EVM Scheduler proxy Solidity contract. | ||
|
|
||
| 1. **EOA** | ||
| 1. Submits an EVM transaction that calls the EVM Scheduler Proxy with all required arguments as well as the amount needed to pay for execution. |
There was a problem hiding this comment.
Maybe add a first step here for EOA having to deploy a contract that contains the logic to execute for the scheduled transaction
| 1. Submits an EVM transaction that calls the EVM Scheduler Proxy with all required arguments as well as the amount needed to pay for execution. | ||
| 2. **Solidity EVM Scheduler Proxy** | ||
| 1. The EVM Scheduler Proxy receives a scheduling request in Solidity with all arguments (handler address, data, priority, timestamp, gas limit). It stores the arguments internally and it also records the sender as the owner of the transaction data. | ||
| 2. If provided funds are sufficient, it forwards them to the EVM Scheduler COA. |
There was a problem hiding this comment.
How are we determining if the provided funds are sufficient? Is there a standard transaction fee calculation for a provided execution effort for Solidity? Are we taking the data storage into account?
There was a problem hiding this comment.
It checks in the contract, so not standard fee, but additional check for the msg.value
| 1. The schedule function is invoked, which internally stores the gas limit. | ||
| 2. It withdraws the funds from EVM to a vault it will use to schedule with Flow transaction scheduler. | ||
| 3. If the funds were successfully withdrawn, it calls the Transaction Scheduler schedule function and provides the funds, priority, effort limit (converted from gas limit), and timestamp. For the handler, it provides its own function. It doesn’t forward any other EVM data. | ||
| 4. It records the scheduled transaction ID it received from the Transaction scheduler contract. |
There was a problem hiding this comment.
What does it do with the ScheduledTransaction resource? does it store it or destroy it? It might be good to keep it until the transaction is executed. The storage would need to be paid for though
There was a problem hiding this comment.
Hm, I was thinking to destroy it since there's no use of keeping it, unless you think of something.
|
|
||
| # Alternatives | ||
|
|
||
| There were multiple alternatives considered, some of which proved to be unviable, most elegant ones due to limitation of Cadence Arch authorization mechanism. The Cadence Arch is a precompile that must follow the [EVM precompile interface](https://github.com/ethereum/go-ethereum/blob/1487a8577d1566497e161a04f8cee3204d4b3d36/core/vm/contracts.go#L52) and unless we fork the EVM we can not introduce more arguments to it. Forking of EVM is not acceptable at this point. |
There was a problem hiding this comment.
ah this makes sense. I think it may be possible without forking EVM (as Call will precede with transfer from msg.sender only issue maybe delegatecall there but I don't think it is too important in this context )
There was a problem hiding this comment.
What do you mean? can you elaborate
There was a problem hiding this comment.
Now every call in EVM side is basically Transfer + Call ( Transfer is the part sending the msg.value ) [0]
This Transfer part is something we can hook into [1] with TransferFunc func(StateDB, common.Address, common.Address, *uint256.Int)
Here we can find out caller ( which is msg.sender )
Now imagine let's say we saved the last caller in somewhere ( blockview, config etc ) then when we are injecting precompiles [2] we can inject that into precompile function. [3]
something like:
return MultiFunctionPrecompiledContract(
address,
[]Function{
&flowBlockHeight{heightProvider},
&proofVerifier{proofVer},
&randomnessSource{randomSourceProvider},
&revertibleRandom{revertibleRandomGenerator},
&scheduleThingy{lastSenderGetter}.
},
)
So technically precompiles can access the caller without forking EVM probably.
There was a problem hiding this comment.
I see what you mean. This approach can work. The only concern I have with it is I guess we would have to copy and modify the TransferFunc which is very critical function that should always be kept exactly in sync with the latest implementation.
I have to think a bit about this approach, but it could potentially unlock more context on the cadence arch. But I need to think about security of it more, since it's quite hacky.
There was a problem hiding this comment.
you can still call from gethCall, basically it will be something like this:
func(sb StateDB, caller common.Address, to common.Address, amount *uint256.Int){
// save caller
xxx.lastCaller = caller
// call original impl.
gethCore.Transfer(sb, caller, to, amount)
}yeah it is kinda hacky, I was using this to hook into transfers when I was developing tinyAN, just recalled from there.
|
very nice work, I think this will be very useful. |
Co-authored-by: Joshua Hannan <joshua.hannan@flowfoundation.org>
Co-authored-by: Dieter Shirley <dete@dapperlabs.com>
Thank you, great feedback. |
Issue: #348