Menu

Blogchain

A blog about Blockchain technology

Distributed Transactions on Blockchain

In my previous article about Event Sourcing and CQRS in Blockchain Transactions (blogchain.space/entries/blockchain/event-sourcing-and-cqrs-in-blockchain-transactions) we have learned that a shared data model is not the only use case that can introduce tight coupling between smart contracts. Another important threat is workflows. A lot of real-life processes cannot be represented with a single, atomic operation. With such workflows, the result only makes sense if all the steps can be executed. If any step in the sequence fails, the resulting state of the relevant system become invalid. In the RDBMS world, such processes are called “transactions.” Database transactions are typically local, contained within the confines of a single database, and rely on locks on tables before updates. If a step fails, you can roll back the steps already attempted before a final commit.

Distributed Transactions
For distributed workflows and stateless microservices, a traditional transaction implementation with data locks and ACID (Atomicity, Consistency, Isolation, Durability) compliance (wikipedia.org/wiki/ACID) is impractical. Sagas (microservices.io/patterns/data/saga.html) are long-lived distributed transactions that allow running workflows in loosely coupled environments, without making any assumption of the reliability of each component of the complex system.
In sagas, every step in the workflow executes its portion of the work, registers a call back to a compensating transaction in a message called “routing slip”, and passes the updated message down the activity chain. If any step downstream fails, that step looks at the routing slip and invokes the most recent step’s compensating transaction, passing back the routing slip. The previous step does the same thing, calling its predecessor's compensating transaction and so on until all already executed transactions are compensated. This pattern leads to eventual consistency of data in a distributed transaction (baeldung.com/transactions-across-microservices). Due to its highly fault-tolerant, distributed nature, sagas are very well suited to a microservice architecture as well as to blockchain smart contracts.

 

Fallback Functions
You can implement a sort of routing slip via fallback functions in Solidity. A fallback function is an unnamed function defined with no input argument and no return value. It’s executed on a call to the contract if none of the other functions match the given function identifier or whenever the contract receives Ether (in the case of Ethereum). Additionally, in order to receive Ether, the fallback function must be marked payable. If no such function exists, the contract cannot receive Ether through regular (address to address) transactions. 
It’s worth mentioning that a contract without a payable fallback function can receive Ether as a recipient of a coinbase transaction, such as a miner block reward. A contract cannot react to such Ether transfers and thus also cannot reject them. This is a design choice of Ethereum, and Solidity cannot work around it. A contract can have exactly one unnamed function, as shown here:


// Fallback function
function() public payable {
    emit AmountTransfered(msg.sender);
}

event AmountTransfered(address sender);

In Ethereum, fallback functions are necessary for a smart contract to allow account-to-account direct transfers. This is because the transferring account may need to make transfers to both Externally-Owned Accounts (EOAs) and to other smart contracts. As EOAs can only accept direct transfers, the transferring account can use solely this way for value transfers. This means that any contract that wants to accept such transfers must be prepared for direct transfers by having a fallback function. Without that function, the transfer would fail, and it would be impossible for the contract to accept Ether from the other contract.
A best practice is to not have any logic in the fallback function. It’s possible to put code in the body of this function, but it’s best to avoid anything beyond very short, simple logging. The reason is important and unique to smart contracts: you don’t want this function to fail because it runs out of gas. As a rule of thumb, you’ll have just enough gas to raise an event, but not enough to write data to storage.

Go Back

Comment