-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathplugin.h
More file actions
622 lines (544 loc) · 23.5 KB
/
plugin.h
File metadata and controls
622 lines (544 loc) · 23.5 KB
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
/*******************************************************************************
* This file is part of the Incubed project.
* Sources: https://github.com/blockchainsllc/in3
*
* Copyright (C) 2018-2020 slock.it GmbH, Blockchains LLC
*
*
* COMMERCIAL LICENSE USAGE
*
* Licensees holding a valid commercial license may use this file in accordance
* with the commercial license agreement provided with the Software or, alternatively,
* in accordance with the terms contained in a written agreement between you and
* slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further
* information please contact slock.it at in3@slock.it.
*
* Alternatively, this file may be used under the AGPL license as follows:
*
* AGPL LICENSE USAGE
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Affero General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
* [Permissions of this strong copyleft license are conditioned on making available
* complete source code of licensed works and modifications, which include larger
* works using a licensed work, under the same license. Copyright and license notices
* must be preserved. Contributors provide an express grant of patent rights.]
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
// @PUBLIC_HEADER
/** @file
* this file defines the plugin-contexts
*
*
* */
#ifndef PLUGIN_H
#define PLUGIN_H
#ifdef __cplusplus
extern "C" {
#endif
#include "client.h"
#include "request.h"
// ---------- plugin management -----------------
/** checks if a plugin for specified action is registered with the client */
#define in3_plugin_is_registered(client, action) (((client)->plugin_acts & (action)) == (action))
/** registers a plugin with the client */
in3_ret_t in3_plugin_register(
in3_t* c, /**< the client */
in3_plugin_supp_acts_t acts, /**< the actions to register for combined with OR */
in3_plugin_act_fn action_fn, /**< the plugin action function */
void* data, /**< an optional data or config struct which will be passed to the action function when executed */
bool replace_ex /**< if this is true and an plugin with the same action is already registered, it will replace it */
);
/**
* adds a plugin rregister function to the default. All defaults functions will automaticly called and registered for every new in3_t instance.
*/
void in3_register_default(plgn_register reg_fn);
/** executes all plugins irrespective of their return values, returns first error (if any) */
in3_ret_t in3_plugin_execute_all(in3_t* c, in3_plugin_act_t action, void* plugin_ctx);
/**
* executes all plugin actions one-by-one, stops when a plugin returns anything other than IN3_EIGNORE.
* returns IN3_EPLGN_NONE if no plugin was able to handle specified action, otherwise returns IN3_OK
* plugin errors are reported via the in3_req_t
*/
in3_ret_t in3_plugin_execute_first(in3_req_t* req, in3_plugin_act_t action, void* plugin_ctx);
/**
* same as in3_plugin_execute_first(), but returns IN3_OK even if no plugin could handle specified action
*/
in3_ret_t in3_plugin_execute_first_or_none(in3_req_t* req, in3_plugin_act_t action, void* plugin_ctx);
/**
* get direct access to plugin data (if registered) based on action function
*/
static inline void* in3_plugin_get_data(in3_t* c, in3_plugin_act_fn fn) {
for (in3_plugin_t* p = c->plugins; p; p = p->next) {
if (p->action_fn == fn) return p->data;
}
return NULL;
}
// ----------- RPC HANDLE -----------
/**
* verification context holding the pointers to all relevant toknes.
*/
typedef struct {
in3_req_t* req; /**< Request context. */
d_token_t* request; /**< request */
in3_response_t** response; /**< the responses which a prehandle-method should set*/
char* method; /**< the method of the request */
d_token_t* params; /**< the params */
} in3_rpc_handle_ctx_t;
#define RPC_THROW(ctx, msg, code) \
{ return req_set_error(ctx->req, msg, code); }
#define RPC_ASSERT(cond, msg) \
{ \
if (!(cond)) return req_set_error(ctx->req, msg, IN3_EINVAL); \
}
#define RPC_ASSERT_CATCH(cond, msg, f) \
{ \
if (!(cond)) { \
{ f; } \
return req_set_error(ctx->req, msg, IN3_EINVAL); \
} \
}
/**
* creates a response and returns a stringbuilder to add the result-data.
*/
NONULL sb_t* in3_rpc_handle_start(in3_rpc_handle_ctx_t* hctx);
/**
* finish the response.
*/
NONULL in3_ret_t in3_rpc_handle_finish(in3_rpc_handle_ctx_t* hctx);
/**
* creates a response with bytes.
*/
NONULL in3_ret_t in3_rpc_handle_with_bytes(in3_rpc_handle_ctx_t* hctx, bytes_t data);
/**
* creates a response with a json token.
*/
NONULL in3_ret_t in3_rpc_handle_with_json(in3_rpc_handle_ctx_t* ctx, d_token_t* result);
/**
* creates a response with string.
*/
NONULL in3_ret_t in3_rpc_handle_with_string(in3_rpc_handle_ctx_t* hctx, char* data);
/**
* creates a response with a value which is added as hex-string.
*/
NONULL in3_ret_t in3_rpc_handle_with_int(in3_rpc_handle_ctx_t* hctx, uint64_t value);
/**
* creates a response with bytes but without a leading 0.
*/
NONULL in3_ret_t in3_rpc_handle_with_uint256(in3_rpc_handle_ctx_t* hctx, bytes_t data);
// -------------- TRANSPORT -------------
/**
* optional request headers
*/
typedef struct in3_req_header {
char* value; /**< the value */
struct in3_req_header* next; /**< pointer to next header */
} in3_req_header_t;
/** request-object.
*
* represents a RPC-request
*/
typedef struct in3_http_request {
char* method; /**< the http-method to be used */
char* payload; /**< the payload to send */
char** urls; /**< array of urls */
uint_fast16_t urls_len; /**< number of urls */
uint32_t payload_len; /**< length of the payload in bytes. */
struct in3_req* req; /**< the current context */
void* cptr; /**< a custom ptr to hold information during */
uint32_t wait; /**< time in ms to wait before sending out the request */
in3_req_header_t* headers; /**< optional additional headers to be send with the request */
} in3_http_request_t;
/**
* getter to retrieve the payload from a in3_http_request_t struct
*/
char* in3_get_request_payload(
in3_http_request_t* request /**< request struct */
);
/**
* getter to retrieve the length of the payload from a in3_http_request_t struct
*/
uint32_t in3_get_request_payload_len(
in3_http_request_t* request /**< request struct */
);
/**
* getter to retrieve the urls list length from a in3_http_request_t struct
*/
int in3_get_request_headers_len(
in3_http_request_t* request /**< request struct */
);
/**
* getter to retrieve the urls list length from a in3_http_request_t struct
*/
char* in3_get_request_headers_at(
in3_http_request_t* request, /**< request struct */
int index /**< the inde xof the header */
);
/**
* getter to retrieve the http-method from a in3_http_request_t struct
*/
char* in3_get_request_method(
in3_http_request_t* request /**< request struct */
);
/**
* getter to retrieve the urls list from a in3_http_request_t struct
*/
char** in3_get_request_urls(
in3_http_request_t* request /**< request struct */
);
/**
* getter to retrieve the urls list length from a in3_http_request_t struct
*/
int in3_get_request_urls_len(
in3_http_request_t* request /**< request struct */
);
/**
* getter to retrieve the urls list length from a in3_http_request_t struct
*/
uint32_t in3_get_request_timeout(
in3_http_request_t* request /**< request struct */
);
/**
* adds a response for a request-object.
* This function should be used in the transport-function to set the response.
*/
NONULL void in3_req_add_response(
in3_http_request_t* req, /**< [in]the the request */
int index, /**< [in] the index of the url, since this request could go out to many urls */
int error, /**< [in] if <0 this will be reported as error. the message should then be the error-message */
const char* data, /**< the data or the the string*/
int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/
uint32_t time /**< the time this request took in ms or 0 if not possible (it will be used to calculate the weights)*/
);
/**
* adds a response to a context.
* This function should be used in the transport-function to set the response.
*/
NONULL void in3_ctx_add_response(
in3_req_t* req, /**< [in]the current context */
int index, /**< [in] the index of the url, since this request could go out to many urls */
int error, /**< [in] if <0 this will be reported as error. the message should then be the error-message */
const char* data, /**< the data or the the string*/
int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/
uint32_t time /**< the time this request took in ms or 0 if not possible (it will be used to calculate the weights)*/
);
typedef in3_ret_t (*in3_transport_legacy)(in3_http_request_t* request);
/**
* defines a default transport which is used when creating a new client.
*/
void in3_set_default_legacy_transport(
in3_transport_legacy transport /**< the default transport-function. */
);
// --------- SIGN_ACCOUNT --------------------
/**
* defines the type of signer used
*/
typedef enum {
SIGNER_ECDSA = 1,
SIGNER_EIP1271 = 2
} in3_signer_type_t;
/** type of the curve used for signing*/
typedef enum {
SIGN_CURVE_ECDSA = 1, /**< sign with ecdsa */
SIGN_CURVE_ED25519 = 2, /**< use ed25519 curve */
} d_curve_type_t;
/**
* action context when retrieving the addresses or accounts of a signer.
*/
typedef struct sign_account_ctx {
struct in3_req* req; /**< the context of the request in order report errors */
uint8_t* accounts; /**< the account to use for the signature */
int accounts_len; /**< number of accounts */
d_curve_type_t curve_type; /**< the type of the curve used */
in3_signer_type_t signer_type; /**< the type of the signer used for this account.*/
} in3_sign_account_ctx_t;
/**
* action context when retrieving the public key of the signer.
*/
typedef struct sign_public_key_ctx {
struct in3_req* req; /**< the context of the request in order report errors */
d_curve_type_t curve_type; /**< the type of the curve used */
uint8_t* account; /**< the account to use for the signature */
uint8_t public_key[64]; /**< the public key in case the plugin returns IN3_OK */
} in3_sign_public_key_ctx_t;
// ----------- SIGN_PREPARE ---------------
/**
* action context when retrieving the account of a signer.
*/
typedef struct sign_prepare_ctx {
struct in3_req* req; /**< the context of the request in order report errors */
address_t account; /**< the account to use for the signature */
d_token_t* tx; /**< the tx-definition, which may contain additional properties */
bytes_t old_tx; /**< the source-transaction */
bytes_t new_tx; /**< the new-transaction, if the transaction should not changed, the data-ptr must be NULL otherwise a new allocated memory is expected, which will be cleaned by the caller. */
sb_t* output; /**< if this is not NULL, the transaction will not be send, but returns only the state */
} in3_sign_prepare_ctx_t;
// -------------- SIGN -----------------------
/** type of the hashing method for the pqyload for the requested signature */
typedef enum {
SIGN_EC_RAW = 0, /**< sign the data directly */
SIGN_EC_HASH = 1, /**< hash and sign the data */
SIGN_EC_PREFIX = 2, /**< add Ethereum Signed Message-Proefix, hash and sign the data */
SIGN_EC_BTC = 3, /**< hashes the data twice with sha256 and signs it */
} d_digest_type_t;
/** payload type of the requested signature. It describes how to deserialize the payload. */
typedef enum {
PL_SIGN_ANY = 0, /**< custom data to be signed*/
PL_SIGN_ETHTX = 1, /**< the payload is a ethereum-tx */
PL_SIGN_BTCTX = 2, /**< the payload is a BTC-Tx-Input */
PL_SIGN_SAFETX = 3 /**< The payload is a rlp-encoded data of a Gnosys Safe Tx */
} d_payload_type_t;
/**
* signing context. This Context is passed to the signer-function.
*/
typedef struct sign_ctx {
bytes_t signature; /**< the resulting signature */
d_digest_type_t digest_type; /**< the type of signature*/
d_curve_type_t curve_type; /**< type of curved used to sign */
d_payload_type_t payload_type; /**< the type of payload in order to deserialize the payload */
struct in3_req* req; /**< the context of the request in order report errors */
bytes_t message; /**< the message to sign*/
bytes_t account; /**< the account to use for the signature */
d_token_t* meta; /**< optional metadata to pass a long, which could include data to present to the user before signing */
} in3_sign_ctx_t;
/**
* helper function to retrieve and message from a in3_sign_ctx_t
*/
bytes_t in3_sign_ctx_get_message(
in3_sign_ctx_t* ctx /**< the signer context */
);
/**
* helper function to retrieve and account from a in3_sign_ctx_t
*/
bytes_t in3_sign_ctx_get_account(
in3_sign_ctx_t* ctx /**< the signer context */
);
/**
* helper function to retrieve the signature from a in3_sign_ctx_t
*/
void in3_sign_ctx_set_signature_hex(
in3_sign_ctx_t* ctx, /**< the signer context */
const char* signature /**< the signature in hex */
);
/**
* creates a signer ctx to be used for async signing.
*/
NONULL in3_sign_ctx_t* create_sign_ctx(
in3_req_t* req /**< [in] the rpc context */
);
// -------- SET_CONFIG ---------
/**
* context used during configure
*/
typedef struct in3_configure_ctx {
in3_t* client; /**< the client to configure */
json_ctx_t* json; /**< the json ctx corresponding to below token */
d_token_t* token; /**< the token not handled yet*/
char* error_msg; /**< message in case of an incorrect config */
} in3_configure_ctx_t;
// -------- GET_CONFIG ---------
/**
* context used during get config
*/
typedef struct in3_get_config_ctx {
in3_t* client; /**< the client to configure */
sb_t* sb; /**< stringbuilder to add json-config*/
} in3_get_config_ctx_t;
// -------- CACHE ---------
/**
* storage handler function for reading from cache.
* @returns the found result. if the key is found this function should return the values as bytes otherwise `NULL`.
**/
typedef bytes_t* (*in3_storage_get_item)(
void* cptr, /**< a custom pointer as set in the storage handler*/
const char* key /**< the key to search in the cache */
);
/**
* storage handler function for writing to the cache.
**/
typedef void (*in3_storage_set_item)(
void* cptr, /**< a custom pointer as set in the storage handler*/
const char* key, /**< the key to store the value.*/
bytes_t* value /**< the value to store.*/
);
/**
* storage handler function for clearing the cache.
**/
typedef void (*in3_storage_clear)(
void* cptr /**< a custom pointer as set in the storage handler*/
);
/**
* context used during get config
*/
typedef struct in3_cache_ctx {
in3_req_t* req; /**< the request context */
const char* key; /**< the key to fetch */
bytes_t* content; /**< the content to set */
} in3_cache_ctx_t;
/**
* create a new storage handler-object to be set on the client.
* the caller will need to free this pointer after usage.
*/
NONULL_FOR((1, 2, 3, 4))
void in3_set_storage_handler(
in3_t* c, /**< the incubed client */
in3_storage_get_item get_item, /**< function pointer returning a stored value for the given key.*/
in3_storage_set_item set_item, /**< function pointer setting a stored value for the given key.*/
in3_storage_clear clear, /**< function pointer clearing all contents of cache.*/
void* cptr /**< custom pointer which will will be passed to functions */
);
// ----------- VERIFY --------------
#ifdef LOGGING
#define vc_err(vc, msg) vc_set_error(vc, msg)
#else
#define vc_err(vc, msg) vc_set_error(vc, NULL)
#endif
/**
* verification context holding the pointers to all relevant toknes.
*/
typedef struct {
in3_req_t* req; /**< Request context. */
in3_chain_t* chain; /**< the chain definition. */
d_token_t* result; /**< the result to verify */
d_token_t* request; /**< the request sent. */
d_token_t* proof; /**< the delivered proof. */
in3_t* client; /**< the client. */
uint64_t last_validator_change; /**< Block number of last change of the validator list */
uint64_t currentBlock; /**< Block number of latest block */
int index; /**< the index of the request within the bulk */
node_match_t* node; /**< the node who delivered this response */
bool dont_blacklist; /**< indicates whether the plugin would like the node to be blacklisted */
char* method; /**< the rpc-method to verify agains */
} in3_vctx_t;
#ifdef LOGGING
NONULL
#endif
/*
* creates an error attaching it to the context and returns -1.
*/
in3_ret_t vc_set_error(
in3_vctx_t* vc, /**< the verification context. */
char* msg /**< the error message. */
);
// ---- PLGN_ACT_PAY_FOLLOWUP -----------
typedef struct {
in3_req_t* req; /**< Request context. */
node_match_t* node; /**< the responding node. */
d_token_t* resp_in3; /**< the response's in3 section */
d_token_t* resp_error; /**< the response's error section */
} in3_pay_followup_ctx_t;
// ---- PLGN_ACT_PAY_HANDLE -----------
typedef struct {
in3_req_t* req; /**< Request context. */
sb_t* payload; /**< the request payload */
bytes32_t pk; /**< the private-key to sign with */
} in3_pay_handle_ctx_t;
// ---- PAY_SIGN_REQ -----------
typedef struct {
in3_req_t* req; /**< Request context. */
d_token_t* request; /**< the request sent. */
bytes32_t request_hash; /**< the hash to sign */
uint8_t signature[65]; /**< the signature */
} in3_pay_sign_req_ctx_t;
// ---- PLGN_ACT_ADD_PAYLOAD -----------
typedef struct {
in3_req_t* req; /**< Request context. */
d_token_t* request; /**< the request sent. */
sb_t* sb; /**< the string builder in the in3-section */
} in3_pay_payload_ctx_t;
// ---- LOG_ERROR -----------
typedef struct {
char* msg; /**< the error message. */
uint16_t error; /**< error code. */
in3_req_t* req; /**< ctx . */
} error_log_ctx_t;
// -------- NL_PICK ---------
typedef enum {
NL_DATA, /**< data provider node. */
NL_SIGNER /**< signer node. */
} in3_nl_pick_type_t;
typedef struct {
in3_nl_pick_type_t type; /**< type of node to pick. */
in3_req_t* req; /**< Request context. */
} in3_nl_pick_ctx_t;
// -------- NL_FOLLOWUP ---------
typedef struct {
in3_req_t* req; /**< Request context. */
node_match_t* node; /**< Node that gave us a valid response */
} in3_nl_followup_ctx_t;
// -------- NL_BLACKLIST ---------
typedef struct {
union {
uint8_t* address; /**< address of node that is to be blacklisted */
const char* url; /**< URL of node that is to be blacklisted */
};
in3_req_t* req; /**< Request context. */
bool is_addr; /**< Specifies whether the identifier is an address or a url */
} in3_nl_blacklist_ctx_t;
// -------- NL_OFFLINE ---------
typedef struct {
in3_vctx_t* vctx; /**< Request context. */
unsigned int missing; /**< bitmask representing nodes - a reset bit indicates missing signatures */
} in3_nl_offline_ctx_t;
// -------- GET_DATA ---------
typedef enum {
GET_DATA_REGISTRY_ID, /* returns a pointer to an internal bytes32_t representation; NO cleanup required */
GET_DATA_NODE_MIN_BLK_HEIGHT, /* returns a pointer to an internal bitmask; NO cleanup required */
GET_DATA_CLIENT_DATA, /* returns an opaque pointer that was previously set by caller */
} in3_get_data_type_t;
/**
* context used during get data
* sample usage -
* in3_get_data_ctx_t dctx = {.type = GET_DATA_REGISTRY_ID};
* in3_plugin_execute_first(ctx, PLGN_ACT_GET_DATA, &dctx);
* // use dctx->data as required
* if (dctx.cleanup) dctx.cleanup(dctx.data);
*/
typedef struct {
in3_req_t* req; /**< the request context */
in3_get_data_type_t type; /**< type of data that the caller wants. */
void* data; /**< output param set by plugin code - pointer to data requested. */
void (*cleanup)(void*); /**< output param set by plugin code - if not NULL use it to cleanup the data. */
} in3_get_data_ctx_t;
/**
* raises a error during config by setting the error-message and returning a error-code.
*/
#define CNF_ERROR(msg) \
{ \
ctx->error_msg = _strdupn(msg, -1); \
return IN3_EINVAL; \
}
/**
* sets the bytes as taken from the given property to the target and raises an error if the len does not fit.
*/
#define CNF_SET_BYTES(dst, token, property, l) \
{ \
const bytes_t tmp = d_bytes(d_get(token, key(property))); \
if (tmp.data) { \
if (tmp.len != l) CNF_ERROR(property " must be " #l " bytes") \
memcpy(dst, tmp.data, l); \
} \
}
/**
* sets the string as taken from the given property to the target and raises an error if the len does not fit.
*/
#define CNF_SET_STRING(dst, token, property) \
{ \
d_token_t* t = d_get(token, key(property)); \
if (d_type(t) != T_NULL && d_type(t) != T_STRING) CNF_ERROR("Invalid config for " property "!") \
const char* tmp = d_string(t); \
if (tmp) { \
if (dst) _free(dst); \
dst = _strdupn(tmp, -1); \
} \
}
#ifdef __cplusplus
}
#endif
#endif // PLUGIN_H