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
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
use std::iter::Iterator;

use derive_more::{Display, From};

use crate::fixed_codec::FixedCodec;
use crate::types::{Address, Epoch, Hash, MerkleRoot, Receipt, ServiceContext, SignedTransaction};
use crate::{ProtocolError, ProtocolErrorKind, ProtocolResult};

#[derive(Debug, Display, From)]
pub enum BindingMacroError {
    #[display(fmt = "service {:?} method {:?} was not found", service, method)]
    NotFoundMethod { service: String, method: String },

    #[display(fmt = "Parsing payload to json failed {:?}", _0)]
    JsonParse(serde_json::Error),
}
impl std::error::Error for BindingMacroError {}

impl From<BindingMacroError> for ProtocolError {
    fn from(err: BindingMacroError) -> ProtocolError {
        ProtocolError::new(ProtocolErrorKind::BindingMacro, Box::new(err))
    }
}

pub trait ServiceMapping: Send + Sync {
    fn get_service<SDK: 'static + ServiceSDK>(
        &self,
        name: &str,
        sdk: SDK,
    ) -> ProtocolResult<Box<dyn Service>>;

    fn list_service_name(&self) -> Vec<String>;
}

// `ServiceState` provides access to` world state` and `account` for` service`.
// The bottom layer is an MPT tree.
//
// Each `service` will have a separate` ServiceState`, so their states are
// isolated from each other.
pub trait ServiceState {
    fn get<Key: FixedCodec, Ret: FixedCodec>(&self, key: &Key) -> ProtocolResult<Option<Ret>>;

    fn contains<Key: FixedCodec>(&self, key: &Key) -> ProtocolResult<bool>;

    // Insert a pair of key / value
    // Note: This key/value pair will go into the cache first
    // and will not be persisted to MPT until `commit` is called.
    fn insert<Key: FixedCodec, Value: FixedCodec>(
        &mut self,
        key: Key,
        value: Value,
    ) -> ProtocolResult<()>;

    fn get_account_value<Key: FixedCodec, Ret: FixedCodec>(
        &self,
        address: &Address,
        key: &Key,
    ) -> ProtocolResult<Option<Ret>>;

    fn set_account_value<Key: FixedCodec, Val: FixedCodec>(
        &mut self,
        address: &Address,
        key: Key,
        val: Val,
    ) -> ProtocolResult<()>;

    // Roll back all data in the cache
    fn revert_cache(&mut self) -> ProtocolResult<()>;

    // Move data from cache to stash
    fn stash(&mut self) -> ProtocolResult<()>;

    // Persist data from stash into MPT
    fn commit(&mut self) -> ProtocolResult<MerkleRoot>;
}

pub trait ChainQuerier {
    fn get_transaction_by_hash(&self, tx_hash: &Hash) -> ProtocolResult<Option<SignedTransaction>>;

    // To get the latest `Epoch` of finality, set `epoch_id` to `None`
    fn get_epoch_by_epoch_id(&self, epoch_id: Option<u64>) -> ProtocolResult<Option<Epoch>>;

    fn get_receipt_by_hash(&self, tx_hash: &Hash) -> ProtocolResult<Option<Receipt>>;
}

// Admission control will be called before entering service
pub trait AdmissionControl {
    fn next<SDK: ServiceSDK>(&self, ctx: ServiceContext, sdk: SDK) -> ProtocolResult<()>;
}

// Developers can use service to customize blockchain business
//
// It contains:
// - init: Initialize the service.
// - hooks: A pair of hooks that allow inserting a piece of logic before and
//   after the epoch is executed.
// - read: Provide some read-only functions for users or other services to call
// - write: provide some writable functions for users or other services to call
pub trait Service {
    // Executed before the epoch is executed.
    fn hook_before_(&mut self) -> ProtocolResult<()> {
        Ok(())
    }

    // Executed after epoch execution.
    fn hook_after_(&mut self) -> ProtocolResult<()> {
        Ok(())
    }

    fn write_(&mut self, ctx: ServiceContext) -> ProtocolResult<String>;

    fn read_(&self, ctx: ServiceContext) -> ProtocolResult<String>;
}

// `ServiceSDK` provides multiple rich interfaces for `service` developers
//
// It contains:
//
// - Various data structures that store data to `world state`(call
//   `alloc_or_recover_*`)
// - Access and modify `account`
// - Access service state
// - Event triggered
// - Access to data on the chain (epoch, transaction, receipt)
// - Read / write other `service`
//
// In fact, these functions depend on:
//
// - ChainDB
// - ServiceState
pub trait ServiceSDK {
    // Alloc or recover a `Map` by` var_name`
    fn alloc_or_recover_map<Key: 'static + FixedCodec + PartialEq, Val: 'static + FixedCodec>(
        &mut self,
        var_name: &str,
    ) -> ProtocolResult<Box<dyn StoreMap<Key, Val>>>;

    // Alloc or recover a `Array` by` var_name`
    fn alloc_or_recover_array<Elm: 'static + FixedCodec>(
        &mut self,
        var_name: &str,
    ) -> ProtocolResult<Box<dyn StoreArray<Elm>>>;

    // Alloc or recover a `Uint64` by` var_name`
    fn alloc_or_recover_uint64(&mut self, var_name: &str) -> ProtocolResult<Box<dyn StoreUint64>>;

    // Alloc or recover a `String` by` var_name`
    fn alloc_or_recover_string(&mut self, var_name: &str) -> ProtocolResult<Box<dyn StoreString>>;

    // Alloc or recover a `Bool` by` var_name`
    fn alloc_or_recover_bool(&mut self, var_name: &str) -> ProtocolResult<Box<dyn StoreBool>>;

    // Get a value from the service state by key
    fn get_value<Key: FixedCodec, Ret: FixedCodec>(&self, key: &Key)
        -> ProtocolResult<Option<Ret>>;

    // Set a value to the service state by key
    fn set_value<Key: FixedCodec, Val: FixedCodec>(
        &mut self,
        key: Key,
        val: Val,
    ) -> ProtocolResult<()>;

    // Get a value from the specified address by key
    fn get_account_value<Key: FixedCodec, Ret: FixedCodec>(
        &self,
        address: &Address,
        key: &Key,
    ) -> ProtocolResult<Option<Ret>>;

    // Insert a pair of key / value to the specified address
    fn set_account_value<Key: FixedCodec, Val: FixedCodec>(
        &mut self,
        address: &Address,
        key: Key,
        val: Val,
    ) -> ProtocolResult<()>;

    // Get a signed transaction by `tx_hash`
    // if not found on the chain, return None
    fn get_transaction_by_hash(&self, tx_hash: &Hash) -> ProtocolResult<Option<SignedTransaction>>;

    // Get a epoch by `epoch_id`
    // if not found on the chain, return None
    // When the parameter `epoch_id` is None, get the latest (executing)` epoch`
    fn get_epoch_by_epoch_id(&self, epoch_id: Option<u64>) -> ProtocolResult<Option<Epoch>>;

    // Get a receipt by `tx_hash`
    // if not found on the chain, return None
    fn get_receipt_by_hash(&self, tx_hash: &Hash) -> ProtocolResult<Option<Receipt>>;

    // Call other read-only methods of `service` and return the results
    // synchronously NOTE: You can use recursive calls, but the maximum call
    // stack is 1024
    fn read(&self, service: &str, method: &str, payload: &str) -> ProtocolResult<&str>;

    // Call other writable methods of `service` and return the results synchronously
    // NOTE: You can use recursive calls, but the maximum call stack is 1024
    fn write(&mut self, service: &str, method: &str, payload: &str) -> ProtocolResult<&str>;
}

pub trait StoreMap<Key: FixedCodec + PartialEq, Value: FixedCodec> {
    fn get(&self, key: &Key) -> ProtocolResult<Value>;

    fn contains(&self, key: &Key) -> ProtocolResult<bool>;

    fn insert(&mut self, key: Key, value: Value) -> ProtocolResult<()>;

    fn remove(&mut self, key: &Key) -> ProtocolResult<()>;

    fn len(&self) -> ProtocolResult<u32>;

    fn is_empty(&self) -> ProtocolResult<bool>;

    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&Key, Value)> + 'a>;
}

pub trait StoreArray<Elm: FixedCodec> {
    fn get(&self, index: u32) -> ProtocolResult<Elm>;

    fn push(&mut self, element: Elm) -> ProtocolResult<()>;

    fn remove(&mut self, index: u32) -> ProtocolResult<()>;

    fn len(&self) -> ProtocolResult<u32>;

    fn is_empty(&self) -> ProtocolResult<bool>;

    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (u32, Elm)> + 'a>;
}

pub trait StoreUint64 {
    fn get(&self) -> ProtocolResult<u64>;

    fn set(&mut self, val: u64) -> ProtocolResult<()>;

    // Add val with self
    // And set the result back to self
    fn add(&mut self, val: u64) -> ProtocolResult<()>;

    // Self minus val
    // And set the result back to self
    fn sub(&mut self, val: u64) -> ProtocolResult<()>;

    // Multiply val with self
    // And set the result back to self
    fn mul(&mut self, val: u64) -> ProtocolResult<()>;

    // Power of self
    // And set the result back to self
    fn pow(&mut self, val: u32) -> ProtocolResult<()>;

    // Self divided by val
    // And set the result back to self
    fn div(&mut self, val: u64) -> ProtocolResult<()>;

    // Remainder of self
    // And set the result back to self
    fn rem(&mut self, val: u64) -> ProtocolResult<()>;
}

pub trait StoreString {
    fn get(&self) -> ProtocolResult<String>;

    fn set(&mut self, val: &str) -> ProtocolResult<()>;

    fn len(&self) -> ProtocolResult<u32>;

    fn is_empty(&self) -> ProtocolResult<bool>;
}

pub trait StoreBool {
    fn get(&self) -> ProtocolResult<bool>;

    fn set(&mut self, b: bool) -> ProtocolResult<()>;
}