ethereumproject / ECIPs

The Ethereum Classic Improvement Proposal
55 stars 40 forks source link

ECIP-? Atomic Transactions #40

Open splix opened 7 years ago

splix commented 7 years ago

Current transaction execution model lacks of Atomicity for multiple transactions.

An atomic [database] transaction is an indivisible and irreducible series of database operations such that either all occur, or nothing occurs. https://en.wikipedia.org/wiki/Atomicity_(database_systems)

Applied to Ethereum it’s a set of calls to several contracts, when either all of them should be executed or none if error happened at any of the steps.

An example would be transferring token to an exchange, making an exchange operation and transfer new tokens back. This should happen atomically, all or none. If at any of the steps an error will occur, state should be reverted to an initial state before first transaction in this set.

Solution

It’s proposed here to create joint transaction type of transaction, which would be literally joined binary data of several transactions, which should be executed atomically.

nonce and gasPrice fields can be added just once, as well as tx signature details. But gasLimit, to, value and data can be repeated.

[nonce, gasPrice, [[gasLimit, to, value, data], [gasLimit, to, value, data]], v, r, s]

Cons

Hard Fork protocol upgrade, change to both p2p protocol (=consensus) and to RPC API

splix commented 7 years ago

I also had an idea about execution arbitrary code within a transaction. Like "ephemeral contract" executed just once without actual deploy. But this is a completely separate idea, and most probably doesn't provide much benefits besides a small gas economy. I can submit it as a separate ECIP though, if it worth discussion

elaineo commented 7 years ago
ghost commented 7 years ago

Distributed or joined transactions, normally is very heavy structure, we need to find very important usecase before we will start thinking about it. What about state machine logic in smart contract, perhaps there are more cheaper alternatives?

splix commented 7 years ago

@elaineo only from account. it's a change to a serialization format of a transaction. an it doesn't affect contract excution

splix commented 7 years ago

@dulanov transactions are serialized into RLP, which already supports arrays. Currently it's [nonce, gasPrice, gasLimit, to, value, data, v, r, s] we add an additional structure [nonce, gasPrice, [[gasLimit, to, value, data], [gasLimit, to, value, data]], v, r, s]

arvicco commented 7 years ago

With guaranteed atomicity, looks like it would be trivial to arrange trustless crypto-asset swaps at a protocol level.

avtarsehra commented 7 years ago

@splix this is interesting. But would this make previous contracts deployed incompatible with this change?

@arvicco It seems in this case the "From" address will always be the sending account, so while the "To" addresses can be different, at most it seems you can send ether to multiple addresses. I guess you could use one array to send ether to that address and the other array to represent some asset flow in the Data field. But still would not be real DVP like in Bitcoin, where you can have multiple inputs (with separate signatures) and multiple outputs with an Op_Return.

Playing devils advocate. Would be interesting to first assess the real benefits of this, in terms of real use-cases, as why couldn't you just send two transactions rather than doing this or using a smart contract? I guess saving time and simplicity would be one reason.

arvicco commented 7 years ago

Ah, I stand corrected. Real use case of tx atomicity would be to have trustless multi-party transactions, imho.

splix commented 7 years ago

@avtarsehra it touches only transaction serialization in blockchain and p2p, so it shouldn't affect existing contracts

Regarding "From" fields. That's interesting moment, if we allow to have different From per subtx it will be much more flexible. It can be following:

[ 
  [nonce, gasPrice, gasLimit, to, value, data, v, r, s], 
  [nonce, gasPrice, gasLimit, to, value, data, v, r, s]
] 

So you''' be able to make atomic operations like A -> B, C -> B, B -> E

With two different transaction the problem that 1) you have to wait transaction mined into a block and validate state before sending second. so operation spread across multiple blocks. 2) or you create a contract, deploy it, execute, delete. several transactions again

Dexaran commented 7 years ago

@splix the problem you are trying to solve is already solved. I solved the same problem developing ERC23 token. You can send ERC23 token to exchange contract, exchange token1 to token2, receive token2, deliver token1 to order owner where you bought token2 with a single transaction. There is no need to change protocol to solve theis problem while it is already solved. Here is my ERC23 token proposal:https://github.com/ethereumproject/ECIPs/pull/36 Here is an example of _data payload realization: https://github.com/Dexaran/dataPayload If you want me to write described exchange contract I can do.

Dexaran commented 7 years ago

I wrote the described exchange. You can browse it here: https://github.com/Dexaran/dataPayload/tree/master/PayloadExchange_example This is a single-exchange-transaction you are looking for: https://testnet.etherscan.io/tx/0xf41529fb61de85a3e1ea45682f285ce7e23ea0c9f5283c392a4ca445eb14c92b

There is also a way to do so without bytes _data attached to token transaction. The only thing that is really needed is fallback function to handle incoming transactions.

splix commented 7 years ago

@Dexaran exchange was just a particular problem we have discussed recently, so i've added it as an example. This ECIP not for Exchanges, it can be used in many different scenarios. Maybe it's not clear, but this joint transaction can have more that two transactions, 2 was used just for example. 2..n in general

Dexaran commented 7 years ago

@splix I understand it but there is already a possible way of interaction between contracts. Can you name any scenarios that need such changes in protocol and can't be executed without it?

splix commented 7 years ago

@Dexaran the advantage that you don't need to deploy a contract for such one-time execution (gas economy, data efficiency and simplicity). When user need to execute same series of operations many times, it worth to implement a special contract for that.

splix commented 7 years ago

My use case was some kind of "optimistic locking" contract, when group of users have a shared contract, and they are safe to execute their own independent operations with using this shared contract as a lock.

execute X when Y have value 1, then set Y to 2

Which makes 3 transactions:

  1. Y.expect(1) - validate that contract Y have 1, will throw error if not 1
  2. X.executeSomething() - execute X, it can throw error
  3. Y.set(2) - set Y to 2

See https://en.wikipedia.org/wiki/Optimistic_concurrency_control

splix commented 7 years ago

"locking" can be executed with a new contract too, actually nearly everything can be implemented as a smart contract. But it seems to be a common pattern of execution, it can be applied in many areas, and it maybe worth it to move it to transaction layer

Dexaran commented 7 years ago

@splix can you describe your proposal more detailed? I'd like to see any code or something that I can execute and try to fully understand how will it work. Or even detailed description.

I think that receiver of joint transaction must know if the transaction is joint or single. And what about this scheme: A executes B and C in joint transaction. C is a contract that is invoking B. So B will be locked if C is changing its content and this kind of transaction will fail in any cases?

nmushegian commented 7 years ago

You can write the general case into a singleton contract anyone can use:

composeActions(code, data) {
    deploy(code).delegatecall(data)
}

Now write your atomic sequence in solidity

dapp1.doThis();
dapp2.doThat();
assert( something(arg) );

will be publicizing solution at github.com/dapphub/ds-proxy when it is usable

splix commented 7 years ago

@Dexaran yes, maybe it's useful for contract to know if it's executed from joint transactions, but I didn't have any plans to add a new OP for that. can be considered later.

Nothing gets locked. It's same as with standard transactions, executed one by one not in parallel.

Atomic transactions:

splix commented 7 years ago

@nmushegian right, you can always write a contract, if you need that more than once. This is proposed for one-time execution, for an arbitrary series of calls. Deploy a contract, executing it, and removing it becomes too expensive and complicated for an operation executed just once.

On other hand, I see that a good Wallet can automate that process for a user, i.e deploying a simple one-time contract for certain operations.

splix commented 7 years ago

Smart contract are much more powerful technology, it includes "atomicity" and any other logic a developer would implement in it, and this proposal doesn't replace smart contracts.

I proposing this as a "nice to have" feature, for a discussion. Maybe we need it, maybe not.

Dexaran commented 7 years ago

@splix finaly I found this feature useful. It is a good idea but I'm not sure we need to change protocol to implement it.

sorpaas commented 7 years ago

I think this is somewhat related to https://github.com/ethereum/EIPs/issues/86 and https://github.com/ethereum/EIPs/pull/208. If transaction fields can be abstracted to dataload, then it is possible to create a single contract, and just call that contract simply with multiple of the transaction dataload for all atomic transaction execution.