Tradeoffs in Account Abstraction Proposals

they may be able to run the byte code of each contract through semantic execution (like KEVM).

This would add more computation cost for validating a tx, so is there an incentive for nonmining nodes to do this?

The scheme I propose (with PANIC) has a 200000 gas limit for this, which is still a fairly low bound. Currently, the pre-gas-payment verification process is an ECDSA signature plus reading two balances, which is equivalent to ~3800 gas, so 200k would be higher, but it’s not insurmountable. We could even restrict to a lower amount initially.

Added one more item above:

Combine PANIC and PAYGAS

  • How it works: remove PANIC. Instead, have all exceptions have behavior equivalent to PANIC if PAYGAS has not yet been called.
  • Pros: allows accounts to set their own base verification gas limit. A miner can run the algorithm of running the code for up to N gas, where N is chosen by the miner, until PAYGAS has been called. Also, removes the need for gasprice to be part of the transaction body.
  • Cons: makes the output state of a message slightly more complicated, as it also needs to carry the information of whether or not a PAYGAS opcode was triggered and if so with what gasprice.

An interesting thing to consider is to give callers an option to provide a unique PoW for each transaction.

In this case PANICLIMIT would be linearly proportional to the PoW complexity submitted by the caller.
Each miner would publish “PoW PANICLIMIT price” in the same way they now advertise gas price.

This could work as an option - there would be a standard small PANICLIMIT, and then to extend PANICLIMIT you would pay linearly with PoW. In this way, one could make the standard PANICLIMIT way smaller (say 10,000), and then if a caller would want a larger limit, she would need to do PoW - this would work as a way to discourage callers from putting too much validation load on miners. A miner would first check the PoW and then do the rest of the validation according to the specific PANICLIMIT value corresponding to the PoW submitted. If the miner decides that it is overloaded, it could raise the “PoW price”.

3 Likes

Very interesting!

Technically this could all be done extra-protocol; miners would specify a PoW algo, and a threshold (that could go up linearly with PANICLIMIT), and transaction senders could figure it out.

1 Like

The “nonce abstraction” was one of the most problematic aspects of the original EIP-86:

Here non-unique tx hashes are listed as a Con, though it was argued before to be a feature.

One interesting use case that could be enabled by a new nonce scheme and tx format is the ability to re-sign a tx with a different gas price, but get the same tx hash. This use case brings to light that there are actually two ways the “tx hash” is currently used: one as a “tx id” for nodes to broadcast and share their pending tx inventory, and the other as the “tx hash” to uniquely identify whether or not a tx has been included in the chain. For this use case, two tx’s with different gas prices would have different pending tx id’s, but the same tx hash.

1 Like

If we want to have unique tx hashes, then we can always not abstract the nonce checking and incrementing part. Any of the abstraction proposals listed here are friendly to that; all you’d need to do is add that stuff back to the apply_transaction function.

As mentioned, with the various PAYGAS proposals it is impossible to pay with anything but Ether. Another limitation is that the first contract has to pay for the gas, so chained validation contracts are more difficult to build (although I’m not sure how relevant this is). I thought a bit about this and realized that we can get both features by the backdoor via a pay-but-refund mechanism, without any additional protocol changes. The general process could work as follows:

  • “entry contract” (i.e. the first called contract) pays for gas
  • entry contract measures gas usage (via two GAS calls)
  • entry contract makes sure that gas is paid in another way (by another contract or with another token)
  • entry contract asks for a refund of the paid gas
  • refunding contract checks eligibility and refunds

As an example, consider a validation contract A that authenticates a user and another contract B that pays for some of A’s transactions (e.g. to a specific third contract, but rate limited to 5 transactions per day for a certain set of users). B expects to be called by A and trusts A to behave faithfully as it has checked the contract code against some template. After the main call, A calls B’s method refund_gas(gas_used) which pays gas_used * GASPRICE to A. So if everything works fine (and the calculation of gas_used is exact), A will have the same balance before and after the transaction and effectively B has paid for the gas. If the transaction fails though, A will not get refunded. This shouldn’t be too much of an issue though as the user should be able to ensure that the transaction won’t fail. To be even more safe A could assert some conditions before the PAYGAS call.

As a second example, consider a miner who wants to be paid in GTK (gas tokens) instead of Ether. He sets up a refund contract that defines a token type (GTK) and an exchange rate (GTK per unit of gas). He accepts only transactions with Ether gas prices of, say, 10 times his minimum gas price in GTK. When the user sends a transaction to an entry contract that wants to pay in GTK, it first asserts that the coinbase is a refund contract and that the GTK-gasprice is acceptable. Next, it PAYsGAS and makes the main call, measuring actual gas usage. Finally, it pays a second time for the gas, but now extra-protocol and in GTK, at the gas price defined in the refund contract. Then, it asks the refund contract to pay gas_used * GASPRICE. The refund contract checks that it trusts the contract (by comparing the contract code against a template) and that the correct amount of GTK has been paid earlier and refunds the Ether.

In the second example, the miner is in fact affected by a failing transaction: He’s paid in Ether instead of GTK. But this is mitigated by a much larger gas price, so that he’s happy in both cases. Again, the sender doesn’t like this, but he can ensure that his transaction won’t fail.

The main problem I’d be concerned about with these kinds of designs is that there are real complexity tradeoffs with making gas payment be function calls, and requiring multiple pieces of contract code to be involved, and in general I don’t think the costs of making it relatively easy to pay gas with ETH only are that high (after all, ETH has been marketed as “the currency for transaction fee payment”). So I personally am inclined not to go this far, at least for v1.

I agree that it is quite complex and that there’s not really a need justifying it (at least today, things might change if (more-)stable coins become reliable). So I’m not advocating to actually implement it. The nice thing about this is though that it doesn’t require protocol changes, it’s merely an illustration of what’s possible with account abstraction.

Ownership model is another alternative. In this model there is gas, but you do not buy it. Instead of paying gas for each transaction, you say that long term ETH ownership entitles a user to a certain average gas per month. Computational limits become soft instead of hard. If you are doing too many transactions, the priority of your transactions goes down.

You then do not need to have any instructions like PAYGAS and you do not need to go buy ETH all the time - you buy it once and forever.

I really need to make a detailed post about why things like this are a bad idea. I know that the DPOS crowd seems to be hyping this approach a lot recently because it makes transactions look free™ (never mind that you’re still paying, you’re just paying capital lockup cost instead of directly, and you’d have to pay in advance for expected future usage so most users would overpay), but the problem is that this screws around with incentives. In any environment where blocks are full, miners or whatever other block proposers have to choose between what transactions they accept, and it’s the game-theoretic equilibrium for them to accept bribes in exchange for doing this. If an “officially sanctioned” mechanism to make this bribe (ie. the txfee) does not exist, then it would happen through side channels (eg. think services like http://confirmtx.com/, plus corporations having private agreements with each other).

Also, it fails at its intended goal, because you still need an opcode that determines when a transaction has passed basic verification; otherwise, attackers will be able to send transactions that burn any user’s gas reserve.

1 Like

I’d like to add a vote for allowing nonceless (or at least parallelizable nonce) schemes. Requiring strictly-incrementing nonces has been a real-world stumbling block for me in dapp development. (Specifically in the context of signing offline transactions without an easy way to check the current nonce or guarantee all transactions get executed.)

If we need unique TX IDs, then requiring some sort of unique salt is fine, I’d just prefer it weren’t strictly incrementing nonces.

A unique salt requirement is not possible because that would impose O(N) state requirements per account. But otherwise thanks for the feedback :slight_smile:

1 Like

I had once an idea concerning the topic of account abstraction but I do not know if it holds especially in respect to financial incentives.

Instead of burden the miner/validator to check somehow if he gets payed, lets delegate that to a third party.
Lets have special validation contracts, which are just contracts that are marked to be used for validation and gas payment.
If a transaction is sendt to such a contract, the gas is paid from that contract. Now the developer, respective the deployer or provider of the ETH of that contract is responsible to ensure that he gets repaid by the execution. To prevent Attacks depleting the contract, such a contract should have a minimal amount of gas which if an exception is thrown before that much is used, then no gas is charged.
This allows the contract to verify signatures etc. with that gas or in case of a more expensive verification scheme ensures that he gets repaid even if the long verification fails by requesting a deposit for the verification upfront.

Some opcode like PAYGAS would still be necessary, to allow contracts that request no more gas than actually used.

It could work if the “salt/nonce space” is sufficiently small. Let’s say we require nonces between 0 and 100 (acceptable nonces have to somewhere in this range, possibly out of order, but never used in the past). The nonce space could be shifted to higher numbers automatically when too many nonces are used up or by special clearing transactions (e.g. nonce == max_nonce). Would something like this work for your example, @PeterBorah?

Unless in some cases you have a fully asynchronous and masterless consensus algorithm like atomic broadcast, where everyone proposes … In this case,
it may be possible to have a broadcast protocol that satiisfies a certain condition (such as choosing the highest priority block out of proposed blocks) nomatter what a particular node is trying to do …