Skip to content

Commit

Permalink
Merge pull request #178 from input-output-hk/nahern-patch-24
Browse files Browse the repository at this point in the history
Plutus updates
  • Loading branch information
nahern committed Sep 10, 2021
2 parents 644a1bc + ad009e6 commit ddabfae
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 0 deletions.
59 changes: 59 additions & 0 deletions content/10-plutus/08-Plutus-validator-scripts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: Plutus scripts
metaTitle: Plutus scripts
---

Cardano uses scripts to validate actions. These scripts, which are pieces of code, implement pure functions with True or False outputs. Script validation is the process of invoking the script interpreter to run a given script on appropriate arguments.

## What are scripts?
A script is a program that decides whether or not the transaction which spends the output is authorized to do so. Such a script is called a validator script, because it validates whether the spending is allowed.

A simple validator script would be one that checked whether the spending transaction was signed by a particular key - this would exactly replicate the behaviour of simple pay-to-pubkey outputs. However, with a bit of careful extension, we can use scripts to let us express a large amount of useful logic on the chain.

The way the EUTXO model works is that validator scripts are passed three arguments:
- Datum: this is a piece of data attached to the output that the script is locking (strictly, again, just the hash is present). This is typically used to carry state.
- Redeemer: this is a piece of data attached to the input that is doing the spending. This is typically used to provide an input to the script from the spender.
- Context: this is a piece of data which represents information about the transaction doing the spending. This is used to make assertions about the way the output is being sent (such as “Bob signed it”).

## Intuitive example
For example, a kid wants to go on a ferris wheel, but before getting on, they must be taller than the safety sign.

We could express that idea in pseudo code, like:

```python
if isTallEnough(attraction=ferrisWheel,passenger=michael):
getOnFerrisWheel()

def isTallEnough(attraction,kid):
return kid["height"] >= attraction["minimumHeight"]

def getOnFerrisWheel():
print ("get On the Ferris Wheel")

ferrisWheel = {"minimumHeight":120}
michael = {"height":135}
```

In this example the following applies:
- The datum is the information about this transaction: `michael.hegiht`.
- The context is the state of the world, at that point meaning: `ferrisWheel.minimumHeght`.
- The reedemer, is the action to perform: `getOnFerrisWheel()`

The validator script is the function that uses all that information `isTallEnough`

## Defi example
Now let’s look at an example from the DeFi domain.

We could implement an atomic swap, as follows:
- The datum contains the keys of the two parties in the swap, and a description of what they are swapping
- The redeemer is unused.
- The context contains a representation of the transaction.

The logic of the validator script is as follows: does the transaction make a payment from the second party to the first party, containing the value that they are supposed to send? If so, then they may spend this output and send it where they want (or we could insist that they send it to their key, but we might as well let them do what they like with it).

## Code examples
You can find real code examples of validator scripts on every smart contract, for example:

- [Plutus transaction tutorial](https://github.com/input-output-hk/Alonzo-testnet/blob/main/Alonzo-tutorials/Plutus_transactions_tutorial.md#transaction-to-lock-funds): On this validator, it always succeeds.
- [Plutus Hello World](https://github.com/input-output-hk/Alonzo-testnet/blob/e27563ec0c0c3723376f4d12881cd003a7a7157f/resources/plutus-sources/plutus-helloworld/src/Cardano/PlutusExample/HelloWorld.hs#L47): On this validator if the datum is equal to ‘Hello’ it is converted to an integer.
- [Plutus Pioneers English Auction](https://github.com/input-output-hk/plutus-pioneer-program/blob/024ebd367bf6c4003b482bfb4c6db7d745ec85aa/code/week01/src/Week01/EnglishAuction.hs#L103): On this line the validator makes sure that the new bid (datum) is superior to the previous one, until time is up.
43 changes: 43 additions & 0 deletions content/10-plutus/09-collateral-mechanism.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: About the collateral mechanism
metaTitle: About the collateral mechanism
---

Alonzo has ushered in the era of smart contracts on Cardano. The collateral mechanism is an important feature that has been designed to ensure successful smart contract execution.

Relying on the guarantees provided by the deterministic design of the Alonzo ledger, Cardano implements a specific two-phase validation scheme. The main reason for introducing two-phase validation is to limit the amount of uncompensated validation work by nodes. Each phase serves a purpose in achieving this goal:

- The first phase checks whether the transaction is constructed correctly and can pay its processing fee
- The second phase runs the scripts included in the transaction.

If the transaction is phase-1 valid, phase-2 scripts run. If phase-1 fails, no scripts run, and the transaction is immediately discarded.

Collateral is used to guarantee that nodes are compensated for their work in case phase-2 validation fails. Thus, collateral is the monetary guarantee a user gives to assure that the contract has been carefully designed and thoroughly tested. Collateral amount is specified at the time of constructing the transaction. Not directly, but by adding collateral inputs to the transaction. The total balance in the UTXOs corresponding to these specially marked inputs is the transaction’s collateral amount. If the user fulfills the conditions of the guarantee, and a contract gets executed, the collateral is safe.

## The scenario
Without collateral, the user is not charged if a smart contract fails. However, by the time the transaction fails, the network has already incurred some costs to initiate and validate the transaction. This means that a malicious actor could flood the network with invalid transactions, denying service to other users at little cost.

## The solution
When a user initiates a transaction, they commit enough ada to cover its execution cost. In Alonzo, transactions that call and use non-native smart contracts (known as phase-2 contracts) also need enough collateral to cover costs related to potential transaction failures. This amount can be small, but it is sufficient to make a denial of service (DOS) attack prohibitively expensive.

Collateral fees are collected only if a transaction fails validation. If the contract passes validation, the transaction fees are collected, but the collateral is not.

## The reasoning:
An honest user is never at risk of losing their collateral.

The Cardano blockchain is deterministic with respect to transaction costs because these costs depend only on local values and local state. That means a user can calculate the execution cost (in ada) of a transaction before submitting it. This feature is different from other blockchains, including Ethereum, where other network activity can influence the gas cost. The required amount of collateral depends only on the execution cost.

The [Cardano testnet](https://testnets.cardano.org/en/testnets/cardano/overview/) provides a safe environment with free test ada, so distributed application (DApp) developers can thoroughly test their smart contracts before deploying to the mainnet. If transactions succeed on the testnet, the developer can be perfectly sure that all the scripts will indeed succeed.

If the on-chain conditions have changed since the transaction was constructed, that transaction will be rejected entirely, and no fees will be charged. If a signature is missing, for example, no collateral would be charged.

## Technical details

The term collateral refers to the total ada contained in the UTXOs referenced by collateral inputs. A transaction uses collateral inputs to cover its fees if a phase-2 script fails.

The Shelley formal specification introduced the concept of “multi-signature” scripts. Phase one
scripts, such as these, are captured entirely by the ledger rules. Execution costs can therefore be easily assessed before they are processed by the implementation, and any fees can be calculated directly within the ledger rule implementation, based on the size of the transaction that includes the script, for example.

In contrast, phase-2 scripts can perform arbitrary (and, in principle, Turing-complete) computations. We require transactions that use phase-2 scripts to have a budget in terms of a number of abstract ExUnits. This budget gives a quantitative bound on resource usage in terms of a number of specific metrics, including memory usage or abstract execution steps. The budget is then used as part of the transaction fee calculation.

The above is extracted from the formal specification for the Alonzo network. For more details, read the [Cardano ledger specification for Plutus Core](https://www.google.com/url?q=https://hydra.iohk.io/build/7172824/download/1/alonzo-changes.pdf&sa=D&source=editors&ust=1631287783465000&usg=AOvVaw09WTwSfKshbLCGW7dyup62).
18 changes: 18 additions & 0 deletions content/10-plutus/10-concurrency.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: Understanding concurrency
metaTitle: Understanding concurrency
---

Concurrency may or may not improve a system’s performance, throughput, or responsiveness. The amount of concurrency limits the maximum number of simultaneous operations that can be performed.

To obtain *actual* performance improvements in a UTXO-based blockchain, processors or other actors should be able to perform multiple actions simultaneously. The higher the level of concurrency, the higher the maximum possible parallelism. Such an approach then translates to performance improvements and throughput. It also provides significant advantages over account based systems (like Ethereum).

## Deploying DApps on UTXO ledgers is *different*

Cardano’s approach to DApp deployment is different and thus it requires a learning curve and a different approach. This is like working with different programming languages: there is one goal – to deploy a solution, but so many programming languages to use for this purpose.

Maximizing concurrency is a skill that needs to be learned: developers need to write code in a way that severely restricts the opportunities for contention (e.g., by avoiding shared states and accidental dependencies). The system must then translate this concurrency into parallelism. A number of developers have already identified ways to approach this, while others are still developing solutions. Simply transplanting lessons learned on one blockchain will not work; while the learning curve is a little steeper, the results make this worthwhile.

Either way, it is important to understand that to deploy a scalable DApp on Cardano, a developer can’t just use an adapted Ethereum contract. Cardano is based on the UTXO model; it is not account-based which means that a single on-chain state will not meet the concurrency property of Cardano. Instead, DApps should split up their on-chain state across many UTXOs. This will increase the concurrency in their application, thereby allowing higher throughput.

To learn more about scalability, you can read [how to design a scalable Plutus application](https://plutus.readthedocs.io/en/latest/plutus/howtos/writing-a-scalable-app.html) and to learn more about how to organise DApps on Cardano using patterns, read the [order book pattern](https://plutus.readthedocs.io/en/latest/plutus/explanations/order-book-pattern.html).
24 changes: 24 additions & 0 deletions content/10-plutus/11-sc-best-practices.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Smart contract best practices
metaTitle: Smart contract best practices
---

Here are some general best practices that you should follow when developing smart contracts with Plutus.

**Knowing the objective of your smart contract**
Know exactly what your smart contract should do and test it to ensure that it fulfills the objective. Does one exist already? and if so, what is different about this smart contract?

**Naming**
Choose a clear and meaningful name for your smart contract. Keep it simple and short and aim to include what the smart contracte does in its name.

**Peer review of code**
The benefits of code review are well known; reviewed code aims to be consistent across the project, defect-free, and optimized for performance. The knowledge of the code is shared among developers, reducing maintenance time and cost in the future. For smart contracts, correctness is absolutely crucial.

**Testing on a testnet**
You should always test your smart contracts on a testnet environment before you run them on the mainnet. Write as many test scenarios as you can and run several iterations of your tests.

**Documenting test cases**
Keep a list of the test cases that you run so that you have them for reference and verification purposes.

**Consider Formal Verification**
The subject of formal verification is too large to adequately cover here. You can assume that your code will run in a hostile environment where highly skilled, well-resourced and unscrupulous actors will be waiting to pounce on any vulnerability.

0 comments on commit ddabfae

Please sign in to comment.