Browse Source

docs: update clarity references to latest from stacks-blockchain:master (#578)

deploy-contracts
Aaron Blankstein 5 years ago
committed by GitHub
parent
commit
799e2c066a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      _core/smart/clarityCLI.md
  2. 200
      _core/smart/clarityRef.md
  3. 116
      _core/smart/functions.md

4
_core/smart/clarityCLI.md

@ -6,7 +6,7 @@ permalink: /:collection/:path.html
# Clarity CLI
{:.no_toc}
You use the `clarity-cli` command to work with smart contracts within the Blockstack virtual environment. This command has the following subcommands:
You use the `clarity-cli` command to work with smart contracts within a local-only Blockstack virtual environment. This command has the following subcommands:
* TOC
{:toc}
@ -89,4 +89,4 @@ Executes a public function of a defined contract.
clarity-cli generate_address
```
Generates a random Stacks public address for testing purposes.
Generates a random Stacks public address for testing purposes.

200
_core/smart/clarityRef.md

@ -10,104 +10,126 @@ This file contains the reference for the Clarity language.
* TOC
{:toc}
## Supported types
This section lists the types available to smart contracts. The only atomic types supported by the Clarity are booleans, integers, fixed length buffers, and principals.
### Int type
The integer type in the Clarity language is a 16-byte signed integer, which allows it to specify the maximum amount of microstacks spendable in a single Stacks transfer. The special `BlockHeightInt` you can obtain with the `get-block-info` function.
### Uint type
The unsigned integer type (`uint`) in the Clarity language is a 16-byte unsigned integer. Using the unsigned type can ensure that any value underflows (negative numbers) will cause a transaction to be aborted.
Anywhere a developer wishes to use a literal unsigned integer (for example, incrementing or decrementing an input by a constant) the integer literal should use the `u` prefix, e.g., `u123`.
### Bool type
Supports values of `true` or `false`.
### Buffer type
Buffer types represent fixed-length byte buffers. A Buffer can either be constructed using:
- String literals, for example `"alice.id"` or `hash160("bob.id")`,
- Hexadecimals literals, for example `0xABCDEF`.
All of the hash functions return buffers:
`hash160`
`sha256`
`keccak256`
The block properties `header-hash`, `burnchain-header-hash`, and `vrf-seed` are all buffers.
### List type
Clarity supports lists of the atomic types. However, the only variable length lists in the language appear as function inputs.
### Principal type
Clarity provides this primitive for checking whether or not the smart contract transaction was signed by a particular principal. Principals represent a spending entity and are roughly equivalent to a Stacks address. The principal's signature is not checked by the smart contract, but by the virtual machine. A smart contract function can use the globally defined `tx-sender` variable to obtain the current principal.
Smart contracts may also be principals (represented by the smart contract's identifier). However, there is no private key associated with the smart contract, and it cannot broadcast a signed transaction on the blockchain. A smart contract uses the special variable `contract-name` to refer to its own principal.
[//]: # You can use the `is-contract?` to determine whether a given principal corresponds to a smart contract.
### Tuple type
To support the use of named fields in keys and values, Clarity allows the construction of named tuples using a function `(tuple ...)`, for example
```cl
(define-constant imaginary-number-a (tuple (real 1) (i 2)))
(define-constant imaginary-number-b (tuple (real 2) (i 3)))
## Clarity Type System
The Clarity language uses a strong static type system. Function arguments
and database schemas require specified types, and use of types is checked
during contract launch. The type system does _not_ have a universal
super type. The type system contains the following types:
* `(tuple (key-name-0 key-type-0) (key-name-1 key-type-1) ...)` -
a typed tuple with named fields.
* `(list max-len entry-type)` - a list of maximum length `max-len`, with
entries of type `entry-type`
* `(response ok-type err-type)` - object used by public functions to commit
their changes or abort. May be returned or used by other functions as
well, however, only public functions have the commit/abort behavior.
* `(optional some-type)` - an option type for objects that can either be
`(some value)` or `none`
* `(buff max-len)` := byte buffer or maximum length `max-len`.
* `principal` := object representing a principal (whether a contract principal
or standard principal).
* `bool` := boolean value (`true` or `false`)
* `int` := signed 128-bit integer
* `uint` := unsigned 128-bit integer
## Public Functions
Functions specified via `define-public` statements are _public_
functions and these are the only types of functions which may
be called directly through signed blockchain transactions. In addition
to being callable directly from a transaction (see the Stacks wire formats
for more details on Stacks transactions), public function may be called
by other smart contracts.
Public functions _must_ return a `(response ...)` type. This is used
by Clarity to determine whether or not to materialize any changes from
the execution of the function. If a function returns an `(err ...)`
type, and mutations on the blockchain state from executing the
function (and any function that it called during execution) will be
aborted.
In addition to function defined via `define-public`, contracts may expose
read-only functions. These functions, defined via `define-read-only`, are
callable by other smart contracts, and may be queryable via public blockchain
explorers. These functions _may not_ mutate any blockchain state. Unlike normal
public functions, read-only functions may return any type.
## Contract Calls
A smart contract may call functions from other smart contracts using a
`(contract-call?)` function.
This function returns a response type result-- the return value of the
called smart contract function.
We distinguish 2 different types of `contract-call?`:
* Static dispatch: the callee is a known, invariant contract available
on-chain when the caller contract is deployed. In this case, the
callee's principal is provided as the first argument, followed by the
name of the method and its arguments:
```scheme
(contract-call?
.registrar
register-name
name-to-register)
```
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. Values in a given mapping are set or fetched using:
<table class="uk-table uk-table-small">
<tr>
<th class="uk-width-small">Function</th>
<th>Description</th>
</tr>
<tr>
<td><code>(map-get map-name key-tuple)</code></td>
<td>Fetches the value associated with a given key in the map, or returns <code>none</code> if there is no such value.</td>
</tr>
<tr>
<td><code>(map-set! map-name key-tuple value-tuple)</code></td>
<td>Sets the value of key-tuple in the data map</td>
</tr>
<tr>
<td><code>(map-insert! map-name key-tuple value-tuple)</code></td>
<td>Sets the value of key-tuple in the data map if and only if an entry does not already exist.</td>
</tr>
<tr>
<td><code>(map-delete! map-name key-tuple)</code></td>
<td>Deletes key-tuple from the data map.</td>
</tr>
</table>
To access a named value of a given tuple, the `(get name tuple)` function returns that item from the tuple.
### Optional type
Represents an optional value. This is used in place of the typical usage of "null" values in other languages, and represents a type that can either be some value or `none`. Optional types are used as the return types of data-map functions.
* Dynamic dispatch: the callee is passed as an argument, and typed
as a trait reference (<A>).
```scheme
(define-public (swap (token-a <can-transfer-tokens>)
(amount-a uint)
(owner-a principal)
(token-b <can-transfer-tokens>)
(amount-b uint)
(owner-b principal)))
(begin
(unwrap! (contract-call? token-a transfer-from? owner-a owner-b amount-a))
(unwrap! (contract-call? token-b transfer-from? owner-b owner-a amount-b))))
```
### Response type
Traits can either be locally defined:
Response types represent the result of a public function. Use this type to indicate and return data associated with the execution of the function. Also, the response should indicate whether the function error'ed (and therefore did not materialize any data in the database) or ran `ok` (in which case data materialized in the database).
```scheme
(define-trait can-transfer-tokens (
(transfer-from? (principal principal uint) (response uint)))
```
Response types contain two subtypes -- a response type in the event of `ok` (that is, a public function returns an integer code on success) and an `err` type (that is, a function returns a buffer on error).
Or imported from an existing contract:
### Algebraic
```scheme
(use-trait can-transfer-tokens
.contract-defining-trait.can-transfer-tokens)
```
Clarity supports limited algebraic data types, it has an `(optional A)` type and a `(response A B)` type. An `(optioanl A)` type can either be `(some A)` or `(none)`, and a `(response A B)` type can either be `(ok A)` or `(err B)`. For example, `(some u3)` and `(none)` would have type `(optional uint)`, and `(ok \"woot!\")` and `(err 'false)` would have type `(response (buff 5) bool)`.
Looking at trait conformance, callee contracts have two different paths.
They can either be "compatible" with a trait by defining methods
matching some of the methods defined in a trait, or explicitely declare
conformance using the `impl-trait` statement:
The algebraic data types have two variants (e.g. `(some ...)` or `(none)`; `(ok ...)` or `(err ...)`).
```scheme
(impl-trait .contract-defining-trait.can-transfer-tokens)
```
The `default-to`, `expects`, and `expects-err!` functions unpack algebraic data types. To *unpack* means to extract one of the "inner" types. Unpacking an `(optional A)` means to do something to get at `A`, and unpacking `(response A B)` means to do something to get at ether `A` or `B` (where "do something" is specific to the function doing the unpacking). The built-in functions that "unpack" an algebraic data type each behave differently.
Explicit conformance should be prefered when adequate.
It acts as a safeguard by helping the static analysis system to detect
deviations in method signatures before contract deployment.
The following limitations are imposed on contract calls:
1. On static dispatches, callee smart contracts _must_ exist at the
time of creation.
2. No cycles may exist in the call graph of a smart contract. This
prevents recursion (and re-entrancy bugs). Such structures can
be detected with static analysis of the call graph, and will be
rejected by the network.
3. `contract-call?` are for inter-contract calls only. Attempts to
execute when the caller is also the callee will abort the
transaction.
## Keyword reference

116
_core/smart/functions.md

@ -1,116 +0,0 @@
---
layout: smart
description: "Clarity: Defining Functions and Maps"
permalink: /:collection/:path.html
---
# Defining Functions and Maps
{:.no_toc}
Clarity includes _defines_ and native functions for creating user-defined functions.
* TOC
{:toc}
## define-private and define-public functions
Functions specified via `define-public` statements are public functions. Functions without these designations, simple `define-private` statements, are private functions. You can run a contract's public functions directly via the `clarity-cli execute` command line directly or from other contracts. You can use the `clarity eval` or `clarity eval_raw` commands to evaluate private functions via the command line.
Public functions return a Response type result. If the function returns an `ok` type, then the function call is considered valid, and any changes made to the blockchain state will be materialized. If the function returns an `err` type, it is considered invalid, and has no effect on the smart contract's state.
For example, consider two functions, `foo.A` and `bar.B` where the `foo.A` function calls `bar.B`, the table below shows the data materialization that results from the possible combination of return values:
<table class="uk-table">
<tr>
<th></th>
<th>foo.A =&gt;</th>
<th>bar.B</th>
<th>Data impact that results</th>
</tr>
<tr>
<th rowspan="2">Function returns</th>
<td><code>err</code></td>
<td><code>ok</code></td>
<td>No changes result from either function.</td>
</tr>
<tr>
<td><code>ok</code></td>
<td><code>err</code></td>
<td>Change from <code>foo.A</code> is possible; no changes from <code>bar.B</code> materialize.</td>
</tr>
</table>
Defining of constants and functions are allowed for simplifying code using a define statement. However, these are purely syntactic. If a definition cannot be inlined, the contract is rejected as illegal. These definitions are also private, in that functions defined this way may only be called by other functions defined in the given smart contract.
## define-read-only functions
Functions specified via `define-read-only` statements are public. Unlike functions created by `define-public`, functions created with `define-read-only` may return any type. However, `define-read-only` statements cannot perform state mutations. Any attempts to modify contract state by these functions or functions called by these functions result in an error.
## define-map functions for data
Data within a smart contract's data-space is stored within maps. These stores relate a typed-tuple to another typed-tuple (almost like a typed key-value store). As opposed to a table data structure, a map only associates a given key with exactly one value. A smart contract defines the data schema of a data map with the `define-map` function.
```cl
(define-map map-name ((key-name-0 key-type-0) ...) ((val-name-0 val-type-0) ...))
```
Clarity contracts can only call the `define-map` function in the top-level of the smart-contract (similar to `define`. This function accepts a name for the map, and a definition of the structure of the key and value types. Each of these is a list of `(name, type)` pairs. Types are either the values `'principal`, `'integer`, `'bool` or the output of one of the hash calls which is an n-byte fixed-length buffer.
To support the use of named fields in keys and values, Clarity allows the construction of tuples using a function `(tuple ((key0 expr0) (key1 expr1) ...))`, for example:
```cl
(tuple (name "blockstack") (id 1337))
```
This allows for creating named tuples on the fly, which is useful for data maps where the keys and values are themselves named tuples. To access a named value of a given tuple, the function (get #name tuple) will return that item from the tuple.
The `define-map` interface, as described, disallows range-queries and queries-by-prefix on data maps. Within a smart contract function, you cannot iterate over an entire map. Values in a given mapping are set or fetched using the following functions:
<table class="uk-table">
<tr>
<th>Function</th>
<th>Description</th>
</tr>
<tr>
<td><code>(map-get? map-name key-tuple)</code></td>
<td>Fetches the value associated with a given key in the map. Returns <code>(optional (tuple))</code></td>
</tr>
<tr>
<td><code>(map-set map-name key-tuple value-tuple)</code></td>
<td>Sets the value of key-tuple in the data map.</td>
</tr>
<tr>
<td><code>(map-insert map-name key-tuple value-tuple)</code></td>
<td>Sets the value of <code>key-tuple</code> in the data map if and only if an entry does not already exist.</td>
</tr>
<tr>
<td><code>(map-delete map-name key-tuple)</code></td>
<td>Removes the value associated with the input key for the given map.</td>
</tr>
</table>
Data maps make reasoning about functions easier. By inspecting a given function definition, it is clear which maps will be modified and, even within those maps, which keys are affected by a given invocation. Also, the interface of data maps ensures that the return types of map operations are fixed length; Fixed length returns is a requirement for static analysis of a contract's runtime, costs, and other properties.
## List operations and functions
Lists may be multi-dimensional. However, note that runtime admission checks on typed function-parameters and data-map functions like `map-set` are charged based on the _maximal_ size of the multi-dimensional list.
You can call `filter` `map` and `fold` functions with user-defined functions (that is, functions defined with `(define-public ...)`, `(define-read-only ...)`, or `(define-public ...)`) or simple, native functions (for example, `+`, `-`, `not`).
## Intra-contract calls
A smart contract may call functions from other smart contracts using a `(contract-call!)` function:
```cl
(contract-call! contract-name function-name arg0 arg1 ...)
```
This function accepts a function name and the smart contract's name as input. For example, to call the function `token-transfer` in the smart contract, you would use:
`(contract-call! tokens token-transfer burn-address name-price))`
For intra-contract calls dynamic dispatch is not supported. When a contract is launched, any contracts it depends on (calls) must exist. Additionally, no cycles may exist in the call graph of a smart contract. This prevents recursion (and re-entrancy bugs. A static analysis of the call graph detects such structures and they are rejected by the network.
A smart contract may not modify other smart contracts' data directly; it can read data stored in those smart contracts' maps. This read ability does not alter any confidentiality guarantees of Clarity. All data in a smart contract is inherently public, andis readable through querying the underlying database in any case.
Finally, and importantly, the `tx-sender` variable does not change during inter-contract calls. This means that if a transaction invokes a function in a given smart contract, that function is able to make calls into other smart contracts on your behalf. This enables a wide variety of applications, but it comes with some dangers for users of smart contracts. However, the static analysis guarantees of Clarity allow clients to know a priori which functions a given smart contract will ever call. Good clients should always warn users about any potential side effects of a given transaction.
Loading…
Cancel
Save