1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! Opaque data encoding the data passed into and returned from snapp smart contracts.
//!
//! The format of this data is opaque to the Mina protocol, and is defined by each individual smart
//! contract. This data is unused by the transaction logic.
//!
//! This data can be used to communicate between snapp smart contracts in a 'caller/callee' model.
//!
//! A 'caller' snapp smart contract is able to 'view' the `call_data` field of its 'callees' by
//! walking into its [`crate::call_stack`] data structure. It will often be useful to model this
//! data as a hash of some arguments to a snapp function and a return value, for example
//! ```rust
//! { arguments: [Fp], results: [Fp] }
//! ```
//! where `arguments` and `results` are encoded as as field elements in a fashion defined by the
//! contract.
//!
//! # Motivation
//!
//! A snapp smart contract that is executed by another snapp smart contract may be thought of as a
//! function
//! ```rust
//! fn do_something(arg1: ..., arg2: ..., ...) -> (result_type1, result_type2, ...)
//! ```
//! In this model, it can be beneficial to pass arguments or return values without explicitly
//! exposing them on chain:
//! * A snapp may take some private data as its input, which should not be exposed to the chain.
//! * A snapp may return some private data in its output, which should not be exposed to the chain.
//! * A snapp may take or return some data that is not publically useful, and wants to avoid the
//! additional cost of submitting this data inside the transaction.
//!
//! This data can be bundled into the `call_data` using a hash or other encoding, for example by
//! checking that
//! ```rust
//! call_data = hash({arguments, results})
//! ```
//! in both the caller and callee smart contracts when using the encoding above.
//!
//! # Examples
//!
//! #### Returning private data from a snapp smart contract
//!
//! A 'knowledge' snapp smart contract could store a value `commitment` in its `app_state` that
//! 'commits' to some known secret value using a hash function:
//! ```rust
//! app_state[0] = hash(secret_random_value, secret_data)
//! ```
//! `secret_random_value` is a fixed number chosen randomly, so that an adversary cannot 'guess and
//! check' the value of `secret_data` by comparing hashes: the chances of them choosing the correct
//! `secret_random_value` is roughly 1 in `2^254`, comparable to randomly choosing the same atom
//! twice out of all atoms in the entire known universe!
//!
//! This smart contract can then return some value derived from the secret data by checking that
//! `secret_data` matches, and then setting `call_data` to the desired value, e.g.
//! ```rust
//! assert_eq!(hash(secret_random_value, secret_data), app_state[0]);
//! let returned_secret_data = do_something_with(secret_data);
//! party.call_data = hash(different_random_value, returned_secret_data);
//! ```
//! Note that again we use a random value `different_random_value` to avoid revealing the private
//! data to any parties, even if it were easy to guess on its own (e.g. either `0` or `1`).
//!
//! The calling smart contract can confirm that this value was returned by checking the callee's
//! party, and then use the data:
//! ```rust
//! assert_eq!(hash(different_random_value, returned_secret_data), called_party.call_data);
//! do_something_else_with(returned_secret_data)
//! ```
//!
//! #### Bundling together arguments and return values
//!
//! An 'addition' snapp smart contract could accept 2 values as its arguments and return their sum
//! with the first value in its `app_state`, by storing all of the data together in `call_data`.
//! For example, in the addition snapp:
//! ```rust
//! fn addition_snapp(party: Party, input1: Fp, input2: Fp) -> (Party, Fp) {
//!     let output = input1 + input2 + app_state[0];
//!     party.call_data = hash(input1, input2, output);
//!     (party, output)
//! }
//! ```
//! and then in the calling snapp:
//! ```rust
//! let called_party, output = call_snapp(addition_snapp, input1, input2);
//! assert_eq!(hash(input1, input2, output), called_party.call_data)
//! ```
//! (The details of `call_snapp` are left to supporting libraries such as SnarkyJS.)

use crate::primitives::*;

/// Opaque data for communicating between a snapp smart contract and its caller(s). See
/// [`crate::call_data`] for more.
pub struct CallData(pub Fp);