Smart contracts are attractive, as they appear easier to understand than many blockchain technologies, which often look like advanced voodoo. Smart contracts, on the other hand, seem to be small programmes.
We forget that smart contracts on a blockchain are not equivalent to computer code in a virtual machine. They’re executed as a side effect of a distributed ledger’s consensus process. This brings with it a certain amount of complexity, and complexity always comes with a cost, as the DAO discovered when it failed on Friday the 17th.
The decision on whether or not to use a technology is determined by a cost-benefit trade-off. This is why in Bitcoin, Blockchain & Distributed Ledgers, we pointed out that you need to ask yourself how ‘smart’ your ledger should be. It’s a choice between: not-at-all smart text records; somewhat smart records that use on-ledger services; and quite smart records using off-ledger services.
Proof of Work and Practical Byzantine Fault Tolerance (PBFT) work by requiring all miners to execute a block of smart contract updates in parallel. Proof of Work determines the final state via a lottery among miners. PBFT has miners determine their own result, but to also compare it with their peers to see if they agree.
This means that any off-ledger action is executed by all miners at the same time. Or, more accurately, executed in parallel by all computers deployed by all miners.
Imagine there is a unique ID service off-ledger that you need to use in your smart contract. If you have 100 miners with 10 computers each, then you’ll create 1,000 different IDs. With Proof of Work, only one ID will stick (the others are wasted, which may not be a problem). With PBFT we now have peers who no longer agree, as each miner’s update incorporates a different unique number.
Now consider other possible off-ledger actions, such as submitting a transaction to SWIFT/VISA, multiple times, or booking a parcel pick-up, multiple times.
Simply requesting data from an off-ledger service can easily result in the miners overloading the service with duplicate requests. The nature of the off-ledger service doesn’t matter. It could even be built on another blockchain. If the service can’t distinguish between duplicate requests then it will see them as unique. Even if the service can identify duplicate requests it still needs to review and then discard them, wasting resources.
There are only two possible solutions.
The first is obvious; put all the services on-ledger so that our smart contracts do not depend on off-ledger services. This is the approach used by the vast majority of smart contracts. They can treat the service call as a function call, though this means that the requestor and target service can interact in interesting and possibly unpredictable ways that can create security problems (which was The DAO’s problem). Or they can use the transitions between blocks to isolate the two, though this imposes a severe performance constraint.
The second is to build a proxy for the external service, with the proxy responsible for filtering out duplicate requests.
It gets worse, though.
Proof of Work has poor transactional characteristics. There’s no acknowledgement when you submit a transaction, so the only way to know that a transaction has been accepted is by seeing it appear in the ledger. Blockchain’s indeterministic nature also means the submitter needs to wait for around five blocks to be comfortable that the transaction has stuck.
Consider a proxy that submits a form on behalf of a smart contract.
The proxy can be eager and submit the form when it first receives the request, dropping any subsequent duplicates. Unfortunately, this can enable an attacker to fake requests. Ideally, the proxy should wait until the request appears on the blockchain, as that’s our source of truth. However, due to the indeterminate nature of Proof of Work, the proxy should wait for five blocks. The requesting smart contract will also need to assume five blocks have passed before the action has taken.
The result is that a simple workflow with a few off-chain integrations could need to wait significant amounts of time for each integration to execute.
The reasoning behind the three levels of ‘smartness’ in our report was straightforward.
A ledger only containing text records doesn’t need to pay for complexity required to support smart contracts. The down side is that any workflow will need to be implemented elsewhere.
Limiting yourself to smart contracts that can only access on-ledger services provides more flexibility, but at a cost. This cost is partly due to the more complex infrastructure, but it is also due to the more complex platform management processes required, particularly if your smart contracts use a general-purpose programming language.
Allowing your smart contracts to access off-ledger services provides the most flexibility, but you need to fund the smart contact infrastructure and management process, as well as building any proxies required to access off-ledger services and funding the additional network capacity required.
So when should you use smart contracts? This really boils down to two separate questions.
The first: Are you in a position to create a vibrant mining community?
The viability of a ledger depends on the viability of it mining community. No miners, no ledger. If you cannot create a vibrant mining community, you can piggyback on an existing one by implementing your ledger as smart contracts on an established ledger. The DAO probably couldn’t support its own mining community, but it could piggyback on Ethereum’s.
The second: Does you ledger need to support user-defined record types?
If your ledger is solving a well-defined problem, then it’s probably easier to write any workflow into the mining application or wallet software, avoiding smart contracts entirely. On the other hand, if your ledger’s users need to create novel record types, then smart contracts will enable them to do that.
If the answer to both of these questions is ‘no’, then smart contracts aren’t for you.
If the either of the answers are ‘yes’, the smart contracts will enable to you or create a more flexible ledger, but at a cost.
However, the world is not black and white, and the answer to at least one of the questions may well be ‘maybe’. In this case, you’ll need to look into the details to see just how smart you can afford to make your ledger.
. Smart Contracts are programmes that that facilitate, verify, or enforce the negotiation or performance of a contract.
. And, in general, any Proof of Something consensus processes, as they all collapse down to Proof of Work in the end.
. A service could choose to limit the rate at which requests are processed, a common strategy for moderating the effect of denial of service attacks, but then many of the miners would see their requests delayed so long that they wouldn’t be able to complete the smart contract within the current block, effectively eliminating them from the mining pool.
. Most Turing-complete smart contract implementations have a per-instruction cost that is paid to the miner, so you need to include some value (called “Gas” in Ethereum) with a transaction when it is submitted. This payment is to prevent runaway or malicious code consuming all the compute cycles, as once all the value is consumed the transaction is simply killed. (Triggering roll-back of partially completed transactions is one of the areas of Ethereum that looks like a rich source of exploits by black hats.) Estimating how much value to allocate to a transaction which calls other smart contracts is a bit of an art, as you can’t estimate a priori how many cycles smart contracts will take to execute, especially if you didn’t create the other smart contracts. Any Turing-complete smart contract implementation needs to include mechanisms to allow smart contract users (not just developers) to manage this problem. It’s a problem that the smart contract users must be prepared to deal with.