Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
Merge interacting-with-contracts and interacting-with-contracts-2 (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonjove authored Jul 29, 2022
1 parent f1a896b commit dc63386
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 44 deletions.
44 changes: 0 additions & 44 deletions docs/learn/interacting-with-contracts-2.mdx

This file was deleted.

45 changes: 45 additions & 0 deletions docs/learn/interacting-with-contracts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,48 @@ Note that everything described in this section is only available if the

This machinery can also be used to test multiple contracts together. For
example, the single offer contract test case [creates a token](https://github.com/stellar/soroban-examples/blob/56fef787395b5aed7cd7b19772cca28e21b3feb5/single_offer/src/test.rs#L22).

<details>
<summary>Advanced</summary>

## Calling contracts

Contracts are invoked through a pair of host functions `call` and `try_call`:

- `try_call(contract, function, args)` calls `function` exported from `contract`, passing `args` and returning a `Status` on any error.
- `call(contract, function, args)` just calls `try_call` with its arguments and traps on `Status`, essentially propagating the error.

In both cases `contract` is a `Binary` host object containing the contract ID, `function` is a `Symbol` holding the name of an exported function to call, and `args` is a `Vector` of values to pass as arguments.

These host functions can be invoked in two separapte ways:

- From outside the host, such as when a user submits a transaction that calls a contract.
- From within the host, when one contract calls another.

Both cases follow the same logic:

- The contract's WASM bytecode is retrieved from a `CONTRACT_DATA` ledger entry in the host's storage system.
- A WASM VM is instantiated for the duration of the invocation.
- The function is looked up and invoked, with arguments passed from caller to callee.

When a call occurs from outside the host, any arguments will typically be provided in serialized XDR form accompanying the transaction, and will be deserialized and converted to host objects automatically before invoking the contract.

When a call occurs from inside the host, the caller and callee contracts _share the same host_ and the caller can pass references to host objects directly to the callee without any need to serialize or deserialize them.

Since host objects are immutable, there is limited risk to passing a shared reference from one contract to another: the callee cannot modify the object in a way that would surprise the caller, only create new objects.

## Storage footprint and preflight

As mentioned in the [persisting data](../learn/persisting-data) section, a contract can only load or store `CONTRACT_DATA` entries that are declared in a _footprint_ associated with its invocation.

A footprint is a set of ledger keys, each marked as either read-only or read-write. Read-only keys are available to the transaction for reading, read-write available for reading, writing or both.

Any transaction submitted by a user has to be accompanied by a footprint. A single footprint encompasses _all_ the data read and written by _all_ contracts transitively invoked by the transaction: not just the initial contract that the transaction calls, but also all contracts it calls, and so on.

Since it can be difficult for a user to always know which ledger entries a given contract call will attempt to read or write -- especially those caused by contracts called by other contracts deep within a transaction -- the host provides an auxiliary **"preflight"** mechanism that executes a transaction against a temporary, possibly slightly-stale _snapshot_ of the ledger. The preflight mechanism is _not_ constrained to only read or write the contents of a footprint; rather it _records_ a footprint describing the transaction's execution, discards the execution's effects, and then returns the recorded footprint it to its caller.

Such a preflight-provided footprint can then be used to accompany a "real" submission of the same transaction to the network for real execution. If the state of the ledger has changed too much between the time of the preflight and the real submission, the footprint may be too stale and no longer accurately identify the _keys_ the transaction needs to read and write, at which point the preflight must be retried to refresh the footprint.

In any event -- whether successful or failing -- the real transaction will execute atomically, deterministically and with serializable consistency semantics. An inaccurate footprint simply causes deterministic transaction failure, not a stale-read anomaly. All effects of such a failed transaction are discarded, as they would be in the presence of any other error.

</details>

0 comments on commit dc63386

Please sign in to comment.