Skip to content

Commit 4612196

Browse files
authored
Merge branch 'master' into feature/nodejs-ci
2 parents 0bb4e46 + 78f54b6 commit 4612196

File tree

11 files changed

+503
-84
lines changed

11 files changed

+503
-84
lines changed

cli/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ by beginning the line with a `#`.
3232

3333
### Getting help
3434
The most simple way is just start cli by `indy-cli` command and put `help` command. Also you can look to
35-
[Indy CLI Design](../doc/cli-design.md) doc that contains the list of commands and architecture overview.
35+
[Indy CLI Design](../doc/design/001-cli) doc that contains the list of commands and architecture overview.
3636

3737
### Old python-based CLI migration
3838
It is possible to import did's stored in the wallet of deprecated python-based CLI tool.
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
## Legend
2+
There are some types of requests to Nodes in the Pool allowing to use StateProof optimization in Client-Node communication.
3+
Instead of sending requests to all nodes in the Pool, a client can send a request to a single Node and expect StateProof signed by BLS multi-signature.
4+
5+
BLS multi-signature (BLS MS) guaranties that there was a consensus of Nodes which signed some State identified by State RootHash.
6+
StateProof (SP) is small amount of data which allows to verify particular values against RootHash.
7+
Combination of BLS MS and SP allows clients to be sure about response of single node is a part of State signed by enough Nodes.
8+
9+
## Goals
10+
Libindy allows to extend building of supported requests via plugged interface and send them.
11+
It is nice to have a way to support BLS MS and SP verification for these plugged transactions.
12+
13+
Implementation of math for SP verification is a bit complicate for plugin logic.
14+
Therefore libindy should perform all math calculation inside.
15+
A plugin should provide handler to parse custom reply to fixed data structure.
16+
17+
## API
18+
The signature of the handler is described below together with custom `free` call to deallocate result data.
19+
20+
```rust
21+
extern fn CustomTransactionParser(reply_from_node: *const c_char, parsed_sp: *mut *const c_char) -> ErrorCode;
22+
extern fn CustomFree(data: *mut c_char) -> ErrorCode;
23+
```
24+
25+
Libindy API will contain call to register handler for specific transaction type:
26+
```rust
27+
extern fn indy_register_transaction_parser_for_sp(command_handle: i32,
28+
pool_handle: i32,
29+
txn_type: *const c_char,
30+
parser: CustomTransactionParser,
31+
free: CustomFree,
32+
cb: extern fn(command_handle_: i32, err: ErrorCode)) -> ErrorCode;
33+
```
34+
35+
### Parsed Data structure
36+
37+
A plugin should parse `reply_from_node` and return back to libindy parsed data as JSON string.
38+
Actually this data is array of entities each of them is describe SP Trie and set of key-value pairs to verify against this trie.
39+
It can be represented as `Vec<ParsedSP>` serialized to JSON.
40+
41+
42+
```rust
43+
/**
44+
Single item to verification:
45+
- SP Trie with RootHash
46+
- BLS MS
47+
- set of key-value to verify
48+
*/
49+
struct ParsedSP {
50+
/// encoded SP Trie transferred from Node to Client
51+
proof_nodes: String,
52+
/// RootHash of the Trie, start point for verification. Should be same with appropriate filed in BLS MS data
53+
root_hash: String,
54+
/// entities to verification against current SP Trie
55+
kvs_to_verify: KeyValuesInSP,
56+
/// BLS MS data for verification
57+
multi_signature: serde_json::Value,
58+
}
59+
60+
/**
61+
Variants of representation for items to verify against SP Trie
62+
Right now 2 options are specified:
63+
- simple array of key-value pair
64+
- whole subtrie
65+
*/
66+
enum KeyValuesInSP {
67+
Simple(KeyValueSimpleData),
68+
SubTrie(KeyValuesSubTrieData),
69+
}
70+
71+
/**
72+
Simple variant of `KeyValuesInSP`.
73+
74+
All required data already present in parent SP Trie (built from `proof_nodes`).
75+
`kvs` can be verified directly in parent trie
76+
*/
77+
struct KeyValueSimpleData {
78+
kvs: Vec<(String /* b64-encoded key */, Option<String /* val */>)>
79+
}
80+
81+
/**
82+
Subtrie variant of `KeyValuesInSP`.
83+
84+
In this case Client (libindy) should construct subtrie and append it into trie based on `proof_nodes`.
85+
After this preparation each kv pair can be checked.
86+
*/
87+
struct KeyValuesSubTrieData {
88+
/// base64-encoded common prefix of each pair in `kvs`. Should be used to correct merging initial trie and subtrie
89+
sub_trie_prefix: Option<String>,
90+
kvs: Vec<(String /* b64-encoded key_suffix */, Option<String /* val */>)>,
91+
}
92+
```
93+
94+
Expected libindy and plugin workflow is the following:
95+
1. Libindy receive reply from a Node, perform initial processing and pass raw reply to plugin.
96+
1. Plugin parse reply from the Node and specify one or more SP Trie with metadata and items for verification.
97+
1. Each SP Trie described by plugin as `ParsedSP`:
98+
1. Set of encoded nodes of the SP Trie, received from Node - `proof_nodes`. May be fetched from response "as is".
99+
1. RootHash of this Trie. May be fetched from the response "as is" also.
100+
1. BLS MS data. Again may be fetched from the response "as is".
101+
1. Key-value items to verification. Here plugin should define correct keys (path in the trie) and corresponded values.
102+
1. Plugin return serialized as JSON array of `ParsedSP`
103+
1. For each `ParsedSP` libindy:
104+
1. build base trie from `proof_nodes`
105+
1. if items to verify is `SubTrie`, construct this subtrie from (key-suffix, value) pairs and merge it with trie from clause above
106+
1. iterate other key-value pairs and verify that trie (with signed `root_hash`) contains `value` at specified `key`
107+
1. verify multi-signature
108+
1. If any verification is failed, libindy ignore particular SP + BLS MS and try to request same data from another node,
109+
or collect consensus of same replies from enough count of Nodes.
110+
111+
112+
Below is JSON structure for `Simple` case.
113+
```json
114+
[
115+
{
116+
"proof_nodes": "string with serialized SP tree",
117+
"root_hash": "string with root hash",
118+
"kvs_to_verify": {
119+
"type": "simple",
120+
"kvs": [["key1", "value1"], ["key2", "value2"]]
121+
},
122+
"multi_signature": "JSON object from Node`s reply as is"
123+
}
124+
]
125+
```
126+
127+
### Simple and SubTrie verification
128+
129+
Some use cases require verification multiply pairs of key-value in one Trie.
130+
Moreover there is possible situation when client would like to verify whole subtrie.
131+
In this case, the amount of data transferred from Node to Client can be significantly reduced.
132+
Instead of including all nodes for SP verification to `proof_nodes`, Node can include only prefix path down to subtrie.
133+
The entire subtrie to verification can be restored on Client side from key-value pairs and combined with prefix part.

libindy/src/api/wallet.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ pub extern fn indy_register_wallet_storage(command_handle: i32,
150150
/// {
151151
/// "storage": <object> List of supported keys are defined by wallet type.
152152
/// }
153-
/// credentials: Wallet credentials json (if NULL, then default config will be used).
153+
/// credentials_json: Wallet credentials json (if NULL, then default config will be used).
154154
/// {
155155
/// "key": string,
156156
/// "rekey": Optional<string>,
@@ -170,29 +170,29 @@ pub extern fn indy_create_wallet(command_handle: i32,
170170
name: *const c_char,
171171
storage_type: *const c_char,
172172
config: *const c_char,
173-
credentials: *const c_char,
173+
credentials_json: *const c_char,
174174
cb: Option<extern fn(xcommand_handle: i32,
175175
err: ErrorCode)>) -> ErrorCode {
176-
trace!("indy_create_wallet: >>> pool_name: {:?}, name: {:?}, storage_type: {:?}, config: {:?}, credentials: {:?}",
177-
pool_name, name, storage_type, config, credentials);
176+
trace!("indy_create_wallet: >>> pool_name: {:?}, name: {:?}, storage_type: {:?}, config: {:?}, credentials_json: {:?}",
177+
pool_name, name, storage_type, config, credentials_json);
178178

179179
check_useful_c_str!(pool_name, ErrorCode::CommonInvalidParam2);
180180
check_useful_c_str!(name, ErrorCode::CommonInvalidParam3);
181181
check_useful_opt_c_str!(storage_type, ErrorCode::CommonInvalidParam4);
182182
check_useful_opt_c_str!(config, ErrorCode::CommonInvalidParam5);
183-
check_useful_c_str!(credentials, ErrorCode::CommonInvalidParam6);
183+
check_useful_c_str!(credentials_json, ErrorCode::CommonInvalidParam6);
184184
check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7);
185185

186-
trace!("indy_create_wallet: entities >>> pool_name: {:?}, name: {:?}, storage_type: {:?}, config: {:?}, credentials: {:?}",
187-
pool_name, name, storage_type, config, credentials);
186+
trace!("indy_create_wallet: entities >>> pool_name: {:?}, name: {:?}, storage_type: {:?}, config: {:?}, credentials_json: {:?}",
187+
pool_name, name, storage_type, config, credentials_json);
188188

189189
let result = CommandExecutor::instance()
190190
.send(Command::Wallet(WalletCommand::Create(
191191
pool_name,
192192
name,
193193
storage_type,
194194
config,
195-
credentials,
195+
credentials_json,
196196
Box::new(move |result| {
197197
let err = result_to_err_code!(result);
198198
trace!("indy_create_wallet:");
@@ -218,7 +218,7 @@ pub extern fn indy_create_wallet(command_handle: i32,
218218
/// {
219219
/// "storage": Optional<object> List of supported keys are defined by wallet type.
220220
/// }
221-
/// credentials: Wallet credentials json.
221+
/// credentials_json: Wallet credentials json.
222222
/// {
223223
/// "key": string,
224224
/// "rekey": Optional<string>,
@@ -236,24 +236,24 @@ pub extern fn indy_create_wallet(command_handle: i32,
236236
pub extern fn indy_open_wallet(command_handle: i32,
237237
name: *const c_char,
238238
runtime_config: *const c_char,
239-
credentials: *const c_char,
239+
credentials_json: *const c_char,
240240
cb: Option<extern fn(xcommand_handle: i32,
241241
err: ErrorCode,
242242
handle: i32)>) -> ErrorCode {
243-
trace!("indy_open_wallet: >>> name: {:?}, runtime_config: {:?}, credentials: {:?}", name, runtime_config, credentials);
243+
trace!("indy_open_wallet: >>> name: {:?}, runtime_config: {:?}, credentials_json: {:?}", name, runtime_config, credentials_json);
244244

245245
check_useful_c_str!(name, ErrorCode::CommonInvalidParam2);
246246
check_useful_opt_c_str!(runtime_config, ErrorCode::CommonInvalidParam3);
247-
check_useful_c_str!(credentials, ErrorCode::CommonInvalidParam4);
247+
check_useful_c_str!(credentials_json, ErrorCode::CommonInvalidParam4);
248248
check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam5);
249249

250-
trace!("indy_open_wallet: entities >>> name: {:?}, runtime_config: {:?}, credentials: {:?}", name, runtime_config, credentials);
250+
trace!("indy_open_wallet: entities >>> name: {:?}, runtime_config: {:?}, credentials_json: {:?}", name, runtime_config, credentials_json);
251251

252252
let result = CommandExecutor::instance()
253253
.send(Command::Wallet(WalletCommand::Open(
254254
name,
255255
runtime_config,
256-
credentials,
256+
credentials_json,
257257
Box::new(move |result| {
258258
let (err, handle) = result_to_err_code_1!(result, 0);
259259
trace!("indy_open_wallet: handle: {:?}", handle);
@@ -340,7 +340,7 @@ pub extern fn indy_close_wallet(command_handle: i32,
340340
///
341341
/// #Params
342342
/// name: Name of the wallet to delete.
343-
/// credentials: Wallet credentials json. List of supported keys are defined by wallet type.
343+
/// credentials_json: Wallet credentials json. List of supported keys are defined by wallet type.
344344
/// if NULL, then default credentials will be used.
345345
///
346346
/// #Returns
@@ -352,21 +352,21 @@ pub extern fn indy_close_wallet(command_handle: i32,
352352
#[no_mangle]
353353
pub extern fn indy_delete_wallet(command_handle: i32,
354354
name: *const c_char,
355-
credentials: *const c_char,
355+
credentials_json: *const c_char,
356356
cb: Option<extern fn(xcommand_handle: i32,
357357
err: ErrorCode)>) -> ErrorCode {
358-
trace!("indy_delete_wallet: >>> name: {:?}, credentials: {:?}", name, credentials);
358+
trace!("indy_delete_wallet: >>> name: {:?}, credentials_json: {:?}", name, credentials_json);
359359

360360
check_useful_c_str!(name, ErrorCode::CommonInvalidParam2);
361-
check_useful_c_str!(credentials, ErrorCode::CommonInvalidParam3);
361+
check_useful_c_str!(credentials_json, ErrorCode::CommonInvalidParam3);
362362
check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam4);
363363

364-
trace!("indy_delete_wallet: entities >>> name: {:?}, credentials: {:?}", name, credentials);
364+
trace!("indy_delete_wallet: entities >>> name: {:?}, credentials_json: {:?}", name, credentials_json);
365365

366366
let result = CommandExecutor::instance()
367367
.send(Command::Wallet(WalletCommand::Delete(
368368
name,
369-
credentials,
369+
credentials_json,
370370
Box::new(move |result| {
371371
let err = result_to_err_code!(result);
372372
trace!("indy_delete_wallet:");
@@ -386,11 +386,11 @@ pub extern fn indy_delete_wallet(command_handle: i32,
386386
/// #Params
387387
/// name: wallet storage name (the same as wallet name)
388388
/// config: wallet storage config (For example, database config)
389-
/// credentials: wallet storage credentials (For example, database credentials)
389+
/// credentials_json: wallet storage credentials (For example, database credentials)
390390
/// metadata: wallet metadata (For example encrypted keys).
391391
pub type WalletCreate = extern fn(name: *const c_char,
392392
config: *const c_char,
393-
credentials: *const c_char,
393+
credentials_json: *const c_char,
394394
metadata: *const c_char) -> ErrorCode;
395395

396396
/// Open the wallet storage (For example, opening database connection)
@@ -399,12 +399,12 @@ pub type WalletCreate = extern fn(name: *const c_char,
399399
/// name: wallet storage name (the same as wallet name)
400400
/// config: wallet storage config (For example, database config)
401401
/// runtime_config: wallet storage runtime config (For example, connection config)
402-
/// credentials: wallet storage credentials (For example, database credentials)
402+
/// credentials_json: wallet storage credentials (For example, database credentials)
403403
/// storage_handle_p: pointer to store opened storage handle
404404
pub type WalletOpen = extern fn(name: *const c_char,
405405
config: *const c_char,
406406
runtime_config: *const c_char,
407-
credentials: *const c_char,
407+
credentials_json: *const c_char,
408408
storage_handle_p: *mut i32) -> ErrorCode;
409409

410410
/// Close the opened walled storage (For example, closing database connection)
@@ -418,10 +418,10 @@ pub type WalletClose = extern fn(storage_handle: i32) -> ErrorCode;
418418
/// #Params
419419
/// name: wallet storage name (the same as wallet name)
420420
/// config: wallet storage config (For example, database config)
421-
/// credentials: wallet storage credentials (For example, database credentials)
421+
/// credentials_json: wallet storage credentials (For example, database credentials)
422422
pub type WalletDelete = extern fn(name: *const c_char,
423423
config: *const c_char,
424-
credentials: *const c_char) -> ErrorCode;
424+
credentials_json: *const c_char) -> ErrorCode;
425425

426426
/// Create a new record in the wallet storage
427427
///

libindy/src/errors/pool.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub enum PoolError {
1616
Terminate,
1717
Timeout,
1818
AlreadyExists(String),
19-
CommonError(CommonError)
19+
CommonError(CommonError),
2020
}
2121

2222
impl fmt::Display for PoolError {
@@ -27,7 +27,7 @@ impl fmt::Display for PoolError {
2727
PoolError::Terminate => write!(f, "Pool work terminated"),
2828
PoolError::Timeout => write!(f, "Timeout"),
2929
PoolError::AlreadyExists(ref description) => write!(f, "Pool ledger config already exists {}", description),
30-
PoolError::CommonError(ref err) => err.fmt(f)
30+
PoolError::CommonError(ref err) => err.fmt(f),
3131
}
3232
}
3333
}
@@ -40,7 +40,7 @@ impl error::Error for PoolError {
4040
PoolError::Terminate => "Pool work terminated",
4141
PoolError::Timeout => "Timeout",
4242
PoolError::AlreadyExists(ref description) => description,
43-
PoolError::CommonError(ref err) => err.description()
43+
PoolError::CommonError(ref err) => err.description(),
4444
}
4545
}
4646

@@ -49,7 +49,7 @@ impl error::Error for PoolError {
4949
PoolError::NotCreated(_) | PoolError::InvalidHandle(_) => None,
5050
PoolError::Terminate | PoolError::Timeout => None,
5151
PoolError::AlreadyExists(_) => None,
52-
PoolError::CommonError(ref err) => Some(err)
52+
PoolError::CommonError(ref err) => Some(err),
5353
}
5454
}
5555
}

0 commit comments

Comments
 (0)