-
Notifications
You must be signed in to change notification settings - Fork 138
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
Native EVM #106
Native EVM #106
Conversation
Your Render PR Server URL is https://nomicon-pr-106.onrender.com. Follow its progress at https://dashboard.render.com/static/srv-bsr6240ti7j8bfe99upg. |
Overall, it's a bad idea to have precompile as is:
|
@ilblackdragon Did you consider transpiling EVM bytecode to WASM? This should provide significantly better performance than having an EVM interpreter in WASM. An even better solution is to compile Solidity directly to WASM. This will allow more efficient arithmetic for types smaller than 256 bits, more efficient storage layout, and possibly other optimizations. But this is more difficult than transpiling EVM bytecode. How do you plan to implement sync transactions on a sharded blockchain? |
There are two problems with what you are suggesting @abacabadabacaba:
RE: @evgenykuzyakov I'm not suggesting we literally dump near-evm into nearcore.
This approach allows to have as many as one wants of EVM contracts. We just need a way to create accounts with this hash.
Updates are easier than currently. If near-evm as a contract has issues, we don't really have a way to upgrade it. But if it's pre-compiled we can fix things inside nearcore and release a new version.
For example?
What would be a different way? This is similar how Ethereum does it, but I'm open for alternative. |
Example of a bug: near/near-evm#46 |
@ilblackdragon What are the use cases of such a feature? If we only have isolated "EVM environments" which behave like an Ethereum instance, this doesn't seem very useful. In general, while it seems desirable to able to make Ethereum contracts usable on NEAR, there is probably no good way to do it. The main issue is the lack of synchronous calls (there are other issues, such as differences in addressing). While there are ways to work around this, they all have serious problems:
Both approaches may introduce security vulnerabilities into contracts. So, a contract that is secure on Ethereum may be vulnerable when run on NEAR. Trying to make as many contracts as possible run on NEAR without any changes will encourage developers to run their existing contracts on NEAR without performing a separate security review, which may have devastating consequences. Also, I am very much against introducing "precompiled contracts" into NEAR. Any functionality built into the node should be exposed as host functions. I am also against building Ethereum into NEAR. Every time there is an Ethereum hard fork, would we need to hard fork NEAR as well? |
Btw @evgenykuzyakov a reason to make EVM precompile vs having a custom tx actions is to later be able to yank it back out into a smart contract land with a simple protocol upgrade. @abacabadabacaba we have dozens of partners who would launch immediately in am EVM environment like described in this proposal (we are currently testing the experience and everything with a smart contract based EVM). To be clear, this is not Ethereum on NEAR. This is EVM environment on NEAR. |
@abacabadabacaba specifically of the two options you outlined, the current approach is the first: the contracts within the environment have full interop, and if you want to "escape" the environment, you use some sort of a bridge. |
One concern to think through is the storage costs. |
Currently, I see three major problems with this proposal:
|
Async-Sync Interoperability
Here is how it would work: Calling NEAR contract from EVM contractSuppose EVM contract wants to call NEAR contract on import "../NearContract.sol";
contract MyEVMContract {
function callNearContract() public {
NearContract contract = NearContract.from("near.dex01");
contract.call("near.method01", "near.args01");
}
} This will schedule an asynchronous call to the NEAR contract that will be done asynchronously after EVM contract is finished. Calling NEAR contract from EVM contract with callbackSuppose we want the same EVM contract (or other EVM contract) to be able to receive the callback from NEAR contract when it is done. import "../NearContract.sol";
contract MyEVMContract {
function callNearContract() public {
NearContract contract = NearContract.from("near.dex01");
contract.callWithEVMCallback("near.method01", "near.args01", address(this), "evmMethod02", "evm.args02");
}
function evmMethod02(bytes memory args, bytes memory callbackArgs) public {
}
} Similarly we can have Calling EVM contract from NEAR contractNEAR contract call API will look exactly the same, except it would require providing address of EVM and address inside EVM. Regular low-level Rust API: env::promise_create("near_contract", b"set_status", b"args_blob", balance, gas); EVM low-level Rust API: env::promise_create("evm_address", "evm_contract_address", b"set_status", b"args_blob", gas); Regular high-level Rust API: ext_status_message::set_status(message, &"near_contract", balance, gas); EVM high-level Rust API: ext_status_message::set_status(message, &"evm_address", &"evm_contract_address", gas); Callbacks and other features of our promises will work out of the box. Multiple EVMsWe can easily allow unlimited number of EVMs, so that once we have sharding these EVMs can even work with each other using the above described API. This will make NEAR and actual Ethereum 2.0! Specifically we hardcode that contract bytes Runtime execution exampleSuppose some NEAR contract does the following call: ext_status_message::set_status(message, &"evm_address", &"evm_contract_address", gas);
EVM calling another EVM with callbackSuppose we want to call one EVM from another EVM (potentially on different shards) and even get a callback! Contract on the first EVM: import "../ShardedEVM.sol";
contract Contract1 {
function doSomething() public {
ShardedEVM other = ShardedEVM.from("another_evm_address");
other.callWithEVMCallback("evmMethod01", "evm.args01", address(this), "callbackMethod", "evm.args02");
}
function callbackMethod(bytes memory args, bytes memory callbackArgs) public {
}
} Contract on the second EVM: contract Contract2 {
function evmMethod01(bytes memory args) public {
}
} Potentially, we don't even need to operate with untyped args |
While EVM contracts will not have good standards for interacting with other EVMs or NEAR contracts, it is fully possible, just dangerous, and people should not be using complex interops for DeFi applications. Only simple interops, like burn this ERC20 token and mint some NEP21 token, we have already established an even more complex interop with Rainbow bridge.
This logic shouldn't be hard to hide behind near-sdk-rs and some Solidity library. Additional information in the receipts (like who is sender from within EVM) should be sufficient for establish safe links between sharded ERC20 contracts or between ERC20 and NEP21.
@ilblackdragon and @abacabadabacaba The goal is to not have any differences but gas price and the above mentioned In Ethereum allocation of one key pair (32 bytes, 32 bytes) costs 20K ETH gas. Suppose we map So if we map |
If we do this, based on our current limit ethereum contract calls that need more than ~300k eth gas will not be able to fit. Do we want to have separate limiters for evm calls? |
Good point. Some exchanges use 2M ETH gas in a single call, so we won't be able to solve it by increasing the limit. It also means we cannot map |
All of this will require writing EVM smart contracts specifically for NEAR. Wasn't the point of NEAR to switch from unfamiliar languages like Solidity to more efficient and well-known languages like Rust and TypeScript? And even if we want to have Solidity as one of supported languages, isn't it better to compile it to WASM instead of having a wholly separate execution environment? Even Ethereum devs want to switch from EVM to WASM in Ethereum 2.0. They can't do it in Ethereum 1.0 because of smart contracts that are already there. We are going in the opposite direction, adding an inferior execution environment which we will have to maintain for years instead of building something better. |
We need to take into account that there is already an ecosystem that exists around EVM/Solidity, which includes contract writing patterns that are not easy to move away from. It is similar to other existing ecosystems, e.g. many web-devs want to move from JS to other well-known languages, e.g. TypeScript and maybe some of the browsers would want to do it too by introducing Wasm, but they still have to support JS because of the numerous JS libraries, frameworks, and ecosystem as a whole. NEAR is analogous to browsers, and Solidity is analogous to JS. Also, we are attempting two difficult transitions here: from Solidity to Wasm, and from synchronous programs to asynchronous programs. It is very difficult to do both at the same time, e.g. I remember how much of the push back there was when multicore CPUs started appearing and an average developer was super skeptical about learning parallel programming patterns. So if we bank on being able to transition the existing Ethereum ecosystem in both directions simultaneously we might not succeed in transitioning at all.
Writing a compiler of even a relatively simple language to Wasm is not an easy task and would require a separate team. There are many languages that claim to have Wasm support, but realistically we can only consider Rust->Wasm production ready. (and maybe with huge question mark C++->Wasm or AS->Wasm) Also, it is not just about compilation of one language into another language. We want to have 100% spec-compatible EVM support, which means we need to mimic gas counting, and host functions. If we are going to pollute our Wasm runtime with EVM-specific host functions, have EVM-specific gas metering (Wasm gas metering is protocol-level thing) then we are already introducing a new "runtime" and there is little added benefit of running the Solidity code itself with Wasm rather than EVM interpreter.
Whether they are going to switch and how exactly it will look like is very uncertain. |
Today's browsers are horrible. Of monstrous complexity, full of kludges, with new vulnerabilities being found all the time. And only two companies in the world are capable of developing a modern browser. I very much hope that NEAR will never be like a browser.
There is a problem: the EVM Ethereum is using now is not 100% compatible with the EVM Ethereum used a year ago. During that period, it gained two new opcodes and one new precompile, and multiple other opcodes had their gas usage changed. Does it make sense to keep 100% in sync with such a moving target? I think that most contracts don't care how the gas is measured at all, as long as they don't run out of it. |
This is actually the reason why they really care about gas measurement. AFAIK in the past Ethereum has increased some op cost and it broke a bunch of contracts because they relied on specific costs. Many DeFi contracts are notoriously optimized in their gas usage, they optimize to reduce the usage of specific op costs and try to not have loops as much as possible. So if we don't have exact gas metering we will risk some random DeFi contracts not working exactly. Also, it is also a very strong message to say that NEAR EVM is exactly the same as Ethereum EVM. |
For this reason, relying on specific costs is discouraged nowadays.
That's because on Ethereum gas is expensive. They do it to reduce costs, not because changing gas metering will break their contracts. If we count gas differently but provide enough of it to make these contracts work, they will work. Eventually, if the contract authors will want to optimize gas usage on NEAR, they will have to use WASM because it is more efficient. |
To make sure we are on the same page with whether we should go with native EVM:
* We cannot compile EVM into Wasm contract because this contract would be too expensive to run and would not be upgradable (we cannot force contract owners to upgrade their protocols, but we can upgrade the protocol itself);
* We cannot compile Solidity to Wasm because there is no production-ready compiler available that does not require rewriting contracts. And even if there was, we would still need to modify our runtime to add EVM support into receipts, and host functions;
* We have a need to run EVM on our blockchain ASAP.
Based on the above constraints we don’t have a choice but to add native EVM support.
… On Sep 4, 2020, at 12:22 PM, Evgeny Kapun ***@***.***> wrote:
AFAIK in the past Ethereum has increased some op cost and it broke a bunch of contracts because they relied on specific costs.
For this reason, relying on specific costs is discouraged nowadays.
Many DeFi contracts are notoriously optimized in their gas usage, they optimize to reduce the usage of specific op costs and try to not have loops as much as possible.
That's because on Ethereum gas is expensive. They do it to reduce costs, not because changing gas metering will break their contracts. If we count gas differently but provide enough of it to make these contracts work, they will work. Eventually, if the contract authors will want to optimize gas usage on NEAR, they will have to use WASM because it is more efficient.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#106 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AILKVBYM6KMX4KQTRFAN6ATSEE5APANCNFSM4P7KZOMQ>.
|
EcRecover handlingContext: there is a pattern of meta-transactions on Ethereum that leverages next flow:
How will NEAR EVM handle this:
Some Cases that this handles
Notes
|
Also good question if we want to restrict creation of EVM accounts. Current suggestion to add a "registrar" method to EVM, that will create sub-account if
|
nit: this should be |
Open question: how to allow Ethereum meta transactions to propagate to WASM contracts. WASM contracts will require account_ids: signer_id and predecessor_id. Use case:
|
Relevant links to meta transaction discussions in Ethereum:
|
Meta transaction message format Requirements:
Data format complaint with EIP-712:
|
@ilblackdragon I think there is a typo. It should be:
|
Meta Transaction payments: We add an extra
Flow:
DApp specific relayers can decide to not charge anything, and accept Question:
Pros for specifying amount, is that relayer can charge whatever they want. User can decide to sign or not based on the cost. Alternatively protocol ( ConcernsRelayer grieving
I don't think it's a big issue, as user doesn't win anything and 1s blocks prevent doing this really easily as relayer may send their tx faster most of the times. |
I believe proposed ability to natively charge a user in ERC20 (NEP21?) is a good addition. It covers two cases: when the relay is disconnected from the user and needs to be payed; and when it is connected to the user being, e.g., a native relay for a dApp, and the relay incentive is lying outside the blockchain economics (e.g. withdraw fees on exchanges). Proposed approach covers the both cases. I think it's better to specify the relay fee amount. Since we do have a gas cost in $NEAR, but probably don't have it in NEP21. Supporting the payment double spend concern. |
NEP-21 would break atomicity of this action, and also would require to have allowance on the token to do so (because it will be executed out of the context). With ERC-20, because we are controlling EVM runtime from the invocation - we can just call |
Ok, got it with the atomicity. Would note here only that this is all about ERC20 in NEAR EVM. |
@ilblackdragon , there's a suggestion on the meta-transaction fees. There might be many tokens a user wants to trade, and the nomination of fees in these tokens can be complicated. However, all Ethereum users are used to pay for the transactions in Ether. Why don't we introduce nETH in NEAR (this can be done through the Bridge)? A user will have some nETH in NEAR EVM and we the relayer will charge user in nETH for the First option, we introduce in NEAR an oracle that commits ETH <> $NEAR weighted exchange rate. Thoughts? |
Your suggestion is too complicated as oracles on-chain and especially inside the protocol would be very complicated to implement correctly and I think is limiting in functionality, as even in Ethereum many people don't have ether but it's even less likely when they migrate to NEAR to use apps (as moving each asset is extra cost). A much simpler solution is to extend the previous idea and allow relayer to define price for whatever currency user wants and user sign on it. This way relayer calculates their costs, can use whatever price for the token user have and then quote it to user. E.g. this will support charging user nETH, DAI or anything else. So flow between frontend and relayer can be:
Initially, it can be that relayer just supports nETH and can extend the relayer interface later with quoting mechanism. |
Implements near/NEPs#106 - [x] PR for Ethereum chain_id - [x] Return deterministic errors - [x] evm accounts are EVM. - [x] Create sub-account from evm are removed and we don't plan to support it originally. - [x] Integrate gas usage #3299 - [x] Meta transaction calls are currently disabled - <s>Precompile in EVM to call outside to NEAR</s> Moved to separate issue - [x] Protocol version upgrade to 42 from which `evm` accounts activate. - [ ] Add a check that the `evm` account doesn't have access keys. Reviews ---- - [ ] @bowenwang1996 please review changes around genesis/protocol, so we don't leak this feature accidentally. - [ ] @nearmax if you want to take a second look at runtime changes. - [ ] @frol do we need to do something from the RPC/indexer perspective? - [ ] @ilblackdragon In case you want to take a look as well. Test plan ---- * Set of Solidity contracts that can be run inside EVM (see runtime/near-evm-runner/tests/contracts) * Interact with CryptoZombies contract via runtime & RPC test * <s>Nightly test that will leverage full e2e tooling to deploy & test a full fledged contract(s)</s> Moved to separate issue * http://nayduck.eastus.cloudapp.azure.com:3000/#/run/764 * To the moon
Alternative design that leaves the interface the same but cleanly separates the performance critical pieces:
Pros:
Cons:
An open for discussion topic is around covering storage. See https://gov.near.org/t/storage-staking-price/399 more discussion on storage staking in general. Given we haven't had a clear decision before, this actually opens up opportunity to say that transactions to EVM should cover storage increases in it via attached amount. Reducing price of storage might be important piece here to make things indeed cheap. |
Quick update on the experiments around separating part of EVM glue code back into a smart contract:
I've brushed the dust off the EVM contract (https://github.com/near/near-evm). |
Closing because of Aurora. |
Motivation
There are few reasons to support EVM as an alternative virtual machine:
Pre-compile vs contract:
Details
TBD
Stability plan
This should list the plan of tests that ensure stability of this change.
Protocol Upgrade
The protocol upgrade will: