diff --git a/CHANGELOG.md b/CHANGELOG.md index e939b58e3..b52d02b36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## v1.0.0-rc3 +Wed Jan 26 18:02:27 CET 2022 + +* [5d0290d](https://github.com/hyperledger/fabric-private-chaincode/commit/5d0290d) Release v1.0-rc3 +* [0dbf76f](https://github.com/hyperledger/fabric-private-chaincode/commit/0dbf76f) Update IRB readme +* [d472bca](https://github.com/hyperledger/fabric-private-chaincode/commit/d472bca) Link existing FSC examples +* [36a60d3](https://github.com/hyperledger/fabric-private-chaincode/commit/36a60d3) Add del_state support (#640) +* [5febb77](https://github.com/hyperledger/fabric-private-chaincode/commit/5febb77) Fix memory leak in cert decoding +* [3bfeeb5](https://github.com/hyperledger/fabric-private-chaincode/commit/3bfeeb5) Add missing pb_release calls +* [2234bb4](https://github.com/hyperledger/fabric-private-chaincode/commit/2234bb4) Add stress test for many invocations +* [58e58a5](https://github.com/hyperledger/fabric-private-chaincode/commit/58e58a5) Upgrade parson +* [a949ca9](https://github.com/hyperledger/fabric-private-chaincode/commit/a949ca9) Extend FPC Shim support (#637) +* [5713269](https://github.com/hyperledger/fabric-private-chaincode/commit/5713269) fix sgx device location for dcap machines (#639) +* [0aea62d](https://github.com/hyperledger/fabric-private-chaincode/commit/0aea62d) Demo FSC integration using the IRB demo (#635) +* [d07bc32](https://github.com/hyperledger/fabric-private-chaincode/commit/d07bc32) fixup! Upgrade to Fabric 2.3.3 +* [eadb34c](https://github.com/hyperledger/fabric-private-chaincode/commit/eadb34c) Upgrade to Fabric 2.3.3 +* [079f357](https://github.com/hyperledger/fabric-private-chaincode/commit/079f357) Upgrade to go 1.16.7 +* [22f32d8](https://github.com/hyperledger/fabric-private-chaincode/commit/22f32d8) Updated helloworld readme +* [29041c8](https://github.com/hyperledger/fabric-private-chaincode/commit/29041c8) Fixed the version of fabric-ccenv to 2.3.0. +* [b2e72ab](https://github.com/hyperledger/fabric-private-chaincode/commit/b2e72ab) Post-Release: Set version to main + ## v1.0.0-rc2 Thu Sep 9 09:57:18 CEST 2021 diff --git a/README.md b/README.md index bde26b18b..5451a18e1 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,7 @@ A few more notes: * If you run behind a proxy, you will have to configure the proxy, e.g., for docker (`~/.docker/config.json`). See [Working from behind a proxy](#working-from-behind-a-proxy) below for more information. -* If your local host is SGX enabled, i.e., there is a device `/dev/sgx` or +* If your local host is SGX enabled, i.e., there is a device `/dev/sgx/enclave` or `/dev/isgx` and your PSW daemon listens to `/var/run/aesmd`, then the docker image will be sgx-enabled and your settings from `./config/ias` will be used. You will have to manually set `SGX_MODE=HW` before building anything to use HW mode. * If you want additional apt packages to be automatically added to your container images, you can do so by modifying `$FPC_PATH/config.override.mk` file in the fabric-private-chaincode directory. @@ -254,7 +254,7 @@ Make sure that you have the following required dependencies installed: * CMake v3.5.1 or higher -* [Go](https://golang.org/) 1.15.4 or higher +* [Go](https://golang.org/) 1.16.7 or higher * Docker 18.09 (or higher) and docker-compose 1.25.x (or higher) Note that version from Ubuntu 18.04 is not recent enough! To upgrade, install a recent version following the instructions from [docker.com](https://docs.docker.com/compose/install/), e.g., for version 1.25.4 execute @@ -287,7 +287,7 @@ Make sure that you have the following required dependencies installed: * [Intel Software Guard Extensions SSL](https://github.com/intel/intel-sgx-ssl) (we recommend using branch `lin_2.10_1.1.1g` OpenSSL `1.1.1g`) -* Hyperledger [Fabric](https://github.com/hyperledger/fabric/tree/v2.3.0) v2.3.0 +* Hyperledger [Fabric](https://github.com/hyperledger/fabric/tree/v2.3.3) v2.3.3 * Clang-format 6.x or higher @@ -344,15 +344,15 @@ export PROTOC_CMD=/usr/local/proto3/bin/protoc #### Hyperledger Fabric Our project fetches the latest supported Fabric binaries during the build process automatically. -However, if you want to use your own Fabric binaries, please checkout Fabric 2.3.0 release using the following commands: +However, if you want to use your own Fabric binaries, please checkout Fabric 2.3.3 release using the following commands: ```bash export FABRIC_PATH=$GOPATH/src/github.com/hyperledger/fabric git clone https://github.com/hyperledger/fabric.git $FABRIC_PATH -cd $FABRIC_PATH; git checkout tags/v2.3.0 +cd $FABRIC_PATH; git checkout tags/v2.3.3 ``` Note that Fabric Private Chaincode may not work with the Fabric `main` branch. -Therefore, make sure you use the Fabric `v2.3.0` tag. +Therefore, make sure you use the Fabric `v2.3.3` tag. Make sure the source of Fabric is in your `$GOPATH`. ## Build Fabric Private Chaincode diff --git a/common/enclave/cc_data.cpp b/common/enclave/cc_data.cpp index fb7276700..d0d7e5ece 100644 --- a/common/enclave/cc_data.cpp +++ b/common/enclave/cc_data.cpp @@ -232,6 +232,21 @@ std::string cc_data::get_enclave_id() return hex; } +std::string cc_data::get_channel_id() +{ + fpc_CCParameters cc_params = fpc_CCParameters_init_zero; + pb_istream_t istream = + pb_istream_from_buffer((const unsigned char*)cc_parameters_.data(), cc_parameters_.size()); + bool b = pb_decode(&istream, fpc_CCParameters_fields, &cc_params); + COND2LOGERR(!b, PB_GET_ERROR(&istream)); + + return std::string(cc_params.channel_id); + +err: + // return empty string in case of error + return std::string(); +} + bool cc_data::sign_message(const ByteArray& message, ByteArray& signature) const { bool b; diff --git a/common/enclave/cc_data.h b/common/enclave/cc_data.h index 49ad3f5c4..2074c32a4 100644 --- a/common/enclave/cc_data.h +++ b/common/enclave/cc_data.h @@ -43,6 +43,8 @@ class cc_data uint32_t* credentials_size); std::string get_enclave_id(); + std::string get_channel_id(); + bool sign_message(const ByteArray& message, ByteArray& signature) const; bool decrypt_key_transport_message( const ByteArray& encrypted_key_transport_message, ByteArray& key_transport_message) const; diff --git a/common/json/parson.c b/common/json/parson.c index fbde218c6..df694f3ae 100644 --- a/common/json/parson.c +++ b/common/json/parson.c @@ -1,6 +1,8 @@ /* - Parson ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2017 Krzysztof Gabis + SPDX-License-Identifier: MIT + + Parson 1.2.1 ( http://kgabis.github.com/parson/ ) + Copyright (c) 2012 - 2021 Krzysztof Gabis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,6 +30,24 @@ #include "parson.h" +#define PARSON_IMPL_VERSION_MAJOR 1 +#define PARSON_IMPL_VERSION_MINOR 2 +#define PARSON_IMPL_VERSION_PATCH 1 + +#if (PARSON_VERSION_MAJOR != PARSON_IMPL_VERSION_MAJOR)\ +|| (PARSON_VERSION_MINOR != PARSON_IMPL_VERSION_MINOR)\ +|| (PARSON_VERSION_PATCH != PARSON_IMPL_VERSION_PATCH) +#error "parson version mismatch between parson.c and parson.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif +int snprintf(char *str, size_t size, const char *format, ...); +#ifdef __cplusplus +} +#endif + #include #include #include @@ -37,7 +57,16 @@ /* Apparently sscanf is not implemented in some "standard" libraries, so don't use it, if you * don't have to. */ +#ifdef sscanf +#undef sscanf #define sscanf THINK_TWICE_ABOUT_USING_SSCANF +#endif + +/* strcpy is unsafe */ +#ifdef strcpy +#undef strcpy +#endif +#define strcpy USE_MEMCPY_INSTEAD_OF_STRCPY #define STARTING_CAPACITY 16 #define MAX_NESTING 2048 @@ -53,14 +82,34 @@ #undef malloc #undef free +#if defined(isnan) && defined(isinf) +#define IS_NUMBER_INVALID(x) (isnan((x)) || isinf((x))) +#else +#define IS_NUMBER_INVALID(x) (((x) * 0.0) != 0.0) +#endif + +#define OBJECT_INVALID_IX ((size_t)-1) + static JSON_Malloc_Function parson_malloc = malloc; static JSON_Free_Function parson_free = free; +static int parson_escape_slashes = 1; + #define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */ +typedef int parson_bool_t; + +#define PARSON_TRUE 1 +#define PARSON_FALSE 0 + +typedef struct json_string { + char *chars; + size_t length; +} JSON_String; + /* Type definitions */ typedef union json_value_value { - char *string; + JSON_String string; double number; JSON_Object *object; JSON_Array *array; @@ -75,11 +124,15 @@ struct json_value_t { }; struct json_object_t { - JSON_Value *wrapping_value; - char **names; - JSON_Value **values; - size_t count; - size_t capacity; + JSON_Value *wrapping_value; + size_t *cells; + unsigned long *hashes; + char **names; + JSON_Value **values; + size_t *cell_ixs; + size_t count; + size_t item_capacity; + size_t cell_capacity; }; struct json_array_t { @@ -90,63 +143,136 @@ struct json_array_t { }; /* Various */ -static char * read_file(const char *filename); +//static char * read_file(const char *filename); static void remove_comments(char *string, const char *start_token, const char *end_token); static char * parson_strndup(const char *string, size_t n); static char * parson_strdup(const char *string); static int hex_char_to_int(char c); -static int parse_utf16_hex(const char *string, unsigned int *result); -static int num_bytes_in_utf8_sequence(unsigned char c); -static int verify_utf8_sequence(const unsigned char *string, int *len); -static int is_valid_utf8(const char *string, size_t string_len); -static int is_decimal(const char *string, size_t length); +static JSON_Status parse_utf16_hex(const char *string, unsigned int *result); +static int num_bytes_in_utf8_sequence(unsigned char c); +static JSON_Status verify_utf8_sequence(const unsigned char *string, int *len); +static parson_bool_t is_valid_utf8(const char *string, size_t string_len); +static parson_bool_t is_decimal(const char *string, size_t length); +static unsigned long hash_string(const char *string, size_t n); /* JSON Object */ -static JSON_Object * json_object_init(JSON_Value *wrapping_value); -static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value); -static JSON_Status json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value); -static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity); +static JSON_Object * json_object_make(JSON_Value *wrapping_value); +static JSON_Status json_object_init(JSON_Object *object, size_t capacity); +static void json_object_deinit(JSON_Object *object, parson_bool_t free_keys, parson_bool_t free_values); +static JSON_Status json_object_grow_and_rehash(JSON_Object *object); +static size_t json_object_get_cell_ix(const JSON_Object *object, const char *key, size_t key_len, unsigned long hash, parson_bool_t *out_found); +static JSON_Status json_object_add(JSON_Object *object, char *name, JSON_Value *value); static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len); -static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, int free_value); -static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value); +static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, parson_bool_t free_value); +static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, parson_bool_t free_value); static void json_object_free(JSON_Object *object); /* JSON Array */ -static JSON_Array * json_array_init(JSON_Value *wrapping_value); +static JSON_Array * json_array_make(JSON_Value *wrapping_value); static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value); static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity); static void json_array_free(JSON_Array *array); /* JSON Value */ -static JSON_Value * json_value_init_string_no_copy(char *string); +static JSON_Value * json_value_init_string_no_copy(char *string, size_t length); +static const JSON_String * json_value_get_string_desc(const JSON_Value *value); /* Parser */ -static JSON_Status skip_quotes(const char **string); -static int parse_utf16(const char **unprocessed, char **processed); -static char * process_string(const char *input, size_t len); -static char * get_quoted_string(const char **string); -static JSON_Value * parse_object_value(const char **string, size_t nesting); -static JSON_Value * parse_array_value(const char **string, size_t nesting); -static JSON_Value * parse_string_value(const char **string); -static JSON_Value * parse_boolean_value(const char **string); -static JSON_Value * parse_number_value(const char **string); -static JSON_Value * parse_null_value(const char **string); -static JSON_Value * parse_value(const char **string, size_t nesting); +static JSON_Status skip_quotes(const char **string); +static JSON_Status parse_utf16(const char **unprocessed, char **processed); +static char * process_string(const char *input, size_t input_len, size_t *output_len); +static char * get_quoted_string(const char **string, size_t *output_string_len); +static JSON_Value * parse_object_value(const char **string, size_t nesting); +static JSON_Value * parse_array_value(const char **string, size_t nesting); +static JSON_Value * parse_string_value(const char **string); +static JSON_Value * parse_boolean_value(const char **string); +static JSON_Value * parse_number_value(const char **string); +static JSON_Value * parse_null_value(const char **string); +static JSON_Value * parse_value(const char **string, size_t nesting); /* Serialization */ -static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf); -static int json_serialize_string(const char *string, char *buf); -static int append_indent(char *buf, int level); -static int append_string(char *buf, const char *string); +static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf); +static int json_serialize_string(const char *string, size_t len, char *buf); +static int append_indent(char *buf, int level); +static int append_string(char *buf, const char *string); /* Various */ +//static char * read_file(const char * filename) { +// FILE *fp = fopen(filename, "r"); +// size_t size_to_read = 0; +// size_t size_read = 0; +// long pos; +// char *file_contents; +// if (!fp) { +// return NULL; +// } +// fseek(fp, 0L, SEEK_END); +// pos = ftell(fp); +// if (pos < 0) { +// fclose(fp); +// return NULL; +// } +// size_to_read = pos; +// rewind(fp); +// file_contents = (char*)parson_malloc(sizeof(char) * (size_to_read + 1)); +// if (!file_contents) { +// fclose(fp); +// return NULL; +// } +// size_read = fread(file_contents, 1, size_to_read, fp); +// if (size_read == 0 || ferror(fp)) { +// fclose(fp); +// parson_free(file_contents); +// return NULL; +// } +// fclose(fp); +// file_contents[size_read] = '\0'; +// return file_contents; +//} + +static void remove_comments(char *string, const char *start_token, const char *end_token) { + parson_bool_t in_string = PARSON_FALSE, escaped = PARSON_FALSE; + size_t i; + char *ptr = NULL, current_char; + size_t start_token_len = strlen(start_token); + size_t end_token_len = strlen(end_token); + if (start_token_len == 0 || end_token_len == 0) { + return; + } + while ((current_char = *string) != '\0') { + if (current_char == '\\' && !escaped) { + escaped = PARSON_TRUE; + string++; + continue; + } else if (current_char == '\"' && !escaped) { + in_string = !in_string; + } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) { + for(i = 0; i < start_token_len; i++) { + string[i] = ' '; + } + string = string + start_token_len; + ptr = strstr(string, end_token); + if (!ptr) { + return; + } + for (i = 0; i < (ptr - string) + end_token_len; i++) { + string[i] = ' '; + } + string = ptr + end_token_len - 1; + } + escaped = PARSON_FALSE; + string++; + } +} + static char * parson_strndup(const char *string, size_t n) { + /* We expect the caller has validated that 'n' fits within the input buffer. */ char *output_string = (char*)parson_malloc(n + 1); if (!output_string) { return NULL; } output_string[n] = '\0'; - strncpy(output_string, string, n); + memcpy(output_string, string, n); return output_string; } @@ -165,20 +291,20 @@ static int hex_char_to_int(char c) { return -1; } -static int parse_utf16_hex(const char *s, unsigned int *result) { +static JSON_Status parse_utf16_hex(const char *s, unsigned int *result) { int x1, x2, x3, x4; if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0' || s[3] == '\0') { - return 0; + return JSONFailure; } x1 = hex_char_to_int(s[0]); x2 = hex_char_to_int(s[1]); x3 = hex_char_to_int(s[2]); x4 = hex_char_to_int(s[3]); if (x1 == -1 || x2 == -1 || x3 == -1 || x4 == -1) { - return 0; + return JSONFailure; } *result = (unsigned int)((x1 << 12) | (x2 << 8) | (x3 << 4) | x4); - return 1; + return JSONSuccess; } static int num_bytes_in_utf8_sequence(unsigned char c) { @@ -196,7 +322,7 @@ static int num_bytes_in_utf8_sequence(unsigned char c) { return 0; /* won't happen */ } -static int verify_utf8_sequence(const unsigned char *string, int *len) { +static JSON_Status verify_utf8_sequence(const unsigned char *string, int *len) { unsigned int cp = 0; *len = num_bytes_in_utf8_sequence(string[0]); @@ -215,244 +341,342 @@ static int verify_utf8_sequence(const unsigned char *string, int *len) { cp = (cp << 6) | (string[2] & 0x3F); cp = (cp << 6) | (string[3] & 0x3F); } else { - return 0; + return JSONFailure; } /* overlong encodings */ if ((cp < 0x80 && *len > 1) || (cp < 0x800 && *len > 2) || (cp < 0x10000 && *len > 3)) { - return 0; + return JSONFailure; } /* invalid unicode */ if (cp > 0x10FFFF) { - return 0; + return JSONFailure; } /* surrogate halves */ if (cp >= 0xD800 && cp <= 0xDFFF) { - return 0; + return JSONFailure; } - return 1; + return JSONSuccess; } static int is_valid_utf8(const char *string, size_t string_len) { int len = 0; const char *string_end = string + string_len; while (string < string_end) { - if (!verify_utf8_sequence((const unsigned char*)string, &len)) { - return 0; + if (verify_utf8_sequence((const unsigned char*)string, &len) != JSONSuccess) { + return PARSON_FALSE; } string += len; } - return 1; + return PARSON_TRUE; } -static int is_decimal(const char *string, size_t length) { +static parson_bool_t is_decimal(const char *string, size_t length) { if (length > 1 && string[0] == '0' && string[1] != '.') { - return 0; + return PARSON_FALSE; } if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') { - return 0; + return PARSON_FALSE; } while (length--) { if (strchr("xX", string[length])) { - return 0; + return PARSON_FALSE; } } - return 1; + return PARSON_TRUE; } -#ifndef ENCLAVE_CODE -static char * read_file(const char * filename) { - FILE *fp = fopen(filename, "r"); - size_t size_to_read = 0; - size_t size_read = 0; - long pos; - char *file_contents; - if (!fp) { - return NULL; - } - fseek(fp, 0L, SEEK_END); - pos = ftell(fp); - if (pos < 0) { - fclose(fp); - return NULL; - } - size_to_read = pos; - rewind(fp); - file_contents = (char*)parson_malloc(sizeof(char) * (size_to_read + 1)); - if (!file_contents) { - fclose(fp); - return NULL; - } - size_read = fread(file_contents, 1, size_to_read, fp); - if (size_read == 0 || ferror(fp)) { - fclose(fp); - parson_free(file_contents); - return NULL; - } - fclose(fp); - file_contents[size_read] = '\0'; - return file_contents; -} -#endif - -static void remove_comments(char *string, const char *start_token, const char *end_token) { - int in_string = 0, escaped = 0; - size_t i; - char *ptr = NULL, current_char; - size_t start_token_len = strlen(start_token); - size_t end_token_len = strlen(end_token); - if (start_token_len == 0 || end_token_len == 0) { - return; - } - while ((current_char = *string) != '\0') { - if (current_char == '\\' && !escaped) { - escaped = 1; - string++; - continue; - } else if (current_char == '\"' && !escaped) { - in_string = !in_string; - } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) { - for(i = 0; i < start_token_len; i++) { - string[i] = ' '; - } - string = string + start_token_len; - ptr = strstr(string, end_token); - if (!ptr) { - return; - } - for (i = 0; i < (ptr - string) + end_token_len; i++) { - string[i] = ' '; - } - string = ptr + end_token_len - 1; +static unsigned long hash_string(const char *string, size_t n) { +#ifdef PARSON_FORCE_HASH_COLLISIONS + (void)string; + (void)n; + return 0; +#else + unsigned long hash = 5381; + unsigned char c; + size_t i = 0; + for (i = 0; i < n; i++) { + c = string[i]; + if (c == '\0') { + break; } - escaped = 0; - string++; + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ } + return hash; +#endif } /* JSON Object */ -static JSON_Object * json_object_init(JSON_Value *wrapping_value) { +static JSON_Object * json_object_make(JSON_Value *wrapping_value) { + JSON_Status res = JSONFailure; JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object)); if (new_obj == NULL) { return NULL; } new_obj->wrapping_value = wrapping_value; - new_obj->names = (char**)NULL; - new_obj->values = (JSON_Value**)NULL; - new_obj->capacity = 0; - new_obj->count = 0; + res = json_object_init(new_obj, 0); + if (res != JSONSuccess) { + parson_free(new_obj); + return NULL; + } return new_obj; } -static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value) { - if (name == NULL) { - return JSONFailure; +static JSON_Status json_object_init(JSON_Object *object, size_t capacity) { + unsigned int i = 0; + + object->cells = NULL; + object->names = NULL; + object->values = NULL; + object->cell_ixs = NULL; + object->hashes = NULL; + + object->count = 0; + object->cell_capacity = capacity; + object->item_capacity = (unsigned int)(capacity * 0.7f); + + if (capacity == 0) { + return JSONSuccess; + } + + object->cells = (size_t*)parson_malloc(object->cell_capacity * sizeof(*object->cells)); + object->names = (char**)parson_malloc(object->item_capacity * sizeof(*object->names)); + object->values = (JSON_Value**)parson_malloc(object->item_capacity * sizeof(*object->values)); + object->cell_ixs = (size_t*)parson_malloc(object->item_capacity * sizeof(*object->cell_ixs)); + object->hashes = (unsigned long*)parson_malloc(object->item_capacity * sizeof(*object->hashes)); + if (object->cells == NULL + || object->names == NULL + || object->values == NULL + || object->cell_ixs == NULL + || object->hashes == NULL) { + goto error; } - return json_object_addn(object, name, strlen(name), value); + for (i = 0; i < object->cell_capacity; i++) { + object->cells[i] = OBJECT_INVALID_IX; + } + return JSONSuccess; +error: + parson_free(object->cells); + parson_free(object->names); + parson_free(object->values); + parson_free(object->cell_ixs); + parson_free(object->hashes); + return JSONFailure; } -static JSON_Status json_object_addn(JSON_Object *object, const char *name, size_t name_len, JSON_Value *value) { - size_t index = 0; - if (object == NULL || name == NULL || value == NULL) { - return JSONFailure; +static void json_object_deinit(JSON_Object *object, parson_bool_t free_keys, parson_bool_t free_values) { + unsigned int i = 0; + for (i = 0; i < object->count; i++) { + if (free_keys) { + parson_free(object->names[i]); + } + if (free_values) { + json_value_free(object->values[i]); + } } - if (json_object_getn_value(object, name, name_len) != NULL) { + + object->count = 0; + object->item_capacity = 0; + object->cell_capacity = 0; + + parson_free(object->cells); + parson_free(object->names); + parson_free(object->values); + parson_free(object->cell_ixs); + parson_free(object->hashes); + + object->cells = NULL; + object->names = NULL; + object->values = NULL; + object->cell_ixs = NULL; + object->hashes = NULL; +} + +static JSON_Status json_object_grow_and_rehash(JSON_Object *object) { + JSON_Value *wrapping_value = NULL; + JSON_Object new_object; + char *key = NULL; + JSON_Value *value = NULL; + unsigned int i = 0; + size_t new_capacity = MAX(object->cell_capacity * 2, STARTING_CAPACITY); + JSON_Status res = json_object_init(&new_object, new_capacity); + if (res != JSONSuccess) { return JSONFailure; } - if (object->count >= object->capacity) { - size_t new_capacity = MAX(object->capacity * 2, STARTING_CAPACITY); - if (json_object_resize(object, new_capacity) == JSONFailure) { + + wrapping_value = json_object_get_wrapping_value(object); + new_object.wrapping_value = wrapping_value; + + for (i = 0; i < object->count; i++) { + key = object->names[i]; + value = object->values[i]; + res = json_object_add(&new_object, key, value); + if (res != JSONSuccess) { + json_object_deinit(&new_object, PARSON_FALSE, PARSON_FALSE); return JSONFailure; } + value->parent = wrapping_value; } - index = object->count; - object->names[index] = parson_strndup(name, name_len); - if (object->names[index] == NULL) { - return JSONFailure; - } - value->parent = json_object_get_wrapping_value(object); - object->values[index] = value; - object->count++; + json_object_deinit(object, PARSON_FALSE, PARSON_FALSE); + *object = new_object; return JSONSuccess; } -static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity) { - char **temp_names = NULL; - JSON_Value **temp_values = NULL; +static size_t json_object_get_cell_ix(const JSON_Object *object, const char *key, size_t key_len, unsigned long hash, parson_bool_t *out_found) { + size_t cell_ix = hash & (object->cell_capacity - 1); + size_t cell = 0; + size_t ix = 0; + unsigned int i = 0; + unsigned long hash_to_check = 0; + const char *key_to_check = NULL; + size_t key_to_check_len = 0; + + *out_found = PARSON_FALSE; - if ((object->names == NULL && object->values != NULL) || - (object->names != NULL && object->values == NULL) || - new_capacity == 0) { - return JSONFailure; /* Shouldn't happen */ + for (i = 0; i < object->cell_capacity; i++) { + ix = (cell_ix + i) & (object->cell_capacity - 1); + cell = object->cells[ix]; + if (cell == OBJECT_INVALID_IX) { + return ix; + } + hash_to_check = object->hashes[cell]; + if (hash != hash_to_check) { + continue; + } + key_to_check = object->names[cell]; + key_to_check_len = strlen(key_to_check); + if (key_to_check_len == key_len && strncmp(key, key_to_check, key_len) == 0) { + *out_found = PARSON_TRUE; + return ix; + } } - temp_names = (char**)parson_malloc(new_capacity * sizeof(char*)); - if (temp_names == NULL) { + return OBJECT_INVALID_IX; +} + +static JSON_Status json_object_add(JSON_Object *object, char *name, JSON_Value *value) { + unsigned long hash = 0; + parson_bool_t found = PARSON_FALSE; + size_t cell_ix = 0; + JSON_Status res = JSONFailure; + + if (!object || !name || !value) { return JSONFailure; } - temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*)); - if (temp_values == NULL) { - parson_free(temp_names); + + hash = hash_string(name, strlen(name)); + found = PARSON_FALSE; + cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); + if (found) { return JSONFailure; } - if (object->names != NULL && object->values != NULL && object->count > 0) { - memcpy(temp_names, object->names, object->count * sizeof(char*)); - memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*)); + + if (object->count >= object->item_capacity) { + res = json_object_grow_and_rehash(object); + if (res != JSONSuccess) { + return JSONFailure; + } + cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); } - parson_free(object->names); - parson_free(object->values); - object->names = temp_names; - object->values = temp_values; - object->capacity = new_capacity; + + object->names[object->count] = name; + object->cells[cell_ix] = object->count; + object->values[object->count] = value; + object->cell_ixs[object->count] = cell_ix; + object->hashes[object->count] = hash; + object->count++; + value->parent = json_object_get_wrapping_value(object); + return JSONSuccess; } static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len) { - size_t i, name_length; - for (i = 0; i < json_object_get_count(object); i++) { - name_length = strlen(object->names[i]); - if (name_length != name_len) { - continue; - } - if (strncmp(object->names[i], name, name_len) == 0) { - return object->values[i]; - } + unsigned long hash = 0; + parson_bool_t found = PARSON_FALSE; + unsigned long cell_ix = 0; + size_t item_ix = 0; + if (!object || !name) { + return NULL; } - return NULL; + hash = hash_string(name, name_len); + found = PARSON_FALSE; + cell_ix = json_object_get_cell_ix(object, name, name_len, hash, &found); + if (!found) { + return NULL; + } + item_ix = object->cells[cell_ix]; + return object->values[item_ix]; } -static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, int free_value) { - size_t i = 0, last_item_index = 0; - if (object == NULL || json_object_get_value(object, name) == NULL) { +static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, parson_bool_t free_value) { + unsigned long hash = 0; + parson_bool_t found = PARSON_FALSE; + size_t cell = 0; + size_t item_ix = 0; + size_t last_item_ix = 0; + size_t i = 0; + size_t j = 0; + size_t x = 0; + size_t k = 0; + JSON_Value *val = NULL; + + if (object == NULL) { return JSONFailure; } - last_item_index = json_object_get_count(object) - 1; - for (i = 0; i < json_object_get_count(object); i++) { - if (strcmp(object->names[i], name) == 0) { - parson_free(object->names[i]); - if (free_value) { - json_value_free(object->values[i]); - } - if (i != last_item_index) { /* Replace key value pair with one from the end */ - object->names[i] = object->names[last_item_index]; - object->values[i] = object->values[last_item_index]; - } - object->count -= 1; - return JSONSuccess; + + hash = hash_string(name, strlen(name)); + found = PARSON_FALSE; + cell = json_object_get_cell_ix(object, name, strlen(name), hash, &found); + if (!found) { + return JSONFailure; + } + + item_ix = object->cells[cell]; + if (free_value) { + val = object->values[item_ix]; + json_value_free(val); + val = NULL; + } + + parson_free(object->names[item_ix]); + last_item_ix = object->count - 1; + if (item_ix < last_item_ix) { + object->names[item_ix] = object->names[last_item_ix]; + object->values[item_ix] = object->values[last_item_ix]; + object->cell_ixs[item_ix] = object->cell_ixs[last_item_ix]; + object->hashes[item_ix] = object->hashes[last_item_ix]; + object->cells[object->cell_ixs[item_ix]] = item_ix; + } + object->count--; + + i = cell; + j = i; + for (x = 0; x < (object->cell_capacity - 1); x++) { + j = (j + 1) & (object->cell_capacity - 1); + if (object->cells[j] == OBJECT_INVALID_IX) { + break; + } + k = object->hashes[object->cells[j]] & (object->cell_capacity - 1); + if ((j > i && (k <= i || k > j)) + || (j < i && (k <= i && k > j))) { + object->cell_ixs[object->cells[j]] = i; + object->cells[i] = object->cells[j]; + i = j; } } - return JSONFailure; /* No execution path should end here */ + object->cells[i] = OBJECT_INVALID_IX; + return JSONSuccess; } -static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, int free_value) { +static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, parson_bool_t free_value) { JSON_Value *temp_value = NULL; JSON_Object *temp_object = NULL; const char *dot_pos = strchr(name, '.'); - if (dot_pos == NULL) { + if (!dot_pos) { return json_object_remove_internal(object, name, free_value); } temp_value = json_object_getn_value(object, name, dot_pos - name); @@ -464,18 +688,12 @@ static JSON_Status json_object_dotremove_internal(JSON_Object *object, const cha } static void json_object_free(JSON_Object *object) { - size_t i; - for (i = 0; i < object->count; i++) { - parson_free(object->names[i]); - json_value_free(object->values[i]); - } - parson_free(object->names); - parson_free(object->values); + json_object_deinit(object, PARSON_TRUE, PARSON_TRUE); parson_free(object); } /* JSON Array */ -static JSON_Array * json_array_init(JSON_Value *wrapping_value) { +static JSON_Array * json_array_make(JSON_Value *wrapping_value) { JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array)); if (new_array == NULL) { return NULL; @@ -490,7 +708,7 @@ static JSON_Array * json_array_init(JSON_Value *wrapping_value) { static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) { if (array->count >= array->capacity) { size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY); - if (json_array_resize(array, new_capacity) == JSONFailure) { + if (json_array_resize(array, new_capacity) != JSONSuccess) { return JSONFailure; } } @@ -528,14 +746,15 @@ static void json_array_free(JSON_Array *array) { } /* JSON Value */ -static JSON_Value * json_value_init_string_no_copy(char *string) { +static JSON_Value * json_value_init_string_no_copy(char *string, size_t length) { JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); if (!new_value) { return NULL; } new_value->parent = NULL; new_value->type = JSONString; - new_value->value.string = string; + new_value->value.string.chars = string; + new_value->value.string.length = length; return new_value; } @@ -560,14 +779,14 @@ static JSON_Status skip_quotes(const char **string) { return JSONSuccess; } -static int parse_utf16(const char **unprocessed, char **processed) { +static JSON_Status parse_utf16(const char **unprocessed, char **processed) { unsigned int cp, lead, trail; - int parse_succeeded = 0; char *processed_ptr = *processed; const char *unprocessed_ptr = *unprocessed; + JSON_Status status = JSONFailure; unprocessed_ptr++; /* skips u */ - parse_succeeded = parse_utf16_hex(unprocessed_ptr, &cp); - if (!parse_succeeded) { + status = parse_utf16_hex(unprocessed_ptr, &cp); + if (status != JSONSuccess) { return JSONFailure; } if (cp < 0x80) { @@ -587,8 +806,8 @@ static int parse_utf16(const char **unprocessed, char **processed) { if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u') { return JSONFailure; } - parse_succeeded = parse_utf16_hex(unprocessed_ptr, &trail); - if (!parse_succeeded || trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */ + status = parse_utf16_hex(unprocessed_ptr, &trail); + if (status != JSONSuccess || trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */ return JSONFailure; } cp = ((((lead - 0xD800) & 0x3FF) << 10) | ((trail - 0xDC00) & 0x3FF)) + 0x010000; @@ -609,9 +828,9 @@ static int parse_utf16(const char **unprocessed, char **processed) { /* Copies and processes passed string up to supplied length. Example: "\u006Corem ipsum" -> lorem ipsum */ -static char* process_string(const char *input, size_t len) { +static char* process_string(const char *input, size_t input_len, size_t *output_len) { const char *input_ptr = input; - size_t initial_size = (len + 1) * sizeof(char); + size_t initial_size = (input_len + 1) * sizeof(char); size_t final_size = 0; char *output = NULL, *output_ptr = NULL, *resized_output = NULL; output = (char*)parson_malloc(initial_size); @@ -619,7 +838,7 @@ static char* process_string(const char *input, size_t len) { goto error; } output_ptr = output; - while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < len) { + while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < input_len) { if (*input_ptr == '\\') { input_ptr++; switch (*input_ptr) { @@ -632,7 +851,7 @@ static char* process_string(const char *input, size_t len) { case 'r': *output_ptr = '\r'; break; case 't': *output_ptr = '\t'; break; case 'u': - if (parse_utf16(&input_ptr, &output_ptr) == JSONFailure) { + if (parse_utf16(&input_ptr, &output_ptr) != JSONSuccess) { goto error; } break; @@ -656,6 +875,7 @@ static char* process_string(const char *input, size_t len) { goto error; } memcpy(resized_output, output, final_size); + *output_len = final_size - 1; parson_free(output); return resized_output; error: @@ -665,15 +885,15 @@ static char* process_string(const char *input, size_t len) { /* Return processed contents of a string between quotes and skips passed argument to a matching quote. */ -static char * get_quoted_string(const char **string) { +static char * get_quoted_string(const char **string, size_t *output_string_len) { const char *string_start = *string; - size_t string_len = 0; + size_t input_string_len = 0; JSON_Status status = skip_quotes(string); if (status != JSONSuccess) { return NULL; } - string_len = *string - string_start - 2; /* length without quotes */ - return process_string(string_start + 1, string_len); + input_string_len = *string - string_start - 2; /* length without quotes */ + return process_string(string_start + 1, input_string_len, output_string_len); } static JSON_Value * parse_value(const char **string, size_t nesting) { @@ -702,9 +922,11 @@ static JSON_Value * parse_value(const char **string, size_t nesting) { } static JSON_Value * parse_object_value(const char **string, size_t nesting) { + JSON_Status status = JSONFailure; JSON_Value *output_value = NULL, *new_value = NULL; JSON_Object *output_object = NULL; char *new_key = NULL; + output_value = json_value_init_object(); if (output_value == NULL) { return NULL; @@ -721,8 +943,15 @@ static JSON_Value * parse_object_value(const char **string, size_t nesting) { return output_value; } while (**string != '\0') { - new_key = get_quoted_string(string); - if (new_key == NULL) { + size_t key_len = 0; + new_key = get_quoted_string(string, &key_len); + /* We do not support key names with embedded \0 chars */ + if (!new_key) { + json_value_free(output_value); + return NULL; + } + if (key_len != strlen(new_key)) { + parson_free(new_key); json_value_free(output_value); return NULL; } @@ -739,13 +968,13 @@ static JSON_Value * parse_object_value(const char **string, size_t nesting) { json_value_free(output_value); return NULL; } - if (json_object_add(output_object, new_key, new_value) == JSONFailure) { + status = json_object_add(output_object, new_key, new_value); + if (status != JSONSuccess) { parson_free(new_key); json_value_free(new_value); json_value_free(output_value); return NULL; } - parson_free(new_key); SKIP_WHITESPACES(string); if (**string != ',') { break; @@ -754,10 +983,9 @@ static JSON_Value * parse_object_value(const char **string, size_t nesting) { SKIP_WHITESPACES(string); } SKIP_WHITESPACES(string); - if (**string != '}' || /* Trim object after parsing is over */ - json_object_resize(output_object, json_object_get_count(output_object)) == JSONFailure) { - json_value_free(output_value); - return NULL; + if (**string != '}') { + json_value_free(output_value); + return NULL; } SKIP_CHAR(string); return output_value; @@ -787,7 +1015,7 @@ static JSON_Value * parse_array_value(const char **string, size_t nesting) { json_value_free(output_value); return NULL; } - if (json_array_add(output_array, new_array_value) == JSONFailure) { + if (json_array_add(output_array, new_array_value) != JSONSuccess) { json_value_free(new_array_value); json_value_free(output_value); return NULL; @@ -801,7 +1029,7 @@ static JSON_Value * parse_array_value(const char **string, size_t nesting) { } SKIP_WHITESPACES(string); if (**string != ']' || /* Trim array after parsing is over */ - json_array_resize(output_array, json_array_get_count(output_array)) == JSONFailure) { + json_array_resize(output_array, json_array_get_count(output_array)) != JSONSuccess) { json_value_free(output_value); return NULL; } @@ -811,11 +1039,12 @@ static JSON_Value * parse_array_value(const char **string, size_t nesting) { static JSON_Value * parse_string_value(const char **string) { JSON_Value *value = NULL; - char *new_string = get_quoted_string(string); + size_t new_string_len = 0; + char *new_string = get_quoted_string(string, &new_string_len); if (new_string == NULL) { return NULL; } - value = json_value_init_string_no_copy(new_string); + value = json_value_init_string_no_copy(new_string, new_string_len); if (value == NULL) { parson_free(new_string); return NULL; @@ -841,7 +1070,10 @@ static JSON_Value * parse_number_value(const char **string) { double number = 0; errno = 0; number = strtod(*string, &end); - if (errno || !is_decimal(*string, end - *string)) { + if (errno == ERANGE && (number <= -HUGE_VAL || number >= HUGE_VAL)) { + return NULL; + } + if ((errno && errno != ERANGE) || !is_decimal(*string, end - *string)) { return NULL; } *string = end; @@ -868,7 +1100,7 @@ static JSON_Value * parse_null_value(const char **string) { if (buf != NULL) { buf += written; }\ written_total += written; } while(0) -static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, int is_pretty, char *num_buf) +static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf) { const char *key = NULL, *string = NULL; JSON_Value *temp_value = NULL; @@ -877,6 +1109,7 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le size_t i = 0, count = 0; double num = 0.0; int written = -1, written_total = 0; + size_t len = 0; switch (json_value_get_type(value)) { case JSONArray: @@ -926,7 +1159,8 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le if (is_pretty) { APPEND_INDENT(level+1); } - written = json_serialize_string(key, buf); + /* We do not support key names with embedded \0 chars */ + written = json_serialize_string(key, strlen(key), buf); if (written < 0) { return -1; } @@ -938,7 +1172,7 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le if (is_pretty) { APPEND_STRING(" "); } - temp_value = json_object_get_value(object, key); + temp_value = json_object_get_value_at(object, i); written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf); if (written < 0) { return -1; @@ -964,7 +1198,8 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le if (string == NULL) { return -1; } - written = json_serialize_string(string, buf); + len = json_value_get_string_len(value); + written = json_serialize_string(string, len, buf); if (written < 0) { return -1; } @@ -985,11 +1220,9 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le if (buf != NULL) { num_buf = buf; } -#ifndef ENCLAVE_CODE - written = sprintf(num_buf, FLOAT_FORMAT, num); -#else - written = snprintf(num_buf, NUM_BUF_SIZE, FLOAT_FORMAT, num); -#endif + // SGX workaround for missing + written = snprintf(num_buf, NUM_BUF_SIZE-written_total, FLOAT_FORMAT, num); +// written = sprintf(num_buf, FLOAT_FORMAT, num); if (written < 0) { return -1; } @@ -1008,8 +1241,8 @@ static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int le } } -static int json_serialize_string(const char *string, char *buf) { - size_t i = 0, len = strlen(string); +static int json_serialize_string(const char *string, size_t len, char *buf) { + size_t i = 0; char c = '\0'; int written = -1, written_total = 0; APPEND_STRING("\""); @@ -1018,7 +1251,6 @@ static int json_serialize_string(const char *string, char *buf) { switch (c) { case '\"': APPEND_STRING("\\\""); break; case '\\': APPEND_STRING("\\\\"); break; - case '/': APPEND_STRING("\\/"); break; /* to make json embeddable in xml\/html */ case '\b': APPEND_STRING("\\b"); break; case '\f': APPEND_STRING("\\f"); break; case '\n': APPEND_STRING("\\n"); break; @@ -1056,6 +1288,13 @@ static int json_serialize_string(const char *string, char *buf) { case '\x1d': APPEND_STRING("\\u001d"); break; case '\x1e': APPEND_STRING("\\u001e"); break; case '\x1f': APPEND_STRING("\\u001f"); break; + case '/': + if (parson_escape_slashes) { + APPEND_STRING("\\/"); /* to make json embeddable in xml\/html */ + } else { + APPEND_STRING("/"); + } + break; default: if (buf != NULL) { buf[0] = c; @@ -1078,42 +1317,42 @@ static int append_indent(char *buf, int level) { return written_total; } -#ifndef ENCLAVE_CODE static int append_string(char *buf, const char *string) { + int len = (int)strlen(string); if (buf == NULL) { - return (int)strlen(string); + return len; } - return sprintf(buf, "%s", string); + // SGX work around + strncpy(buf, string, len+1); + return len; + // return sprintf(buf, "%s", string); } -#endif #undef APPEND_STRING #undef APPEND_INDENT -#ifndef ENCLAVE_CODE /* Parser API */ -JSON_Value * json_parse_file(const char *filename) { - char *file_contents = read_file(filename); - JSON_Value *output_value = NULL; - if (file_contents == NULL) { - return NULL; - } - output_value = json_parse_string(file_contents); - parson_free(file_contents); - return output_value; -} - -JSON_Value * json_parse_file_with_comments(const char *filename) { - char *file_contents = read_file(filename); - JSON_Value *output_value = NULL; - if (file_contents == NULL) { - return NULL; - } - output_value = json_parse_string_with_comments(file_contents); - parson_free(file_contents); - return output_value; -} -#endif +//JSON_Value * json_parse_file(const char *filename) { +// char *file_contents = read_file(filename); +// JSON_Value *output_value = NULL; +// if (file_contents == NULL) { +// return NULL; +// } +// output_value = json_parse_string(file_contents); +// parson_free(file_contents); +// return output_value; +//} + +//JSON_Value * json_parse_file_with_comments(const char *filename) { +// char *file_contents = read_file(filename); +// JSON_Value *output_value = NULL; +// if (file_contents == NULL) { +// return NULL; +// } +// output_value = json_parse_string_with_comments(file_contents); +// parson_free(file_contents); +// return output_value; +//} JSON_Value * json_parse_string(const char *string) { if (string == NULL) { @@ -1153,6 +1392,10 @@ const char * json_object_get_string(const JSON_Object *object, const char *name) return json_value_get_string(json_object_get_value(object, name)); } +size_t json_object_get_string_len(const JSON_Object *object, const char *name) { + return json_value_get_string_len(json_object_get_value(object, name)); +} + double json_object_get_number(const JSON_Object *object, const char *name) { return json_value_get_number(json_object_get_value(object, name)); } @@ -1182,6 +1425,10 @@ const char * json_object_dotget_string(const JSON_Object *object, const char *na return json_value_get_string(json_object_dotget_value(object, name)); } +size_t json_object_dotget_string_len(const JSON_Object *object, const char *name) { + return json_value_get_string_len(json_object_dotget_value(object, name)); +} + double json_object_dotget_number(const JSON_Object *object, const char *name) { return json_value_get_number(json_object_dotget_value(object, name)); } @@ -1217,6 +1464,9 @@ JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index) { } JSON_Value *json_object_get_wrapping_value(const JSON_Object *object) { + if (!object) { + return NULL; + } return object->wrapping_value; } @@ -1250,6 +1500,10 @@ const char * json_array_get_string(const JSON_Array *array, size_t index) { return json_value_get_string(json_array_get_value(array, index)); } +size_t json_array_get_string_len(const JSON_Array *array, size_t index) { + return json_value_get_string_len(json_array_get_value(array, index)); +} + double json_array_get_number(const JSON_Array *array, size_t index) { return json_value_get_number(json_array_get_value(array, index)); } @@ -1271,6 +1525,9 @@ size_t json_array_get_count(const JSON_Array *array) { } JSON_Value * json_array_get_wrapping_value(const JSON_Array *array) { + if (!array) { + return NULL; + } return array->wrapping_value; } @@ -1287,8 +1544,18 @@ JSON_Array * json_value_get_array(const JSON_Value *value) { return json_value_get_type(value) == JSONArray ? value->value.array : NULL; } +static const JSON_String * json_value_get_string_desc(const JSON_Value *value) { + return json_value_get_type(value) == JSONString ? &value->value.string : NULL; +} + const char * json_value_get_string(const JSON_Value *value) { - return json_value_get_type(value) == JSONString ? value->value.string : NULL; + const JSON_String *str = json_value_get_string_desc(value); + return str ? str->chars : NULL; +} + +size_t json_value_get_string_len(const JSON_Value *value) { + const JSON_String *str = json_value_get_string_desc(value); + return str ? str->length : 0; } double json_value_get_number(const JSON_Value *value) { @@ -1309,7 +1576,7 @@ void json_value_free(JSON_Value *value) { json_object_free(value->value.object); break; case JSONString: - parson_free(value->value.string); + parson_free(value->value.string.chars); break; case JSONArray: json_array_free(value->value.array); @@ -1327,7 +1594,7 @@ JSON_Value * json_value_init_object(void) { } new_value->parent = NULL; new_value->type = JSONObject; - new_value->value.object = json_object_init(new_value); + new_value->value.object = json_object_make(new_value); if (!new_value->value.object) { parson_free(new_value); return NULL; @@ -1342,7 +1609,7 @@ JSON_Value * json_value_init_array(void) { } new_value->parent = NULL; new_value->type = JSONArray; - new_value->value.array = json_array_init(new_value); + new_value->value.array = json_array_make(new_value); if (!new_value->value.array) { parson_free(new_value); return NULL; @@ -1351,21 +1618,26 @@ JSON_Value * json_value_init_array(void) { } JSON_Value * json_value_init_string(const char *string) { + if (string == NULL) { + return NULL; + } + return json_value_init_string_with_len(string, strlen(string)); +} + +JSON_Value * json_value_init_string_with_len(const char *string, size_t length) { char *copy = NULL; JSON_Value *value; - size_t string_len = 0; if (string == NULL) { return NULL; } - string_len = strlen(string); - if (!is_valid_utf8(string, string_len)) { + if (!is_valid_utf8(string, length)) { return NULL; } - copy = parson_strndup(string, string_len); + copy = parson_strndup(string, length); if (copy == NULL) { return NULL; } - value = json_value_init_string_no_copy(copy); + value = json_value_init_string_no_copy(copy, length); if (value == NULL) { parson_free(copy); } @@ -1374,7 +1646,7 @@ JSON_Value * json_value_init_string(const char *string) { JSON_Value * json_value_init_number(double number) { JSON_Value *new_value = NULL; - if ((number * 0.0) != 0.0) { /* nan and inf test */ + if (IS_NUMBER_INVALID(number)) { return NULL; } new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); @@ -1411,10 +1683,13 @@ JSON_Value * json_value_init_null(void) { JSON_Value * json_value_deep_copy(const JSON_Value *value) { size_t i = 0; JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL; - const char *temp_string = NULL, *temp_key = NULL; + const JSON_String *temp_string = NULL; + const char *temp_key = NULL; char *temp_string_copy = NULL; JSON_Array *temp_array = NULL, *temp_array_copy = NULL; JSON_Object *temp_object = NULL, *temp_object_copy = NULL; + JSON_Status res = JSONFailure; + char *key_copy = NULL; switch (json_value_get_type(value)) { case JSONArray: @@ -1431,7 +1706,7 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { json_value_free(return_value); return NULL; } - if (json_array_add(temp_array_copy, temp_value_copy) == JSONFailure) { + if (json_array_add(temp_array_copy, temp_value_copy) != JSONSuccess) { json_value_free(return_value); json_value_free(temp_value_copy); return NULL; @@ -1441,7 +1716,7 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { case JSONObject: temp_object = json_value_get_object(value); return_value = json_value_init_object(); - if (return_value == NULL) { + if (!return_value) { return NULL; } temp_object_copy = json_value_get_object(return_value); @@ -1449,13 +1724,21 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { temp_key = json_object_get_name(temp_object, i); temp_value = json_object_get_value(temp_object, temp_key); temp_value_copy = json_value_deep_copy(temp_value); - if (temp_value_copy == NULL) { + if (!temp_value_copy) { json_value_free(return_value); return NULL; } - if (json_object_add(temp_object_copy, temp_key, temp_value_copy) == JSONFailure) { + key_copy = parson_strdup(temp_key); + if (!key_copy) { + json_value_free(temp_value_copy); json_value_free(return_value); + return NULL; + } + res = json_object_add(temp_object_copy, key_copy, temp_value_copy); + if (res != JSONSuccess) { + parson_free(key_copy); json_value_free(temp_value_copy); + json_value_free(return_value); return NULL; } } @@ -1465,15 +1748,15 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { case JSONNumber: return json_value_init_number(json_value_get_number(value)); case JSONString: - temp_string = json_value_get_string(value); + temp_string = json_value_get_string_desc(value); if (temp_string == NULL) { return NULL; } - temp_string_copy = parson_strdup(temp_string); + temp_string_copy = parson_strndup(temp_string->chars, temp_string->length); if (temp_string_copy == NULL) { return NULL; } - return_value = json_value_init_string_no_copy(temp_string_copy); + return_value = json_value_init_string_no_copy(temp_string_copy, temp_string->length); if (return_value == NULL) { parson_free(temp_string_copy); } @@ -1489,8 +1772,8 @@ JSON_Value * json_value_deep_copy(const JSON_Value *value) { size_t json_serialization_size(const JSON_Value *value) { char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ - int res = json_serialize_to_buffer_r(value, NULL, 0, 0, num_buf); - return res < 0 ? 0 : (size_t)(res + 1); + int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_FALSE, num_buf); + return res < 0 ? 0 : (size_t)(res) + 1; } JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) { @@ -1499,36 +1782,34 @@ JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { return JSONFailure; } - written = json_serialize_to_buffer_r(value, buf, 0, 0, NULL); + written = json_serialize_to_buffer_r(value, buf, 0, PARSON_FALSE, NULL); if (written < 0) { return JSONFailure; } return JSONSuccess; } -#ifndef ENCLAVE_CODE -JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) { - JSON_Status return_code = JSONSuccess; - FILE *fp = NULL; - char *serialized_string = json_serialize_to_string(value); - if (serialized_string == NULL) { - return JSONFailure; - } - fp = fopen(filename, "w"); - if (fp == NULL) { - json_free_serialized_string(serialized_string); - return JSONFailure; - } - if (fputs(serialized_string, fp) == EOF) { - return_code = JSONFailure; - } - if (fclose(fp) == EOF) { - return_code = JSONFailure; - } - json_free_serialized_string(serialized_string); - return return_code; -} -#endif +//JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) { +// JSON_Status return_code = JSONSuccess; +// FILE *fp = NULL; +// char *serialized_string = json_serialize_to_string(value); +// if (serialized_string == NULL) { +// return JSONFailure; +// } +// fp = fopen(filename, "w"); +// if (fp == NULL) { +// json_free_serialized_string(serialized_string); +// return JSONFailure; +// } +// if (fputs(serialized_string, fp) == EOF) { +// return_code = JSONFailure; +// } +// if (fclose(fp) == EOF) { +// return_code = JSONFailure; +// } +// json_free_serialized_string(serialized_string); +// return return_code; +//} char * json_serialize_to_string(const JSON_Value *value) { JSON_Status serialization_result = JSONFailure; @@ -1542,7 +1823,7 @@ char * json_serialize_to_string(const JSON_Value *value) { return NULL; } serialization_result = json_serialize_to_buffer(value, buf, buf_size_bytes); - if (serialization_result == JSONFailure) { + if (serialization_result != JSONSuccess) { json_free_serialized_string(buf); return NULL; } @@ -1551,8 +1832,8 @@ char * json_serialize_to_string(const JSON_Value *value) { size_t json_serialization_size_pretty(const JSON_Value *value) { char num_buf[NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ - int res = json_serialize_to_buffer_r(value, NULL, 0, 1, num_buf); - return res < 0 ? 0 : (size_t)(res + 1); + int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_TRUE, num_buf); + return res < 0 ? 0 : (size_t)(res) + 1; } JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) { @@ -1561,36 +1842,34 @@ JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { return JSONFailure; } - written = json_serialize_to_buffer_r(value, buf, 0, 1, NULL); + written = json_serialize_to_buffer_r(value, buf, 0, PARSON_TRUE, NULL); if (written < 0) { return JSONFailure; } return JSONSuccess; } -#ifndef ENCLAVE_CODE -JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) { - JSON_Status return_code = JSONSuccess; - FILE *fp = NULL; - char *serialized_string = json_serialize_to_string_pretty(value); - if (serialized_string == NULL) { - return JSONFailure; - } - fp = fopen(filename, "w"); - if (fp == NULL) { - json_free_serialized_string(serialized_string); - return JSONFailure; - } - if (fputs(serialized_string, fp) == EOF) { - return_code = JSONFailure; - } - if (fclose(fp) == EOF) { - return_code = JSONFailure; - } - json_free_serialized_string(serialized_string); - return return_code; -} -#endif +//JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) { +// JSON_Status return_code = JSONSuccess; +// FILE *fp = NULL; +// char *serialized_string = json_serialize_to_string_pretty(value); +// if (serialized_string == NULL) { +// return JSONFailure; +// } +// fp = fopen(filename, "w"); +// if (fp == NULL) { +// json_free_serialized_string(serialized_string); +// return JSONFailure; +// } +// if (fputs(serialized_string, fp) == EOF) { +// return_code = JSONFailure; +// } +// if (fclose(fp) == EOF) { +// return_code = JSONFailure; +// } +// json_free_serialized_string(serialized_string); +// return return_code; +//} char * json_serialize_to_string_pretty(const JSON_Value *value) { JSON_Status serialization_result = JSONFailure; @@ -1604,7 +1883,7 @@ char * json_serialize_to_string_pretty(const JSON_Value *value) { return NULL; } serialization_result = json_serialize_to_buffer_pretty(value, buf, buf_size_bytes); - if (serialization_result == JSONFailure) { + if (serialization_result != JSONSuccess) { json_free_serialized_string(buf); return NULL; } @@ -1642,7 +1921,19 @@ JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* s if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { + json_value_free(value); + return JSONFailure; + } + return JSONSuccess; +} + +JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len) { + JSON_Value *value = json_value_init_string_with_len(string, len); + if (value == NULL) { + return JSONFailure; + } + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1654,7 +1945,7 @@ JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1666,7 +1957,7 @@ JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1678,7 +1969,7 @@ JSON_Status json_array_replace_null(JSON_Array *array, size_t i) { if (value == NULL) { return JSONFailure; } - if (json_array_replace_value(array, i, value) == JSONFailure) { + if (json_array_replace_value(array, i, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1709,7 +2000,19 @@ JSON_Status json_array_append_string(JSON_Array *array, const char *string) { if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { + json_value_free(value); + return JSONFailure; + } + return JSONSuccess; +} + +JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len) { + JSON_Value *value = json_value_init_string_with_len(string, len); + if (value == NULL) { + return JSONFailure; + } + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1721,7 +2024,7 @@ JSON_Status json_array_append_number(JSON_Array *array, double number) { if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1733,7 +2036,7 @@ JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) { if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1745,7 +2048,7 @@ JSON_Status json_array_append_null(JSON_Array *array) { if (value == NULL) { return JSONFailure; } - if (json_array_append_value(array, value) == JSONFailure) { + if (json_array_append_value(array, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1753,40 +2056,91 @@ JSON_Status json_array_append_null(JSON_Array *array) { } JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) { - size_t i = 0; - JSON_Value *old_value; - if (object == NULL || name == NULL || value == NULL || value->parent != NULL) { + unsigned long hash = 0; + parson_bool_t found = PARSON_FALSE; + size_t cell_ix = 0; + size_t item_ix = 0; + JSON_Value *old_value = NULL; + char *key_copy = NULL; + + if (!object || !name || !value || value->parent) { return JSONFailure; } - old_value = json_object_get_value(object, name); - if (old_value != NULL) { /* free and overwrite old value */ + hash = hash_string(name, strlen(name)); + found = PARSON_FALSE; + cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); + if (found) { + item_ix = object->cells[cell_ix]; + old_value = object->values[item_ix]; json_value_free(old_value); - for (i = 0; i < json_object_get_count(object); i++) { - if (strcmp(object->names[i], name) == 0) { - value->parent = json_object_get_wrapping_value(object); - object->values[i] = value; - return JSONSuccess; - } + object->values[item_ix] = value; + value->parent = json_object_get_wrapping_value(object); + return JSONSuccess; + } + if (object->count >= object->item_capacity) { + JSON_Status res = json_object_grow_and_rehash(object); + if (res != JSONSuccess) { + return JSONFailure; } + cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); + } + key_copy = parson_strdup(name); + if (!key_copy) { + return JSONFailure; } - /* add new key value pair */ - return json_object_add(object, name, value); + object->names[object->count] = key_copy; + object->cells[cell_ix] = object->count; + object->values[object->count] = value; + object->cell_ixs[object->count] = cell_ix; + object->hashes[object->count] = hash; + object->count++; + value->parent = json_object_get_wrapping_value(object); + return JSONSuccess; } JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) { - return json_object_set_value(object, name, json_value_init_string(string)); + JSON_Value *value = json_value_init_string(string); + JSON_Status status = json_object_set_value(object, name, value); + if (status != JSONSuccess) { + json_value_free(value); + } + return status; +} + +JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len) { + JSON_Value *value = json_value_init_string_with_len(string, len); + JSON_Status status = json_object_set_value(object, name, value); + if (status != JSONSuccess) { + json_value_free(value); + } + return status; } JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) { - return json_object_set_value(object, name, json_value_init_number(number)); + JSON_Value *value = json_value_init_number(number); + JSON_Status status = json_object_set_value(object, name, value); + if (status != JSONSuccess) { + json_value_free(value); + } + return status; } JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) { - return json_object_set_value(object, name, json_value_init_boolean(boolean)); + JSON_Value *value = json_value_init_boolean(boolean); + JSON_Status status = json_object_set_value(object, name, value); + if (status != JSONSuccess) { + json_value_free(value); + } + return status; } JSON_Status json_object_set_null(JSON_Object *object, const char *name) { - return json_object_set_value(object, name, json_value_init_null()); + JSON_Value *value = json_value_init_null(); + JSON_Status status = json_object_set_value(object, name, value); + if (status != JSONSuccess) { + json_value_free(value); + } + return status; } JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) { @@ -1795,6 +2149,8 @@ JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON JSON_Object *temp_object = NULL, *new_object = NULL; JSON_Status status = JSONFailure; size_t name_len = 0; + char *name_copy = NULL; + if (object == NULL || name == NULL || value == NULL) { return JSONFailure; } @@ -1822,8 +2178,15 @@ JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON json_value_free(new_value); return JSONFailure; } - status = json_object_addn(object, name, name_len, new_value); + name_copy = parson_strndup(name, name_len); + if (!name_copy) { + json_object_dotremove_internal(new_object, dot_pos + 1, 0); + json_value_free(new_value); + return JSONFailure; + } + status = json_object_add(object, name_copy, new_value); if (status != JSONSuccess) { + parson_free(name_copy); json_object_dotremove_internal(new_object, dot_pos + 1, 0); json_value_free(new_value); return JSONFailure; @@ -1836,7 +2199,19 @@ JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, con if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { + json_value_free(value); + return JSONFailure; + } + return JSONSuccess; +} + +JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len) { + JSON_Value *value = json_value_init_string_with_len(string, len); + if (value == NULL) { + return JSONFailure; + } + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1848,7 +2223,7 @@ JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, dou if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1860,7 +2235,7 @@ JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, in if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1872,7 +2247,7 @@ JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) { if (value == NULL) { return JSONFailure; } - if (json_object_dotset_value(object, name, value) == JSONFailure) { + if (json_object_dotset_value(object, name, value) != JSONSuccess) { json_value_free(value); return JSONFailure; } @@ -1880,11 +2255,11 @@ JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) { } JSON_Status json_object_remove(JSON_Object *object, const char *name) { - return json_object_remove_internal(object, name, 1); + return json_object_remove_internal(object, name, PARSON_TRUE); } JSON_Status json_object_dotremove(JSON_Object *object, const char *name) { - return json_object_dotremove_internal(object, name, 1); + return json_object_dotremove_internal(object, name, PARSON_TRUE); } JSON_Status json_object_clear(JSON_Object *object) { @@ -1927,7 +2302,7 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) { temp_schema_value = json_array_get_value(schema_array, 0); for (i = 0; i < json_array_get_count(value_array); i++) { temp_value = json_array_get_value(value_array, i); - if (json_validate(temp_schema_value, temp_value) == JSONFailure) { + if (json_validate(temp_schema_value, temp_value) != JSONSuccess) { return JSONFailure; } } @@ -1948,7 +2323,7 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) { if (temp_value == NULL) { return JSONFailure; } - if (json_validate(temp_schema_value, temp_value) == JSONFailure) { + if (json_validate(temp_schema_value, temp_value) != JSONSuccess) { return JSONFailure; } } @@ -1963,14 +2338,14 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) { int json_value_equals(const JSON_Value *a, const JSON_Value *b) { JSON_Object *a_object = NULL, *b_object = NULL; JSON_Array *a_array = NULL, *b_array = NULL; - const char *a_string = NULL, *b_string = NULL; + const JSON_String *a_string = NULL, *b_string = NULL; const char *key = NULL; size_t a_count = 0, b_count = 0, i = 0; JSON_Value_Type a_type, b_type; a_type = json_value_get_type(a); b_type = json_value_get_type(b); if (a_type != b_type) { - return 0; + return PARSON_FALSE; } switch (a_type) { case JSONArray: @@ -1979,48 +2354,49 @@ int json_value_equals(const JSON_Value *a, const JSON_Value *b) { a_count = json_array_get_count(a_array); b_count = json_array_get_count(b_array); if (a_count != b_count) { - return 0; + return PARSON_FALSE; } for (i = 0; i < a_count; i++) { if (!json_value_equals(json_array_get_value(a_array, i), json_array_get_value(b_array, i))) { - return 0; + return PARSON_FALSE; } } - return 1; + return PARSON_TRUE; case JSONObject: a_object = json_value_get_object(a); b_object = json_value_get_object(b); a_count = json_object_get_count(a_object); b_count = json_object_get_count(b_object); if (a_count != b_count) { - return 0; + return PARSON_FALSE; } for (i = 0; i < a_count; i++) { key = json_object_get_name(a_object, i); if (!json_value_equals(json_object_get_value(a_object, key), json_object_get_value(b_object, key))) { - return 0; + return PARSON_FALSE; } } - return 1; + return PARSON_TRUE; case JSONString: - a_string = json_value_get_string(a); - b_string = json_value_get_string(b); + a_string = json_value_get_string_desc(a); + b_string = json_value_get_string_desc(b); if (a_string == NULL || b_string == NULL) { - return 0; /* shouldn't happen */ + return PARSON_FALSE; /* shouldn't happen */ } - return strcmp(a_string, b_string) == 0; + return a_string->length == b_string->length && + memcmp(a_string->chars, b_string->chars, a_string->length) == 0; case JSONBoolean: return json_value_get_boolean(a) == json_value_get_boolean(b); case JSONNumber: return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */ case JSONError: - return 1; + return PARSON_TRUE; case JSONNull: - return 1; + return PARSON_TRUE; default: - return 1; + return PARSON_TRUE; } } @@ -2032,15 +2408,19 @@ JSON_Object * json_object (const JSON_Value *value) { return json_value_get_object(value); } -JSON_Array * json_array (const JSON_Value *value) { +JSON_Array * json_array(const JSON_Value *value) { return json_value_get_array(value); } -const char * json_string (const JSON_Value *value) { +const char * json_string(const JSON_Value *value) { return json_value_get_string(value); } -double json_number (const JSON_Value *value) { +size_t json_string_len(const JSON_Value *value) { + return json_value_get_string_len(value); +} + +double json_number(const JSON_Value *value) { return json_value_get_number(value); } @@ -2052,3 +2432,7 @@ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Fu parson_malloc = malloc_fun; parson_free = free_fun; } + +void json_set_escape_slashes(int escape_slashes) { + parson_escape_slashes = escape_slashes; +} \ No newline at end of file diff --git a/common/json/parson.h b/common/json/parson.h index 6438c9367..19a4de83a 100644 --- a/common/json/parson.h +++ b/common/json/parson.h @@ -1,6 +1,8 @@ /* - Parson ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2017 Krzysztof Gabis + SPDX-License-Identifier: MIT + + Parson 1.2.1 ( http://kgabis.github.com/parson/ ) + Copyright (c) 2012 - 2021 Krzysztof Gabis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -29,6 +31,12 @@ extern "C" { #endif +#define PARSON_VERSION_MAJOR 1 +#define PARSON_VERSION_MINOR 2 +#define PARSON_VERSION_PATCH 1 + +#define PARSON_VERSION_STRING "1.2.1" + #include /* size_t */ /* Types and enums */ @@ -60,12 +68,16 @@ typedef void (*JSON_Free_Function)(void *); from stdlib will be used for all allocations */ void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun); +/* Sets if slashes should be escaped or not when serializing JSON. By default slashes are escaped. + This function sets a global setting and is not thread safe. */ +void json_set_escape_slashes(int escape_slashes); + /* Parses first JSON value in a file, returns NULL in case of error */ -JSON_Value * json_parse_file(const char *filename); +//JSON_Value * json_parse_file(const char *filename); /* Parses first JSON value in a file and ignores comments (/ * * / and //), returns NULL in case of error */ -JSON_Value * json_parse_file_with_comments(const char *filename); +//JSON_Value * json_parse_file_with_comments(const char *filename); /* Parses first JSON value in a string, returns NULL in case of error */ JSON_Value * json_parse_string(const char *string); @@ -77,13 +89,13 @@ JSON_Value * json_parse_string_with_comments(const char *string); /* Serialization */ size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */ JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes); -JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename); +//JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename); char * json_serialize_to_string(const JSON_Value *value); /* Pretty serialization */ size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */ JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes); -JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename); +//JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename); char * json_serialize_to_string_pretty(const JSON_Value *value); void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */ @@ -108,6 +120,7 @@ JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value); */ JSON_Value * json_object_get_value (const JSON_Object *object, const char *name); const char * json_object_get_string (const JSON_Object *object, const char *name); +size_t json_object_get_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */ JSON_Object * json_object_get_object (const JSON_Object *object, const char *name); JSON_Array * json_object_get_array (const JSON_Object *object, const char *name); double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ @@ -119,6 +132,7 @@ int json_object_get_boolean(const JSON_Object *object, const char *nam this way. */ JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name); const char * json_object_dotget_string (const JSON_Object *object, const char *name); +size_t json_object_dotget_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */ JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name); JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name); double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ @@ -142,6 +156,7 @@ int json_object_dothas_value_of_type(const JSON_Object *object, const char *name * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */ JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value); JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string); +JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */ JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number); JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean); JSON_Status json_object_set_null(JSON_Object *object, const char *name); @@ -150,6 +165,7 @@ JSON_Status json_object_set_null(JSON_Object *object, const char *name); * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */ JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value); JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string); +JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */ JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number); JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean); JSON_Status json_object_dotset_null(JSON_Object *object, const char *name); @@ -168,13 +184,14 @@ JSON_Status json_object_clear(JSON_Object *object); */ JSON_Value * json_array_get_value (const JSON_Array *array, size_t index); const char * json_array_get_string (const JSON_Array *array, size_t index); +size_t json_array_get_string_len(const JSON_Array *array, size_t index); /* doesn't account for last null character */ JSON_Object * json_array_get_object (const JSON_Array *array, size_t index); JSON_Array * json_array_get_array (const JSON_Array *array, size_t index); double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */ int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */ size_t json_array_get_count (const JSON_Array *array); JSON_Value * json_array_get_wrapping_value(const JSON_Array *array); - + /* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist. * Order of values in array may change during execution. */ JSON_Status json_array_remove(JSON_Array *array, size_t i); @@ -184,6 +201,7 @@ JSON_Status json_array_remove(JSON_Array *array, size_t i); * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */ JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value); JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string); +JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len); /* length shouldn't include last null character */ JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number); JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean); JSON_Status json_array_replace_null(JSON_Array *array, size_t i); @@ -195,6 +213,7 @@ JSON_Status json_array_clear(JSON_Array *array); * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */ JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value); JSON_Status json_array_append_string(JSON_Array *array, const char *string); +JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len); /* length shouldn't include last null character */ JSON_Status json_array_append_number(JSON_Array *array, double number); JSON_Status json_array_append_boolean(JSON_Array *array, int boolean); JSON_Status json_array_append_null(JSON_Array *array); @@ -205,6 +224,7 @@ JSON_Status json_array_append_null(JSON_Array *array); JSON_Value * json_value_init_object (void); JSON_Value * json_value_init_array (void); JSON_Value * json_value_init_string (const char *string); /* copies passed string */ +JSON_Value * json_value_init_string_with_len(const char *string, size_t length); /* copies passed string, length shouldn't include last null character */ JSON_Value * json_value_init_number (double number); JSON_Value * json_value_init_boolean(int boolean); JSON_Value * json_value_init_null (void); @@ -215,6 +235,7 @@ JSON_Value_Type json_value_get_type (const JSON_Value *value); JSON_Object * json_value_get_object (const JSON_Value *value); JSON_Array * json_value_get_array (const JSON_Value *value); const char * json_value_get_string (const JSON_Value *value); +size_t json_value_get_string_len(const JSON_Value *value); /* doesn't account for last null character */ double json_value_get_number (const JSON_Value *value); int json_value_get_boolean(const JSON_Value *value); JSON_Value * json_value_get_parent (const JSON_Value *value); @@ -224,6 +245,7 @@ JSON_Value_Type json_type (const JSON_Value *value); JSON_Object * json_object (const JSON_Value *value); JSON_Array * json_array (const JSON_Value *value); const char * json_string (const JSON_Value *value); +size_t json_string_len(const JSON_Value *value); /* doesn't account for last null character */ double json_number (const JSON_Value *value); int json_boolean(const JSON_Value *value); @@ -231,4 +253,4 @@ int json_boolean(const JSON_Value *value); } #endif -#endif +#endif \ No newline at end of file diff --git a/config.mk b/config.mk index 79d5aa629..f8af5b140 100644 --- a/config.mk +++ b/config.mk @@ -66,9 +66,9 @@ PLANTUML_IMG_FORMAT ?= png # pdf / png / svg #-------------------------------------------------- PROJECT_NAME=fabric-private-chaincode -export FABRIC_VERSION ?= 2.3.0 +export FABRIC_VERSION ?= 2.3.3 -export FPC_VERSION := v1.0-rc2 +export FPC_VERSION := v1.0-rc3 export FABRIC_PATH ?= ${GOPATH}/src/github.com/hyperledger/fabric diff --git a/ecc/Makefile b/ecc/Makefile index 004b3346c..0cb071f9b 100644 --- a/ecc/Makefile +++ b/ecc/Makefile @@ -79,7 +79,7 @@ docker-fpc-app: docker-boilerplate-ecc docker-run: if [ "$(SGX_MODE)" = "HW" ]; then \ - SGX_DEVICE_PATH=$(if [ -e "/dev/isgx" ]; then echo "/dev/isgx"; elif [ -e "/dev/sgx" ]; then echo "/dev/sgx"; else echo "ERROR: NO SGX DEVICE FOUND"; fi);\ + SGX_DEVICE_PATH=$(if [ -e "/dev/isgx" ]; then echo "/dev/isgx"; elif [ -e "/dev/sgx/enclave" ]; then echo "/dev/sgx/enclave"; else echo "ERROR: NO SGX DEVICE FOUND"; fi);\ DOCKER_SGX_ARGS="--device $${SGX_DEVICE_PATH} -v /var/run/aesmd:/var/run/aesmd";\ fi;\ $(DOCKER) run \ diff --git a/ecc/chaincode/enclave/shim.go b/ecc/chaincode/enclave/shim.go index 0ec7fa03c..67da68f96 100644 --- a/ecc/chaincode/enclave/shim.go +++ b/ecc/chaincode/enclave/shim.go @@ -11,15 +11,12 @@ package enclave import ( "bytes" - "crypto/x509" - "encoding/pem" "fmt" "sync" "unsafe" "github.com/hyperledger/fabric-chaincode-go/shim" "github.com/hyperledger/fabric-private-chaincode/internal/utils" - "github.com/hyperledger/fabric/protoutil" ) // #cgo CFLAGS: -I${SRCDIR}/../../common/sgxcclib @@ -99,40 +96,6 @@ func (r *stubRegistry) get(i int) *Stubs { return stubs } -//export get_creator_name -func get_creator_name(msp_id *C.char, max_msp_id_len C.uint32_t, dn *C.char, max_dn_len C.uint32_t, ctx unsafe.Pointer) { - stubs := registry.get(*(*int)(ctx)) - - // TODO (eventually): replace/simplify below via ext.ClientIdentity, - // should also make it easier to eventually return more than only - // msp & dn .. - - serializedID, err := stubs.shimStub.GetCreator() - if err != nil { - panic("error while getting creator") - } - sId, err := protoutil.UnmarshalSerializedIdentity(serializedID) - if err != nil { - panic("Could not deserialize a SerializedIdentity") - } - - bl, _ := pem.Decode(sId.IdBytes) - if bl == nil { - panic("Failed to decode PEM structure") - } - cert, err := x509.ParseCertificate(bl.Bytes) - if err != nil { - panic("Unable to parse certificate %s") - } - - var goMspId = sId.Mspid - C._cpy_str(msp_id, goMspId, max_msp_id_len) - - var goDn = cert.Subject.String() - C._cpy_str(dn, goDn, max_dn_len) - // TODO (eventually): return the eror case of the dn buffer being too small -} - //export get_state func get_state(key *C.char, val *C.uint8_t, max_val_len C.uint32_t, val_len *C.uint32_t, ctx unsafe.Pointer) { stubs := registry.get(*(*int)(ctx)) @@ -219,3 +182,20 @@ func get_state_by_partial_composite_key(comp_key *C.char, values *C.uint8_t, max C._cpy_bytes(values, (*C.uint8_t)(C.CBytes(data)), C.uint32_t(len(data))) C._set_int(values_len, C.uint32_t(len(data))) } + +//export del_state +func del_state(key *C.char, ctx unsafe.Pointer) { + stubs := registry.get(*(*int)(ctx)) + + // check if composite key + key_str := C.GoString(key) + if utils.IsFPCCompositeKey(key_str) { + comp := utils.SplitFPCCompositeKey(key_str) + key_str, _ = stubs.shimStub.CreateCompositeKey(comp[0], comp[1:]) + } + + err := stubs.shimStub.DelState(key_str) + if err != nil { + panic("error while deleting state") + } +} diff --git a/ecc_enclave/enclave/CMakeLists-common-app-enclave.txt b/ecc_enclave/enclave/CMakeLists-common-app-enclave.txt index 48553cfc5..db33250e8 100644 --- a/ecc_enclave/enclave/CMakeLists-common-app-enclave.txt +++ b/ecc_enclave/enclave/CMakeLists-common-app-enclave.txt @@ -23,12 +23,16 @@ add_library(enclave SHARED ${SOURCE_FILES}) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${COMMON_SOURCE_DIR} + ${COMMON_SOURCE_DIR}/base64 ${COMMON_SOURCE_DIR}/json ${COMMON_SOURCE_DIR}/logging/trusted ${ECC_ENCLAVE_DIR}/enclave ${SGX_SDK}/include ${SGX_SDK}/include/tlibc ${SGX_SDK}/include/libcxx + #following only needed for demo + ${SGX_SSL}/include + ${COMMON_SOURCE_DIR}/crypto/pdo/common ) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SGX_COMMON_CFLAGS} -nostdinc -fno-builtin -fvisibility=hidden -fpie -fstack-protector -std=c11") diff --git a/ecc_enclave/enclave/CMakeLists.txt b/ecc_enclave/enclave/CMakeLists.txt index 36a2c4bfb..650395971 100644 --- a/ecc_enclave/enclave/CMakeLists.txt +++ b/ecc_enclave/enclave/CMakeLists.txt @@ -17,12 +17,14 @@ set(SOURCE_FILES ${COMMON_SOURCE_DIR}/utils.c ${COMMON_SOURCE_DIR}/json/parson.c ${COMMON_SOURCE_DIR}/protos/fpc/fpc.pb.c + ${COMMON_SOURCE_DIR}/protos/fabric/common/common.pb.c ${COMMON_SOURCE_DIR}/protos/fabric/peer/proposal.pb.c ${COMMON_SOURCE_DIR}/protos/fabric/peer/proposal_response.pb.c ${COMMON_SOURCE_DIR}/protos/fabric/peer/chaincode.pb.c ${COMMON_SOURCE_DIR}/protos/fabric/common/policies.pb.c ${COMMON_SOURCE_DIR}/protos/fabric/ledger/rwset/kvrwset/kv_rwset.pb.c ${COMMON_SOURCE_DIR}/protos/fabric/msp/msp_principal.pb.c + ${COMMON_SOURCE_DIR}/protos/fabric/msp/identities.pb.c ${COMMON_SOURCE_DIR}/protos/google/protobuf/any.pb.c ${COMMON_SOURCE_DIR}/protos/google/protobuf/timestamp.pb.c ${NANOPB_PATH}/pb_common.c diff --git a/ecc_enclave/enclave/crypto.cpp b/ecc_enclave/enclave/crypto.cpp index 7124613a8..52d57fa7b 100644 --- a/ecc_enclave/enclave/crypto.cpp +++ b/ecc_enclave/enclave/crypto.cpp @@ -6,6 +6,11 @@ */ #include "crypto.h" +#include +#include +#include +#include +#include #include "error.h" #include "logging.h" #include "pdo/common/crypto/crypto.h" @@ -65,3 +70,147 @@ bool compute_message_hash(const ByteArray message, ByteArray& message_hash) err: return false; } + +bool validate_message_signature( + const ByteArray signature, const ByteArray message, const ByteArray signer_cert) +{ + try + { + // deserialize public key + pdo::crypto::sig::PublicKey pk(extract_encoded_public_key(signer_cert)); + + // check signature + int r = pk.VerifySignature(message, signature); + COND2ERR(r != 1); + } + catch (const std::exception& e) + { + COND2LOGERR(true, e.what()); + } + + return true; + +err: + return false; +} + +std::string extract_encoded_public_key(const ByteArray cert_pem) +{ + BIO* certBio = BIO_new(BIO_s_mem()); + if (!certBio) + { + throw std::runtime_error("cannot create cert bio"); + } + + int r = BIO_write(certBio, cert_pem.data(), cert_pem.size()); + if (r <= 0) + { + BIO_free_all(certBio); + throw std::runtime_error("cannot read pem data"); + } + + X509* cert = PEM_read_bio_X509(certBio, NULL, NULL, NULL); + if (!cert) + { + BIO_free_all(certBio); + throw std::runtime_error("cannot parse cert"); + } + + // extract pk from cert and convert it back to pem format since PDO crypto requires encoded pk + EVP_PKEY* pubkey = X509_get_pubkey(cert); + if (!pubkey) + { + X509_free(cert); + BIO_free_all(certBio); + throw std::runtime_error("cannot get public key from cert"); + } + EC_KEY* eckey = EVP_PKEY_get1_EC_KEY(pubkey); + if (!eckey) + { + EVP_PKEY_free(pubkey); + X509_free(cert); + BIO_free_all(certBio); + throw std::runtime_error("cannot get EC public key"); + } + + BIO* pkBio = BIO_new(BIO_s_mem()); + if (!pkBio) + { + EVP_PKEY_free(pubkey); + EC_KEY_free(eckey); + X509_free(cert); + BIO_free_all(certBio); + throw std::runtime_error("cannot create cert bio"); + } + + r = PEM_write_bio_EC_PUBKEY(pkBio, eckey); + if (r == 0) + { + EVP_PKEY_free(pubkey); + EC_KEY_free(eckey); + X509_free(cert); + BIO_free_all(certBio); + throw std::runtime_error("cannot create cert bio"); + } + int keylen = BIO_pending(pkBio); + ByteArray pem_str(keylen + 1); + r = BIO_read(pkBio, pem_str.data(), keylen); + if (r <= 0) + { + EVP_PKEY_free(pubkey); + EC_KEY_free(eckey); + X509_free(cert); + BIO_free_all(certBio); + throw std::runtime_error("cannot serialize public key"); + } + pem_str[keylen] = '\0'; + BIO_free_all(pkBio); + + EVP_PKEY_free(pubkey); + EC_KEY_free(eckey); + X509_free(cert); + BIO_free_all(certBio); + + return std::string((const char*)pem_str.data(), pem_str.size()); +} + +std::string extract_subject_from_cert(const ByteArray cert_pem) +{ + BIO* certBio = BIO_new(BIO_s_mem()); + if (!certBio) + { + throw std::runtime_error("cannot create cert bio"); + } + + int r = BIO_write(certBio, cert_pem.data(), cert_pem.size()); + if (r <= 0) + { + BIO_free_all(certBio); + throw std::runtime_error("cannot read pem data"); + } + + X509* cert = PEM_read_bio_X509(certBio, NULL, NULL, NULL); + if (!cert) + { + BIO_free_all(certBio); + throw std::runtime_error("cannot parse cert"); + } + + char* subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + if (!subj) + { + X509_free(cert); + BIO_free_all(certBio); + throw std::runtime_error("cert does not contain a subject"); + } + std::string out(subj); + free(subj); + + X509_free(cert); + BIO_free_all(certBio); + + // Go: CN=peer0.org1.example.com,OU=COP,L=San Francisco,ST=California,C=US + // This: /C=US/ST=California/L=San Francisco/OU=COP/CN=peer0.org1.example.com + + return out; +} diff --git a/ecc_enclave/enclave/crypto.h b/ecc_enclave/enclave/crypto.h index 7e0aca6cd..435828f9f 100644 --- a/ecc_enclave/enclave/crypto.h +++ b/ecc_enclave/enclave/crypto.h @@ -21,3 +21,10 @@ bool decrypt_message(const ByteArray key, const ByteArray& encrypted_message, By bool encrypt_message(const ByteArray key, const ByteArray& message, ByteArray& encrypted_message); bool compute_message_hash(const ByteArray message, ByteArray& message_hash); + +bool validate_message_signature( + const ByteArray signature, const ByteArray message, const ByteArray serialized_signer); + +std::string extract_encoded_public_key(const ByteArray cert_pem); + +std::string extract_subject_from_cert(const ByteArray cert_pem); diff --git a/ecc_enclave/enclave/enclave.cpp b/ecc_enclave/enclave/enclave.cpp index 4e48c5c6e..6c9365b1e 100644 --- a/ecc_enclave/enclave/enclave.cpp +++ b/ecc_enclave/enclave/enclave.cpp @@ -10,6 +10,10 @@ #include "crypto.h" #include "enclave_t.h" #include "error.h" +#include "fabric/common/common.pb.h" +#include "fabric/msp/identities.pb.h" +#include "fabric/peer/chaincode.pb.h" +#include "fabric/peer/proposal.pb.h" #include "fpc/fpc.pb.h" #include "logging.h" #include "pb_decode.h" @@ -48,6 +52,104 @@ int ecall_cc_invoke(const uint8_t* signed_proposal_proto_bytes, ByteArray response_encryption_key; ctx.u_shim_ctx = u_shim_ctx; + ctx.signed_proposal = ByteArray( + signed_proposal_proto_bytes, signed_proposal_proto_bytes + signed_proposal_proto_bytes_len); + + // unmarshall proposal + { + pb_istream_t istream; + + protos_SignedProposal signed_proposal = protos_SignedProposal_init_zero; + istream = pb_istream_from_buffer( + (const unsigned char*)signed_proposal_proto_bytes, signed_proposal_proto_bytes_len); + b = pb_decode(&istream, protos_SignedProposal_fields, &signed_proposal); + COND2LOGERR(!b, PB_GET_ERROR(&istream)); + + protos_Proposal proposal = protos_Proposal_init_zero; + istream = + pb_istream_from_buffer((const unsigned char*)signed_proposal.proposal_bytes->bytes, + signed_proposal.proposal_bytes->size); + b = pb_decode(&istream, protos_Proposal_fields, &proposal); + COND2LOGERR(!b, PB_GET_ERROR(&istream)); + + common_Header header = common_Header_init_zero; + istream = pb_istream_from_buffer( + (const unsigned char*)proposal.header->bytes, proposal.header->size); + b = pb_decode(&istream, common_Header_fields, &header); + COND2LOGERR(!b, PB_GET_ERROR(&istream)); + + // set tx_id and channel id + common_ChannelHeader channel_header = common_ChannelHeader_init_zero; + istream = pb_istream_from_buffer( + (const unsigned char*)header.channel_header->bytes, header.channel_header->size); + b = pb_decode(&istream, common_ChannelHeader_fields, &channel_header); + COND2LOGERR(!b, PB_GET_ERROR(&istream)); + + ctx.tx_id = std::string(channel_header.tx_id); + ctx.channel_id = std::string(channel_header.channel_id); + COND2LOGERR(ctx.channel_id != g_cc_data->get_channel_id(), + "channel id of the tx proposal does not match as initialized with cc_parameters"); + + // TODO implement me + // transient data + // protos_ChaincodeProposalPayload cc_proposal_payload = + // protos_ChaincodeProposalPayload_init_zero; + // istream = pb_istream_from_buffer( + // (const unsigned char*)proposal.payload->bytes, proposal.payload->size); + // b = pb_decode(&istream, protos_ChaincodeProposalPayload_fields, &cc_proposal_payload); + // COND2LOGERR(!b, PB_GET_ERROR(&istream)); + + // transform _protos_ChaincodeProposalPayload_TransientMapEntry to std::map + // ctx.transient_data = ; + + // set creator + common_SignatureHeader signature_header = common_SignatureHeader_init_zero; + istream = pb_istream_from_buffer( + (const unsigned char*)header.signature_header->bytes, header.signature_header->size); + b = pb_decode(&istream, common_SignatureHeader_fields, &signature_header); + COND2LOGERR(!b, PB_GET_ERROR(&istream)); + + ByteArray signature = ByteArray(signed_proposal.signature->bytes, + signed_proposal.signature->bytes + signed_proposal.signature->size); + ByteArray message = ByteArray(signed_proposal.proposal_bytes->bytes, + signed_proposal.proposal_bytes->bytes + signed_proposal.proposal_bytes->size); + + ctx.creator = ByteArray(signature_header.creator->bytes, + signature_header.creator->bytes + signature_header.creator->size); + + msp_SerializedIdentity identity = msp_SerializedIdentity_init_zero; + istream = pb_istream_from_buffer((const unsigned char*)(signature_header.creator->bytes), + signature_header.creator->size); + b = pb_decode(&istream, msp_SerializedIdentity_fields, &identity); + COND2LOGERR(!b, PB_GET_ERROR(&istream)); + + ByteArray encoded_signer_cert = + ByteArray(identity.id_bytes->bytes, identity.id_bytes->bytes + identity.id_bytes->size); + b = validate_message_signature(signature, message, encoded_signer_cert); + COND2LOGERR(!b, "signature validation failed"); + + ctx.creator_msp_id = std::string(identity.mspid); + ctx.creator_name = extract_subject_from_cert(encoded_signer_cert); + + // TODO unwrap ChaincodeRequestMessage from signed proposal + // once this is in place we can remove ChaincodeRequestMessage from ecall + + // TODO implement me + // ByteArray binding_data; + // binding_data.insert(binding_data.end(), signature_header.nonce->bytes, + // signature_header.nonce->size); binding_data.insert(binding_data.end(), + // signature_header.creator->bytes, signature_header.creator->size); + // TODO add channel_header->epoch (as ByteArray) to binding (enforce little endian) + // b = compute_message_hash(binding_data, ctx->binding); + // COND2LOGERR(!b, "cannot compute binding"); + + pb_release(msp_SerializedIdentity_fields, &identity); + pb_release(common_SignatureHeader_fields, &signature_header); + pb_release(common_ChannelHeader_fields, &channel_header); + pb_release(common_Header_fields, &header); + pb_release(protos_Proposal_fields, &proposal); + pb_release(protos_SignedProposal_fields, &signed_proposal); + } { pb_istream_t istream; @@ -275,6 +377,8 @@ int ecall_cc_invoke(const uint8_t* signed_proposal_proto_bytes, // release dynamic allocations (TODO:release in case of error) pb_release(fpc_ChaincodeRequestMessage_fields, &cc_request_message); + pb_release(fpc_CleartextChaincodeRequest_fields, &cleartext_cc_request); + pb_release(fpc_KeyTransportMessage_fields, &key_transport_message); // TODO: generate signature (as short-cut for now over proposal _and_ args with consistency of // proposal and args verified in "__endorse" rather than enclave) diff --git a/ecc_enclave/enclave/enclave.edl b/ecc_enclave/enclave/enclave.edl index 3b91db21d..15ec2d4e0 100644 --- a/ecc_enclave/enclave/enclave.edl +++ b/ecc_enclave/enclave/enclave.edl @@ -21,11 +21,6 @@ enclave { }; untrusted { - void ocall_get_creator_name( - [out, size=max_msp_id_len] char *msp_id, uint32_t max_msp_id_len, - [out, size=max_dn_len] char *dn, uint32_t max_dn_len, - [user_check] void *u_shim_ctx); - void ocall_get_state( [in, string] const char *key, [out, size=max_val_len] uint8_t *val, uint32_t max_val_len, [out] uint32_t *val_len, @@ -40,6 +35,10 @@ enclave { [in, string] const char *comp_key, [out, size=max_len] uint8_t *values, uint32_t max_len, [out] uint32_t *values_len, [user_check] void *u_shim_ctx); + + void ocall_del_state( + [in, string] const char *key, + [user_check] void *u_shim_ctx); }; }; diff --git a/ecc_enclave/enclave/shim.cpp b/ecc_enclave/enclave/shim.cpp index c64e9fc8f..cfcdd943b 100644 --- a/ecc_enclave/enclave/shim.cpp +++ b/ecc_enclave/enclave/shim.cpp @@ -27,15 +27,10 @@ static sgx_thread_mutex_t global_mutex = SGX_THREAD_MUTEX_INITIALIZER; void get_creator_name( char* msp_id, uint32_t max_msp_id_len, char* dn, uint32_t max_dn_len, shim_ctx_ptr_t ctx) { - // TODO: right now the implementation is not secure yet as below function is unvalidated - // from the (untrusted) peer. - // To securely implement it, we will require the signed proposal to be passed - // from the stub (see, e.g., ChaincodeStub in go shim core/chaincode/shim/stub.go) - // and then verified. This in turn will require verification of certificates based - // on the MSP info channel. As TLCC already has to do keep track of MSP and do related - // verification , we can off-load some of that to TLCC (as we anyway have to talk to it - // to get channel MSP info) - ocall_get_creator_name(msp_id, max_msp_id_len, dn, max_dn_len, ctx->u_shim_ctx); + strcpy_s(msp_id, max_msp_id_len, ctx->creator_msp_id.c_str()); + strcpy_s(dn, max_dn_len, ctx->creator_name.c_str()); + + return; } void get_state( @@ -175,6 +170,7 @@ void put_public_state(const char* key, uint8_t* val, uint32_t val_len, shim_ctx_ // save write -- only the last one for the same key ctx->write_set.erase(key); ctx->write_set.insert({key, ByteArray(val, val + val_len)}); + ctx->del_set.erase(key); ocall_put_state(key, val, val_len, ctx->u_shim_ctx); } @@ -255,6 +251,15 @@ void get_public_state_by_partial_composite_key( unmarshal_values(values, (const char*)json, len); } +void del_state(const char* key, shim_ctx_ptr_t ctx) +{ + ctx->write_set.erase(key); + ctx->del_set.insert(key); + + ocall_del_state(key, ctx->u_shim_ctx); + return; +} + int get_string_args(std::vector& argss, shim_ctx_ptr_t ctx) { argss = ctx->string_args; @@ -274,3 +279,23 @@ int get_func_and_params( err: return -1; } + +void get_signed_proposal(ByteArray& signed_proposal, shim_ctx_ptr_t ctx) +{ + signed_proposal = ctx->signed_proposal; +} + +void get_channel_id(std::string& channel_id, shim_ctx_ptr_t ctx) +{ + channel_id = ctx->channel_id; +} + +void get_tx_id(std::string& tx_id, shim_ctx_ptr_t ctx) +{ + tx_id = ctx->tx_id; +} + +void get_creator(ByteArray& creator, shim_ctx_ptr_t ctx) +{ + creator = ctx->creator; +} diff --git a/ecc_enclave/enclave/shim.h b/ecc_enclave/enclave/shim.h index 3a75cce25..f5ede1a2b 100644 --- a/ecc_enclave/enclave/shim.h +++ b/ecc_enclave/enclave/shim.h @@ -15,6 +15,7 @@ #include "logging.h" typedef struct t_shim_ctx* shim_ctx_ptr_t; +typedef std::vector ByteArray; /* FPC Lite Constraints @@ -165,6 +166,9 @@ void get_public_state_by_partial_composite_key( // // - other functions: {get,set}StateValidationParameter, getHistoryForKey. Can/should we ignore? +// - records the given `key` to be deleted in the writeset. +void del_state(const char* key, shim_ctx_ptr_t ctx); + // retrieval for arguments //------------------------------------------------- // - retrieve the list of invocation parameters @@ -183,22 +187,12 @@ int get_func_and_params( // transaction APIs //------------------------------------------------- -// - getChannelID -// // TOD0 (possible extensions): might be useful to support and should be easy? -// // If this is just the name, would it be useful also to have a variant which -// // has the unique id ("content-addressable"/genesis-block-hash)? -// void get_channel_id(char* channel_id, -// uint32_t max_channel_id_len, -// shim_ctx_ptr_t ctx); +// - getChannelID - returns the channel name (ID) the FPC chaincode enclave +// Note that the channel ID is attested during enclave initialization. +void get_channel_id(std::string& channel_id, shim_ctx_ptr_t ctx); -// - TxID -// // TODO (possible extensions): at least coming from a Sawtooth/PDO perspective, -// // i would think access to this info might be important for cross-cc transactions? -// // - Is it commonly used in fabric? -// // - Is this something we can easily support (insecurely short-term / securely long-term)? -// void get_tx_id(char* tx_id, -// uint32_t max_tx_id_len, -// shim_ctx_ptr_t ctx); +// - getTxID +void get_tx_id(std::string& tx_id, shim_ctx_ptr_t ctx); // - getTxTimestamp // // TODO (possible extensions): enclave has no access to trusted time. Time @@ -222,11 +216,13 @@ int get_func_and_params( // // // TODO: other tx-related apis which exist but probably doesn't make sense to support // // - getTransient: if we encrypt everything, then everything is essentially Transient? -// // - getSignedProposal: should be easy to support but probably not worth? -// - creator -// return the distinguished name of the creator as well as the msp_id of the corresponding -// organization. +// - getSignedProposal - returns a serialized signed proposal +void get_signed_proposal(ByteArray& signed_proposal, shim_ctx_ptr_t ctx); + +// - get_creator_name +// return the distinguished name of the creator (the subject field of the creator cert) +// as well as the msp_id of the corresponding organization. // Note: // - The name might be truncated (but guaranteed to be null-terminated) // if the provided buffer is too small. @@ -235,11 +231,11 @@ void get_creator_name(char* msp_id, // MSP id of organization to which transact char* dn, // distinguished name of transaction creator uint32_t max_dn_len, // size of allocated buffer for dn shim_ctx_ptr_t ctx); -// -// TODO (eventually): The go shim GoCreator returns protobuf serialized identity which (usally) -// is the pair of msp_id and a (PEM-encoded) certificate. We might eventually add a function -// also to expose the certificate itself. However, for most current use-cases the DN should -// be sufficient and makes CC-programming easier. + +// - get_creator - returns a serialized identity from the signed proposal +// Note that the returned identity is not validated against the MSP/ledger since +// the enclave does not have trustworthy data to do so. +void get_creator(ByteArray& creator, shim_ctx_ptr_t ctx); // Chaincode to Chaincode //--------------------------- diff --git a/ecc_enclave/enclave/shim_internals.cpp b/ecc_enclave/enclave/shim_internals.cpp index 1ce703f07..55454f6a5 100644 --- a/ecc_enclave/enclave/shim_internals.cpp +++ b/ecc_enclave/enclave/shim_internals.cpp @@ -21,7 +21,7 @@ bool rwset_to_proto(t_shim_ctx_t* ctx, fpc_FPCKVSet* fpc_rwset_proto) COND2LOGERR(ctx == NULL || fpc_rwset_proto == NULL, "invalid input parameters"); - LOG_DEBUG("Prepare rwset serialization"); + LOG_DEBUG("Prepare Fabric RWSet construction"); // reset structure *fpc_rwset_proto = fpc_FPCKVSet_init_default; @@ -39,12 +39,12 @@ bool rwset_to_proto(t_shim_ctx_t* ctx, fpc_FPCKVSet* fpc_rwset_proto) COND2ERR(fpc_rwset_proto->rw_set.reads == NULL); // initialiaze write sets (i.e., the arrays; later we serialize single items) - fpc_rwset_proto->rw_set.writes_count = ctx->write_set.size(); + fpc_rwset_proto->rw_set.writes_count = ctx->write_set.size() + ctx->del_set.size(); fpc_rwset_proto->rw_set.writes = (kvrwset_KVWrite*)pb_realloc( NULL, fpc_rwset_proto->rw_set.writes_count * sizeof(kvrwset_KVWrite)); COND2ERR(fpc_rwset_proto->rw_set.writes == NULL); - LOG_DEBUG("Serializing read set items"); + LOG_DEBUG("Add read_set items"); i = 0; for (auto it = ctx->read_set.begin(); it != ctx->read_set.end(); it++, i++) { @@ -70,7 +70,7 @@ bool rwset_to_proto(t_shim_ctx_t* ctx, fpc_FPCKVSet* fpc_rwset_proto) COND2ERR(ret != 0); } - LOG_DEBUG("Serializing write set items"); + LOG_DEBUG("Add write_set items"); i = 0; for (auto it = ctx->write_set.begin(); it != ctx->write_set.end(); it++, i++) { @@ -98,7 +98,30 @@ bool rwset_to_proto(t_shim_ctx_t* ctx, fpc_FPCKVSet* fpc_rwset_proto) COND2ERR(ret != 0); } - LOG_DEBUG("Serialization successful"); + LOG_DEBUG("Add del_set items"); + for (auto it = ctx->del_set.begin(); it != ctx->del_set.end(); it++, i++) + { + // note that we continue to use i without resetting since we are appending to the + // rw_set.writes + LOG_DEBUG("k=%s", it->c_str()); + + // serialize write + fpc_rwset_proto->rw_set.writes[i].is_delete = true; + + // serialize key + fpc_rwset_proto->rw_set.writes[i].key = (char*)pb_realloc(NULL, it->length() + 1); + COND2ERR(fpc_rwset_proto->rw_set.writes[i].key == NULL); + ret = memcpy_s( + fpc_rwset_proto->rw_set.writes[i].key, it->length(), it->c_str(), it->length()); + fpc_rwset_proto->rw_set.writes[i].key[it->length()] = '\0'; + COND2ERR(ret != 0); + + fpc_rwset_proto->rw_set.writes[i].value = + (pb_bytes_array_t*)pb_realloc(NULL, PB_BYTES_ARRAY_T_ALLOCSIZE(0)); + COND2ERR(fpc_rwset_proto->rw_set.writes[i].value == NULL); + } + + LOG_DEBUG("Fabric RWSet construction successful"); return true; err: diff --git a/ecc_enclave/enclave/shim_internals.h b/ecc_enclave/enclave/shim_internals.h index d9f0f08be..4cc7c1f32 100644 --- a/ecc_enclave/enclave/shim_internals.h +++ b/ecc_enclave/enclave/shim_internals.h @@ -16,6 +16,7 @@ // read/writeset typedef std::map write_set_t; typedef std::map read_set_t; +typedef std::set del_set_t; // shim context typedef struct t_shim_ctx @@ -23,7 +24,17 @@ typedef struct t_shim_ctx void* u_shim_ctx; read_set_t read_set; write_set_t write_set; + del_set_t del_set; std::vector string_args; + ByteArray signed_proposal; + std::string tx_id; + std::string channel_id; + ByteArray creator; + std::string creator_msp_id; + std::string creator_name; + // TODO to be implemented + // ByteArray binding; + // std::map transient_data; } t_shim_ctx_t; #include "fpc.pb.h" diff --git a/ecc_enclave/sgxcclib/sgxcclib.c b/ecc_enclave/sgxcclib/sgxcclib.c index fa41cf81a..0ef464517 100644 --- a/ecc_enclave/sgxcclib/sgxcclib.c +++ b/ecc_enclave/sgxcclib/sgxcclib.c @@ -12,16 +12,13 @@ #include #include -// - creator access -extern void get_creator_name( - const char* msp_id, uint32_t max_msp_id_len, const char* dn, uint32_t max_dn_len, void* ctx); - // - for accessing ledger kvs extern void get_state( const char* key, uint8_t* val, uint32_t max_val_len, uint32_t* val_len, void* ctx); extern void get_state_by_partial_composite_key( const char* comp_key, uint8_t* values, uint32_t max_len, uint32_t* values_len, void* ctx); extern void put_state(const char* key, uint8_t* val, uint32_t val_len, void* ctx); +extern void del_state(const char* key, void* ctx); int sgxcc_invoke(enclave_id_t eid, const uint8_t* signed_proposal_proto_bytes, @@ -44,13 +41,6 @@ int sgxcc_invoke(enclave_id_t eid, return SGX_SUCCESS; } -/* OCall functions */ -void ocall_get_creator_name( - char* msp_id, uint32_t max_msp_id_len, char* dn, uint32_t max_dn_len, void* ctx) -{ - get_creator_name(msp_id, max_msp_id_len, dn, max_dn_len, ctx); -} - void ocall_get_state( const char* key, uint8_t* val, uint32_t max_val_len, uint32_t* val_len, void* ctx) { @@ -67,3 +57,8 @@ void ocall_get_state_by_partial_composite_key( { get_state_by_partial_composite_key(key, bids_bytes, max_len, bids_bytes_len, ctx); } + +void ocall_del_state(const char* key, void* ctx) +{ + del_state(key, ctx); +} diff --git a/fabric/Makefile b/fabric/Makefile index feddbefd1..8a2715452 100644 --- a/fabric/Makefile +++ b/fabric/Makefile @@ -20,7 +20,7 @@ fetch: $(FABS_FETCHED) $(FABS_FETCHED): mkdir -p $(FABS) && cd $(FABS) \ - && curl -sSL https://bit.ly/2ysbOFE | bash -s -- $(FABRIC_VERSION) 1.4.9 -s -d \ + && curl -sSL https://bit.ly/2ysbOFE | bash -s -- $(FABRIC_VERSION) 1.4.9 -s \ && touch .fetched diff --git a/fabric/README.md b/fabric/README.md index 970e75bba..1287f6a2a 100644 --- a/fabric/README.md +++ b/fabric/README.md @@ -27,9 +27,9 @@ To clean the native build, type `cd $FPC_PATH/fabric; make clean-native`. ### Wrong Fabric version ``` Patching Fabric ... -Aborting! Tag on current HEAD () does not match expected tag/v2.3.0! +Aborting! Tag on current HEAD () does not match expected tag/v2.3.3! ... ``` Seems that your Fabric is on the wrong branch. -Try to run `pushd $FABRIC_PATH; git checkout tags/v2.3.0; popd;` followed by `make` again. +Try to run `pushd $FABRIC_PATH; git checkout tags/v2.3.3; popd;` followed by `make` again. diff --git a/fabric/bin/peer.sh b/fabric/bin/peer.sh index 6b744b36c..9d5437222 100755 --- a/fabric/bin/peer.sh +++ b/fabric/bin/peer.sh @@ -99,7 +99,7 @@ handle_lifecycle_chaincode_package() { # Above is the flags we really care, but we need also the outputfile # which doesn't have a flag. So let's enumerate the known no-arg # flags (i.e., --tls -h/--help), assume all other flags have exactly - # one arg (true as of v2.3.0) and then the remaining one is the + # one arg (true as of v2.3.3) and then the remaining one is the # output file ... -h|--help) # with help, no point to continue but run it right here .. @@ -206,7 +206,7 @@ handle_lifecycle_chaincode_install() { # we care only about package file name but this is not prefixed # with a flag. So let's enumerate the known no-arg flags (i.e., # --tls -h/--help), assume all other flags have exactly - # one arg (true as of v2.3.0) and then the remaining one is the + # one arg (true as of v2.3.3) and then the remaining one is the # output file ... -h|--help) # with help, no point to continue but run it right here .. diff --git a/go.mod b/go.mod index bee988f02..a6e538030 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/hyperledger/fabric-private-chaincode -go 1.15 +go 1.16 // Note: // - fabric has a go.mod but the normal tagging, e.g., v2.2.0 does NOT diff --git a/integration/client_sdk/go/stress_test/stress_test.go b/integration/client_sdk/go/stress_test/stress_test.go index f29ec1574..272a35226 100644 --- a/integration/client_sdk/go/stress_test/stress_test.go +++ b/integration/client_sdk/go/stress_test/stress_test.go @@ -11,7 +11,9 @@ import ( "crypto/rand" "encoding/base64" "fmt" + "os" "path/filepath" + "strconv" "testing" fpc "github.com/hyperledger/fabric-private-chaincode/client_sdk/go/pkg/gateway" @@ -27,9 +29,14 @@ func TestStress(t *testing.T) { RunSpecs(t, "Chaincode Suite") } +const ( + defaultInvocationCount = 1000 + envKeyInvocationCount = "STRESS_TEST_INVOCATION_COUNT" +) + var ( - network *gateway.Network - echoContract fpc.Contract + network *gateway.Network + contract fpc.Contract ) var _ = BeforeSuite(func() { @@ -46,8 +53,8 @@ var _ = BeforeSuite(func() { Expect(network).ShouldNot(BeNil()) // Get FPC Contract - echoContract = fpc.GetContract(network, ccID) - Expect(echoContract).ShouldNot(BeNil()) + contract = fpc.GetContract(network, ccID) + Expect(contract).ShouldNot(BeNil()) }) var _ = Describe("Stress tests", func() { @@ -66,11 +73,46 @@ var _ = Describe("Stress tests", func() { key := "some-key" value := base64.StdEncoding.EncodeToString(payload) - res, err := echoContract.SubmitTransaction("put_state", key, value) + res, err := contract.SubmitTransaction("put_state", key, value) Expect(err).ShouldNot(HaveOccurred()) Expect(res).Should(Equal([]byte("OK"))) - res, err = echoContract.EvaluateTransaction("get_state", key) + res, err = contract.EvaluateTransaction("get_state", key) + Expect(err).ShouldNot(HaveOccurred()) + Expect(res).Should(Equal([]byte(value))) + + res, err = contract.SubmitTransaction("del_state", key) + Expect(err).ShouldNot(HaveOccurred()) + Expect(res).Should(Equal([]byte("OK"))) + } + }) + }) + }) + + Context("long run", func() { + When("submitting many invocations", func() { + It("should succeed", func() { + invocations := readIntValueFromEnv(envKeyInvocationCount, defaultInvocationCount) + key := "some-other-key" + size := 1000 + + payload := make([]byte, size) + n, err := rand.Read(payload) + + Expect(err).ShouldNot(HaveOccurred()) + Expect(n).Should(Equal(size)) + + value := base64.StdEncoding.EncodeToString(payload) + res, err := contract.SubmitTransaction("put_state", key, value) + Expect(err).ShouldNot(HaveOccurred()) + Expect(res).Should(Equal([]byte("OK"))) + + fmt.Printf("Running %d get_state invocations\n", invocations) + for i := 0; i < invocations; i++ { + if i%10 == 0 { + fmt.Printf("i=%d\n", i) + } + res, err = contract.EvaluateTransaction("get_state", key) Expect(err).ShouldNot(HaveOccurred()) Expect(res).Should(Equal([]byte(value))) } @@ -80,3 +122,15 @@ var _ = Describe("Stress tests", func() { // TODO more stress tests added here }) + +func readIntValueFromEnv(key string, defaultValue int) int { + invocationCountString := os.Getenv(key) + if len(invocationCountString) > 0 { + fmt.Printf("set %s to %s\n", key, invocationCountString) + i, err := strconv.Atoi(invocationCountString) + Expect(err).ShouldNot(HaveOccurred()) + return i + } else { + return defaultValue + } +} diff --git a/integration/kv_test.sh b/integration/kv_test.sh index b32b0192a..6721dd3bb 100755 --- a/integration/kv_test.sh +++ b/integration/kv_test.sh @@ -43,6 +43,10 @@ kv_test() { try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"put_state", "Args": ["echo-0", "echo-0"]}' --waitForEvent check_result "OK" + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"get_state", "Args": ["echo-0"]}' --waitForEvent + check_result "echo-0" + try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"del_state", "Args": ["echo-0"]}' --waitForEvent + check_result "OK" } # 1. prepare diff --git a/integration/stress_test.sh b/integration/stress_test.sh index 26c459b07..38584502b 100755 --- a/integration/stress_test.sh +++ b/integration/stress_test.sh @@ -23,7 +23,7 @@ CC_EP="OR('SampleOrg.member')" # note that we use .member as NodeOUs is disabled run_test() { # call sdk test - try cd client_sdk/go/stress_test && go test -v + try go test -v "${SCRIPTDIR}/client_sdk/go/stress_test" # cleanup rm -rf keystore wallet diff --git a/internal/endorsement/validation.go b/internal/endorsement/validation.go index 99fdc7825..dd944fc66 100644 --- a/internal/endorsement/validation.go +++ b/internal/endorsement/validation.go @@ -60,6 +60,13 @@ func (v *ValidatorImpl) ReplayReadWrites(stub shim.ChaincodeStubInterface, fpcrw for i := 0; i < len(rwset.Reads); i++ { k := utils.TransformToFPCKey(rwset.Reads[i].Key) + + // check if composite key, if so, derive Fabric key + if utils.IsFPCCompositeKey(k) { + comp := utils.SplitFPCCompositeKey(k) + k, _ = stub.CreateCompositeKey(comp[0], comp[1:]) + } + v, err := stub.GetState(k) if err != nil { return fmt.Errorf("error (%s) reading key %s", err, k) @@ -118,12 +125,17 @@ func (v *ValidatorImpl) ReplayReadWrites(stub shim.ChaincodeStubInterface, fpcrw k, _ = stub.CreateCompositeKey(comp[0], comp[1:]) } - err := stub.PutState(k, w.Value) - if err != nil { - return fmt.Errorf("error (%s) writing key %s value(hex) %s", err, k, hex.EncodeToString(w.Value)) + if w.IsDelete { + if err := stub.DelState(k); err != nil { + return fmt.Errorf("error (%s) deleting key %s", err, k) + } + logger.Debugf("key %s deleted", k) + } else { + if err := stub.PutState(k, w.Value); err != nil { + return fmt.Errorf("error (%s) writing key %s value(hex) %s", err, k, hex.EncodeToString(w.Value)) + } + logger.Debugf("written key %s value(hex) %s", k, hex.EncodeToString(w.Value)) } - - logger.Debugf("written key %s value(hex) %s", k, hex.EncodeToString(w.Value)) } } diff --git a/protos/fabric.options b/protos/fabric.options index d59e5a1f9..2ec8fd2ed 100644 --- a/protos/fabric.options +++ b/protos/fabric.options @@ -89,6 +89,10 @@ protos.Response.payload type:FT_POINTER protos.SignedProposal.proposal_bytes type:FT_POINTER protos.SignedProposal.signature type:FT_POINTER +protos.Proposal.header type:FT_POINTER +protos.Proposal.payload type:FT_POINTER +protos.Proposal.extension type:FT_POINTER + protos.ApplicationPolicy.channel_config_policy_reference type:FT_POINTER rwset.TxReadWriteSet.ns_rwset type:FT_POINTER diff --git a/protos/fpc.options b/protos/fpc.options index 910f66607..952abc239 100644 --- a/protos/fpc.options +++ b/protos/fpc.options @@ -14,3 +14,6 @@ fpc.ChaincodeResponseMessage.enclave_id type:FT_POINTER fpc.SignedChaincodeResponseMessage.chaincode_response_message type:FT_POINTER fpc.SignedChaincodeResponseMessage.signature type:FT_POINTER + +fpc.CCParameters.channel_id type:FT_POINTER +fpc.CCParameters.chaincode_id type:FT_POINTER diff --git a/samples/Makefile b/samples/Makefile index 73cbfe50f..a277fe514 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -6,7 +6,7 @@ TOP = .. include $(TOP)/build.mk -SAMPLES = application chaincode #deployment +SAMPLES = application chaincode demos #deployment build clean: $(foreach DIR, $(SAMPLES), $(MAKE) -C $(DIR) $@ || exit;) diff --git a/samples/chaincode/helloworld/README.md b/samples/chaincode/helloworld/README.md index 3b56b0b7a..65d1188af 100644 --- a/samples/chaincode/helloworld/README.md +++ b/samples/chaincode/helloworld/README.md @@ -294,11 +294,11 @@ make Following is a part of expected output. Please note `[100%] Built target enclave` message in the output. This suggests that build was successful. Output: ```bash -make[3]: Leaving directory '/home/bcuser/work/src/github.com/hyperledger/fabric-private-chaincode/examples/helloworld/_build' +make[3]: Leaving directory '/home/bcuser/work/src/github.com/hyperledger/fabric-private-chaincode/samples/chaincode/helloworld/_build' [100%] Built target enclave -make[2]: Leaving directory '/home/bcuser/work/src/github.com/hyperledger/fabric-private-chaincode/examples/helloworld/_build' -/usr/bin/cmake -E cmake_progress_start /home/bcuser/work/src/github.com/hyperledger/fabric-private-chaincode/examples/helloworld/_build/CMakeFiles 0 -make[1]: Leaving directory '/home/bcuser/work/src/github.com/hyperledger/fabric-private-chaincode/examples/helloworld/_build' +make[2]: Leaving directory '/home/bcuser/work/src/github.com/hyperledger/fabric-private-chaincode/samples/chaincode/helloworld/_build' +/usr/bin/cmake -E cmake_progress_start /home/bcuser/work/src/github.com/hyperledger/fabric-private-chaincode/samples/chaincode/helloworld/_build/CMakeFiles 0 +make[1]: Leaving directory '/home/bcuser/work/src/github.com/hyperledger/fabric-private-chaincode/samples/chaincode/helloworld/_build' ``` @@ -324,7 +324,7 @@ FABRIC_SCRIPTDIR="${FPC_PATH}/fabric/bin/" . ${FABRIC_SCRIPTDIR}/lib/common_ledger.sh # this is the path points to FPC chaincode binary -CC_PATH=${FPC_PATH}/examples/helloworld/_build/lib/ +CC_PATH=${FPC_PATH}/samples/chaincode/helloworld/_build/lib/ CC_ID=helloworld_test CC_VER="$(cat ${CC_PATH}/mrenclave)" @@ -420,7 +420,7 @@ FABRIC_SCRIPTDIR="${FPC_PATH}/fabric/bin/" . ${FABRIC_SCRIPTDIR}/lib/common_ledger.sh # this is the path points to FPC chaincode binary -CC_PATH=${FPC_PATH}/examples/helloworld/_build/lib/ +CC_PATH=${FPC_PATH}/samples/chaincode/helloworld/_build/lib/ CC_ID=helloworld_test CC_VER="$(cat ${CC_PATH}/mrenclave)" diff --git a/samples/chaincode/kv-test/kv-test-cc.cpp b/samples/chaincode/kv-test/kv-test-cc.cpp index 4e14a633c..8cf25f851 100644 --- a/samples/chaincode/kv-test/kv-test-cc.cpp +++ b/samples/chaincode/kv-test/kv-test-cc.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "base64.h" #include "shim.h" #include @@ -21,6 +22,8 @@ int invoke( std::string result; get_func_and_params(function_name, params, ctx); + LOG_DEBUG("Call function: %s", function_name.c_str()); + if (function_name == "put_state") { if (params.size() != 2) @@ -58,11 +61,49 @@ int invoke( result = std::string((const char*)value, actual_value_len); } } + else if (function_name == "del_state") + { + if (params.size() != 1) + { + result = std::string("del_state needs 1 parameter: key"); + } + else + { + del_state(params[0].c_str(), ctx); + result = std::string("OK"); + } + } else { result = std::string("BAD FUNCTION"); } + // test more fpc shim functions + + std::string channel_id; + get_channel_id(channel_id, ctx); + LOG_DEBUG("Channel id: %s", channel_id.c_str()); + + std::string tx_id; + get_tx_id(tx_id, ctx); + LOG_DEBUG("Tx id: %s", tx_id.c_str()); + + ByteArray signed_proposal; + get_signed_proposal(signed_proposal, ctx); + LOG_DEBUG("Signed proposal: %s", + base64_encode((unsigned char*)signed_proposal.data(), signed_proposal.size()).c_str()); + + ByteArray creator; + get_creator(creator, ctx); + LOG_DEBUG("Creator: %s", base64_encode((unsigned char*)creator.data(), creator.size()).c_str()); + + char creator_msp_id[1024]; + char creator_name[1024]; + get_creator_name( + creator_msp_id, sizeof(creator_msp_id), creator_name, sizeof(creator_name), ctx); + LOG_DEBUG("Creator msp: %s", creator_msp_id); + LOG_DEBUG("Creator name: %s", creator_name); + // check that result fits into response int neededSize = result.size(); if (max_response_len < neededSize) diff --git a/samples/demos/Makefile b/samples/demos/Makefile new file mode 100644 index 000000000..d78fe63ec --- /dev/null +++ b/samples/demos/Makefile @@ -0,0 +1,13 @@ +# Copyright 2019 Intel Corporation +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +TOP = ../.. +include $(TOP)/build.mk + +DEMOS = irb + +build clean: + $(foreach DIR, $(DEMOS), $(MAKE) -C $(DIR) $@ || exit;) + diff --git a/samples/demos/irb/.gitignore b/samples/demos/irb/.gitignore new file mode 100644 index 000000000..7ec3949c3 --- /dev/null +++ b/samples/demos/irb/.gitignore @@ -0,0 +1,2 @@ +cmd/** +users/** \ No newline at end of file diff --git a/samples/demos/irb/Makefile b/samples/demos/irb/Makefile new file mode 100644 index 000000000..2f5e2b52c --- /dev/null +++ b/samples/demos/irb/Makefile @@ -0,0 +1,21 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +TOP = ../../.. +include $(TOP)/build.mk + +COMPONENTS = chaincode experimenter + +all: build test + +build: + $(foreach DIR, $(COMPONENTS), $(MAKE) -C $(DIR) $@ || exit;) + +test: + $(GO) test -v ./... + +clean: + $(GO) clean + rm -rf cmd users + $(foreach DIR, $(COMPONENTS), $(MAKE) -C $(DIR) $@ || exit;) diff --git a/samples/demos/irb/README.md b/samples/demos/irb/README.md new file mode 100644 index 000000000..4f67de4ee --- /dev/null +++ b/samples/demos/irb/README.md @@ -0,0 +1,69 @@ +# Institutional Review Board (IRB) Sample + +This demo implements an FPC-based IRB experiment approval services to protect the confidentiality of data being used in analytical experiments. +The problem addressed here is relevant in a healthcare context, where sensitive patient data is processed in clinical trails. +Multiple participants, namely, data providers, experimenter, and principal investigators are collaborating to conduct analytical research using sensitive data. + +We show a prototype of an application that performs analytical experiments on data such that: +- Any constraints on the use of the data are respected (consent). +- The confidentiality of data and policies for its use is maintained. +- Analytical experiments must be approved by an IRB which ensures that the description and implementation of the experiment are appropriate. +- Analytical experiments are executed in an SGX container (Graphene) that can attest to the integrity of the computation. + +The demo was presented at the Hyperledger Global Forum (HLGF) 2021. Check the recordings on [youtube](https://www.youtube.com/watch?v=MU4BpZp8A1Y). + +Note that the demo source code here is a simplified version of the demo presented at HLGF21, to fully focus on the FPC implementation. +In particular, the experiment is not protected with SGX and the WebUI component is not present. +The full source code for the HLFG21 presentation is located in the [irb-demo](https://github.com/hyperledger/fabric-private-chaincode/tree/irb-demo/samples/demos/irb) branch. + +The IRB use case requires the interaction between the participants. +A typical application flow begins with the data registration and consent, following the approval protocol, and finally executing the experiment and publishing the results. +We use [Fabric Smart Client](https://github.com/hyperledger-labs/fabric-smart-client) to implement the complex interactions. + +## What the demo shows + +The demo runs in the terminal and demonstrates the application flow. +In particular, the demo starts a Fabric network with multiple organizations participating and hosting fabric peers. +The Fabric Smart Client installs the FPC Chaincode that implements the IRB experiment approval service. + +Once the network is ready, the application flow begins with the investigator, creating a new study. +Next, the data provider registers and uploads new patient data to the systems, assigning the data to be used in the study. +Now we have a study and data to process. + +The experimenter proceeds with creating a new experiment and asks the investigator for approval. +Once the approval arrived, that is, the investigator has reviewed the experiment proposal and submitted an approval to the IRB experiment approval service, the execution of the experiment is triggered. + +Finally, the experimenter requests an evaluation pack from the IRB experiment approval service, that contains the access information to collect the patient data. +The evaluation pack is passed to the experiment instance, which fetches the patient data, performs the experiment computation, and returns the result. +Note that the patient data is encrypted in a way that only an approved experiment instance can decrypt the data. +More details on that, see the HLGF21 presentation. + +## Code structure +- `/chaincode` contains the FPC chaincode that implements the IRV approval service +- `/experimenter` contains the analytic experiment code based on [PyTorch](https://pytorch.org/). +- `/pkg` contains implementations for various components, including crypto, container management, etc. +- `/protos` contains the message definitions used in this application +- `/views` contains the protocol implementation for the data provider, experimenter, and investigator. +- `irb_test.go` is the starting point of the demo. +- `topology.go` defines the Fabric network used in this demo. + +## Setup + +The demo uses redis to store the data provided by the patients. Get a redis docker image. +```bash +docker pull redis:latest +``` + +Next, we build the components of the demo by running: +```bash +make build +``` + +## Run the demo + +To run the demo just use the `test` target. +You will see the output of the interaction between the participants in your terminal. + +```bash +make test +``` diff --git a/samples/demos/irb/chaincode/.gitignore b/samples/demos/irb/chaincode/.gitignore new file mode 100644 index 000000000..c116293c4 --- /dev/null +++ b/samples/demos/irb/chaincode/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 +_protos/** +_build/** diff --git a/samples/demos/irb/chaincode/CMakeLists.txt b/samples/demos/irb/chaincode/CMakeLists.txt new file mode 100644 index 000000000..623122a58 --- /dev/null +++ b/samples/demos/irb/chaincode/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright 2019 Intel Corporation +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.5.1) +project(FPC_DEMO_EAS) + +set(SOURCE_FILES + entry.cpp + dispatcher.cpp + chaincode.cpp + errors.cpp + messages.cpp + _protos/irb.pb.c + storage.cpp + id.cpp + experiment.cpp + study.cpp + signedapproval.cpp + evaluationpack.cpp + ) + +# NANOPB for protos +include($ENV{FPC_PATH}/cmake/NanoPB.cmake) +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${NANOPB_PATH} + ) + +# FPC Common chaincode +include($ENV{FPC_PATH}/ecc_enclave/enclave/CMakeLists-common-app-enclave.txt) diff --git a/samples/demos/irb/chaincode/Makefile b/samples/demos/irb/chaincode/Makefile new file mode 100644 index 000000000..a97a90656 --- /dev/null +++ b/samples/demos/irb/chaincode/Makefile @@ -0,0 +1,48 @@ +# Copyright 2019 Intel Corporation +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +TOP = ../../../.. +include $(TOP)/build.mk + +BUILD_DIR := _build +DOCKER_IMAGE_NAME := fpc/irb-experiment + +all: docker + +$(BUILD_DIR): + @if [ ! -d $(BUILD_DIR) ]; then \ + mkdir -p $(BUILD_DIR) && \ + cd $(BUILD_DIR) && \ + cmake ./..; \ + fi + +build: protos $(BUILD_DIR) + $(MAKE) --directory=$(BUILD_DIR) + +clean: protos-clean + rm -rf $(BUILD_DIR) + +docker: build + if [ "${SGX_MODE}" = "HW" ]; then \ + export HW_EXTENSION="-hw" ; \ + fi && \ + make -C ${FPC_PATH}/ecc DOCKER_IMAGE=${DOCKER_IMAGE_NAME}$${HW_EXTENSION} DOCKER_ENCLAVE_SO_PATH=${FPC_PATH}/samples/demos/irb/chaincode/${BUILD_DIR}/lib all docker + +PROTO_BUILD_DIR := _protos +PROTO_PATH := ../protos +PROTO_FILES := irb.proto + +.PHONY: protos +protos: $(PROTO_BUILD_DIR) + $(PROTOC_CMD) \ + --plugin=protoc-gen-nanopb=$(NANOPB_PATH)/generator/protoc-gen-nanopb-py2 \ + --proto_path=$(PROTO_PATH) "--nanopb_out=-f ${PROTO_PATH}/irb.options:$(PROTO_BUILD_DIR)" $(PROTO_FILES) + +$(PROTO_BUILD_DIR): + mkdir -p $@ + +.PHONY: protos-clean +protos-clean: + rm -rf $(PROTO_BUILD_DIR) diff --git a/samples/demos/irb/chaincode/chaincode.cpp b/samples/demos/irb/chaincode/chaincode.cpp new file mode 100644 index 000000000..9a51cae9e --- /dev/null +++ b/samples/demos/irb/chaincode/chaincode.cpp @@ -0,0 +1,247 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "chaincode.h" +#include +#include "errors.h" +#include "messages.h" + +Contract::ExperimentApprovalService::ExperimentApprovalService(shim_ctx_ptr_t ctx) : storage_(ctx) +{ + // set Study Approval Service verification key + + // set initial approver (investigator) + + // set Experimenter IDs +} + +CONTRACT_API_PROTOTYPE(Contract::ExperimentApprovalService::registerData) +{ + std::string uuid, dataHandler; + ByteArray pk, dk; + bool b; + Contract::EASMessage icm(inputString); + + // get relevant fields + b = icm.fromRegisterDataRequest(uuid, pk, dk, dataHandler); + FAST_FAIL_CHECK_EX(er, &icm.er_, EC_INVALID_INPUT, !b); + + LOG_DEBUG("Participant uuid: %s", uuid); + LOG_DEBUG("Participant pk: %s", std::string((char*)pk.data(), pk.size())); + LOG_DEBUG("Data handler: %s", dataHandler); + + // Store all fields on the ledger + storage_.ledgerPrivatePutString("user." + uuid + ".uuid", uuid); + storage_.ledgerPrivatePutString( + "user." + uuid + ".pk", std::string((char*)pk.data(), pk.size())); + storage_.ledgerPrivatePutString("user." + uuid + ".data.handler", dataHandler); + storage_.ledgerPrivatePutString( + "user." + uuid + ".data.dk", ByteArrayToBase64EncodedString(dk)); + + // Prepare status message + Contract::EASMessage ocm; + b = ocm.toStatus("", 1, outputString); + FAST_FAIL_CHECK_EX(er, &ocm.er_, EC_INVALID_INPUT, !b); + + er.set(EC_SUCCESS, ""); + return true; +} + +CONTRACT_API_PROTOTYPE(Contract::ExperimentApprovalService::registerStudy) +{ + Contract::Study study; + bool b; + Contract::EASMessage icm(inputString); + std::string storedStudy; + std::string returnString(""); + int status = 1; + + // get relevant fields + b = icm.fromStudyDetails(study); + FAST_FAIL_CHECK_EX(er, &icm.er_, EC_INVALID_INPUT, !b); + + LOG_DEBUG("Study id: %s", study.studyId_); + LOG_DEBUG("Metadata: %s", study.metadata_); + LOG_DEBUG("Users: %d", study.userIds_.size()); + + b = study.retrieve(storage_, storedStudy); + if (!b) + { + // TODO check study approval service signature (request.details.signature) + b = study.store(storage_, inputString); + FAST_FAIL_CHECK(er, EC_ERROR, !b); + } + else + { + // if study already exists abort + returnString = "Study already registered"; + status = 0; + } + + // prepare status message + Contract::EASMessage ocm; + b = ocm.toStatus(returnString, status, outputString); + FAST_FAIL_CHECK_EX(er, &ocm.er_, EC_INVALID_INPUT, !b); + + er.set(EC_SUCCESS, ""); + + return true; +} + +CONTRACT_API_PROTOTYPE(Contract::ExperimentApprovalService::newExperiment) +{ + Contract::Experiment experiment; + bool b; + Contract::EASMessage icm(inputString); + std::string storedExperiment; + std::string returnString(""); + int status = 1; + + // get relevant fields + b = icm.fromNewExperiment(experiment); + FAST_FAIL_CHECK_EX(er, &icm.er_, EC_INVALID_INPUT, !b); + + LOG_DEBUG("Experiment id: %s", experiment.experimentId_); + + // If not already registered, store experiment + b = experiment.retrieve(storage_, storedExperiment); + if (!b) + { + // TODO(optional) check experimenter identity + // TODO sanity check that experiment details are complete + // TODO check worker attestation (using workerPK, MRENCLAVE) + b = experiment.store(storage_, inputString); + FAST_FAIL_CHECK(er, EC_ERROR, !b); + } + else + { + // check that experiment does not exist already + returnString = "Experiment already registered"; + status = 0; + } + + // prepare status message + Contract::EASMessage ocm; + b = ocm.toStatus(returnString, status, outputString); + FAST_FAIL_CHECK_EX(er, &ocm.er_, EC_INVALID_INPUT, !b); + + er.set(EC_SUCCESS, ""); + return true; +} + +CONTRACT_API_PROTOTYPE(Contract::ExperimentApprovalService::getExperimentProposal) +{ + Contract::Experiment experiment; + bool b; + Contract::EASMessage icm(inputString); + std::string storedExperiment; + std::string returnString(""); + int status = 1; + + b = icm.fromGetExperimentRequest(experiment); + FAST_FAIL_CHECK_EX(er, &icm.er_, EC_INVALID_INPUT, !b); + + LOG_DEBUG("Request for experiment id: %s", experiment.experimentId_); + + // get experiment from state and return + b = experiment.retrieve(storage_, storedExperiment); + if (!b) + { + returnString = "Experiment not found"; + status = 0; + // prepare status message + Contract::EASMessage ocm; + b = ocm.toStatus(returnString, status, outputString); + FAST_FAIL_CHECK_EX(er, &ocm.er_, EC_INVALID_INPUT, !b); + } + else + { + // return the retrieve experiment (b64 experiment proposal) + outputString = storedExperiment; + } + + er.set(EC_SUCCESS, ""); + return true; +} + +CONTRACT_API_PROTOTYPE(Contract::ExperimentApprovalService::approveExperiment) +{ + Contract::SignedApproval signedApproval; + Contract::Experiment experiment; + bool b; + Contract::EASMessage icm(inputString); + std::string storedExperiment; + std::string returnString(""); + int status = 1; + + b = icm.fromSignedApproval(signedApproval); + FAST_FAIL_CHECK_EX(er, &icm.er_, EC_INVALID_INPUT, !b); + + LOG_DEBUG("Approval for experiment id: %s", signedApproval.experimentId_); + LOG_DEBUG( + "Approval decision: %s", signedApproval.approved_ ? "approved" : "rejected/undefined"); + + // check experiment exists for approval + experiment.experimentId_ = signedApproval.experimentId_; + b = experiment.retrieve(storage_, storedExperiment); + if (!b) + { + returnString = "Experiment not found"; + status = 0; + } + else + { + // if approval criteria reached; mark experiment as approved + b = signedApproval.store(storage_, inputString); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + } + + // prepare status message + Contract::EASMessage ocm; + b = ocm.toStatus(returnString, status, outputString); + FAST_FAIL_CHECK_EX(er, &ocm.er_, EC_INVALID_INPUT, !b); + + er.set(EC_SUCCESS, ""); + return true; +} + +CONTRACT_API_PROTOTYPE(Contract::ExperimentApprovalService::requestEvaluationPack) +{ + bool b; + Contract::EASMessage icm(inputString); + std::string storedExperiment; + Contract::Experiment experiment; + Contract::EvaluationPack evaluationPack; + std::string returnString(""); + int status = 1; + + b = icm.fromEvaluationPackRequest(evaluationPack); + FAST_FAIL_CHECK_EX(er, &icm.er_, EC_INVALID_INPUT, !b); + + LOG_DEBUG("Request for evaluation pack for experimend id: %s", evaluationPack.experimentId_); + + // check that study and experiment exist + experiment.experimentId_ = evaluationPack.experimentId_; + b = experiment.retrieve(storage_, storedExperiment); + if (!b) + { + returnString = "Experiment not found"; + status = 0; + // prepare status message + Contract::EASMessage ocm; + b = ocm.toStatus(returnString, status, outputString); + FAST_FAIL_CHECK_EX(er, &ocm.er_, EC_INVALID_INPUT, !b); + } + else + { + b = evaluationPack.build(storage_, outputString); + FAST_FAIL_CHECK_EX(er, &evaluationPack.er_, EC_ERROR, !b) + } + + er.set(EC_SUCCESS, ""); + return true; +} diff --git a/samples/demos/irb/chaincode/chaincode.h b/samples/demos/irb/chaincode/chaincode.h new file mode 100644 index 000000000..836c906de --- /dev/null +++ b/samples/demos/irb/chaincode/chaincode.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "errors.h" +#include "shim.h" +#include "storage.h" + +#define CONTRACT_API_PROTOTYPE(api_name) \ + bool api_name( \ + const std::string& inputString, std::string& outputString, Contract::ErrorReport& er) + +namespace Contract +{ +class ExperimentApprovalService +{ +private: + Contract::Storage storage_; + +public: + ExperimentApprovalService(shim_ctx_ptr_t ctx); + ErrorReport er_; + + CONTRACT_API_PROTOTYPE(registerData); + CONTRACT_API_PROTOTYPE(registerStudy); + CONTRACT_API_PROTOTYPE(newExperiment); + CONTRACT_API_PROTOTYPE(getExperimentProposal); + CONTRACT_API_PROTOTYPE(approveExperiment); + CONTRACT_API_PROTOTYPE(requestEvaluationPack); +}; +} // namespace Contract + +typedef CONTRACT_API_PROTOTYPE((Contract::ExperimentApprovalService::*contractFunctionP)); diff --git a/samples/demos/irb/chaincode/common.h b/samples/demos/irb/chaincode/common.h new file mode 100644 index 000000000..a332fee10 --- /dev/null +++ b/samples/demos/irb/chaincode/common.h @@ -0,0 +1,27 @@ +/* + * Copyright 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +//#define DO_DEBUG true + +#include +#include +#include +#include +#include +#include +#include "json/parson.h" +#include "logging.h" +#include "shim.h" + +// needed for types and Base64 conversion primitives +// TODO: see if this can be moved in shim +#include "../../../../common/crypto/pdo/common/types.h" + +// needed for crypto primitives +// TODO: see if this can be moved in shim +#include "../../../../common/crypto/pdo/common/crypto/crypto.h" diff --git a/samples/demos/irb/chaincode/dispatcher.cpp b/samples/demos/irb/chaincode/dispatcher.cpp new file mode 100644 index 000000000..a9a14a71a --- /dev/null +++ b/samples/demos/irb/chaincode/dispatcher.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "dispatcher.h" +#include +#include "chaincode.h" +#include "errors.h" + +Contract::Dispatcher::Dispatcher(const std::string& functionName, + const std::vector& functionParameters, + uint8_t* response, + const uint32_t max_response_len, + uint32_t* actual_response_len, + shim_ctx_ptr_t ctx) + : functionName_(functionName), + functionParameters_(functionParameters), + response_(response), + max_response_len_(max_response_len), + actual_response_len_(actual_response_len), + contract_(ctx) +{ + static std::map fMap_ = { + {"registerData", &Contract::ExperimentApprovalService::registerData}, + {"registerStudy", &Contract::ExperimentApprovalService::registerStudy}, + {"newExperiment", &Contract::ExperimentApprovalService::newExperiment}, + {"getExperimentProposal", &Contract::ExperimentApprovalService::getExperimentProposal}, + {"approveExperiment", &Contract::ExperimentApprovalService::approveExperiment}, + {"requestEvaluationPack", &Contract::ExperimentApprovalService::requestEvaluationPack}}; + + LOG_DEBUG("Try dispatch function %s with parameters %s", functionName_.c_str(), + functionParameters[0].c_str()); + + // Call function + auto fIter = fMap_.find(functionName_); + if (fIter == fMap_.end()) + { + // No such function + CUSTOM_ERROR_REPORT(errorReport_, EC_BAD_FUNCTION_NAME, "Chaincode function not found"); + } + else + { + LOG_DEBUG("Chaincode function found, call it"); + (contract_.*(fIter->second))(functionParameters[0], responseString_, errorReport_); + LOG_DEBUG("Response string: %s", responseString_.c_str()); + } + + // prepare response string + if (responseString_.length() == 0 || !errorReport_.isSuccess()) + { + // an error occurred: fill the response with the error/status message + errorReport_.toStatusProtoString(responseString_); + LOG_DEBUG("Error response string set: %s", responseString_.c_str()); + } + + if (responseString_.length() > max_response_len_) + { + LOG_ERROR("Response string too long to be output"); + CUSTOM_ERROR_REPORT( + errorReport_, EC_SHORT_RESPONSE_BUFFER, "Response string too long to be output"); + errorReport_.toStatusProtoString(responseString_); + } + + // write response string (if possible) + *actual_response_len_ = + (responseString_.length() > max_response_len_ ? 0 : responseString_.length()); + memcpy(response_, responseString_.c_str(), *actual_response_len_); + LOG_DEBUG("Response written (length %u)", *actual_response_len_); +} diff --git a/samples/demos/irb/chaincode/dispatcher.h b/samples/demos/irb/chaincode/dispatcher.h new file mode 100644 index 000000000..d4fd73993 --- /dev/null +++ b/samples/demos/irb/chaincode/dispatcher.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "chaincode.h" + +namespace Contract +{ +class Dispatcher +{ +private: + const std::string functionName_; + const std::vector functionParameters_; + uint8_t* response_; + const uint32_t max_response_len_; + uint32_t* actual_response_len_; + std::string responseString_; + + Contract::ExperimentApprovalService contract_; + +public: + Contract::ErrorReport errorReport_; + + Dispatcher(const std::string& functionName, + const std::vector& functionParameters, + uint8_t* response, + const uint32_t max_response_len, + uint32_t* actual_response_len, + shim_ctx_ptr_t ctx); +}; +} // namespace Contract diff --git a/samples/demos/irb/chaincode/entry.cpp b/samples/demos/irb/chaincode/entry.cpp new file mode 100644 index 000000000..21e901a4c --- /dev/null +++ b/samples/demos/irb/chaincode/entry.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "dispatcher.h" +#include "logging.h" +#include "shim.h" + +int invoke( + uint8_t* response, uint32_t max_response_len, uint32_t* actual_response_len, shim_ctx_ptr_t ctx) +{ + int ret = -1; + std::string functionName; + std::vector functionParameters; + + get_func_and_params(functionName, functionParameters, ctx); + + Contract::Dispatcher dispatcher( + functionName, functionParameters, response, max_response_len, actual_response_len, ctx); + if (!dispatcher.errorReport_.isSuccess()) + { + LOG_ERROR("Execution failed."); + ret = -1; + } + else + { + LOG_DEBUG("Execution successful"); + ret = 0; + } + + // double check that the response has been filled + if (*actual_response_len == 0) + { + LOG_ERROR("Response length is zero"); + ret = -1; + } + + return ret; +} diff --git a/samples/demos/irb/chaincode/errors.cpp b/samples/demos/irb/chaincode/errors.cpp new file mode 100644 index 000000000..ebafa5efb --- /dev/null +++ b/samples/demos/irb/chaincode/errors.cpp @@ -0,0 +1,34 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "errors.h" +#include +#include "messages.h" + +Contract::ErrorReport::ErrorReport() {} + +void Contract::ErrorReport::set(error_codes_e e, const std::string& s) +{ + ec_ = e; + errorString_ = s; +} + +void Contract::ErrorReport::toStatusProtoString(std::string& outputString) +{ +Contract: + EASMessage m; + m.toStatus(errorString_, ec_, outputString); +} + +bool Contract::ErrorReport::isSuccess() +{ + if (ec_ == EC_SUCCESS) + { + return true; + } + return false; +} diff --git a/samples/demos/irb/chaincode/errors.h b/samples/demos/irb/chaincode/errors.h new file mode 100644 index 000000000..aab92fbc8 --- /dev/null +++ b/samples/demos/irb/chaincode/errors.h @@ -0,0 +1,84 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +typedef enum +{ + EC_UNDEFINED, // 0 + EC_SUCCESS, // 1 + EC_ERROR, // 2 + EC_HIDDEN, // 3 + EC_BAD_FUNCTION_NAME, // 4 + EC_INVALID_INPUT, // 5 + EC_MEMORY_ERROR, // 6 + EC_SHORT_RESPONSE_BUFFER, // 7 + EC_BAD_PARAMETERS, // 8 +} error_codes_e; + +namespace Contract +{ +class ErrorReport +{ +private: + error_codes_e ec_; + std::string errorString_; + +public: + ErrorReport(); + + void toStatusProtoString(std::string& outputString); + void set(error_codes_e ec, const std::string& errorString); + bool isSuccess(); +}; +} // namespace Contract + +#define CUSTOM_ERROR_REPORT(er, code, message) er.set(code, std::string(#code) + ":" + message); + +#define DEFAULT_ERROR_REPORT(er, code) \ + er.set(code, std::string(#code) + ":" + std::string(__FILE__) + ":" + std::to_string(__LINE__)); + +#define FAST_FAIL_CHECK(errorReport, code, b) \ + { \ + if (b) \ + { \ + DEFAULT_ERROR_REPORT(errorReport, code) \ + return false; \ + } \ + } + +#define FAST_FAIL_CHECK_EX(parentErrorReport, pChildErrorReport, code, b) \ + { \ + if (b) \ + { \ + if (pChildErrorReport) \ + { \ + parentErrorReport = *pChildErrorReport; \ + } \ + else \ + { \ + DEFAULT_ERROR_REPORT(parentErrorReport, code) \ + } \ + return false; \ + } \ + } + +#define CATCH(b, expr) \ + do \ + { \ + try \ + { \ + expr; \ + b = true; \ + } \ + catch (...) \ + { \ + b = false; \ + } \ + } while (0); diff --git a/samples/demos/irb/chaincode/evaluationpack.cpp b/samples/demos/irb/chaincode/evaluationpack.cpp new file mode 100644 index 000000000..3ebfebb50 --- /dev/null +++ b/samples/demos/irb/chaincode/evaluationpack.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// TODO: This should go at compile time +#define PB_ENABLE_MALLOC + +#include "evaluationpack.h" +#include +#include +#include +#include "_protos/irb.pb.h" +#include "experiment.h" +#include "messages.h" +#include "study.h" + +bool Contract::EvaluationPack::build( + Contract::Storage& storage, std::string& encryptedEvaluationPackB64) +{ + Contract::Experiment experiment; + Contract::Study study; + std::string storedExperiment, storedStudy; + EvaluationPackMessage epm; + ByteArray evaluationPackMessageBytes; + ByteArray encryptedEvaluationPackMessageBytes; + ByteArray encryptedEvaluationPackBytes; + ByteArray encryptionKey; + ByteArray encryptedEncryptionKey; + EncryptedEvaluationPack eep; + bool b; + + // check that experiment exist + experiment.experimentId_ = experimentId_; + b = experiment.retrieve(storage, storedExperiment); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + { + Contract::EASMessage icm(storedExperiment); + b = icm.fromNewExperiment(experiment); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + } + + // check that study exist + study.studyId_ = experiment.studyId_; + b = study.retrieve(storage, storedStudy); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + { + Contract::EASMessage icm(storedStudy); + b = icm.fromStudyDetails(study); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + } + + // check if experiment is approved; otherwise abort + // TODO + + // create evaluation pack + // get all participant IDs from study + epm.registered_data_count = study.userIds_.size(); + epm.registered_data = (RegisterDataRequest*)pb_realloc( + NULL, epm.registered_data_count * sizeof(RegisterDataRequest)); + FAST_FAIL_CHECK(er_, EC_ERROR, epm.registered_data == NULL); + + // encode registered data fields (only the decryption key!!) + for (int i = 0; i < epm.registered_data_count; i++) + { + epm.registered_data[i] = RegisterDataRequest_init_zero; + + // retrieve decryption key + ByteArray decryptionKey; + std::string decryptionKeyB64; + storage.ledgerPrivateGetString( + "user." + study.userIds_[i].uuid_ + ".data.dk", decryptionKeyB64); + FAST_FAIL_CHECK(er_, EC_ERROR, decryptionKeyB64.empty()); + decryptionKey = Base64EncodedStringToByteArray(decryptionKeyB64); + + // encode key in proto struct + epm.registered_data[i].decryption_key = + (pb_bytes_array_t*)pb_realloc(NULL, PB_BYTES_ARRAY_T_ALLOCSIZE(decryptionKey.size())); + FAST_FAIL_CHECK(er_, EC_ERROR, epm.registered_data[i].decryption_key == NULL); + epm.registered_data[i].decryption_key->size = decryptionKey.size(); + memcpy(epm.registered_data[i].decryption_key->bytes, decryptionKey.data(), + decryptionKey.size()); + + // retrieve data handler + std::string dataHandler; + storage.ledgerPrivateGetString( + "user." + study.userIds_[i].uuid_ + ".data.handler", dataHandler); + FAST_FAIL_CHECK(er_, EC_ERROR, dataHandler.empty()); + + // encode data handler in proto struct + epm.registered_data[i].data_handler = (char*)pb_realloc(NULL, dataHandler.length() + 1); + FAST_FAIL_CHECK(er_, EC_ERROR, epm.registered_data[i].data_handler == NULL); + memcpy(epm.registered_data[i].data_handler, dataHandler.c_str(), dataHandler.length()); + epm.registered_data[i].data_handler[dataHandler.length()] = '\0'; + } + + { + // get encoding size + size_t estimated_size; + b = pb_get_encoded_size(&estimated_size, EvaluationPackMessage_fields, &epm); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + + // encode evaluation pack + evaluationPackMessageBytes.resize(estimated_size); + + pb_ostream_t ostream; + ostream = pb_ostream_from_buffer( + evaluationPackMessageBytes.data(), evaluationPackMessageBytes.size()); + b = pb_encode(&ostream, EvaluationPackMessage_fields, &epm); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + FAST_FAIL_CHECK(er_, EC_ERROR, evaluationPackMessageBytes.size() != ostream.bytes_written); + + pb_release(EvaluationPackMessage_fields, &epm); + } + + { + // encrypt evaluation pack + CATCH(b, encryptionKey = pdo::crypto::skenc::GenerateKey()); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + CATCH(b, encryptedEvaluationPackMessageBytes = + pdo::crypto::skenc::EncryptMessage(encryptionKey, evaluationPackMessageBytes)); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + + // encrypt encryption key with worker's public encryption key + pdo::crypto::pkenc::PublicKey pek; + CATCH(b, pek.Deserialize(std::string(experiment.workerId_.publicEncryptionKey_.data(), + experiment.workerId_.publicEncryptionKey_.data() + + experiment.workerId_.publicEncryptionKey_.size()))); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + CATCH(b, encryptedEncryptionKey = pek.EncryptMessage(encryptionKey)); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + } + + { + eep = EncryptedEvaluationPack_init_zero; + + // encode encrypted pack + eep.encrypted_evaluationpack = (pb_bytes_array_t*)pb_realloc( + NULL, PB_BYTES_ARRAY_T_ALLOCSIZE(encryptedEvaluationPackMessageBytes.size())); + FAST_FAIL_CHECK(er_, EC_ERROR, eep.encrypted_evaluationpack == NULL); + eep.encrypted_evaluationpack->size = encryptedEvaluationPackMessageBytes.size(); + memcpy(eep.encrypted_evaluationpack->bytes, encryptedEvaluationPackMessageBytes.data(), + encryptedEvaluationPackMessageBytes.size()); + + // encode encrypted key + eep.encrypted_encryption_key = (pb_bytes_array_t*)pb_realloc( + NULL, PB_BYTES_ARRAY_T_ALLOCSIZE(encryptedEncryptionKey.size())); + FAST_FAIL_CHECK(er_, EC_ERROR, eep.encrypted_encryption_key == NULL); + eep.encrypted_encryption_key->size = encryptedEncryptionKey.size(); + memcpy(eep.encrypted_encryption_key->bytes, encryptedEncryptionKey.data(), + encryptedEncryptionKey.size()); + + // get encoding size + size_t estimated_size; + b = pb_get_encoded_size(&estimated_size, EncryptedEvaluationPack_fields, &eep); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + + encryptedEvaluationPackBytes.resize(estimated_size); + + pb_ostream_t ostream; + ostream = pb_ostream_from_buffer( + encryptedEvaluationPackBytes.data(), encryptedEvaluationPackBytes.size()); + b = pb_encode(&ostream, EncryptedEvaluationPack_fields, &eep); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + FAST_FAIL_CHECK( + er_, EC_ERROR, encryptedEvaluationPackBytes.size() != ostream.bytes_written); + + pb_release(EncryptedEvaluationPack_fields, &eep); + } + + encryptedEvaluationPackB64 = ByteArrayToBase64EncodedString(encryptedEvaluationPackBytes); + + // return evaluation pack + return true; +} diff --git a/samples/demos/irb/chaincode/evaluationpack.h b/samples/demos/irb/chaincode/evaluationpack.h new file mode 100644 index 000000000..5b95d7fa1 --- /dev/null +++ b/samples/demos/irb/chaincode/evaluationpack.h @@ -0,0 +1,24 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "common.h" +#include "errors.h" +#include "id.h" +#include "storage.h" + +namespace Contract +{ +class EvaluationPack +{ +public: + std::string experimentId_; + ErrorReport er_; + + bool build(Contract::Storage& storage, std::string& encryptedEvaluationPackB64); +}; +} // namespace Contract diff --git a/samples/demos/irb/chaincode/experiment.cpp b/samples/demos/irb/chaincode/experiment.cpp new file mode 100644 index 000000000..4b0dd4584 --- /dev/null +++ b/samples/demos/irb/chaincode/experiment.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "experiment.h" + +Contract::Experiment::Experiment() {} + +Contract::Experiment::Experiment( + std::string studyId, std::string experimentId, Contract::Id& workerId) + : studyId_(studyId), experimentId_(experimentId), workerId_(workerId) +{ +} + +bool Contract::Experiment::store( + Contract::Storage& storage, const std::string& experimentProposalB64) +{ + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, experimentId_.empty()); + + std::string experimentKey("experiment." + experimentId_); + + storage.ledgerPrivatePutString(experimentKey, experimentProposalB64); + + return true; +} + +bool Contract::Experiment::retrieve(Contract::Storage& storage, std::string& experimentProposalB64) +{ + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, experimentId_.empty()); + + std::string experimentKey("experiment." + experimentId_); + experimentProposalB64.empty(); + storage.ledgerPrivateGetString(experimentKey, experimentProposalB64); + + if (experimentProposalB64.length() > 0) + { + return true; + } + return false; +} diff --git a/samples/demos/irb/chaincode/experiment.h b/samples/demos/irb/chaincode/experiment.h new file mode 100644 index 000000000..c6d7215fe --- /dev/null +++ b/samples/demos/irb/chaincode/experiment.h @@ -0,0 +1,30 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "common.h" +#include "errors.h" +#include "id.h" +#include "storage.h" + +namespace Contract +{ +class Experiment +{ +public: + std::string studyId_; + std::string experimentId_; + Id workerId_; + ErrorReport er_; + + Experiment(); + Experiment(std::string studyId, std::string experimentId, Contract::Id& workerId); + + bool store(Contract::Storage& storage, const std::string& experimentProposalB64); + bool retrieve(Contract::Storage& storage, std::string& experimentProposalB64); +}; +} // namespace Contract diff --git a/samples/demos/irb/chaincode/id.cpp b/samples/demos/irb/chaincode/id.cpp new file mode 100644 index 000000000..1ab834334 --- /dev/null +++ b/samples/demos/irb/chaincode/id.cpp @@ -0,0 +1,14 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "id.h" + +Contract::Id::Id() {} + +Contract::Id::Id(std::string& uuid, ByteArray& publicKey, ByteArray& publicEncryptionKey) + : uuid_(uuid), publicKey_(publicKey), publicEncryptionKey_(publicEncryptionKey) +{ +} diff --git a/samples/demos/irb/chaincode/id.h b/samples/demos/irb/chaincode/id.h new file mode 100644 index 000000000..bd7c3b0ab --- /dev/null +++ b/samples/demos/irb/chaincode/id.h @@ -0,0 +1,23 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "common.h" + +namespace Contract +{ +class Id +{ +public: + std::string uuid_; + ByteArray publicKey_; + ByteArray publicEncryptionKey_; + + Id(); + Id(std::string& uuid, ByteArray& publicKey, ByteArray& publicEncryptionKey); +}; +} // namespace Contract diff --git a/samples/demos/irb/chaincode/messages.cpp b/samples/demos/irb/chaincode/messages.cpp new file mode 100644 index 000000000..88f1656b4 --- /dev/null +++ b/samples/demos/irb/chaincode/messages.cpp @@ -0,0 +1,272 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// TODO: This should go at compile time +#define PB_ENABLE_MALLOC + +#include "messages.h" +#include /* for memcpy_s etc */ +#include +#include +#include +#include +#include "_protos/irb.pb.h" + +Contract::EASMessage::EASMessage() {} + +Contract::EASMessage::EASMessage(const std::string& message) : inputString_(message) +{ + // base64-decode every message at the beginning + inputMessageBytes_ = Base64EncodedStringToByteArray(inputString_); +} + +Contract::EASMessage::EASMessage(const ByteArray& messageBytes) : inputMessageBytes_(messageBytes) +{ +} + +ByteArray Contract::EASMessage::getInputMessageBytes() +{ + return inputMessageBytes_; +} + +bool Contract::EASMessage::toStatus(const std::string& message, int rc, std::string& outputMessage) +{ + Status status; + int ret; + bool b; + + if (message.empty()) + { + status.msg = NULL; + } + else + { + status.msg = (char*)pb_realloc(status.msg, message.length() + 1); + FAST_FAIL_CHECK(er_, EC_ERROR, status.msg == NULL); + ret = memcpy_s(status.msg, message.length(), message.c_str(), message.length()); + FAST_FAIL_CHECK(er_, EC_ERROR, ret != 0); + status.msg[message.length()] = '\0'; + } + + status.return_code = (Status_ReturnCode)rc; + + // encode in protobuf + pb_ostream_t ostream; + uint32_t response_len = 1024; + uint8_t response[response_len]; + ostream = pb_ostream_from_buffer(response, response_len); + b = pb_encode(&ostream, Status_fields, &status); + FAST_FAIL_CHECK(er_, EC_ERROR, !b); + + // once encoded on buffer, release dynamic fields + pb_release(Status_fields, &status); + + // base64-encode + outputMessage = + ByteArrayToBase64EncodedString(ByteArray(response, response + ostream.bytes_written)); + + return true; +} + +bool Contract::EASMessage::fromRegisterDataRequest( + std::string& uuid, ByteArray& publicKey, ByteArray& decryptionKey, std::string& dataHandler) +{ + pb_istream_t istream; + bool b; + RegisterDataRequest registerDataRequest; + + istream = pb_istream_from_buffer( + (const unsigned char*)inputMessageBytes_.data(), inputMessageBytes_.size()); + b = pb_decode(&istream, RegisterDataRequest_fields, ®isterDataRequest); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !registerDataRequest.has_participant); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, registerDataRequest.participant.uuid == NULL); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, registerDataRequest.data_handler == NULL); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, registerDataRequest.decryption_key == NULL); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, registerDataRequest.participant.public_key == NULL); + + uuid = std::string(registerDataRequest.participant.uuid); + dataHandler = std::string(registerDataRequest.data_handler); + + publicKey = ByteArray(registerDataRequest.participant.public_key->bytes, + registerDataRequest.participant.public_key->bytes + + registerDataRequest.participant.public_key->size); + + decryptionKey = ByteArray(registerDataRequest.decryption_key->bytes, + registerDataRequest.decryption_key->bytes + registerDataRequest.decryption_key->size); + + return true; +} + +void _fromIdentityToContractId(Identity& identity, Contract::Id& contractId) +{ + contractId.uuid_ = std::string((identity.uuid == NULL ? "" : identity.uuid)); + + if (identity.public_key != NULL) + { + contractId.publicKey_ = ByteArray( + identity.public_key->bytes, identity.public_key->bytes + identity.public_key->size); + } + + if (identity.public_encryption_key != NULL) + { + contractId.publicEncryptionKey_ = ByteArray(identity.public_encryption_key->bytes, + identity.public_encryption_key->bytes + identity.public_encryption_key->size); + } +} + +bool Contract::EASMessage::fromIdentity(Contract::Id& contractId) +{ + pb_istream_t istream; + bool b; + Identity identity; + + istream = pb_istream_from_buffer( + (const unsigned char*)inputMessageBytes_.data(), inputMessageBytes_.size()); + b = pb_decode(&istream, Identity_fields, &identity); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + + _fromIdentityToContractId(identity, contractId); + + return true; +} + +bool Contract::EASMessage::fromNewExperiment(Contract::Experiment& experiment) +{ + pb_istream_t istream; + bool b; + ExperimentProposal experimentProposal; + + istream = pb_istream_from_buffer( + (const unsigned char*)inputMessageBytes_.data(), inputMessageBytes_.size()); + b = pb_decode(&istream, ExperimentProposal_fields, &experimentProposal); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, experimentProposal.study_id == NULL); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, experimentProposal.experiment_id == NULL); + FAST_FAIL_CHECK( + er_, EC_INVALID_INPUT, experimentProposal.worker_credentials.identity_bytes == NULL); + + experiment.studyId_ = std::string(experimentProposal.study_id); + experiment.experimentId_ = std::string(experimentProposal.experiment_id); + + ByteArray identityBytes(experimentProposal.worker_credentials.identity_bytes->bytes, + experimentProposal.worker_credentials.identity_bytes->bytes + + experimentProposal.worker_credentials.identity_bytes->size); + Contract::EASMessage m(identityBytes); + b = m.fromIdentity(experiment.workerId_); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + + return true; +} + +bool Contract::EASMessage::fromGetExperimentRequest(Contract::Experiment& experiment) +{ + pb_istream_t istream; + bool b; + GetExperimentRequest getExperimentRequest; + + istream = pb_istream_from_buffer( + (const unsigned char*)inputMessageBytes_.data(), inputMessageBytes_.size()); + b = pb_decode(&istream, GetExperimentRequest_fields, &getExperimentRequest); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, getExperimentRequest.experiment_id == NULL); + + experiment.experimentId_ = std::string(getExperimentRequest.experiment_id); + return true; +} + +bool Contract::EASMessage::fromStudyDetails(Contract::Study& study) +{ + pb_istream_t istream; + bool b; + StudyDetailsMessage studyDetailsMessage; + + istream = pb_istream_from_buffer( + (const unsigned char*)inputMessageBytes_.data(), inputMessageBytes_.size()); + b = pb_decode(&istream, StudyDetailsMessage_fields, &studyDetailsMessage); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, studyDetailsMessage.study_id == NULL); + + study.studyId_ = std::string(studyDetailsMessage.study_id); + study.metadata_ = + std::string(studyDetailsMessage.metadata == NULL ? "" : studyDetailsMessage.metadata); + + for (int i = 0; i < studyDetailsMessage.user_identities_count; i++) + { + Contract::Id id; + _fromIdentityToContractId(studyDetailsMessage.user_identities[i], id); + study.userIds_.push_back(id); + } + + return true; +} + +bool Contract::EASMessage::fromSignedApproval(Contract::SignedApproval& signedApproval) +{ + pb_istream_t istream; + bool b; + SignedApprovalMessage sa; + + istream = pb_istream_from_buffer( + (const unsigned char*)inputMessageBytes_.data(), inputMessageBytes_.size()); + b = pb_decode(&istream, SignedApprovalMessage_fields, &sa); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, sa.approval == NULL); + + // get the approval bytes + signedApproval.approvalBytes_ = + ByteArray(sa.approval->bytes, sa.approval->bytes + sa.approval->size); + // get signature (if any) + if (sa.signature != NULL) + { + signedApproval.signature_ = + ByteArray(sa.signature->bytes, sa.signature->bytes + sa.signature->size); + } + + { + // unmashal approval + pb_istream_t istream; + Approval a; + + istream = pb_istream_from_buffer( + signedApproval.approvalBytes_.data(), signedApproval.approvalBytes_.size()); + b = pb_decode(&istream, Approval_fields, &a); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, a.experiment_id == NULL); + + signedApproval.experimentId_ = std::string(a.experiment_id); + + if (a.decision == Approval_Decision_APPROVED) + { + // approved == false, means rejected or undefined + signedApproval.approved_ = true; + } + + if (a.has_approver) + { + _fromIdentityToContractId(a.approver, signedApproval.approverId_); + } + } + + return true; +} + +bool Contract::EASMessage::fromEvaluationPackRequest(Contract::EvaluationPack& evaluationPack) +{ + pb_istream_t istream; + bool b; + EvaluationPackRequest evaluationPackRequest; + + istream = pb_istream_from_buffer( + (const unsigned char*)inputMessageBytes_.data(), inputMessageBytes_.size()); + b = pb_decode(&istream, EvaluationPackRequest_fields, &evaluationPackRequest); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, !b); + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, evaluationPackRequest.experiment_id == NULL); + + evaluationPack.experimentId_ = std::string(evaluationPackRequest.experiment_id); + return true; +} diff --git a/samples/demos/irb/chaincode/messages.h b/samples/demos/irb/chaincode/messages.h new file mode 100644 index 000000000..2ada6d9ba --- /dev/null +++ b/samples/demos/irb/chaincode/messages.h @@ -0,0 +1,49 @@ +/* + * Copyright 2019 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "common.h" +#include "errors.h" +#include "evaluationpack.h" +#include "experiment.h" +#include "id.h" +#include "signedapproval.h" +#include "study.h" + +namespace Contract +{ +class EASMessage +{ +private: + const std::string inputString_; + ByteArray inputMessageBytes_; + +public: + ErrorReport er_; + + EASMessage(); + EASMessage(const std::string& message); + EASMessage(const ByteArray& messageBytes); + ErrorReport getErrorReport(); + ByteArray getInputMessageBytes(); + + bool toStatus(const std::string& message, int rc, std::string& outputMessage); + + bool fromIdentity(Contract::Id& contractId); + bool fromRegisterDataRequest(std::string& uuid, + ByteArray& publicKey, + ByteArray& decryptionKey, + std::string& dataHandler); + bool fromNewExperiment(Contract::Experiment& experiment); + bool fromGetExperimentRequest(Contract::Experiment& experiment); + bool fromStudyDetails(Contract::Study& study); + bool fromSignedApproval(Contract::SignedApproval& signedApproval); + bool fromEvaluationPackRequest(Contract::EvaluationPack& evaluationPack); +}; +} // namespace Contract diff --git a/samples/demos/irb/chaincode/signedapproval.cpp b/samples/demos/irb/chaincode/signedapproval.cpp new file mode 100644 index 000000000..f6824d7e3 --- /dev/null +++ b/samples/demos/irb/chaincode/signedapproval.cpp @@ -0,0 +1,34 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "signedapproval.h" + +bool Contract::SignedApproval::store( + Contract::Storage& storage, const std::string& signedApprovalB64) +{ + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, experimentId_.empty()); + + std::string approvalKey("approval." + experimentId_); + + storage.ledgerPrivatePutString(approvalKey, signedApprovalB64); + + return true; +} + +bool Contract::SignedApproval::retrieve(Contract::Storage& storage, std::string& signedApprovalB64) +{ + FAST_FAIL_CHECK(er_, EC_INVALID_INPUT, experimentId_.empty()); + + std::string approvalKey("approval." + experimentId_); + signedApprovalB64.empty(); + storage.ledgerPrivateGetString(approvalKey, signedApprovalB64); + + if (signedApprovalB64.length() > 0) + { + return true; + } + return false; +} diff --git a/samples/demos/irb/chaincode/signedapproval.h b/samples/demos/irb/chaincode/signedapproval.h new file mode 100644 index 000000000..f62be1e14 --- /dev/null +++ b/samples/demos/irb/chaincode/signedapproval.h @@ -0,0 +1,29 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "common.h" +#include "errors.h" +#include "id.h" +#include "storage.h" + +namespace Contract +{ +class SignedApproval +{ +public: + std::string experimentId_; + bool approved_; + Id approverId_; + ByteArray approvalBytes_; + ByteArray signature_; + ErrorReport er_; + + bool store(Contract::Storage& storage, const std::string& signedApprovalB64); + bool retrieve(Contract::Storage& storage, std::string& signedApprovalB64); +}; +} // namespace Contract diff --git a/samples/demos/irb/chaincode/storage.cpp b/samples/demos/irb/chaincode/storage.cpp new file mode 100644 index 000000000..b502549bd --- /dev/null +++ b/samples/demos/irb/chaincode/storage.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "storage.h" +#include "common.h" + +#define MAX_LENGTH_STRING_SIZE 10 // order of gigabytes + +Contract::Storage::Storage(shim_ctx_ptr_t ctx) : ctx_(ctx) {} + +void Contract::Storage::ledgerPrivatePutString(const std::string& key, const std::string& value) +{ + // first write length -- string with null char + unsigned int valueLength = value.length() + 1; + std::string valueLengthString = std::to_string(valueLength); + if (valueLengthString.length() == 0 || valueLengthString.length() > MAX_LENGTH_STRING_SIZE) + { + LOG_ERROR("value length is 0 or too large. No data will be written to ledger"); + return; + } + std::string valueLengthKey = key + "L"; + ledgerPrivatePutBinary((const uint8_t*)valueLengthKey.c_str(), valueLengthKey.length(), + (const uint8_t*)valueLengthString.c_str(), valueLengthString.length() + 1); + + // second, write actual value + std::string valueKey = key + "K"; + ledgerPrivatePutBinary( + (uint8_t*)valueKey.c_str(), valueKey.length(), (const uint8_t*)value.c_str(), valueLength); +} + +void Contract::Storage::ledgerPrivateGetString(const std::string& key, std::string& value) +{ + // first, get the value length + uint8_t valueLengthArray[MAX_LENGTH_STRING_SIZE + 1]; + uint32_t actualValueLengthLength = 0; + std::string valueLengthKey = key + "L"; + ledgerPrivateGetBinary((uint8_t*)valueLengthKey.c_str(), valueLengthKey.length(), + valueLengthArray, MAX_LENGTH_STRING_SIZE + 1, &actualValueLengthLength); + if (actualValueLengthLength == 0) + { + LOG_DEBUG("Key not found -- length not stored"); + return; + } + if (actualValueLengthLength > MAX_LENGTH_STRING_SIZE) + { + LOG_ERROR("Value length returned is too large"); + return; + } + if (valueLengthArray[actualValueLengthLength - 1] != '\0') + { + LOG_ERROR("Value length returned is not null terminated"); + return; + } + uint32_t storedValueLength = std::stoul(std::string((char*)valueLengthArray), NULL, 10); + + // second, get the value + std::string valueKey = key + "K"; + uint8_t valueBinary[storedValueLength]; + uint32_t actualValueLength = 0; + ledgerPrivateGetBinary((uint8_t*)valueKey.c_str(), valueKey.length(), valueBinary, + storedValueLength, &actualValueLength); + if (actualValueLength != storedValueLength) + { + LOG_ERROR("Unexpected length of retrieved value -- no value returned"); + return; + } + if (valueBinary[storedValueLength - 1] != '\0') + { + LOG_ERROR("Retrieved value is not null terminated -- no value returned"); + return; + } + value.assign((char*)valueBinary); +} + +void Contract::Storage::ledgerPublicPutString(const std::string& key, const std::string& value) +{ + // first write length -- string with null char + unsigned int valueLength = value.length() + 1; + std::string valueLengthString = std::to_string(valueLength); + if (valueLengthString.length() == 0 || valueLengthString.length() > MAX_LENGTH_STRING_SIZE) + { + LOG_ERROR("value length is 0 or too large. No data will be written to ledger"); + return; + } + std::string valueLengthKey = key + "L"; + ledgerPublicPutBinary((const uint8_t*)valueLengthKey.c_str(), valueLengthKey.length(), + (const uint8_t*)valueLengthString.c_str(), valueLengthString.length() + 1); + + // second, write actual value + std::string valueKey = key + "K"; + ledgerPublicPutBinary( + (uint8_t*)valueKey.c_str(), valueKey.length(), (const uint8_t*)value.c_str(), valueLength); +} + +void Contract::Storage::ledgerPublicPutBinary( + const uint8_t* key, const uint32_t keyLength, const uint8_t* value, const uint32_t valueLength) +{ + put_public_state((const char*)key, (uint8_t*)value, valueLength, ctx_); +} + +void Contract::Storage::ledgerPrivatePutBinary( + const uint8_t* key, const uint32_t keyLength, const uint8_t* value, const uint32_t valueLength) +{ + put_state((const char*)key, (uint8_t*)value, valueLength, ctx_); +} + +void Contract::Storage::ledgerPrivateGetBinary(const uint8_t* key, + const uint32_t keyLength, + uint8_t* value, + const uint32_t valueLength, + uint32_t* actualValueLength) +{ + get_state((const char*)key, value, valueLength, actualValueLength, ctx_); +} diff --git a/samples/demos/irb/chaincode/storage.h b/samples/demos/irb/chaincode/storage.h new file mode 100644 index 000000000..804ec454a --- /dev/null +++ b/samples/demos/irb/chaincode/storage.h @@ -0,0 +1,40 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "common.h" + +namespace Contract +{ +class Storage +{ +private: + shim_ctx_ptr_t ctx_; + +public: + Storage(shim_ctx_ptr_t ctx); + void ledgerPrivatePutString(const std::string& key, const std::string& value); + void ledgerPrivateGetString(const std::string& key, std::string& value); + + void ledgerPublicPutString(const std::string& key, const std::string& value); + + void ledgerPublicPutBinary(const uint8_t* key, + const uint32_t keyLength, + const uint8_t* value, + const uint32_t valueLength); + + void ledgerPrivatePutBinary(const uint8_t* key, + const uint32_t keyLength, + const uint8_t* value, + const uint32_t valueLength); + void ledgerPrivateGetBinary(const uint8_t* key, + const uint32_t keyLength, + uint8_t* value, + const uint32_t valueLength, + uint32_t* actualValueLength); +}; +} // namespace Contract diff --git a/samples/demos/irb/chaincode/study.cpp b/samples/demos/irb/chaincode/study.cpp new file mode 100644 index 000000000..6438f0f83 --- /dev/null +++ b/samples/demos/irb/chaincode/study.cpp @@ -0,0 +1,33 @@ +/* + * Copyright 2021 Intel Corporation + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "study.h" +#include "storage.h" + +bool Contract::Study::store(Contract::Storage& storage, const std::string& studyDetailsB64) +{ + FAST_FAIL_CHECK(er_, EC_ERROR, studyId_.empty()); + std::string studyKey("study." + studyId_); + + storage.ledgerPrivatePutString(studyKey, studyDetailsB64); + + return true; +} + +bool Contract::Study::retrieve(Contract::Storage& storage, std::string& studyDetailsB64) +{ + FAST_FAIL_CHECK(er_, EC_ERROR, studyId_.empty()); + std::string studyKey("study." + studyId_); + studyDetailsB64.empty(); + storage.ledgerPrivateGetString(studyKey, studyDetailsB64); + + if (studyDetailsB64.length() > 0) + { + return true; + } + return false; +} diff --git a/samples/demos/irb/chaincode/study.h b/samples/demos/irb/chaincode/study.h new file mode 100644 index 000000000..35566f12f --- /dev/null +++ b/samples/demos/irb/chaincode/study.h @@ -0,0 +1,27 @@ +/* + * Copyright 2021 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "common.h" +#include "errors.h" +#include "id.h" +#include "storage.h" + +namespace Contract +{ +class Study +{ +public: + std::string studyId_; + std::string metadata_; + std::vector userIds_; + ErrorReport er_; + + bool store(Contract::Storage& storage, const std::string& studyDetailsB64); + bool retrieve(Contract::Storage& storage, std::string& studyDetailsB64); +}; +} // namespace Contract diff --git a/samples/demos/irb/experimenter/Dockerfile b/samples/demos/irb/experimenter/Dockerfile new file mode 100644 index 000000000..20f446fc2 --- /dev/null +++ b/samples/demos/irb/experimenter/Dockerfile @@ -0,0 +1,43 @@ +# Copyright IBM Corp. All Rights Reserved. +# Copyright 2020 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +FROM python:3.8 + +# set the working directory in the container +WORKDIR /irb/experimenter/worker + +RUN apt-get update -q \ + && apt-get install -y -q \ + libnss-mdns \ + libnss-myhostname \ + lsb-release \ + swig + +RUN pip install torch==1.8.1+cpu torchvision==0.9.1+cpu torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html +RUN pip install pillow twisted +RUN pip install redis +RUN pip install protobuf +RUN pip install tensorflow +RUN pip install matplotlib +RUN pip install cryptography + +## copy pdo crypto patch +#COPY experimenter/pdo_python_setup.py.patch /tmp +# +#RUN cd /tmp \ +# && git clone https://github.com/hyperledger-labs/private-data-objects.git \ +# && cd private-data-objects/python \ +# && git apply /tmp/pdo_python_setup.py.patch \ +# && python3.8 setup.py build_ext + +# copy experimenter code +COPY experimenter/worker /irb/experimenter/worker +COPY pkg /irb/pkg +COPY protos /irb/protos + +# expose server port +EXPOSE 5000 + +CMD ["sh", "-c", "PYTHONPATH=../../ python3 workerCLI.py"] \ No newline at end of file diff --git a/samples/demos/irb/experimenter/Makefile b/samples/demos/irb/experimenter/Makefile new file mode 100644 index 000000000..2e21efdb8 --- /dev/null +++ b/samples/demos/irb/experimenter/Makefile @@ -0,0 +1,17 @@ +# Copyright 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +TOP = ../../../.. +include $(TOP)/build.mk + +all: docker + +docker: + DOCKER_BUILDKIT=0 docker build -f Dockerfile -t irb-experimenter-worker .. + +run: docker + $(MAKE) -C worker stop-docker run-docker + +test: + $(GO) test -v ./... diff --git a/samples/demos/irb/experimenter/test/worker_test.go b/samples/demos/irb/experimenter/test/worker_test.go new file mode 100644 index 000000000..75ec18df8 --- /dev/null +++ b/samples/demos/irb/experimenter/test/worker_test.go @@ -0,0 +1,217 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package test + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "testing" + "time" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/container" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/crypto" + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/storage" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/utils" + "github.com/pkg/errors" +) + +func requestAttestation() ([]byte, error) { + + resp, err := http.Get("http://localhost:5000/attestation") + if err != nil { + return nil, err + } + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + fmt.Printf("got: %s\n", bodyBytes) + + workerCredential := &pb.WorkerCredentials{} + err = proto.Unmarshal(bodyBytes, workerCredential) + if err != nil { + return nil, err + } + + fmt.Printf("got %s\n", workerCredential) + + identity := &pb.Identity{} + err = proto.Unmarshal(workerCredential.GetIdentityBytes(), identity) + if err != nil { + return nil, err + } + + fmt.Printf("got id: %s\n", identity.GetPublicEncryptionKey()) + + return identity.GetPublicEncryptionKey(), nil +} + +func submitEvaluationPack(pk []byte, req *pb.RegisterDataRequest) error { + + epm := &pb.EvaluationPackMessage{} + epm.RegisteredData = []*pb.RegisterDataRequest{req} + + epmBytes, err := proto.Marshal(epm) + if err != nil { + return err + } + + c := crypto.NewGoCrypto() + + k, err := c.NewSymmetricKey() + if err != nil { + return err + } + + encryptedKey, err := c.PkEncryptMessage(pk, k) + if err != nil { + return err + } + + encryptedEvaluationPack, err := c.EncryptMessage(k, epmBytes) + if err != nil { + return err + } + + evalPack := &pb.EncryptedEvaluationPack{} + evalPack.EncryptedEncryptionKey = encryptedKey + evalPack.EncryptedEvaluationpack = encryptedEvaluationPack + + evalPackBytes, err := proto.Marshal(evalPack) + if err != nil { + return err + } + + resp, err := http.Post("http://localhost:5000/execute-evaluationpack", "", bytes.NewBuffer(evalPackBytes)) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + fmt.Printf("Result: %s\n", bodyBytes) + + return nil +} + +func upload() (*pb.RegisterDataRequest, error) { + cp := crypto.NewGoCrypto() + sk, err := cp.NewSymmetricKey() + if err != nil { + return nil, errors.Wrap(err, "cannot create new symmetric key") + } + + data := []byte("37.7, 0, 0, 1, 1, 0") + + encryptedData, err := cp.EncryptMessage(sk, data) + if err != nil { + return nil, errors.Wrap(err, "cannot encrypt message") + } + + // upload encrypted data + kvs := storage.NewClient() + handle, err := kvs.Upload(encryptedData) + if err != nil { + return nil, errors.Wrap(err, "cannot upload data to kvs") + } + + userIdentity := pb.Identity{ + Uuid: "somePatient", + PublicKey: []byte("some verification key"), + } + + //build request + registerDataRequest := &pb.RegisterDataRequest{ + Participant: &userIdentity, + DecryptionKey: sk, + DataHandler: handle, + StudyId: "some study", + } + + return registerDataRequest, nil +} + +const networkID = "mytestnetwork" + +func TestWorker(t *testing.T) { + + network := &container.Network{Name: networkID} + err := network.Create() + defer network.Remove() + if err != nil { + panic(err) + } + + // setup redis + redis := &container.Container{ + Image: "redis", + Name: "redis-container", + HostIP: "localhost", + HostPort: "6379", + Network: networkID, + } + err = redis.Start() + defer redis.Stop() + if err != nil { + panic(err) + } + + // setup experiment container + experiment := &container.Container{ + Image: "irb-experimenter-worker", + Name: "experiment-container", + HostIP: "localhost", + HostPort: "5000", + Env: []string{"REDIS_HOST=redis-container"}, + Network: networkID, + } + err = experiment.Start() + defer experiment.Stop() + if err != nil { + panic(err) + } + + // let's wait until experiment service is up an running + err = utils.Retry(func() bool { + resp, err := http.Get("http://localhost:5000/info") + if err != nil { + return false + } + return resp.StatusCode == 200 + }, 5, 60*time.Second, 2*time.Second) + if err != nil { + panic(err) + } + + req, err := upload() + if err != nil { + panic(err) + } + + fmt.Println("Testing attestation...") + pk, err := requestAttestation() + if err != nil { + panic(err) + } + + fmt.Println("Testing evaluation pack...") + if err := submitEvaluationPack(pk, req); err != nil { + panic(err) + } + + fmt.Println("Test done.") +} diff --git a/samples/demos/irb/experimenter/worker/.gitignore b/samples/demos/irb/experimenter/worker/.gitignore new file mode 100644 index 000000000..b0dae83b6 --- /dev/null +++ b/samples/demos/irb/experimenter/worker/.gitignore @@ -0,0 +1,5 @@ +results.txt +pdo +*.pid +diagnosis* +diagnoss* diff --git a/samples/demos/irb/experimenter/worker/ACKNOWLEDGEMENTS b/samples/demos/irb/experimenter/worker/ACKNOWLEDGEMENTS new file mode 100644 index 000000000..28b06438a --- /dev/null +++ b/samples/demos/irb/experimenter/worker/ACKNOWLEDGEMENTS @@ -0,0 +1,13 @@ +https://archive.ics.uci.edu/ml/citation_policy.html + +Dua, D. and Graff, C. (2019). UCI Machine Learning Repository [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California, School of Information and Computer Science. + +- + +https://archive.ics.uci.edu/ml/datasets/Acute+Inflammations + +J.Czerniak, H.Zarzycki, Application of rough sets in the presumptive diagnosis of urinary system diseases, +Artifical Inteligence and Security in Computing Systems, ACS'2002 9th International Conference Proceedings, +Kluwer Academic Publishers,2003, pp. 41-51 + + diff --git a/samples/demos/irb/experimenter/worker/Makefile b/samples/demos/irb/experimenter/worker/Makefile new file mode 100644 index 000000000..e1f0b8256 --- /dev/null +++ b/samples/demos/irb/experimenter/worker/Makefile @@ -0,0 +1,49 @@ +# Copyright 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +PID_FILE=.worker.pid + +PID="$(shell cat ${PID_FILE} 2> /dev/null)" + +WORKER_DOCKER_IMAGE="irb-experimenter-worker" + +REDIS_HOST ?= "localhost" +REDIS_PORT ?= "6379" + +run: + @if [ -z ${PID} ]; then \ + PYTHONPATH=../../ python3 workerCLI.py & echo -n "$$!" > ${PID_FILE} ;\ + fi + +stop: + @if [ ! -z ${PID} ]; then \ + wget --quiet --spider localhost:5000/shutdown -O /dev/null ;\ + rm -rf ${PID_FILE} ;\ + fi + +RUNNING_CONTAINER="$(shell docker ps -a --filter name=${WORKER_DOCKER_IMAGE} --quiet)" + +run-docker: + @if [ -z "${RUNNING_CONTAINER}" ]; then \ + docker run --name ${WORKER_DOCKER_IMAGE} \ + --env REDIS_HOST=${REDIS_HOST} --env REDIS_PORT=${REDIS_PORT} \ + --network host \ + -d ${WORKER_DOCKER_IMAGE}; \ + fi + +mac-run-docker: + @if [ -z "${RUNNING_CONTAINER}" ]; then \ + docker run --name ${WORKER_DOCKER_IMAGE} \ + --env REDIS_HOST=${REDIS_HOST} --env REDIS_PORT=${REDIS_PORT} \ + -p 5000:5000 \ + -d ${WORKER_DOCKER_IMAGE}; \ + fi + +.PHONY: stop +stop-docker: + @if [ ! -z "${RUNNING_CONTAINER}" ]; then \ + docker stop ${WORKER_DOCKER_IMAGE} ; \ + docker rm ${WORKER_DOCKER_IMAGE} ; \ + fi + diff --git a/samples/demos/irb/experimenter/worker/attestation.py b/samples/demos/irb/experimenter/worker/attestation.py new file mode 100644 index 000000000..91e73a1e4 --- /dev/null +++ b/samples/demos/irb/experimenter/worker/attestation.py @@ -0,0 +1,21 @@ +# Copyright 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +import os +import json +import base64 + +def GetAttestation(): + sgx_mode = os.environ.get("SGX_MODE", "SIM") + + print("Get attestation in SGX {0} mode".format(sgx_mode)) + + if sgx_mode == "SIM": + attestation = dict() + attestation['attestation_type'] = "simulated" + attestation['attestation'] = base64.b64encode(b"0").decode() + return json.dumps(attestation, separators=(',', ':')) + + if sgx_mode == "HW": + return str("TODO: get Graphene attestation") diff --git a/samples/demos/irb/experimenter/worker/diagnose.py b/samples/demos/irb/experimenter/worker/diagnose.py new file mode 100644 index 000000000..f9c9237df --- /dev/null +++ b/samples/demos/irb/experimenter/worker/diagnose.py @@ -0,0 +1,35 @@ +# Copyright 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +from torchvision import models +import torch +from torch.autograd import Variable +import torch.nn as nn +from train_model import LogisticRegression + +# This function performs one diagnosis and returns a result string and an error string (Go style) +def diagnose(data_bytes): + data_string = data_bytes.decode() + data_items = data_string.split(',') + if len(data_items) != 6: + return "", "wrong number of parameters: " + str(len(data_items)) + + data_items[0] = float(data_items[0]) + data_items[1] = int(data_items[1]) + data_items[2] = int(data_items[2]) + data_items[3] = int(data_items[3]) + data_items[4] = int(data_items[4]) + data_items[5] = int(data_items[5]) + + data_list = [data_items] + + model = LogisticRegression() + model.load_state_dict(torch.load("diagnoss2.pt")) + model.eval() + + input = Variable(torch.tensor(data_list, dtype = torch.float32)) + prediction = model(input).data.numpy()[:, 0] + + return "Decision: " + str(round(prediction[0] * 100, 5)) + "% of having Nephritis of renal pelvis origin", "" + diff --git a/samples/demos/irb/experimenter/worker/keys.py b/samples/demos/irb/experimenter/worker/keys.py new file mode 100644 index 000000000..3a21bb7c0 --- /dev/null +++ b/samples/demos/irb/experimenter/worker/keys.py @@ -0,0 +1,77 @@ +from cryptography.fernet import Fernet +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.ciphers.aead import AESGCM +import logging + +logger = logging.getLogger() + +def InitializeKeys(): + global signing_key + global verifying_key + + global decryption_key + global encryption_key + + try: + signing_key = ec.generate_private_key(ec.SECP256R1()) + verifying_key = signing_key.public_key() + except Exception: + logger.error("error creating signing keys") + return False + + try: + decryption_key = rsa.generate_private_key(public_exponent=65537,key_size=3072) + encryption_key = decryption_key.public_key() + except Exception: + logger.error("error creating encryption keys") + return False + + logger.info("Created keys:") + logger.info("Verifying key: {0}".format(GetSerializedVerifyingKey())) + logger.info("Encryption key: {0}".format(GetSerializedEncryptionKey())) + + return True + +def GetSerializedVerifyingKey(): + return verifying_key.public_bytes(encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) + +def GetSerializedEncryptionKey(): + return encryption_key.public_bytes(encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.PKCS1) + +#This function decrypts the message with the private decryption key and returns m, err (Go style) +def PkDecrypt(encryptedMessageBytes): + try: + m = decryption_key.decrypt( + encryptedMessageBytes, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + algorithm=hashes.SHA1(), + label=None + )) + + except Exception as e: + return None, str(e) + + return m, None + +#This function decrypts the message with the symmetric key "key", and returns m, err (Go style) +def Decrypt(key, encryptedMessageBytes): + NonceLength = 12 + TagLength = 16 + + nonce = encryptedMessageBytes[:NonceLength] + tag = encryptedMessageBytes[NonceLength : NonceLength+TagLength] + ciphertext = encryptedMessageBytes[NonceLength+TagLength:] + + try: + aesgcm = AESGCM(key) + m = aesgcm.decrypt(nonce, ciphertext + tag, None) + except Exception as e: + return None, str(e) + + return m, None + diff --git a/samples/demos/irb/experimenter/worker/server.py b/samples/demos/irb/experimenter/worker/server.py new file mode 100644 index 000000000..0b3c1e4e8 --- /dev/null +++ b/samples/demos/irb/experimenter/worker/server.py @@ -0,0 +1,95 @@ +# Copyright 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +import sys +import signal +from twisted.web import server, resource, http +from twisted.internet import reactor, defer + +import attestation +import server_api +import diagnose + +class WorkerServer(resource.Resource): + isLeaf = True + + def render_GET(self, request): + print('GET REQUEST: %s' % (request.uri).decode("ascii")) + if request.uri == b'/info': + request.setHeader(b"content-type", b"text/plain") + request.setResponseCode(http.OK) + return "I'm up and running ..".encode("ascii") + + if request.uri == b'/attestation': + return server_api.HandleAttestation() + + if request.uri == b'/shutdown': + __shutdown__() + return request.uri + + if request.uri == b'/test-diagnose': + data = b'37.7, 0, 0, 1, 1, 0' + try: + result = diagnose.diagnose(data) + except Exception as e: + return str(e).encode("ascii") + + if result[0] == "": + return result[1].encode("ascii") + else: + return result[0].encode("ascii") + + + return ("Unsupported: " + (request.uri).decode("ascii")).encode("ascii") + + def render_POST(self, request): + print('POST REQUEST: %s' % (request.uri).decode("ascii")) + + if request.uri == b'/execute-evaluationpack': + try: + #data should contain the encrypted evaluation pack protobuf + data = request.content.read() + result = server_api.HandleExecuteEvaluationPack(data) + return result.encode("ascii") + + except Exception as e: + request.setResponseCode(400) + return ("Error: " + str(e)).encode("ascii") + + return ("Unsupported: " + (request.uri).decode("ascii")).encode("ascii") + + +def __shutdown__(*args) : + print("Shutdown request received") + reactor.callLater(1, reactor.stop) + + +def RunWorkerServer(): + + signal.signal(signal.SIGQUIT, __shutdown__) + signal.signal(signal.SIGTERM, __shutdown__) + + root = WorkerServer() + site = server.Site(root) + reactor.listenTCP(5000, site, interface="0.0.0.0") + + @defer.inlineCallbacks + def shutdown_twisted(): + print("Stopping Twisted") + yield reactor.callFromThread(reactor.stop) + + reactor.addSystemEventTrigger('before', 'shutdown', shutdown_twisted) + + try : + reactor.run() + except ReactorNotRunning: + print('exception reactor') + sys.exit(-1) + except : + print('generic exception reactor') + sys.exit(-1) + + print("Server terminated") + sys.exit(0) + diff --git a/samples/demos/irb/experimenter/worker/server_api.py b/samples/demos/irb/experimenter/worker/server_api.py new file mode 100644 index 000000000..7781e57cf --- /dev/null +++ b/samples/demos/irb/experimenter/worker/server_api.py @@ -0,0 +1,77 @@ +# Copyright 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +import attestation +import keys +import protos.irb_pb2 as irb +import storage_client +import diagnose +import base64 + +def HandleAttestation(): + attestation_bytes = attestation.GetAttestation() + print(attestation_bytes) + + #build identity bytes + id = irb.Identity() + id.public_key = keys.GetSerializedVerifyingKey() + id.public_encryption_key = keys.GetSerializedEncryptionKey() + id_bytes = id.SerializeToString() + + #build worker credentials + wc = irb.WorkerCredentials() + wc.identity_bytes = id_bytes + wc.attestation = attestation_bytes.encode('utf_8') + return wc.SerializeToString() + +def HandleExecuteEvaluationPack(evaluation_pack): + eep = irb.EncryptedEvaluationPack() + eep.ParseFromString(evaluation_pack) + + #decrypt encrypted evalution pack + res = keys.PkDecrypt(eep.encrypted_encryption_key) + if res[1] != None: + return "Error decrypting eval encryption key: " + res[1] + key = bytearray(res[0]) + res = keys.Decrypt(key, eep.encrypted_evaluationpack) + if res[1] != None: + return "Error decrypting eval pack: " + res[1] + evaluationpack = bytearray(res[0]) + + epm = irb.EvaluationPackMessage() + epm.ParseFromString(evaluationpack) + + sc = storage_client.StorageClient() + + return_string = "" + + first = True + for r in epm.registered_data: + if first: + first = False + else: + return_string += ", " + + print("Data handler: {0}".format(r.data_handler)) + + val = sc.get(r.data_handler) + if val[1] == False: + return "Error: Cannot retrieve value of key: " + r.data_handler + + print("Encoded data: {0}".format(val[0])) + encrypted_data = base64.b64decode(val[0]) + + res = keys.Decrypt(r.decryption_key, encrypted_data) + if res[1] != None: + return "Error decrypting data item: " + res[1] + data = bytearray(res[0]) + + result = diagnose.diagnose(data) + if result[1] != "" : + return "Error running diagnosis: " + result[1] + + return_string += result[0] + + print("Final result: {0}".format(return_string)) + return return_string diff --git a/samples/demos/irb/experimenter/worker/storage_client.py b/samples/demos/irb/experimenter/worker/storage_client.py new file mode 100644 index 000000000..b1598650e --- /dev/null +++ b/samples/demos/irb/experimenter/worker/storage_client.py @@ -0,0 +1,34 @@ +# Copyright 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +import redis +import logging +from os import environ + +logger = logging.getLogger() + +class StorageClient: + def __init__(self): + self.host = environ.get('REDIS_HOST', 'localhost') + self.port = environ.get('REDIS_PORT', '6379') + self.db = '0' + + self.r = redis.Redis(self.host, self.port, self.db) + + def set(self, key, value): + try: + self.r.set(key, value) + except Exception as e: + logger.error("Error set: {}".format(str(e))) + return False + return True + + def get(self, key): + try: + value = self.r.get(key) + except Exception as e: + logger.error("Error get: {}".format(str(e))) + return None, False + return value, True + diff --git a/samples/demos/irb/experimenter/worker/train_model.py b/samples/demos/irb/experimenter/worker/train_model.py new file mode 100644 index 000000000..aeedcb89f --- /dev/null +++ b/samples/demos/irb/experimenter/worker/train_model.py @@ -0,0 +1,178 @@ +import urllib.request +import numpy as np +def download_url(url, save_as): + response = urllib.request.urlopen(url) + data = response.read() + file = open(save_as, 'wb') + file.write(data) + file.close() + response.close() + +def read_binary_file(file): + f = open(file,'rb') + block = f.read() + return block.decode('utf-16') + +def split_text_in_lines(text): + return text.split('\r\n') + +def split_by_tabs(line): + return line.split('\t') + + +names_link = 'https://archive.ics.uci.edu/ml/machine-learning-databases/acute/diagnosis.names' +data_link = 'https://archive.ics.uci.edu/ml/machine-learning-databases/acute/diagnosis.data' +#names_link = 'localhost:/home/bruno/misc-packages/uci-ml-data/diagnosis.names' +#data_link = '/home/bruno/misc-packages/uci-ml-data/diagnosis.data' +diagnosis_names = 'diagnosis.names' +diagnosis_data = 'diagnosis.data' +download_url(names_link, diagnosis_names) +download_url(data_link, diagnosis_data) + + + +def parse_double(field): + field = field.replace(',', '.') + return float(field) + +def parse_boolean(field): + return 1. if field == 'yes' else 0. + +def read_np_array(file = diagnosis_data): + text = read_binary_file(file) + lines = split_text_in_lines(text) + rows = [] + for line in lines: + if line == '': continue + line = line.replace('\r\n', '') + fields = split_by_tabs(line) + row = [] + j = 0 + for field in fields: + value = parse_double(field) if j == 0 else parse_boolean(field) + row.append(value) + j += 1 + rows.append(row) + matrix = np.array(rows, dtype = np.float32) + return matrix + + + +def get_random_indexes(n): + indexes = list(range(n)) + random_indexes = [] + for i in range(n): + r = np.random.randint(len(indexes)) + random_indexes.append(indexes.pop(r)) + return random_indexes + +def get_indexes_for_2_datasets(n, training = 80): + indexes = get_random_indexes(n) + train = int(training / 100. * n) + return indexes[:train], indexes[train:] + +matrix = read_np_array() +n_samples, n_dimensions = matrix.shape + +train_indexes, test_indexes = get_indexes_for_2_datasets(n_samples) +train_data = matrix[train_indexes] +test_data = matrix[test_indexes] + +def print_dataset(name, data): + print('Dataset {}. Shape: {}'.format(name, data.shape)) + print(data) + + +print_dataset('Train', train_data) +print_dataset('Test', test_data) + +import tensorflow as tf + +tf.__version__ + +import torch +from torch.autograd import Variable +import torch.nn as nn +import torch.nn.functional as F + +input_size = 6 +learning_rate = 0.01 +num_iterations = 20000 + +class LogisticRegression(torch.nn.Module): + + def __init__(self): + super(LogisticRegression, self).__init__() + self.linear = torch.nn.Linear(input_size, 1) + + def forward(self, x): + return torch.sigmoid(self.linear(x)) + + +def decide(y): + return 1. if y >= 0.5 else 0. + +decide_vectorized = np.vectorize(decide) + +to_percent = lambda x: '{:.2f}%'.format(x) + + +def compute_accuracy(model, input, output): + prediction = model(input).data.numpy()[:, 0] + n_samples = prediction.shape[0] + 0. + prediction = decide_vectorized(prediction) + equal = prediction == output.data.numpy() + return 100. * equal.sum() / n_samples + +def get_input_and_output(data): + input = Variable(torch.tensor(data[:, :6], dtype = torch.float32)) + output1 = Variable(torch.tensor(data[:, 6], dtype = torch.float32)) + output2 = Variable(torch.tensor(data[:, 7], dtype = torch.float32)) + return input, output1, output2 + +input, output1, output2 = get_input_and_output(train_data) +test_input, test_output1, test_output2 = get_input_and_output(test_data) + + +import matplotlib.pyplot as plt + +diagnosis_title1 = 'Inflammation of Urinary Bladder' +diagnosis_title2 = 'Nephritis of Renal Pelvis Origin' + + +def train_model(diagnosis_title, input, output, test_input, test_output): + model = LogisticRegression() + criterion = torch.nn.BCELoss(size_average=True) + optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) + losses = [] + accuracies = [] + n_samples, _ = input.shape + for iteration in range(num_iterations): + optimizer.zero_grad() + prediction = model(input) + + loss = criterion(prediction, output) + loss.backward() + optimizer.step() + if iteration % 500 == 0: + train_acc = compute_accuracy(model, input, output) + train_loss = loss.item() + losses.append(train_loss) + accuracies.append(train_acc) + test_acc = compute_accuracy(model, test_input, test_output) + print('\nTesting Accuracy = {}'.format(to_percent(test_acc))) + return model + + +output1 = np.reshape(output1,(-1,1)) +model1 = train_model(diagnosis_title1, input, output1, test_input, test_output1) +output2 = np.reshape(output2,(-1,1)) +model2 = train_model(diagnosis_title2, input, output2, test_input, test_output2) + +output_filename1 = "diagnoss1.pt" +torch.save(model1.state_dict(), output_filename1) +diagnoss1 = torch.load(output_filename1) + +output_filename2 = "diagnoss2.pt" +torch.save(model2.state_dict(), output_filename2) +diagnoss2 = torch.load(output_filename2) diff --git a/samples/demos/irb/experimenter/worker/workerCLI.py b/samples/demos/irb/experimenter/worker/workerCLI.py new file mode 100644 index 000000000..766f1bd78 --- /dev/null +++ b/samples/demos/irb/experimenter/worker/workerCLI.py @@ -0,0 +1,19 @@ +import server +import logging +import sys + +logging.basicConfig() +logger = logging.getLogger() + +logger.setLevel(logging.DEBUG) + +import keys + +if keys.InitializeKeys() == False: + logger.error("error initializing keys") + sys.exit(-1) + +server.RunWorkerServer() + +sys.exit(-1) + diff --git a/samples/demos/irb/go.mod b/samples/demos/irb/go.mod new file mode 100644 index 000000000..725faa4af --- /dev/null +++ b/samples/demos/irb/go.mod @@ -0,0 +1,30 @@ +module github.com/hyperledger/fabric-private-chaincode/samples/demos/irb + +go 1.16 + +replace ( + github.com/fsouza/go-dockerclient => github.com/fsouza/go-dockerclient v1.4.1 + github.com/go-kit/kit => github.com/go-kit/kit v0.7.0 + github.com/hyperledger/fabric => github.com/hyperledger/fabric v1.4.0-rc1.0.20210722174351-9815a7a8f0f7 + github.com/hyperledger/fabric-protos-go => github.com/hyperledger/fabric-protos-go v0.0.0-20201028172056-a3136dde2354 + go.etcd.io/etcd => go.etcd.io/etcd v0.5.0-alpha.5.0.20181228115726-23731bf9ba55 +) + +//replace github.com/hyperledger-labs/fabric-smart-client => ../../../../../hyperledger-labs/fabric-smart-client + +require ( + github.com/Microsoft/go-winio v0.5.0 // indirect + github.com/containerd/containerd v1.5.7 // indirect + github.com/docker/docker v20.10.8+incompatible + github.com/docker/go-connections v0.4.0 + github.com/go-redis/redis v6.15.9+incompatible + github.com/golang/protobuf v1.5.2 + github.com/hyperledger-labs/fabric-smart-client v0.0.0-20211015115528-782c5aee50b7 + github.com/hyperledger/fabric v1.4.0-rc1.0.20210722174351-9815a7a8f0f7 + github.com/libp2p/go-libp2p-core v0.3.0 + github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.7.1-0.20210116013205-6990a05d54c2 + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + google.golang.org/protobuf v1.27.1 +) diff --git a/samples/demos/irb/go.sum b/samples/demos/irb/go.sum new file mode 100644 index 000000000..cc16e6573 --- /dev/null +++ b/samples/demos/irb/go.sum @@ -0,0 +1,1739 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +code.cloudfoundry.org/clock v1.0.0 h1:kFXWQM4bxYvdBw2X8BbBeXwQNgfoWv1vqAk2ZZyBN2o= +code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-txdb v0.1.3/go.mod h1:DhAhxMXZpUJVGnT+p9IbzJoRKvlArO2pkHjnGX7o0n0= +github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= +github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/IBM/idemix v0.0.0-20210930104432-e4a1410f5353 h1:gOG+V3F5J7gsWzHAoNSHAiYV2o3OvgM7uTrF7BUSt2Y= +github.com/IBM/idemix v0.0.0-20210930104432-e4a1410f5353/go.mod h1:Fazy7pMxGGdXRRSFgTipzH4Q02bIEPatJa3km9H3w78= +github.com/IBM/mathlib v0.0.0-20210928081244-f5486459a290 h1:usgCPts8YnOT6ba6CQLPzQ5Yb1crnQ8iU132Zm679IM= +github.com/IBM/mathlib v0.0.0-20210928081244-f5486459a290/go.mod h1:grSmaMdY3LbW9QwqMrzuTUCHjES4rzT4Dm7q6yIL9vs= +github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= +github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.21 h1:btRfUDThBE5IKcvI8O8jOiIkujUsAMBSRsYDYmEi6oM= +github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= +github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/Shopify/sarama v1.20.1/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.26.3 h1:wSN3FpDXLe3e2z47OzGii5VAK693oVkyHFwh240jWjg= +github.com/Shopify/sarama v1.26.3/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= +github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw= +github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20210912230133-d1bdfacee922 h1:8ypNbf5sd3Sm3cKJ9waOGoQv6dKAFiFty9L6NP1AqJ4= +github.com/alecthomas/units v0.0.0-20210912230133-d1bdfacee922/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= +github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= +github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= +github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= +github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= +github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/consensys/bavard v0.1.8-0.20210329205436-c3e862ba4e5f/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= +github.com/consensys/gnark-crypto v0.4.0 h1:KHf7Ta876Ys6L8+i0DLRRKOAa3PfJ8oobAX1CEeIa4A= +github.com/consensys/gnark-crypto v0.4.0/go.mod h1:wK/gpXP9B06qTzTVML71GhKD1ygP9xOzukbI68NJqsQ= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.7 h1:rQyoYtj4KddB3bxG6SAqd4+08gePNyJjRqvOIfV3rkM= +github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a h1:W8b4lQ4tFF21aspRGoBuCNV6V2fFJBF+pm1J6OY8Lys= +github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cucumber/godog v0.8.0/go.mod h1:Cp3tEV1LRAyH/RuCThcxHS/+9ORZ+FMzPva2AZ5Ki+A= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= +github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgraph-io/badger/v3 v3.2011.1 h1:Hmyof0WMEF/QtutX5SQHzIMnJQxb/IrSzhjckV2SD6g= +github.com/dgraph-io/badger/v3 v3.2011.1/go.mod h1:0rLLrQpKVQAL0or/lBLMQznhr6dWWX7h5AKnmnqx268= +github.com/dgraph-io/ristretto v0.0.4-0.20210122082011-bb5d392ed82d h1:eQYOG6A4td1tht0NdJB9Ls6DsXRGb2Ft6X9REU/MbbE= +github.com/dgraph-io/ristretto v0.0.4-0.20210122082011-bb5d392ed82d/go.mod h1:tv2ec8nA7vRpSYX7/MbP52ihrUMXIHit54CQMq8npXQ= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v17.12.0-ce-rc1.0.20190628135806-70f67c6240bb+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.8+incompatible h1:RVqD337BgQicVCzYrrlhLDWhq6OAD2PJDUg2LsEUvKM= +github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.2.0 h1:v7g92e/KSN71Rq7vSThKaWIq68fL4YHvWyiUKorFR1Q= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= +github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= +github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsouza/go-dockerclient v1.4.1 h1:W7wuJ3IB48WYZv/UBk9dCTIb9oX805+L9KIm65HcUYs= +github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-delve/delve v1.5.0/go.mod h1:c6b3a1Gry6x8a4LGCe/CWzrocrfaHvkUxCj3k4bvSUQ= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.7.0 h1:ApufNmWF1H6/wUbAG81hZOHmqwd0zRf8mNfLjYj/064= +github.com/go-kit/kit v0.7.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= +github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= +github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= +github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/addlicense v1.0.0/go.mod h1:Sm/DHu7Jk+T5miFHHehdIjbi4M5+dJDRS3Cq0rncIxA= +github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/flatbuffers v1.12.0 h1:/PtAHvnBY4Kqnx/xCQ3OIV9uYcSFGScBsWI3Oogeh6w= +github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-dap v0.2.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.4.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= +github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/hyperledger-labs/fabric-smart-client v0.0.0-20211015115528-782c5aee50b7 h1:w+Da49/tLGTJIB8JChvEZLUb+knU4YBpbwSJ1tmt/8E= +github.com/hyperledger-labs/fabric-smart-client v0.0.0-20211015115528-782c5aee50b7/go.mod h1:5nb+I767ih87ABv96XRWxVXVncVdolPv3MvjlQ7hkIQ= +github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.2.3-alpha.1 h1:vBvo0PNm82ht7wpBjlYY4ZHxV3YprCfdVd3T4JG9vBw= +github.com/hyperledger-labs/weaver-dlt-interoperability/common/protos-go v1.2.3-alpha.1/go.mod h1:POCGO/RK9YDfgdhuyqjoD9tRNtWfK7Rh5AYYmsb1Chc= +github.com/hyperledger-labs/weaver-dlt-interoperability/sdks/fabric/go-sdk v1.2.3-alpha.1.0.20210812140206-37f430515b8c h1:pKr8VnHlduEgdInwLWykYAw+lpUizjQJaJ8I5fVoRUo= +github.com/hyperledger-labs/weaver-dlt-interoperability/sdks/fabric/go-sdk v1.2.3-alpha.1.0.20210812140206-37f430515b8c/go.mod h1:si2XAWZclHXC359OyYMpNHfonf2P7P2nzABdCA8mPqs= +github.com/hyperledger/fabric v1.4.0-rc1.0.20210722174351-9815a7a8f0f7 h1:LKWVg/yHT1GdNrcmnwp+Fzij8Wlwl7T7l22MP66TVNY= +github.com/hyperledger/fabric v1.4.0-rc1.0.20210722174351-9815a7a8f0f7/go.mod h1:g/IlXbV5x5GEprnavUFN+YoJZeIjwDocRcmO5ZG4ugc= +github.com/hyperledger/fabric-amcl v0.0.0-20200128223036-d1aa2665426a/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= +github.com/hyperledger/fabric-amcl v0.0.0-20210603140002-2670f91851c8 h1:BCR8ZlOZ+deUbWxyY6fpoY8LbB7PR5wGGwCTvWQOU2g= +github.com/hyperledger/fabric-amcl v0.0.0-20210603140002-2670f91851c8/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20190823162523-04390e015b85/go.mod h1:HZK6PKLWrvdD/t0oSLiyaRaUM6fZ7qjJuOlb0zrn0mo= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20200128192331-2d899240a7ed/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20200424173110-d7076418f212/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20201119163726-f8ef75b17719/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20210718160520-38d29fabecb9 h1:1cAZHHrBYFrX3bwQGhOZtOB4sCM9QWVppd81O8vsPXs= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20210718160520-38d29fabecb9/go.mod h1:N7H3sA7Tx4k/YzFq7U0EPdqJtqvM4Kild0JoCc7C0Dc= +github.com/hyperledger/fabric-config v0.0.5/go.mod h1:YpITBI/+ZayA3XWY5lF302K7PAsFYjEEPM/zr3hegA8= +github.com/hyperledger/fabric-config v0.0.7 h1:sHuUxTTP6l0p8BDWeag5tvGUNCsiOYZ3Mux2CXZVWe8= +github.com/hyperledger/fabric-config v0.0.7/go.mod h1:aeDZ0moG/qKvwLjddcqYr8+58/oNaJy3HE0tI01546c= +github.com/hyperledger/fabric-contract-api-go v1.1.1/go.mod h1:+39cWxbh5py3NtXpRA63rAH7NzXyED+QJx1EZr0tJPo= +github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324= +github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= +github.com/hyperledger/fabric-private-chaincode v0.0.0-20210907122433-d56466264e4d h1:LR34x2vhXUuXsETE9HBhz+eZM6nTuzPiWsF5jnNI550= +github.com/hyperledger/fabric-private-chaincode v0.0.0-20210907122433-d56466264e4d/go.mod h1:CBeWypXEi4LndnexZzEEqVIIqjdrUzUUHmmFcEcGRX4= +github.com/hyperledger/fabric-protos-go v0.0.0-20201028172056-a3136dde2354 h1:6vLLEpvDbSlmUJFjg1hB5YMBpI+WgKguztlONcAFBoY= +github.com/hyperledger/fabric-protos-go v0.0.0-20201028172056-a3136dde2354/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= +github.com/hyperledger/fabric-samples/chaincode/marbles02/go v0.0.0-20210428060230-9db8164f049b/go.mod h1:MvJbTLiLI/KBavKkC+OAqYU1IGvbY8WOu+Qzs/jncnA= +github.com/hyperledger/fabric-sdk-go v1.0.0/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd h1:anPrsicrIi2ColgWTVPk+TrN42hJIWlfPHSBP9S0ZkM= +github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= +github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU= +github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= +github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= +github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-datastore v0.3.1 h1:SS1t869a6cctoSYmZXUk8eL6AzVXgASmKIWFNQkQ1jU= +github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= +github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= +github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= +github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= +github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= +github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= +github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= +github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= +github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= +github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= +github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= +github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc= +github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= +github.com/ipfs/go-todocounter v0.0.2 h1:9UBngSQhylg2UDcxSAtpkT+rEWFr26hDPXVStE8LFyc= +github.com/ipfs/go-todocounter v0.0.2/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc= +github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= +github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= +github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A= +github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= +github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= +github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10= +github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= +github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= +github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.0.0/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88= +github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= +github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= +github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= +github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-conn-security-multistream v0.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0= +github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= +github.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ= +github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= +github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= +github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= +github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p v0.5.0/go.mod h1:Os7a5Z3B+ErF4v7zgIJ7nBHNu2LYt8ZMLkTQUB3G/wA= +github.com/libp2p/go-libp2p v0.5.2 h1:fjQUTyB7x/4XgO31OEWkJ5uFeHRgpoExlf0rXz5BO8k= +github.com/libp2p/go-libp2p v0.5.2/go.mod h1:o2r6AcpNl1eNGoiWhRtPji03NYOvZumeQ6u+X6gSxnM= +github.com/libp2p/go-libp2p-autonat v0.1.1 h1:WLBZcIRsjZlWdAZj9CiBSvU2wQXoUOiS1Zk1tM7DTJI= +github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= +github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= +github.com/libp2p/go-libp2p-blankhost v0.1.4 h1:I96SWjR4rK9irDHcHq3XHN6hawCRTPUADzkJacgZLvk= +github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= +github.com/libp2p/go-libp2p-circuit v0.1.4 h1:Phzbmrg3BkVzbqd4ZZ149JxCuUWu2wZcXf/Kr6hZJj8= +github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= +github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= +github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= +github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= +github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= +github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= +github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= +github.com/libp2p/go-libp2p-core v0.3.0 h1:F7PqduvrztDtFsAa/bcheQ3azmNo+Nq7m8hQY5GiUW8= +github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= +github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= +github.com/libp2p/go-libp2p-discovery v0.2.0 h1:1p3YSOq7VsgaL+xVHPi8XAmtGyas6D2J6rWBEfz/aiY= +github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= +github.com/libp2p/go-libp2p-kad-dht v0.5.0 h1:kDMtCftpQOL2s84/dZmw5z4NmBe6ByeDLKpcn6TcyxU= +github.com/libp2p/go-libp2p-kad-dht v0.5.0/go.mod h1:42YDfiKXzIgaIexiEQ3rKZbVPVPziLOyHpXbOCVd814= +github.com/libp2p/go-libp2p-kbucket v0.2.3 h1:XtNfN4WUy0cfeJoJgWCf1lor4Pp3kBkFJ9vQ+Zs+VUM= +github.com/libp2p/go-libp2p-kbucket v0.2.3/go.mod h1:opWrBZSWnBYPc315q497huxY3sz1t488X6OiXUEYWKA= +github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= +github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= +github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI= +github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= +github.com/libp2p/go-libp2p-nat v0.0.5 h1:/mH8pXFVKleflDL1YwqMg27W9GD8kjEx7NY0P6eGc98= +github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= +github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= +github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= +github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= +github.com/libp2p/go-libp2p-peerstore v0.1.4 h1:d23fvq5oYMJ/lkkbO4oTwBp/JP+I/1m5gZJobNXCE/k= +github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= +github.com/libp2p/go-libp2p-record v0.1.2 h1:M50VKzWnmUrk/M5/Dz99qO9Xh4vs8ijsK+7HkJvRP+0= +github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= +github.com/libp2p/go-libp2p-routing v0.1.0 h1:hFnj3WR3E2tOcKaGpyzfP4gvFZ3t8JkQmbapN0Ct+oU= +github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE= +github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= +github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= +github.com/libp2p/go-libp2p-secio v0.2.1 h1:eNWbJTdyPA7NxhP7J3c5lT97DC5d+u+IldkgCYFTPVA= +github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= +github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= +github.com/libp2p/go-libp2p-swarm v0.2.2 h1:T4hUpgEs2r371PweU3DuH7EOmBIdTBCwWs+FLcgx3bQ= +github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= +github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= +github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU= +github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw= +github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= +github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= +github.com/libp2p/go-libp2p-yamux v0.2.1 h1:Q3XYNiKCC2vIxrvUJL+Jg1kiyeEaIDNKLjgEjo3VQdI= +github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= +github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= +github.com/libp2p/go-maddr-filter v0.0.5 h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg= +github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= +github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0= +github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= +github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= +github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-nat v0.0.4 h1:KbizNnq8YIf7+Hn7+VFL/xE0eDrkPru2zIO9NMwL8UQ= +github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= +github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= +github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-openssl v0.0.4 h1:d27YZvLoTyMhIN4njrkr8zMDOM4lfpHIp6A+TK9fovg= +github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= +github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4= +github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= +github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg= +github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= +github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= +github.com/libp2p/go-tcp-transport v0.1.1 h1:yGlqURmqgNA2fvzjSgZNlHcsd/IulAnKM8Ncu+vlqnw= +github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= +github.com/libp2p/go-ws-transport v0.2.0 h1:MJCw2OrPA9+76YNRvdo1wMnSOxb9Bivj6sVFY1Xrj6w= +github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= +github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI= +github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.0/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxbrunsfeld/counterfeiter/v6 v6.3.0/go.mod h1:fcEyUyXZXoV4Abw8DX0t7wyL8mCDxXyU4iAFZfT3IHw= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/miracl/conflate v1.2.1 h1:QlB+Hjh8vnPIjimCK2VKEvtLVxVGIVxNQ4K95JRpi90= +github.com/miracl/conflate v1.2.1/go.mod h1:F85f+vrE7SwfRoL31EpLZFa1sub0SDxzcwxDBxFvy7k= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mmcloughlin/avo v0.0.0-20201105074841-5d2f697d268f/go.mod h1:6aKT4zZIrpGqB3RpFU14ByCSSyKY6LfJz4J/JJChHfI= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM= +github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= +github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= +github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= +github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= +github.com/multiformats/go-multiaddr v0.2.0 h1:lR52sFwcTCuQb6bTfnXF6zA2XfyYvyd+5a9qECv/J90= +github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= +github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= +github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= +github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= +github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= +github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= +github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= +github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= +github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= +github.com/multiformats/go-multiaddr-net v0.1.2 h1:P7zcBH9FRETdPkDrylcXVjQLQ2t1JQtNItZULWNWgeg= +github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= +github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA= +github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= +github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= +github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= +github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= +github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= +github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI= +github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= +github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/otiai10/copy v1.5.1 h1:a/cs2E1/1V0az8K5nblbl+ymEa4E11AfaOLMar8V34w= +github.com/otiai10/copy v1.5.1/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.5.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= +github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20180612222113-7d6f385de8be/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= +github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/afero v1.3.1 h1:GPTpEAuNr98px18yNQ66JllNil98wfRZ/5Ukny8FeQA= +github.com/spf13/afero v1.3.1/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.0-20170417170307-b6cb39589372/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.1.1/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= +github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1-0.20210116013205-6990a05d54c2 h1:oevpAKCW58ZYJe1hqfgLqg+1zXmYrQ9xf7HLUdfS+qM= +github.com/stretchr/testify v1.7.1-0.20210116013205-6990a05d54c2/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/sykesm/zap-logfmt v0.0.2/go.mod h1:TerDJT124HaO8UTpZ2wJCipJRAKQ9XONM1mzUabIh6M= +github.com/sykesm/zap-logfmt v0.0.4 h1:U2WzRvmIWG1wDLCFY3sz8UeEmsdHQjHFNlIdmroVFaI= +github.com/sykesm/zap-logfmt v0.0.4/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= +github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= +github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= +github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00 h1:mujcChM89zOHwgZBBNr5WZ77mBXP1yR+gLThGCYZgAg= +github.com/tedsuo/ifrit v0.0.0-20191009134036-9a97d0632f00/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0= +github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= +github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/twitchyliquid64/golang-asm v0.15.0/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= +github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= +github.com/whyrusleeping/go-logging v0.0.1 h1:fwpzlmT0kRC/Fmd0MdmGgJG/CXIZ6gFq46FQZjprUcc= +github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= +github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA= +github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= +github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= +github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8= +github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY= +go.etcd.io/bbolt v1.3.1-etcd.7/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20181228115726-23731bf9ba55 h1:YTC92EdyM9lnD0aVRqN28/CILPLZSzdmoomOFAjxBbk= +go.etcd.io/etcd v0.5.0-alpha.5.0.20181228115726-23731bf9ba55/go.mod h1:weASp41xM3dk0YHg1s/W8ecdGP5G4teSTMBPpYAaUgA= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.starlark.net v0.0.0-20190702223751-32f345186213/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180608092829-8ac0e0d97ce4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191125084936-ffdde1057850/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200819091447-39769834ee22/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200131233409-575de47986ce/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201105001634-bc3cf281b174/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20180608181217-32ee49c4dd80/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210201184850-646a494a81ea h1:B/tOZ5zKaomKBjKJJMjuqwmIc3YNX10q5DcCt8xLYY4= +google.golang.org/genproto v0.0.0-20210201184850-646a494a81ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1 h1:f37vZbBVTiJ6jKG5mWz8ySOBxNqy6ViPgyhSdVnxF3E= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0 h1:1duIyWiTaYvVx3YX2CYtpJbUFd7/UuPYCfgXtQ3VTbI= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0 h1:a9tsXlIDD9SKxotJMK3niV7rPZAJeX2aD/0yg3qlIrg= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= +gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/samples/demos/irb/irb_test.go b/samples/demos/irb/irb_test.go new file mode 100644 index 000000000..199353f73 --- /dev/null +++ b/samples/demos/irb/irb_test.go @@ -0,0 +1,113 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package irb + +import ( + "fmt" + "strconv" + "testing" + + "github.com/hyperledger-labs/fabric-smart-client/integration" + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/common" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/container" + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/storage" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/users" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/views/dataprovider" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/views/experimenter" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/views/investigator" + "github.com/stretchr/testify/assert" +) + +const ( + studyID = "pineapple" + experimentID = "exp001" + dockerNetwork = "irb-network" + redisImageName = "redis" + redisContainerName = "redis-container" + experimentImageName = "irb-experimenter-worker" + experimentContainerName = "experiment-container" + testPatientData = "29, 0, 0, 1, 0, 0" +) + +func TestFlow(t *testing.T) { + + // + network := &container.Network{Name: dockerNetwork} + err := network.Create() + assert.NoError(t, err) + defer network.Remove() + + // setup redis + redis := &container.Container{ + Image: redisImageName, + Name: redisContainerName, + HostIP: "localhost", + HostPort: strconv.Itoa(storage.DefaultRedisPort), + Network: dockerNetwork, + } + err = redis.Start() + assert.NoError(t, err) + defer redis.Stop() + + // setup experiment container + experiment := &container.Container{ + Image: experimentImageName, + Name: experimentContainerName, + HostIP: "localhost", + HostPort: "5000", + Network: dockerNetwork, + Env: []string{fmt.Sprintf("REDIS_HOST=%s", redisContainerName)}, + } + err = experiment.Start() + defer experiment.Stop() + assert.NoError(t, err) + + // setup fabric network + ii, err := integration.Generate(23000, Topology()...) + assert.NoError(t, err) + ii.Start() + defer ii.Stop() + + // create test patients participating in our study + patients := []string{"patient1"} + var patientIdentities []*pb.Identity + for _, p := range patients { + uuid, _, vk, err := users.LoadOrCreateUser(p) + assert.NoError(t, err) + patientIdentities = append(patientIdentities, &pb.Identity{Uuid: string(uuid), PublicKey: vk}) + } + assert.Equal(t, len(patients), len(patientIdentities)) + + // create new study with our patients + _, err = ii.Client("investigator").CallView("CreateStudy", common.JSONMarshall(&investigator.CreateStudy{ + StudyID: studyID, + Metadata: "some fancy study", + Participants: patientIdentities, + })) + assert.NoError(t, err) + + // data provider flow + _, err = ii.Client("provider").CallView("RegisterData", common.JSONMarshall(&dataprovider.Register{ + StudyID: studyID, + PatientData: []byte(testPatientData), + PatientUUID: patientIdentities[0].GetUuid(), + PatientVK: patientIdentities[0].GetPublicKey(), + })) + assert.NoError(t, err) + + // starting experimenter flow + // this starts with the submission view which interacts with the investigator approval view + // once the new experiment is approved, the execution view is triggered + _, err = ii.Client("experimenter").CallView("SubmitExperiment", common.JSONMarshall(&experimenter.SubmitExperiment{ + StudyId: studyID, + ExperimentId: experimentID, + Investigator: ii.Identity("investigator"), + })) + assert.NoError(t, err) + +} diff --git a/samples/demos/irb/pkg/container/container.go b/samples/demos/irb/pkg/container/container.go new file mode 100644 index 000000000..7602bd7a7 --- /dev/null +++ b/samples/demos/irb/pkg/container/container.go @@ -0,0 +1,107 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package container + +import ( + "bufio" + "context" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/client" + "github.com/docker/go-connections/nat" +) + +type Container struct { + Image string + CMD []string + Name string + HostIP string + HostPort string + containerID string + Env []string + Network string +} + +func (c *Container) Start() error { + ctx := context.Background() + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return err + } + + resp, err := cli.ContainerCreate(ctx, + &container.Config{ + Image: c.Image, + Cmd: c.CMD, + Env: c.Env, + }, + &container.HostConfig{ + PortBindings: nat.PortMap{ + nat.Port(fmt.Sprintf("%s/tcp", c.HostPort)): []nat.PortBinding{{HostIP: c.HostIP, HostPort: c.HostPort}}, + }, + }, nil, nil, c.Name) + if err != nil { + return err + } + + if err := cli.NetworkConnect(context.Background(), c.Network, resp.ID, nil); err != nil { + return err + } + + if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil { + return err + } + + go func() { + reader, err := cli.ContainerLogs(context.Background(), resp.ID, types.ContainerLogsOptions{ + ShowStdout: true, + ShowStderr: true, + Follow: true, + Timestamps: false, + }) + defer reader.Close() + if err != nil { + return + } + + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + fmt.Printf("%s: %s", c.Name, scanner.Text()) + } + }() + c.containerID = resp.ID + fmt.Printf("Container started: %s (%s)\n", c.Name, resp.ID) + + return nil +} + +func (c *Container) Stop() error { + if len(c.containerID) == 0 { + // no container started + return nil + } + + ctx := context.Background() + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return err + } + + if err := cli.ContainerStop(ctx, c.containerID, nil); err != nil { + return err + } + + if err := cli.ContainerRemove(ctx, c.containerID, types.ContainerRemoveOptions{}); err != nil { + return err + } + + fmt.Printf("Container stopped: %s\n", c.containerID) + + return nil +} diff --git a/samples/demos/irb/pkg/container/network.go b/samples/demos/irb/pkg/container/network.go new file mode 100644 index 000000000..40b88c96c --- /dev/null +++ b/samples/demos/irb/pkg/container/network.go @@ -0,0 +1,56 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package container + +import ( + "context" + "fmt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/client" +) + +type Network struct { + Name string + id string +} + +func (n *Network) Create() error { + ctx := context.Background() + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return err + } + + opts := types.NetworkCreate{ + Driver: "bridge", + } + resp, err := cli.NetworkCreate(ctx, n.Name, opts) + if err != nil { + return err + } + + n.id = resp.ID + + fmt.Printf("Network created: %s (%s)\n", n.Name, resp.ID) + return nil +} + +func (n *Network) Remove() error { + if len(n.id) == 0 { + // no network to remove + return nil + } + + ctx := context.Background() + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return err + } + + return cli.NetworkRemove(ctx, n.id) +} diff --git a/samples/demos/irb/pkg/crypto/crypto_go.go b/samples/demos/irb/pkg/crypto/crypto_go.go new file mode 100644 index 000000000..4bd5fe8c9 --- /dev/null +++ b/samples/demos/irb/pkg/crypto/crypto_go.go @@ -0,0 +1,265 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package crypto + +import "C" +import ( + "crypto/aes" + "crypto/cipher" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/sha1" + "crypto/sha256" + "crypto/x509" + "encoding/pem" + "fmt" + "io" + + "github.com/pkg/errors" +) + +const ( + NonceLength = 12 + SymKeyLength = 16 + TagLength = 16 + RSAKeyLength = 3072 +) + +// GoCrypto implements CSP using pure go +type GoCrypto struct { +} + +func NewGoCrypto() *GoCrypto { + return &GoCrypto{} +} + +func (g GoCrypto) NewSymmetricKey() ([]byte, error) { + keyLength := SymKeyLength + key := make([]byte, keyLength) + n, err := rand.Read(key) + if n != len(key) || err != nil { + return nil, err + } + + return key, nil +} + +func (g GoCrypto) NewRSAKeys() (publicKey []byte, privateKey []byte, err error) { + + // create rsa private key + pri, err := rsa.GenerateKey(rand.Reader, RSAKeyLength) + if err != nil { + return nil, nil, err + } + + // serialize + privateKey = pem.EncodeToMemory(&pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(pri), + }) + + publicKey = pem.EncodeToMemory(&pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: x509.MarshalPKCS1PublicKey(pri.Public().(*rsa.PublicKey)), + }) + + return publicKey, privateKey, nil +} + +func (g GoCrypto) NewECDSAKeys() (publicKey []byte, privateKey []byte, err error) { + + // use secp256r1 (prime256v1) + curve := elliptic.P256() + + // create ecdsa private key + pri, err := ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + return nil, nil, errors.Wrapf(err, "cannot generate ecdsa key with curve %v", curve) + } + + // serialize + x509encodedPri, err := x509.MarshalECPrivateKey(pri) + if err != nil { + return nil, nil, errors.Wrap(err, "cannot serialize private key") + } + + privateKey = pem.EncodeToMemory(&pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: x509encodedPri, + }) + + x509encodedPub, err := x509.MarshalPKIXPublicKey(pri.Public()) + if err != nil { + return nil, nil, err + } + + publicKey = pem.EncodeToMemory(&pem.Block{ + Type: "PUBLIC KEY", + Bytes: x509encodedPub, + }) + + return publicKey, privateKey, nil +} + +func (g GoCrypto) VerifyMessage(publicKey []byte, message []byte, signature []byte) error { + + // hash + hash := sha256.Sum256(message) + + block, _ := pem.Decode(publicKey) + if block == nil || block.Type != "PUBLIC KEY" { + return fmt.Errorf("failed to decode PEM block containing public key, got %v", block) + } + + pub, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + return errors.Wrap(err, "cannot parse public key") + } + + valid := ecdsa.VerifyASN1(pub.(*ecdsa.PublicKey), hash[:], signature) + if !valid { + return fmt.Errorf("failed to verify signature") + } + return nil +} + +func (g GoCrypto) SignMessage(privateKey []byte, message []byte) (signature []byte, e error) { + + // hash + hash := sha256.Sum256(message) + + // convert key + block, _ := pem.Decode(privateKey) + if block == nil || block.Type != "EC PRIVATE KEY" { + return nil, fmt.Errorf("failed to decode PEM block containing private key, got %v", block) + } + + priv, err := x509.ParseECPrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + // sign + + sig, err := ecdsa.SignASN1(rand.Reader, priv, hash[:]) + if err != nil { + return nil, err + } + + return sig, nil +} + +func (g GoCrypto) PkDecryptMessage(privateKey []byte, encryptedMessage []byte) (message []byte, err error) { + block, _ := pem.Decode(privateKey) + if block == nil || block.Type != "RSA PRIVATE KEY" { + return nil, fmt.Errorf("failed to decode PEM block containing private key") + } + + priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + // using sha1 as used by default with Openssl RSA_PKCS1_OAEP_PADDING + // https://www.openssl.org/docs/man1.1.1/man3/RSA_public_encrypt.html + message, err = rsa.DecryptOAEP(sha1.New(), rand.Reader, priv, encryptedMessage, nil) + if err != nil { + return nil, err + } + + return message, nil +} + +func (g GoCrypto) PkEncryptMessage(publicKey []byte, message []byte) ([]byte, error) { + + block, _ := pem.Decode(publicKey) + if block == nil || block.Type != "RSA PUBLIC KEY" { + return nil, fmt.Errorf("failed to decode PEM block containing public key") + } + + pub, err := x509.ParsePKCS1PublicKey(block.Bytes) + if err != nil { + return nil, err + } + + // using sha1 as used by default with Openssl RSA_PKCS1_OAEP_PADDING + // https://www.openssl.org/docs/man1.1.1/man3/RSA_public_encrypt.html + ciphertext, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, pub, message, nil) + if err != nil { + return nil, err + } + + return ciphertext, nil +} + +func (g GoCrypto) DecryptMessage(key []byte, encryptedMessage []byte) ([]byte, error) { + + if len(encryptedMessage) <= NonceLength+TagLength { + return nil, fmt.Errorf("encrypted message to small. expect len to be larger than %d, actual %d", NonceLength+TagLength, len(encryptedMessage)) + } + + // Note that PDO encryptMessage prepends the nonce and the authentication tag to the ciphertext + // therefore we extract these values and provide it to aesgcm.Open in the correct format + nonce := encryptedMessage[:NonceLength] + tag := encryptedMessage[NonceLength : NonceLength+TagLength] + ciphertext := encryptedMessage[NonceLength+TagLength:] + + // append tag to ciphertext + aesgcmCiphertext := ciphertext + aesgcmCiphertext = append(aesgcmCiphertext, tag...) + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + plaintext, err := aesgcm.Open(nil, nonce, aesgcmCiphertext, nil) + if err != nil { + return nil, err + } + + return plaintext, nil +} + +func (g GoCrypto) EncryptMessage(key []byte, message []byte) (encryptedMessage []byte, err error) { + + // generate nonce (IV) + nonce := make([]byte, NonceLength) + _, err = io.ReadFull(rand.Reader, nonce) + if err != nil { + return nil, err + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + aesgcmCiphertext := aesgcm.Seal(nil, nonce, message, nil) + + // Note that Seal appends the authentication tag to the cipertext, whereas PDO crypto prepends the tag + ciphertext, tag := aesgcmCiphertext[:len(aesgcmCiphertext)-TagLength], aesgcmCiphertext[len(aesgcmCiphertext)-TagLength:] + + // nonce + tag + cipher + encryptedMessage = nonce[:] + encryptedMessage = append(encryptedMessage, tag...) + encryptedMessage = append(encryptedMessage, ciphertext...) + return encryptedMessage, nil + +} diff --git a/samples/demos/irb/pkg/experiment/controller.go b/samples/demos/irb/pkg/experiment/controller.go new file mode 100644 index 000000000..96842b67c --- /dev/null +++ b/samples/demos/irb/pkg/experiment/controller.go @@ -0,0 +1,106 @@ +/* +Copyright IBM Corp. All Rights Reserved. +Copyright 2021 Intel Corporation + +SPDX-License-Identifier: Apache-2.0 +*/ + +package experiment + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "net/http" + "os" + "os/exec" + "path/filepath" + "strings" + + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "google.golang.org/protobuf/proto" +) + +func getEnv(key, defaultValue string) string { + value := os.Getenv(key) + if value == "" { + return defaultValue + } + return value +} + +func getWorkerEndpoint() string { + host := getEnv("WORKER_HOST", "localhost") + port := getEnv("WORKER_PORT", "5000") + + return fmt.Sprintf("http://%s:%s/", host, port) +} + +func toEvidence(attestation []byte) ([]byte, error) { + fpcPath := os.Getenv("FPC_PATH") + if fpcPath == "" { + return nil, fmt.Errorf("FPC_PATH not set") + } + + convertScript := filepath.Join(fpcPath, "common/crypto/attestation-api/conversion/attestation_to_evidence.sh") + cmd := exec.Command(convertScript, string(attestation)) + + if out, err := cmd.Output(); err != nil { + return nil, err + } else { + return []byte(strings.TrimSuffix(string(out), "\n")), nil + } +} + +func GetWorkerCredentials() (*pb.WorkerCredentials, error) { + resp, err := http.Get(getWorkerEndpoint() + "attestation") + if err != nil { + return nil, err + } + + workerCredentialsBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + workerCredentials := &pb.WorkerCredentials{} + err = proto.Unmarshal(workerCredentialsBytes, workerCredentials) + if err != nil { + return nil, err + } + + evidence, err := toEvidence(workerCredentials.Attestation) + if err != nil { + return nil, err + } + + workerCredentials.Evidence = evidence + + return workerCredentials, nil +} + +func ExecuteEvaluationPack(encryptedEvaluationPack *pb.EncryptedEvaluationPack) ([]byte, error) { + encryptedEvaluationPackBytes, err := proto.Marshal(encryptedEvaluationPack) + if err != nil { + return nil, err + } + + fmt.Println("Send evaluation pack to worker!") + resp, err := http.Post(getWorkerEndpoint()+"execute-evaluationpack", "", bytes.NewBuffer(encryptedEvaluationPackBytes)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + bodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + if resp.StatusCode >= 400 { + return nil, errors.New(fmt.Sprintf("Error %d: %s", resp.StatusCode, string(bodyBytes))) + } + + return bodyBytes, nil +} diff --git a/samples/demos/irb/pkg/messages/messages.go b/samples/demos/irb/pkg/messages/messages.go new file mode 100644 index 000000000..59e4d4465 --- /dev/null +++ b/samples/demos/irb/pkg/messages/messages.go @@ -0,0 +1,19 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package messages + +import "encoding/json" + +type ApprovalRequestNotification struct { + Message string + Sender string + ExperimentID string +} + +func (a ApprovalRequestNotification) Serialize() ([]byte, error) { + return json.Marshal(a) +} diff --git a/samples/demos/irb/pkg/protos/irb.pb.go b/samples/demos/irb/pkg/protos/irb.pb.go new file mode 100644 index 000000000..28c827232 --- /dev/null +++ b/samples/demos/irb/pkg/protos/irb.pb.go @@ -0,0 +1,2155 @@ +// Copyright IBM Corp. All Rights Reserved. +// Copyright 2020 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0 +// protoc v3.6.1 +// source: irb.proto + +package protos + +import ( + reflect "reflect" + sync "sync" + + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type Approval_Decision int32 + +const ( + Approval_UNDEFINED Approval_Decision = 0 + Approval_APPROVED Approval_Decision = 1 + Approval_REJECTED Approval_Decision = 2 +) + +// Enum value maps for Approval_Decision. +var ( + Approval_Decision_name = map[int32]string{ + 0: "UNDEFINED", + 1: "APPROVED", + 2: "REJECTED", + } + Approval_Decision_value = map[string]int32{ + "UNDEFINED": 0, + "APPROVED": 1, + "REJECTED": 2, + } +) + +func (x Approval_Decision) Enum() *Approval_Decision { + p := new(Approval_Decision) + *p = x + return p +} + +func (x Approval_Decision) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Approval_Decision) Descriptor() protoreflect.EnumDescriptor { + return file_irb_proto_enumTypes[0].Descriptor() +} + +func (Approval_Decision) Type() protoreflect.EnumType { + return &file_irb_proto_enumTypes[0] +} + +func (x Approval_Decision) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Approval_Decision.Descriptor instead. +func (Approval_Decision) EnumDescriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{12, 0} +} + +type Status_ReturnCode int32 + +const ( + Status_ERROR_UNKNOWN Status_ReturnCode = 0 + Status_OK Status_ReturnCode = 1 +) + +// Enum value maps for Status_ReturnCode. +var ( + Status_ReturnCode_name = map[int32]string{ + 0: "ERROR_UNKNOWN", + 1: "OK", + } + Status_ReturnCode_value = map[string]int32{ + "ERROR_UNKNOWN": 0, + "OK": 1, + } +) + +func (x Status_ReturnCode) Enum() *Status_ReturnCode { + p := new(Status_ReturnCode) + *p = x + return p +} + +func (x Status_ReturnCode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Status_ReturnCode) Descriptor() protoreflect.EnumDescriptor { + return file_irb_proto_enumTypes[1].Descriptor() +} + +func (Status_ReturnCode) Type() protoreflect.EnumType { + return &file_irb_proto_enumTypes[1] +} + +func (x Status_ReturnCode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Status_ReturnCode.Descriptor instead. +func (Status_ReturnCode) EnumDescriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{23, 0} +} + +type StudyDetailsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StudyId string `protobuf:"bytes,1,opt,name=study_id,json=studyId,proto3" json:"study_id,omitempty"` +} + +func (x *StudyDetailsRequest) Reset() { + *x = StudyDetailsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StudyDetailsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StudyDetailsRequest) ProtoMessage() {} + +func (x *StudyDetailsRequest) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StudyDetailsRequest.ProtoReflect.Descriptor instead. +func (*StudyDetailsRequest) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{0} +} + +func (x *StudyDetailsRequest) GetStudyId() string { + if x != nil { + return x.StudyId + } + return "" +} + +type StudyDetailsMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StudyId string `protobuf:"bytes,1,opt,name=study_id,json=studyId,proto3" json:"study_id,omitempty"` + Metadata string `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"` + UserIdentities []*Identity `protobuf:"bytes,3,rep,name=user_identities,json=userIdentities,proto3" json:"user_identities,omitempty"` +} + +func (x *StudyDetailsMessage) Reset() { + *x = StudyDetailsMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StudyDetailsMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StudyDetailsMessage) ProtoMessage() {} + +func (x *StudyDetailsMessage) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StudyDetailsMessage.ProtoReflect.Descriptor instead. +func (*StudyDetailsMessage) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{1} +} + +func (x *StudyDetailsMessage) GetStudyId() string { + if x != nil { + return x.StudyId + } + return "" +} + +func (x *StudyDetailsMessage) GetMetadata() string { + if x != nil { + return x.Metadata + } + return "" +} + +func (x *StudyDetailsMessage) GetUserIdentities() []*Identity { + if x != nil { + return x.UserIdentities + } + return nil +} + +type StudyDetailsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StudyDetailsMessage []byte `protobuf:"bytes,1,opt,name=study_details_message,json=studyDetailsMessage,proto3" json:"study_details_message,omitempty"` + // signed by Study Approval Service (SAS) + // used to be verified by EAS when new study is created + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` + Status *Status `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *StudyDetailsResponse) Reset() { + *x = StudyDetailsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StudyDetailsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StudyDetailsResponse) ProtoMessage() {} + +func (x *StudyDetailsResponse) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StudyDetailsResponse.ProtoReflect.Descriptor instead. +func (*StudyDetailsResponse) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{2} +} + +func (x *StudyDetailsResponse) GetStudyDetailsMessage() []byte { + if x != nil { + return x.StudyDetailsMessage + } + return nil +} + +func (x *StudyDetailsResponse) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +func (x *StudyDetailsResponse) GetStatus() *Status { + if x != nil { + return x.Status + } + return nil +} + +type RegisterDataRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Participant *Identity `protobuf:"bytes,1,opt,name=participant,proto3" json:"participant,omitempty"` + DecryptionKey []byte `protobuf:"bytes,2,opt,name=decryption_key,json=decryptionKey,proto3" json:"decryption_key,omitempty"` + DataHandler string `protobuf:"bytes,3,opt,name=data_handler,json=dataHandler,proto3" json:"data_handler,omitempty"` + StudyId string `protobuf:"bytes,4,opt,name=study_id,json=studyId,proto3" json:"study_id,omitempty"` +} + +func (x *RegisterDataRequest) Reset() { + *x = RegisterDataRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterDataRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterDataRequest) ProtoMessage() {} + +func (x *RegisterDataRequest) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterDataRequest.ProtoReflect.Descriptor instead. +func (*RegisterDataRequest) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{3} +} + +func (x *RegisterDataRequest) GetParticipant() *Identity { + if x != nil { + return x.Participant + } + return nil +} + +func (x *RegisterDataRequest) GetDecryptionKey() []byte { + if x != nil { + return x.DecryptionKey + } + return nil +} + +func (x *RegisterDataRequest) GetDataHandler() string { + if x != nil { + return x.DataHandler + } + return "" +} + +func (x *RegisterDataRequest) GetStudyId() string { + if x != nil { + return x.StudyId + } + return "" +} + +type SubmitStudyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Details *StudyDetailsResponse `protobuf:"bytes,1,opt,name=details,proto3" json:"details,omitempty"` +} + +func (x *SubmitStudyRequest) Reset() { + *x = SubmitStudyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubmitStudyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubmitStudyRequest) ProtoMessage() {} + +func (x *SubmitStudyRequest) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubmitStudyRequest.ProtoReflect.Descriptor instead. +func (*SubmitStudyRequest) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{4} +} + +func (x *SubmitStudyRequest) GetDetails() *StudyDetailsResponse { + if x != nil { + return x.Details + } + return nil +} + +type NewExperimentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Experiment *Experiment `protobuf:"bytes,1,opt,name=experiment,proto3" json:"experiment,omitempty"` +} + +func (x *NewExperimentRequest) Reset() { + *x = NewExperimentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NewExperimentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NewExperimentRequest) ProtoMessage() {} + +func (x *NewExperimentRequest) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NewExperimentRequest.ProtoReflect.Descriptor instead. +func (*NewExperimentRequest) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{5} +} + +func (x *NewExperimentRequest) GetExperiment() *Experiment { + if x != nil { + return x.Experiment + } + return nil +} + +type GetExperimentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ExperimentId string `protobuf:"bytes,1,opt,name=experiment_id,json=experimentId,proto3" json:"experiment_id,omitempty"` +} + +func (x *GetExperimentRequest) Reset() { + *x = GetExperimentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetExperimentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetExperimentRequest) ProtoMessage() {} + +func (x *GetExperimentRequest) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetExperimentRequest.ProtoReflect.Descriptor instead. +func (*GetExperimentRequest) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{6} +} + +func (x *GetExperimentRequest) GetExperimentId() string { + if x != nil { + return x.ExperimentId + } + return "" +} + +type GetExperimentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ExperimentProposal *ExperimentProposal `protobuf:"bytes,1,opt,name=experiment_proposal,json=experimentProposal,proto3" json:"experiment_proposal,omitempty"` + Status *Status `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *GetExperimentResponse) Reset() { + *x = GetExperimentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetExperimentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetExperimentResponse) ProtoMessage() {} + +func (x *GetExperimentResponse) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetExperimentResponse.ProtoReflect.Descriptor instead. +func (*GetExperimentResponse) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{7} +} + +func (x *GetExperimentResponse) GetExperimentProposal() *ExperimentProposal { + if x != nil { + return x.ExperimentProposal + } + return nil +} + +func (x *GetExperimentResponse) GetStatus() *Status { + if x != nil { + return x.Status + } + return nil +} + +type WorkerCredentials struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IdentityBytes []byte `protobuf:"bytes,1,opt,name=identity_bytes,json=identityBytes,proto3" json:"identity_bytes,omitempty"` + Attestation []byte `protobuf:"bytes,2,opt,name=attestation,proto3" json:"attestation,omitempty"` + Evidence []byte `protobuf:"bytes,3,opt,name=evidence,proto3" json:"evidence,omitempty"` +} + +func (x *WorkerCredentials) Reset() { + *x = WorkerCredentials{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WorkerCredentials) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkerCredentials) ProtoMessage() {} + +func (x *WorkerCredentials) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WorkerCredentials.ProtoReflect.Descriptor instead. +func (*WorkerCredentials) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{8} +} + +func (x *WorkerCredentials) GetIdentityBytes() []byte { + if x != nil { + return x.IdentityBytes + } + return nil +} + +func (x *WorkerCredentials) GetAttestation() []byte { + if x != nil { + return x.Attestation + } + return nil +} + +func (x *WorkerCredentials) GetEvidence() []byte { + if x != nil { + return x.Evidence + } + return nil +} + +type ExperimentProposal struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StudyId string `protobuf:"bytes,1,opt,name=study_id,json=studyId,proto3" json:"study_id,omitempty"` + ExperimentId string `protobuf:"bytes,2,opt,name=experiment_id,json=experimentId,proto3" json:"experiment_id,omitempty"` + Mrenclave string `protobuf:"bytes,3,opt,name=mrenclave,proto3" json:"mrenclave,omitempty"` + Metadata string `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` + WorkerCredentials *WorkerCredentials `protobuf:"bytes,5,opt,name=worker_credentials,json=workerCredentials,proto3" json:"worker_credentials,omitempty"` +} + +func (x *ExperimentProposal) Reset() { + *x = ExperimentProposal{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExperimentProposal) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExperimentProposal) ProtoMessage() {} + +func (x *ExperimentProposal) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExperimentProposal.ProtoReflect.Descriptor instead. +func (*ExperimentProposal) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{9} +} + +func (x *ExperimentProposal) GetStudyId() string { + if x != nil { + return x.StudyId + } + return "" +} + +func (x *ExperimentProposal) GetExperimentId() string { + if x != nil { + return x.ExperimentId + } + return "" +} + +func (x *ExperimentProposal) GetMrenclave() string { + if x != nil { + return x.Mrenclave + } + return "" +} + +func (x *ExperimentProposal) GetMetadata() string { + if x != nil { + return x.Metadata + } + return "" +} + +func (x *ExperimentProposal) GetWorkerCredentials() *WorkerCredentials { + if x != nil { + return x.WorkerCredentials + } + return nil +} + +type Experiment struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // we keep bytes + ExperimentProposal []byte `protobuf:"bytes,1,opt,name=experiment_proposal,json=experimentProposal,proto3" json:"experiment_proposal,omitempty"` + Approval *Approval `protobuf:"bytes,2,opt,name=approval,proto3" json:"approval,omitempty"` +} + +func (x *Experiment) Reset() { + *x = Experiment{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Experiment) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Experiment) ProtoMessage() {} + +func (x *Experiment) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Experiment.ProtoReflect.Descriptor instead. +func (*Experiment) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{10} +} + +func (x *Experiment) GetExperimentProposal() []byte { + if x != nil { + return x.ExperimentProposal + } + return nil +} + +func (x *Experiment) GetApproval() *Approval { + if x != nil { + return x.Approval + } + return nil +} + +type ApprovalRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Approval *Approval `protobuf:"bytes,1,opt,name=approval,proto3" json:"approval,omitempty"` +} + +func (x *ApprovalRequest) Reset() { + *x = ApprovalRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApprovalRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApprovalRequest) ProtoMessage() {} + +func (x *ApprovalRequest) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApprovalRequest.ProtoReflect.Descriptor instead. +func (*ApprovalRequest) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{11} +} + +func (x *ApprovalRequest) GetApproval() *Approval { + if x != nil { + return x.Approval + } + return nil +} + +type Approval struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ExperimentId string `protobuf:"bytes,1,opt,name=experiment_id,json=experimentId,proto3" json:"experiment_id,omitempty"` + // serialized Experiment Proposal + ExperimentProposal []byte `protobuf:"bytes,2,opt,name=experiment_proposal,json=experimentProposal,proto3" json:"experiment_proposal,omitempty"` + Decision Approval_Decision `protobuf:"varint,3,opt,name=decision,proto3,enum=Approval_Decision" json:"decision,omitempty"` + Approver *Identity `protobuf:"bytes,4,opt,name=approver,proto3" json:"approver,omitempty"` +} + +func (x *Approval) Reset() { + *x = Approval{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Approval) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Approval) ProtoMessage() {} + +func (x *Approval) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Approval.ProtoReflect.Descriptor instead. +func (*Approval) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{12} +} + +func (x *Approval) GetExperimentId() string { + if x != nil { + return x.ExperimentId + } + return "" +} + +func (x *Approval) GetExperimentProposal() []byte { + if x != nil { + return x.ExperimentProposal + } + return nil +} + +func (x *Approval) GetDecision() Approval_Decision { + if x != nil { + return x.Decision + } + return Approval_UNDEFINED +} + +func (x *Approval) GetApprover() *Identity { + if x != nil { + return x.Approver + } + return nil +} + +type SignedApprovalMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Approval []byte `protobuf:"bytes,1,opt,name=approval,proto3" json:"approval,omitempty"` + Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` +} + +func (x *SignedApprovalMessage) Reset() { + *x = SignedApprovalMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SignedApprovalMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SignedApprovalMessage) ProtoMessage() {} + +func (x *SignedApprovalMessage) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SignedApprovalMessage.ProtoReflect.Descriptor instead. +func (*SignedApprovalMessage) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{13} +} + +func (x *SignedApprovalMessage) GetApproval() []byte { + if x != nil { + return x.Approval + } + return nil +} + +func (x *SignedApprovalMessage) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + +type EvaluationPackRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StudyId string `protobuf:"bytes,1,opt,name=study_id,json=studyId,proto3" json:"study_id,omitempty"` + ExperimentId string `protobuf:"bytes,2,opt,name=experiment_id,json=experimentId,proto3" json:"experiment_id,omitempty"` +} + +func (x *EvaluationPackRequest) Reset() { + *x = EvaluationPackRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EvaluationPackRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EvaluationPackRequest) ProtoMessage() {} + +func (x *EvaluationPackRequest) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EvaluationPackRequest.ProtoReflect.Descriptor instead. +func (*EvaluationPackRequest) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{14} +} + +func (x *EvaluationPackRequest) GetStudyId() string { + if x != nil { + return x.StudyId + } + return "" +} + +func (x *EvaluationPackRequest) GetExperimentId() string { + if x != nil { + return x.ExperimentId + } + return "" +} + +type EncryptedEvaluationPack struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EncryptedEncryptionKey []byte `protobuf:"bytes,1,opt,name=encrypted_encryption_key,json=encryptedEncryptionKey,proto3" json:"encrypted_encryption_key,omitempty"` + // this is ciphertext of a serialized EvaluationPack msg + EncryptedEvaluationpack []byte `protobuf:"bytes,2,opt,name=encrypted_evaluationpack,json=encryptedEvaluationpack,proto3" json:"encrypted_evaluationpack,omitempty"` +} + +func (x *EncryptedEvaluationPack) Reset() { + *x = EncryptedEvaluationPack{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EncryptedEvaluationPack) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EncryptedEvaluationPack) ProtoMessage() {} + +func (x *EncryptedEvaluationPack) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EncryptedEvaluationPack.ProtoReflect.Descriptor instead. +func (*EncryptedEvaluationPack) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{15} +} + +func (x *EncryptedEvaluationPack) GetEncryptedEncryptionKey() []byte { + if x != nil { + return x.EncryptedEncryptionKey + } + return nil +} + +func (x *EncryptedEvaluationPack) GetEncryptedEvaluationpack() []byte { + if x != nil { + return x.EncryptedEvaluationpack + } + return nil +} + +type EvaluationPackMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item []*EvaluationPackItem `protobuf:"bytes,1,rep,name=item,proto3" json:"item,omitempty"` + RegisteredData []*RegisterDataRequest `protobuf:"bytes,2,rep,name=registered_data,json=registeredData,proto3" json:"registered_data,omitempty"` +} + +func (x *EvaluationPackMessage) Reset() { + *x = EvaluationPackMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EvaluationPackMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EvaluationPackMessage) ProtoMessage() {} + +func (x *EvaluationPackMessage) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EvaluationPackMessage.ProtoReflect.Descriptor instead. +func (*EvaluationPackMessage) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{16} +} + +func (x *EvaluationPackMessage) GetItem() []*EvaluationPackItem { + if x != nil { + return x.Item + } + return nil +} + +func (x *EvaluationPackMessage) GetRegisteredData() []*RegisterDataRequest { + if x != nil { + return x.RegisteredData + } + return nil +} + +type EvaluationPackItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DecryptionKey []byte `protobuf:"bytes,1,opt,name=decryption_key,json=decryptionKey,proto3" json:"decryption_key,omitempty"` + DataHandler string `protobuf:"bytes,2,opt,name=data_handler,json=dataHandler,proto3" json:"data_handler,omitempty"` +} + +func (x *EvaluationPackItem) Reset() { + *x = EvaluationPackItem{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EvaluationPackItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EvaluationPackItem) ProtoMessage() {} + +func (x *EvaluationPackItem) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EvaluationPackItem.ProtoReflect.Descriptor instead. +func (*EvaluationPackItem) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{17} +} + +func (x *EvaluationPackItem) GetDecryptionKey() []byte { + if x != nil { + return x.DecryptionKey + } + return nil +} + +func (x *EvaluationPackItem) GetDataHandler() string { + if x != nil { + return x.DataHandler + } + return "" +} + +// note that the State message is just here to represent the KVS accessable via putState and getState functions within FPC +type State struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // as key we use study id + State map[string]*Study `protobuf:"bytes,1,rep,name=state,proto3" json:"state,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // as key we use an identity.uuid + RegisteredData map[string]*Data `protobuf:"bytes,2,rep,name=registered_data,json=registeredData,proto3" json:"registered_data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *State) Reset() { + *x = State{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *State) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*State) ProtoMessage() {} + +func (x *State) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use State.ProtoReflect.Descriptor instead. +func (*State) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{18} +} + +func (x *State) GetState() map[string]*Study { + if x != nil { + return x.State + } + return nil +} + +func (x *State) GetRegisteredData() map[string]*Data { + if x != nil { + return x.RegisteredData + } + return nil +} + +type Study struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StudyId string `protobuf:"bytes,1,opt,name=study_id,json=studyId,proto3" json:"study_id,omitempty"` + Participant []*Identity `protobuf:"bytes,2,rep,name=participant,proto3" json:"participant,omitempty"` + Experiment []*Experiment `protobuf:"bytes,3,rep,name=experiment,proto3" json:"experiment,omitempty"` +} + +func (x *Study) Reset() { + *x = Study{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Study) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Study) ProtoMessage() {} + +func (x *Study) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Study.ProtoReflect.Descriptor instead. +func (*Study) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{19} +} + +func (x *Study) GetStudyId() string { + if x != nil { + return x.StudyId + } + return "" +} + +func (x *Study) GetParticipant() []*Identity { + if x != nil { + return x.Participant + } + return nil +} + +func (x *Study) GetExperiment() []*Experiment { + if x != nil { + return x.Experiment + } + return nil +} + +type Data struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Participant *Identity `protobuf:"bytes,1,opt,name=participant,proto3" json:"participant,omitempty"` + DecryptionKey []byte `protobuf:"bytes,2,opt,name=decryption_key,json=decryptionKey,proto3" json:"decryption_key,omitempty"` + DataHandler string `protobuf:"bytes,3,opt,name=data_handler,json=dataHandler,proto3" json:"data_handler,omitempty"` +} + +func (x *Data) Reset() { + *x = Data{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Data) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Data) ProtoMessage() {} + +func (x *Data) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Data.ProtoReflect.Descriptor instead. +func (*Data) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{20} +} + +func (x *Data) GetParticipant() *Identity { + if x != nil { + return x.Participant + } + return nil +} + +func (x *Data) GetDecryptionKey() []byte { + if x != nil { + return x.DecryptionKey + } + return nil +} + +func (x *Data) GetDataHandler() string { + if x != nil { + return x.DataHandler + } + return "" +} + +type ExecuteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ExperimentId string `protobuf:"bytes,1,opt,name=experiment_id,json=experimentId,proto3" json:"experiment_id,omitempty"` + EncryptedEvaluationPack []byte `protobuf:"bytes,2,opt,name=encrypted_evaluationPack,json=encryptedEvaluationPack,proto3" json:"encrypted_evaluationPack,omitempty"` +} + +func (x *ExecuteRequest) Reset() { + *x = ExecuteRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExecuteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecuteRequest) ProtoMessage() {} + +func (x *ExecuteRequest) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecuteRequest.ProtoReflect.Descriptor instead. +func (*ExecuteRequest) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{21} +} + +func (x *ExecuteRequest) GetExperimentId() string { + if x != nil { + return x.ExperimentId + } + return "" +} + +func (x *ExecuteRequest) GetEncryptedEvaluationPack() []byte { + if x != nil { + return x.EncryptedEvaluationPack + } + return nil +} + +// Common messages +type Identity struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` + PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + PublicEncryptionKey []byte `protobuf:"bytes,3,opt,name=public_encryption_key,json=publicEncryptionKey,proto3" json:"public_encryption_key,omitempty"` +} + +func (x *Identity) Reset() { + *x = Identity{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Identity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Identity) ProtoMessage() {} + +func (x *Identity) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Identity.ProtoReflect.Descriptor instead. +func (*Identity) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{22} +} + +func (x *Identity) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +func (x *Identity) GetPublicKey() []byte { + if x != nil { + return x.PublicKey + } + return nil +} + +func (x *Identity) GetPublicEncryptionKey() []byte { + if x != nil { + return x.PublicEncryptionKey + } + return nil +} + +type Status struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` + ReturnCode Status_ReturnCode `protobuf:"varint,2,opt,name=return_code,json=returnCode,proto3,enum=Status_ReturnCode" json:"return_code,omitempty"` +} + +func (x *Status) Reset() { + *x = Status{} + if protoimpl.UnsafeEnabled { + mi := &file_irb_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Status) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Status) ProtoMessage() {} + +func (x *Status) ProtoReflect() protoreflect.Message { + mi := &file_irb_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Status.ProtoReflect.Descriptor instead. +func (*Status) Descriptor() ([]byte, []int) { + return file_irb_proto_rawDescGZIP(), []int{23} +} + +func (x *Status) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +func (x *Status) GetReturnCode() Status_ReturnCode { + if x != nil { + return x.ReturnCode + } + return Status_ERROR_UNKNOWN +} + +var File_irb_proto protoreflect.FileDescriptor + +var file_irb_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x69, 0x72, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x30, 0x0a, 0x13, 0x53, + 0x74, 0x75, 0x64, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x74, 0x75, 0x64, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x74, 0x75, 0x64, 0x79, 0x49, 0x64, 0x22, 0x80, 0x01, + 0x0a, 0x13, 0x53, 0x74, 0x75, 0x64, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x74, 0x75, 0x64, 0x79, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x74, 0x75, 0x64, 0x79, 0x49, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x0f, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x22, 0x89, 0x01, 0x0a, 0x14, 0x53, 0x74, 0x75, 0x64, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x73, 0x74, 0x75, + 0x64, 0x79, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x73, 0x74, 0x75, 0x64, 0x79, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1f, 0x0a, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xa7, 0x01, 0x0a, + 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x61, 0x74, 0x61, + 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x64, 0x61, 0x74, 0x61, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x73, + 0x74, 0x75, 0x64, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, + 0x74, 0x75, 0x64, 0x79, 0x49, 0x64, 0x22, 0x45, 0x0a, 0x12, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x53, 0x74, 0x75, 0x64, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, + 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x53, 0x74, 0x75, 0x64, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x43, 0x0a, + 0x14, 0x4e, 0x65, 0x77, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, + 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x45, 0x78, 0x70, 0x65, + 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, + 0x6e, 0x74, 0x22, 0x3b, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, + 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, + 0x7e, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x13, 0x65, 0x78, 0x70, 0x65, + 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, + 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, 0x12, 0x65, 0x78, 0x70, 0x65, + 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x1f, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, + 0x78, 0x0a, 0x11, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x61, + 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0b, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, + 0x08, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x08, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x22, 0xd1, 0x01, 0x0a, 0x12, 0x45, 0x78, + 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, + 0x12, 0x19, 0x0a, 0x08, 0x73, 0x74, 0x75, 0x64, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x73, 0x74, 0x75, 0x64, 0x79, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x65, + 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x72, 0x65, 0x6e, 0x63, 0x6c, 0x61, 0x76, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x72, 0x65, 0x6e, 0x63, 0x6c, 0x61, 0x76, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x12, 0x77, 0x6f, + 0x72, 0x6b, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x43, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, + 0x65, 0x72, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x64, 0x0a, + 0x0a, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x13, 0x65, + 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, + 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x25, 0x0a, 0x08, + 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, + 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x52, 0x08, 0x61, 0x70, 0x70, 0x72, 0x6f, + 0x76, 0x61, 0x6c, 0x22, 0x38, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, + 0x76, 0x61, 0x6c, 0x52, 0x08, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x22, 0xee, 0x01, + 0x0a, 0x08, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, + 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, + 0x2f, 0x0a, 0x13, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, + 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x65, 0x78, + 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, + 0x12, 0x2e, 0x0a, 0x08, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x2e, 0x44, 0x65, + 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x64, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x25, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x61, + 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x72, 0x22, 0x35, 0x0a, 0x08, 0x44, 0x65, 0x63, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x01, + 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x4a, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x22, 0x51, + 0x0a, 0x15, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x70, 0x70, 0x72, 0x6f, + 0x76, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x61, 0x70, 0x70, 0x72, 0x6f, + 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x22, 0x57, 0x0a, 0x15, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, + 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x74, + 0x75, 0x64, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x74, + 0x75, 0x64, 0x79, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, + 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, + 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x8e, 0x01, 0x0a, 0x17, 0x45, + 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, 0x12, 0x38, 0x0a, 0x18, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x16, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x65, 0x64, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, + 0x12, 0x39, 0x0a, 0x18, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x76, + 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x45, 0x76, 0x61, + 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x22, 0x7f, 0x0a, 0x15, 0x45, + 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x27, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, + 0x61, 0x63, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3d, 0x0a, + 0x0f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0e, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x22, 0x5e, 0x0a, 0x12, + 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, 0x49, 0x74, + 0x65, 0x6d, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x61, 0x74, + 0x61, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x61, 0x74, 0x61, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x22, 0x81, 0x02, 0x0a, + 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x43, 0x0a, 0x0f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, + 0x44, 0x61, 0x74, 0x61, 0x1a, 0x40, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x48, 0x0a, 0x13, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x1b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x05, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x7c, 0x0a, 0x05, 0x53, 0x74, 0x75, 0x64, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x74, 0x75, + 0x64, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x74, 0x75, + 0x64, 0x79, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, + 0x74, 0x12, 0x2b, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, + 0x6e, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x7d, + 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, + 0x69, 0x70, 0x61, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x22, 0x70, 0x0a, + 0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x23, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, + 0x6e, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x18, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, + 0x64, 0x5f, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x17, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, + 0x64, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, 0x22, + 0x71, 0x0a, 0x08, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x75, + 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, + 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x32, + 0x0a, 0x15, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x70, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, + 0x65, 0x79, 0x22, 0x78, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x10, 0x0a, 0x03, + 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x33, + 0x0a, 0x0b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x52, 0x65, 0x74, + 0x75, 0x72, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x43, + 0x6f, 0x64, 0x65, 0x22, 0x27, 0x0a, 0x0a, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x43, 0x6f, 0x64, + 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, + 0x57, 0x4e, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x01, 0x32, 0x58, 0x0a, 0x14, + 0x53, 0x74, 0x75, 0x64, 0x79, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x40, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x74, 0x75, 0x64, 0x79, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x14, 0x2e, 0x53, 0x74, 0x75, 0x64, 0x79, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, + 0x53, 0x74, 0x75, 0x64, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x32, 0xf9, 0x02, 0x0a, 0x19, 0x45, 0x78, 0x70, 0x65, 0x72, + 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x2f, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x14, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x07, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x53, 0x74, 0x75, 0x64, 0x79, 0x12, 0x13, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x53, + 0x74, 0x75, 0x64, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x07, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x45, 0x78, 0x70, + 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x15, 0x2e, 0x4e, 0x65, 0x77, 0x45, 0x78, 0x70, + 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x07, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x15, 0x47, 0x65, 0x74, + 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, + 0x61, 0x6c, 0x12, 0x15, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x47, 0x65, 0x74, 0x45, + 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x30, 0x0a, 0x11, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x45, 0x78, + 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, + 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x07, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x15, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, 0x12, 0x16, + 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x65, 0x64, 0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x63, 0x6b, + 0x22, 0x00, 0x32, 0x2f, 0x0a, 0x06, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x07, + 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x12, 0x0f, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x07, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x22, 0x00, 0x42, 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2f, 0x66, 0x61, + 0x62, 0x72, 0x69, 0x63, 0x2d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x2d, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x2f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x64, + 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x69, 0x72, 0x62, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_irb_proto_rawDescOnce sync.Once + file_irb_proto_rawDescData = file_irb_proto_rawDesc +) + +func file_irb_proto_rawDescGZIP() []byte { + file_irb_proto_rawDescOnce.Do(func() { + file_irb_proto_rawDescData = protoimpl.X.CompressGZIP(file_irb_proto_rawDescData) + }) + return file_irb_proto_rawDescData +} + +var file_irb_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_irb_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_irb_proto_goTypes = []interface{}{ + (Approval_Decision)(0), // 0: Approval.Decision + (Status_ReturnCode)(0), // 1: Status.ReturnCode + (*StudyDetailsRequest)(nil), // 2: StudyDetailsRequest + (*StudyDetailsMessage)(nil), // 3: StudyDetailsMessage + (*StudyDetailsResponse)(nil), // 4: StudyDetailsResponse + (*RegisterDataRequest)(nil), // 5: RegisterDataRequest + (*SubmitStudyRequest)(nil), // 6: SubmitStudyRequest + (*NewExperimentRequest)(nil), // 7: NewExperimentRequest + (*GetExperimentRequest)(nil), // 8: GetExperimentRequest + (*GetExperimentResponse)(nil), // 9: GetExperimentResponse + (*WorkerCredentials)(nil), // 10: WorkerCredentials + (*ExperimentProposal)(nil), // 11: ExperimentProposal + (*Experiment)(nil), // 12: Experiment + (*ApprovalRequest)(nil), // 13: ApprovalRequest + (*Approval)(nil), // 14: Approval + (*SignedApprovalMessage)(nil), // 15: SignedApprovalMessage + (*EvaluationPackRequest)(nil), // 16: EvaluationPackRequest + (*EncryptedEvaluationPack)(nil), // 17: EncryptedEvaluationPack + (*EvaluationPackMessage)(nil), // 18: EvaluationPackMessage + (*EvaluationPackItem)(nil), // 19: EvaluationPackItem + (*State)(nil), // 20: State + (*Study)(nil), // 21: Study + (*Data)(nil), // 22: Data + (*ExecuteRequest)(nil), // 23: ExecuteRequest + (*Identity)(nil), // 24: Identity + (*Status)(nil), // 25: Status + nil, // 26: State.StateEntry + nil, // 27: State.RegisteredDataEntry +} +var file_irb_proto_depIdxs = []int32{ + 24, // 0: StudyDetailsMessage.user_identities:type_name -> Identity + 25, // 1: StudyDetailsResponse.status:type_name -> Status + 24, // 2: RegisterDataRequest.participant:type_name -> Identity + 4, // 3: SubmitStudyRequest.details:type_name -> StudyDetailsResponse + 12, // 4: NewExperimentRequest.experiment:type_name -> Experiment + 11, // 5: GetExperimentResponse.experiment_proposal:type_name -> ExperimentProposal + 25, // 6: GetExperimentResponse.status:type_name -> Status + 10, // 7: ExperimentProposal.worker_credentials:type_name -> WorkerCredentials + 14, // 8: Experiment.approval:type_name -> Approval + 14, // 9: ApprovalRequest.approval:type_name -> Approval + 0, // 10: Approval.decision:type_name -> Approval.Decision + 24, // 11: Approval.approver:type_name -> Identity + 19, // 12: EvaluationPackMessage.item:type_name -> EvaluationPackItem + 5, // 13: EvaluationPackMessage.registered_data:type_name -> RegisterDataRequest + 26, // 14: State.state:type_name -> State.StateEntry + 27, // 15: State.registered_data:type_name -> State.RegisteredDataEntry + 24, // 16: Study.participant:type_name -> Identity + 12, // 17: Study.experiment:type_name -> Experiment + 24, // 18: Data.participant:type_name -> Identity + 1, // 19: Status.return_code:type_name -> Status.ReturnCode + 21, // 20: State.StateEntry.value:type_name -> Study + 22, // 21: State.RegisteredDataEntry.value:type_name -> Data + 2, // 22: StudyApprovalService.GetStudyDetails:input_type -> StudyDetailsRequest + 5, // 23: ExperimentApprovalService.RegisterData:input_type -> RegisterDataRequest + 6, // 24: ExperimentApprovalService.CreateStudy:input_type -> SubmitStudyRequest + 7, // 25: ExperimentApprovalService.SubmitExperiment:input_type -> NewExperimentRequest + 8, // 26: ExperimentApprovalService.GetExperimentProposal:input_type -> GetExperimentRequest + 13, // 27: ExperimentApprovalService.ApproveExperiment:input_type -> ApprovalRequest + 16, // 28: ExperimentApprovalService.RequestEvaluationPack:input_type -> EvaluationPackRequest + 23, // 29: Worker.Execute:input_type -> ExecuteRequest + 4, // 30: StudyApprovalService.GetStudyDetails:output_type -> StudyDetailsResponse + 25, // 31: ExperimentApprovalService.RegisterData:output_type -> Status + 25, // 32: ExperimentApprovalService.CreateStudy:output_type -> Status + 25, // 33: ExperimentApprovalService.SubmitExperiment:output_type -> Status + 9, // 34: ExperimentApprovalService.GetExperimentProposal:output_type -> GetExperimentResponse + 25, // 35: ExperimentApprovalService.ApproveExperiment:output_type -> Status + 17, // 36: ExperimentApprovalService.RequestEvaluationPack:output_type -> EncryptedEvaluationPack + 25, // 37: Worker.Execute:output_type -> Status + 30, // [30:38] is the sub-list for method output_type + 22, // [22:30] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name +} + +func init() { file_irb_proto_init() } +func file_irb_proto_init() { + if File_irb_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_irb_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StudyDetailsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StudyDetailsMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StudyDetailsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterDataRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubmitStudyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NewExperimentRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetExperimentRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetExperimentResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WorkerCredentials); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExperimentProposal); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Experiment); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApprovalRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Approval); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SignedApprovalMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EvaluationPackRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EncryptedEvaluationPack); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EvaluationPackMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EvaluationPackItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*State); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Study); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Data); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExecuteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Identity); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_irb_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Status); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_irb_proto_rawDesc, + NumEnums: 2, + NumMessages: 26, + NumExtensions: 0, + NumServices: 3, + }, + GoTypes: file_irb_proto_goTypes, + DependencyIndexes: file_irb_proto_depIdxs, + EnumInfos: file_irb_proto_enumTypes, + MessageInfos: file_irb_proto_msgTypes, + }.Build() + File_irb_proto = out.File + file_irb_proto_rawDesc = nil + file_irb_proto_goTypes = nil + file_irb_proto_depIdxs = nil +} diff --git a/samples/demos/irb/pkg/storage/client.go b/samples/demos/irb/pkg/storage/client.go new file mode 100644 index 000000000..716d8e17f --- /dev/null +++ b/samples/demos/irb/pkg/storage/client.go @@ -0,0 +1,57 @@ +/* + Copyright IBM Corp. All Rights Reserved. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package storage + +import ( + "crypto/sha256" + "encoding/base64" + "fmt" + "os" + "strconv" + + "github.com/go-redis/redis" +) + +const DefaultRedisPort = 6379 + +func getEnv(key, defaultValue string) string { + value := os.Getenv(key) + if value == "" { + return defaultValue + } + return value +} + +type Client struct { + redis *redis.Client +} + +func NewClient() *Client { + host := getEnv("REDIS_HOST", "localhost") + port := getEnv("REDIS_PORT", strconv.Itoa(DefaultRedisPort)) + password := getEnv("REDIS_PASSWORD", "") + + return &Client{redis: redis.NewClient(&redis.Options{ + Addr: host + ":" + port, + Password: password, // no password set + DB: 0, // use default DB + })} +} + +func (c *Client) Upload(data []byte) (string, error) { + hashedContent := sha256.Sum256(data) + encodedContent := base64.StdEncoding.EncodeToString(data) + key := base64.StdEncoding.EncodeToString(hashedContent[:]) + + if err := c.redis.Set(key, encodedContent, 0).Err(); err != nil { + return "", err + } + + fmt.Printf("PatientData successfully uploaded to storage service!\nkey: %s\nvalue: %s\n", key, encodedContent) + + return key, nil +} diff --git a/samples/demos/irb/pkg/users/user.go b/samples/demos/irb/pkg/users/user.go new file mode 100644 index 000000000..ea1a0b130 --- /dev/null +++ b/samples/demos/irb/pkg/users/user.go @@ -0,0 +1,82 @@ +/* + Copyright 2021 Intel Corporation + + SPDX-License-Identifier: Apache-2.0 +*/ + +package users + +import ( + "io/ioutil" + "os" + "path/filepath" + + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/crypto" +) + +var usersDir string = "users" +var uuidFileName string = "uuid.txt" +var publicKeyFileName string = "publickey.txt" +var privateKeyFileName string = "privatekey.txt" + +func CreateUser(userName string) error { + err := os.MkdirAll(filepath.Join(usersDir, userName), 0755) + if err != nil { + return err + } + + err = ioutil.WriteFile(filepath.Join(usersDir, userName, uuidFileName), []byte(userName), 0755) + if err != nil { + return err + } + + cp := crypto.NewGoCrypto() + vk, sk, err := cp.NewECDSAKeys() + if err != nil { + return err + } + + err = ioutil.WriteFile(filepath.Join(usersDir, userName, publicKeyFileName), vk, 0755) + if err != nil { + return err + } + err = ioutil.WriteFile(filepath.Join(usersDir, userName, privateKeyFileName), sk, 0755) + if err != nil { + return err + } + + return nil +} + +func LoadUser(userName string) (uuid []byte, sk []byte, vk []byte, e error) { + sk, err := ioutil.ReadFile(filepath.Join(usersDir, userName, privateKeyFileName)) + if err != nil { + return nil, nil, nil, err + } + + vk, err = ioutil.ReadFile(filepath.Join(usersDir, userName, publicKeyFileName)) + if err != nil { + return nil, nil, nil, err + } + + uuid, err = ioutil.ReadFile(filepath.Join(usersDir, userName, uuidFileName)) + if err != nil { + return nil, nil, nil, err + } + + return uuid, sk, vk, nil +} + +func LoadOrCreateUser(userName string) (uuid []byte, sk []byte, vk []byte, e error) { + a, b, c, err := LoadUser(userName) + if err == nil { + return a, b, c, nil + } + + err = CreateUser(userName) + if err != nil { + return nil, nil, nil, err + } + + return LoadUser(userName) +} diff --git a/samples/demos/irb/pkg/utils/utils.go b/samples/demos/irb/pkg/utils/utils.go new file mode 100644 index 000000000..e19b6c1fc --- /dev/null +++ b/samples/demos/irb/pkg/utils/utils.go @@ -0,0 +1,51 @@ +/* + Copyright IBM Corp. All Rights Reserved. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package utils + +import ( + "context" + "encoding/base64" + "fmt" + "time" + + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "google.golang.org/protobuf/proto" +) + +func MarshalProtoBase64(msg proto.Message) string { + bytes, _ := proto.Marshal(msg) + return base64.StdEncoding.EncodeToString(bytes) +} + +func Retry(f func() bool, maxAttempt int, maxTimeout time.Duration, delay time.Duration) error { + ctx, cancel := context.WithTimeout(context.Background(), maxTimeout) + defer cancel() + for i := 0; i < maxAttempt; i++ { + select { + case <-ctx.Done(): + return ctx.Err() + default: + if f() { + return nil + } + time.Sleep(delay) + delay *= 2 + } + } + + return fmt.Errorf("max attempts reached") +} + +func UnmarshalStatus(statusBytes []byte) (*pb.Status, error) { + status := &pb.Status{} + err := proto.Unmarshal(statusBytes, status) + if err != nil { + return nil, err + } + + return status, nil +} diff --git a/samples/demos/irb/protos/.gitignore b/samples/demos/irb/protos/.gitignore new file mode 100644 index 000000000..732075117 --- /dev/null +++ b/samples/demos/irb/protos/.gitignore @@ -0,0 +1,3 @@ +*.py +*.go +__pycache__ diff --git a/samples/demos/irb/protos/Makefile b/samples/demos/irb/protos/Makefile new file mode 100644 index 000000000..1a8cc0720 --- /dev/null +++ b/samples/demos/irb/protos/Makefile @@ -0,0 +1,19 @@ +# Copyright 2021 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +PROTOS=$(basename $(wildcard *.proto)) + +all: build + +$(addsuffix _pb2.py,$(PROTOS)): + protoc -I=. --python_out=. $(patsubst %_pb2.py,%.proto,$@) + +$(addsuffix .pb.go,$(PROTOS)): + protoc -I=. --go_out=${GOPATH}/src $(patsubst %.pb.go,%.proto,$@) + +build: $(addsuffix _pb2.py,$(PROTOS)) $(addsuffix .pb.go,$(PROTOS)) +#build: $(addsuffix .pb.go,$(PROTOS)) + +clean: + rm -rf *.py *.go diff --git a/samples/demos/irb/protos/irb.options b/samples/demos/irb/protos/irb.options new file mode 100644 index 000000000..5c0a4b602 --- /dev/null +++ b/samples/demos/irb/protos/irb.options @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: Apache-2.0 + +RegisterDataRequest.decryption_key type:FT_POINTER +RegisterDataRequest.data_handler type:FT_POINTER +RegisterDataRequest.study_id type:FT_POINTER + +Identity.uuid type:FT_POINTER +Identity.public_key type:FT_POINTER +Identity.public_encryption_key type:FT_POINTER + +Status.msg type:FT_POINTER + +ExperimentProposal.study_id type:FT_POINTER +ExperimentProposal.experiment_id type:FT_POINTER + +WorkerCredentials.identity_bytes type:FT_POINTER +WorkerCredentials.attestation type:FT_POINTER +WorkerCredentials.evidence type:FT_POINTER + +StudyDetailsMessage.study_id type:FT_POINTER +StudyDetailsMessage.metadata type:FT_POINTER +StudyDetailsMessage.user_identities type:FT_POINTER + +SignedApprovalMessage.approval type:FT_POINTER +SignedApprovalMessage.signature type:FT_POINTER + +Approval.experiment_id type:FT_POINTER +Approval.experiment_proposal type:FT_POINTER + +GetExperimentRequest.experiment_id type:FT_POINTER + +EvaluationPackRequest.experiment_id type:FT_POINTER + +EvaluationPackMessage.registered_data type:FT_POINTER + +EncryptedEvaluationPack.encrypted_evaluationpack type:FT_POINTER +EncryptedEvaluationPack.encrypted_encryption_key type:FT_POINTER + diff --git a/samples/demos/irb/protos/irb.proto b/samples/demos/irb/protos/irb.proto new file mode 100644 index 000000000..aa9b1702d --- /dev/null +++ b/samples/demos/irb/protos/irb.proto @@ -0,0 +1,185 @@ +// Copyright IBM Corp. All Rights Reserved. +// Copyright 2020 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +option go_package = "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos"; + +// SAS +service StudyApprovalService { + // Note that only details of approved studies are returned + rpc GetStudyDetails (StudyDetailsRequest) returns (StudyDetailsResponse) {} +} + +message StudyDetailsRequest { + string study_id = 1; +} + +message StudyDetailsMessage { + string study_id = 1; + string metadata = 2; + repeated Identity user_identities = 3; +} + +message StudyDetailsResponse { + bytes study_details_message = 1; + + // signed by Study Approval Service (SAS) + // used to be verified by EAS when new study is created + bytes signature = 2; + + Status status = 3; +} + +// EAS +service ExperimentApprovalService { + rpc RegisterData (RegisterDataRequest) returns (Status) {} + + rpc RegisterStudy (SubmitStudyRequest) returns (Status) {} + + rpc NewExperiment (NewExperimentRequest) returns (Status) {} + rpc GetExperimentProposal (GetExperimentRequest) returns (GetExperimentResponse) {} + rpc ApproveExperiment (ApprovalRequest) returns (Status) {} + + rpc RequestEvaluationPack (EvaluationPackRequest) returns (EncryptedEvaluationPack) {} + + // helper functions + // rpc GetStudy ... return ... {} +} + +message RegisterDataRequest { + Identity participant = 1; + bytes decryption_key = 2; + string data_handler = 3; + string study_id = 4; +} + +message SubmitStudyRequest { + StudyDetailsResponse details = 1; +} + +message NewExperimentRequest { + Experiment experiment = 1; +} + +message GetExperimentRequest { + string experiment_id = 1; +} + +message GetExperimentResponse { + ExperimentProposal experiment_proposal = 1; + Status status = 2; +} + +message WorkerCredentials { + bytes identity_bytes = 1; + bytes attestation = 2; + bytes evidence = 3; +} + +message ExperimentProposal { + string study_id = 1; + string experiment_id = 2; + string mrenclave = 3; + string metadata = 4; + WorkerCredentials worker_credentials = 5; +} + +message Experiment { + // we keep bytes + bytes experiment_proposal = 1; + Approval approval = 2; +} + +message ApprovalRequest { + Approval approval = 1; +} + +message Approval { + string experiment_id = 1; + // serialized Experiment Proposal + bytes experiment_proposal = 2; + enum Decision { + UNDEFINED = 0; + APPROVED = 1; + REJECTED = 2; + } + Decision decision = 3; + Identity approver = 4; +} + +message SignedApprovalMessage { + bytes approval = 1; + bytes signature = 2; +} + +message EvaluationPackRequest { + string study_id = 1; + string experiment_id = 2; +} + +message EncryptedEvaluationPack { + bytes encrypted_encryption_key = 1; + // this is ciphertext of a serialized EvaluationPack msg + bytes encrypted_evaluationpack = 2; +} + +message EvaluationPackMessage { + repeated EvaluationPackItem item = 1; + repeated RegisterDataRequest registered_data = 2; +} + +message EvaluationPackItem { + bytes decryption_key = 1; + string data_handler = 2; +} + +// EAS State + +// note that the State message is just here to represent the KVS accessable via putState and getState functions within FPC +message State { + // as key we use study id + map state = 1; + // as key we use an identity.uuid + map registered_data = 2; +} + +message Study { + string study_id = 1; + repeated Identity participant = 2; + repeated Experiment experiment = 3; +} + +message Data { + Identity participant = 1; + bytes decryption_key = 2; + string data_handler = 3; +} + +// Graphene Worker +service Worker { + rpc Execute (ExecuteRequest) returns (Status) {} +} + +message ExecuteRequest { + string experiment_id = 1; + bytes encrypted_evaluationPack = 2; +} + +// Common messages +message Identity { + string uuid = 1; + bytes public_key = 2; + bytes public_encryption_key = 3; +} + +message Status { + string msg = 1; + enum ReturnCode { + ERROR_UNKNOWN = 0; + OK = 1; + } + ReturnCode return_code = 2; +} diff --git a/samples/demos/irb/tools.go b/samples/demos/irb/tools.go new file mode 100644 index 000000000..b423ee3f9 --- /dev/null +++ b/samples/demos/irb/tools.go @@ -0,0 +1,23 @@ +//go:build tools +// +build tools + +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package tools + +import ( + _ "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/weaver/relay/fabric" + _ "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/comm" + _ "github.com/hyperledger/fabric/cmd/orderer" + _ "github.com/hyperledger/fabric/cmd/peer" + _ "github.com/hyperledger/fabric/common/ledger/util/leveldbhelper" + _ "github.com/hyperledger/fabric/common/metrics/prometheus" + _ "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb/statecouchdb" + _ "github.com/hyperledger/fabric/core/ledger/pvtdatastorage" + _ "github.com/hyperledger/fabric/core/operations" + _ "github.com/libp2p/go-libp2p-core/network" +) diff --git a/samples/demos/irb/topology.go b/samples/demos/irb/topology.go new file mode 100644 index 000000000..0c8392529 --- /dev/null +++ b/samples/demos/irb/topology.go @@ -0,0 +1,41 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package irb + +import ( + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/api" + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fabric" + "github.com/hyperledger-labs/fabric-smart-client/integration/nwo/fsc" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/views/dataprovider" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/views/experimenter" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/views/investigator" +) + +func Topology() []api.Topology { + fabricTopology := fabric.NewDefaultTopology() + fabricTopology.AddOrganizationsByName("Org1", "Org2", "Org3") + fabricTopology.AddFPC("experimenter-approval-service", "fpc/irb-experiment") + fscTopology := fsc.NewTopology() + + // data provider + providerNode := fscTopology.AddNodeByName("provider") + providerNode.AddOptions(fabric.WithOrganization("Org1")) + providerNode.RegisterViewFactory("RegisterData", &dataprovider.RegisterViewFactory{}) + + // investigator + investigatorNode := fscTopology.AddNodeByName("investigator") + investigatorNode.AddOptions(fabric.WithOrganization("Org2")) + investigatorNode.RegisterViewFactory("CreateStudy", &investigator.CreateStudyViewFactory{}) + investigatorNode.RegisterResponder(&investigator.ApprovalView{}, &experimenter.SubmitExperimentView{}) + + //experimenter + experimenterNode := fscTopology.AddNodeByName("experimenter") + experimenterNode.AddOptions(fabric.WithOrganization("Org3")) + experimenterNode.RegisterViewFactory("SubmitExperiment", &experimenter.SubmitExperimentViewFactory{}) + + return []api.Topology{fabricTopology, fscTopology} +} diff --git a/samples/demos/irb/views/dataprovider/register.go b/samples/demos/irb/views/dataprovider/register.go new file mode 100644 index 000000000..006d3c9bd --- /dev/null +++ b/samples/demos/irb/views/dataprovider/register.go @@ -0,0 +1,91 @@ +/* + Copyright IBM Corp. All Rights Reserved. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package dataprovider + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/fpc" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/crypto" + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/storage" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/utils" + "github.com/pkg/errors" +) + +type Register struct { + StudyID string + PatientData []byte + PatientUUID string + PatientVK []byte +} + +type RegisterView struct { + *Register +} + +func (c *RegisterView) Call(context view.Context) (interface{}, error) { + fmt.Printf("Register new patient data") + + // encrypt with new random key + cp := crypto.NewGoCrypto() + sk, err := cp.NewSymmetricKey() + if err != nil { + return nil, errors.Wrap(err, "cannot create new symmetric key") + } + + encryptedData, err := cp.EncryptMessage(sk, c.PatientData) + if err != nil { + return nil, errors.Wrap(err, "cannot encrypt message") + } + + // upload encrypted data + kvs := storage.NewClient() + handle, err := kvs.Upload(encryptedData) + if err != nil { + return nil, errors.Wrap(err, "cannot upload data to kvs") + } + + fmt.Printf("Patient data successfully uploaded to storage (handle = %s)\n", handle) + + userIdentity := pb.Identity{ + Uuid: c.PatientUUID, + PublicKey: c.PatientVK, + } + + //build request + registerDataRequest := &pb.RegisterDataRequest{ + Participant: &userIdentity, + DecryptionKey: sk, + DataHandler: handle, + StudyId: c.StudyID, + } + + cid := "experimenter-approval-service" + f := "registerData" + arg := utils.MarshalProtoBase64(registerDataRequest) + + if _, err := fpc.GetDefaultChannel(context).Chaincode(cid).Invoke(f, arg).Call(); err != nil { + return nil, errors.Wrapf(err, "error invoking %s", f) + } + + fmt.Println("Patient data successfully registered! thanks") + + return nil, nil +} + +type RegisterViewFactory struct{} + +func (c *RegisterViewFactory) NewView(in []byte) (view.View, error) { + f := &RegisterView{Register: &Register{}} + if err := json.Unmarshal(in, f.Register); err != nil { + return nil, err + } + return f, nil +} diff --git a/samples/demos/irb/views/experimenter/execute.go b/samples/demos/irb/views/experimenter/execute.go new file mode 100644 index 000000000..dfbef1397 --- /dev/null +++ b/samples/demos/irb/views/experimenter/execute.go @@ -0,0 +1,85 @@ +/* + Copyright IBM Corp. All Rights Reserved. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package experimenter + +import ( + "encoding/base64" + "fmt" + + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/fpc" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/experiment" + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/utils" + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" +) + +type Execution struct { + ExperimentId string +} + +type ExecutionView struct { + *Execution +} + +func (c *ExecutionView) Call(context view.Context) (interface{}, error) { + fmt.Println("All cool, now we can run our experimenter") + + //build experiment proposal + evaluationPackRequest := pb.EvaluationPackRequest{ + ExperimentId: c.ExperimentId, + } + + evaluationPackRequestBytes, err := proto.Marshal(&evaluationPackRequest) + if err != nil { + return nil, errors.Wrap(err, "cannot marshal evaluation pack request") + } + + cid := "experimenter-approval-service" + f := "requestEvaluationPack" + arg := base64.StdEncoding.EncodeToString(evaluationPackRequestBytes) + + response, err := fpc.GetDefaultChannel(context).Chaincode(cid).Query(f, arg).Call() + if err != nil { + return nil, errors.Wrapf(err, "error invoking %s", f) + } + + encryptedEvaluationPackBytes, err := base64.StdEncoding.DecodeString(string(response)) + if err != nil { + return nil, err + } + + encryptedEvaluationPack := &pb.EncryptedEvaluationPack{} + err = proto.Unmarshal(encryptedEvaluationPackBytes, encryptedEvaluationPack) + if err != nil || encryptedEvaluationPack.GetEncryptedEvaluationpack() == nil { + //error decoding means something wrong with making the pack + status, e := utils.UnmarshalStatus(encryptedEvaluationPackBytes) + if e != nil { + //cannot even unmarshal status, so just return the error + return nil, err + } + + //return error from status + m := fmt.Sprintf("error getExperimentProposal: %s, %s", status.GetReturnCode(), status.GetMsg()) + return nil, errors.New(m) + } + fmt.Println("Received evaluation pack from FPC Experiment Approval Service!") + + // next, we send the eval pack to the worker + // TODO double check that the worker can access redis + resultBytes, err := experiment.ExecuteEvaluationPack(encryptedEvaluationPack) + fmt.Printf("Result received from worker: \"%s\"\n", string(resultBytes)) + + return nil, nil +} + +func NewExecutionView(ExperimentID string) view.View { + return &ExecutionView{ + Execution: &Execution{ExperimentId: ExperimentID}, + } +} diff --git a/samples/demos/irb/views/experimenter/submit.go b/samples/demos/irb/views/experimenter/submit.go new file mode 100644 index 000000000..bdc8ced48 --- /dev/null +++ b/samples/demos/irb/views/experimenter/submit.go @@ -0,0 +1,110 @@ +/* + Copyright IBM Corp. All Rights Reserved. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package experimenter + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/fpc" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/experiment" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/messages" + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/utils" + "github.com/pkg/errors" +) + +type SubmitExperiment struct { + StudyId string + ExperimentId string + Investigator view.Identity +} + +type SubmitExperimentView struct { + *SubmitExperiment +} + +func (c *SubmitExperimentView) Call(context view.Context) (interface{}, error) { + // get worker credentials + workerCredentials, err := experiment.GetWorkerCredentials() + if err != nil { + fmt.Printf("error: %v\n", err) + return nil, err + } + + // submit new experimenter proposal + experimentProposal := &pb.ExperimentProposal{ + StudyId: c.StudyId, + ExperimentId: c.ExperimentId, + WorkerCredentials: workerCredentials, + } + cid := "experimenter-approval-service" + f := "newExperiment" + arg := utils.MarshalProtoBase64(experimentProposal) + + if _, err := fpc.GetDefaultChannel(context).Chaincode(cid).Invoke(f, arg).Call(); err != nil { + return nil, errors.Wrap(err, "error invoking "+f) + } + + // reach out to investigator to trigger review and approval + if err := c.waitForApprovals(context); err != nil { + return nil, err + } + + fmt.Println("It seems I got my approval! Ready to start the real work!") + + // trigger execution flow + return context.RunView(NewExecutionView(c.ExperimentId)) +} + +func (c *SubmitExperimentView) waitForApprovals(context view.Context) error { + session, err := context.GetSession(context.Initiator(), c.Investigator) + if err != nil { + return err + } + + msg := &messages.ApprovalRequestNotification{ + Message: "Hey my friend, I just submitted a new experimenter! Please review and approve asap; Thanks", + Sender: context.Me().String(), + ExperimentID: c.ExperimentId, + } + + raw, err := msg.Serialize() + if err != nil { + return err + } + + if err = session.Send(raw); err != nil { + return err + } + + // wait for response + ch := session.Receive() + select { + case msg := <-ch: + if msg.Status != view.OK { + return fmt.Errorf("got error: %v", string(msg.Payload)) + } + fmt.Printf("Got answer: %v\n", string(msg.Payload)) + case <-time.After(1 * time.Minute): + return fmt.Errorf("responder didn't answer in time") + } + + return nil +} + +type SubmitExperimentViewFactory struct{} + +func (c *SubmitExperimentViewFactory) NewView(in []byte) (view.View, error) { + f := &SubmitExperimentView{SubmitExperiment: &SubmitExperiment{}} + if err := json.Unmarshal(in, f.SubmitExperiment); err != nil { + return nil, err + } + return f, nil +} diff --git a/samples/demos/irb/views/investigator/approve.go b/samples/demos/irb/views/investigator/approve.go new file mode 100644 index 000000000..a2c5c1003 --- /dev/null +++ b/samples/demos/irb/views/investigator/approve.go @@ -0,0 +1,111 @@ +/* + Copyright IBM Corp. All Rights Reserved. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package investigator + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "time" + + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/fpc" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/messages" + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/utils" + "github.com/pkg/errors" + "google.golang.org/protobuf/proto" +) + +type ApprovalView struct { +} + +func (c *ApprovalView) Call(context view.Context) (interface{}, error) { + session := context.Session() + ch := session.Receive() + + msg := &messages.ApprovalRequestNotification{} + select { + case m := <-ch: + if err := json.Unmarshal(m.Payload, msg); err != nil { + return nil, err + } + case <-time.After(5 * time.Second): + return nil, fmt.Errorf("time out reached") + } + fmt.Printf("Received approval request from: %s\n%s\n", msg.Sender, msg.Message) + + if err := c.reviewAndApprove(context, msg.ExperimentID); err != nil { + msg := fmt.Sprintf("something went wrong, cannot approve, sorry! reason: %v", err) + _ = session.SendError([]byte(msg)) + return nil, errors.Wrap(err, msg) + } + + if err := session.Send([]byte("great experimenter! approved!")); err != nil { + return nil, errors.Wrap(err, "cannot send reply") + } + + return nil, nil +} + +func (c *ApprovalView) reviewAndApprove(context view.Context, experimentID string) error { + fmt.Println("Trying to get experiment proposal") + + cid := "experimenter-approval-service" + f := "getExperimentProposal" + arg := utils.MarshalProtoBase64(&pb.GetExperimentRequest{ + ExperimentId: experimentID, + }) + + res, err := fpc.GetDefaultChannel(context).Chaincode(cid).Query(f, arg).Call() + if err != nil { + return errors.Wrapf(err, "error invoking %s", f) + } + + experimentProposalBytes, err := base64.StdEncoding.DecodeString(string(res)) + if err != nil { + return errors.Wrap(err, "cannot decode experiment proposal bytes") + } + + experimentProposal := &pb.ExperimentProposal{} + if err = proto.Unmarshal(experimentProposalBytes, experimentProposal); err != nil { + return errors.Wrap(err, "cannot unmarshal experiment proposal") + } + + // review + // TODO review experimentProposal + + // make a decision + approvalDecision := pb.Approval_APPROVED + //approvalDecision := pb.Approval_UNDEFINED + //approvalDecision = pb.Approval_REJECTED + + approval := pb.Approval{ + ExperimentId: experimentProposal.GetExperimentId(), + ExperimentProposal: experimentProposalBytes, + Decision: approvalDecision, + } + + approvalBytes, err := proto.Marshal(&approval) + if err != nil { + return errors.Wrap(err, "cannot marshal approval") + } + + f = "approveExperiment" + arg = utils.MarshalProtoBase64(&pb.SignedApprovalMessage{ + Approval: approvalBytes, + // TODO create approval signature; note that the chaincode currently does not check the signature + //Signature: signature, + }) + + if _, err := fpc.GetDefaultChannel(context).Chaincode(cid).Invoke(f, arg).Call(); err != nil { + return errors.Wrapf(err, "error invoking %s", f) + } + + fmt.Println("LGTM! Approved!") + return nil +} diff --git a/samples/demos/irb/views/investigator/create_study.go b/samples/demos/irb/views/investigator/create_study.go new file mode 100644 index 000000000..d88824a0d --- /dev/null +++ b/samples/demos/irb/views/investigator/create_study.go @@ -0,0 +1,62 @@ +/* + Copyright IBM Corp. All Rights Reserved. + + SPDX-License-Identifier: Apache-2.0 +*/ + +package investigator + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/fpc" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + pb "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/protos" + "github.com/hyperledger/fabric-private-chaincode/samples/demos/irb/pkg/utils" + "github.com/pkg/errors" +) + +type CreateStudy struct { + StudyID string + Metadata string + Participants []*pb.Identity +} + +type CreateStudyView struct { + *CreateStudy +} + +func (c *CreateStudyView) Call(context view.Context) (interface{}, error) { + fmt.Println("Let's register first a new study ") + + //build request + studyDetailsMessage := &pb.StudyDetailsMessage{ + StudyId: c.StudyID, + Metadata: c.Metadata, + UserIdentities: c.Participants, + } + + // chaincode details + cid := "experimenter-approval-service" + f := "registerStudy" + arg := utils.MarshalProtoBase64(studyDetailsMessage) + + _, err := fpc.GetDefaultChannel(context).Chaincode(cid).Invoke(f, arg).Call() + if err != nil { + return nil, errors.Wrapf(err, "error invoking %s", f) + } + + fmt.Println("Study created! thanks") + return nil, nil +} + +type CreateStudyViewFactory struct{} + +func (c *CreateStudyViewFactory) NewView(in []byte) (view.View, error) { + f := &CreateStudyView{CreateStudy: &CreateStudy{}} + if err := json.Unmarshal(in, f.CreateStudy); err != nil { + return nil, err + } + return f, nil +} diff --git a/samples/deployment/fabric-smart-client/README.md b/samples/deployment/fabric-smart-client/README.md new file mode 100644 index 000000000..59ebf592a --- /dev/null +++ b/samples/deployment/fabric-smart-client/README.md @@ -0,0 +1,19 @@ +# Fabric Smart Client + +Fabric Private Chaincode integrates with the [Fabric Smart Client](https://github.com/hyperledger-labs/fabric-smart-client) to build complex distributed-applications while simplify the development and testing. +In particular, with Fabric Smart Client, it becomes easy to build and test prototypes and proof-of-concepts without the need to deploy a Fabric network. +That is, developers can focus on the development of the FPC chaincode. + +The Fabric Smart Client integrates the FPC Client API to interact with a FPC Chaincode and protect the invocation arguments. +Moreover, the deployment process of a FPC Chaincode is integrated in the test network suite provided by Fabric Smart Client. +The FPC developer just packages the FPC Chaincode as a docker image and points to it in the Fabric network definition. + +## Getting started + +The Fabric Smart Client (FSC) repository contains a neat tutorial how FSC can be used with FPC. +It shows how to setup a Fabric network, deploy the FPC echo chaincode (see [/samples/chaincode/echo](../../chaincode/echo)), and invoke it from a FSC view. +You can find the tutorial [here](https://github.com/hyperledger-labs/fabric-smart-client/tree/main/integration/fabric/fpc/echo). + +## More advanced example + +In [/samples/demos/irb](../../demos/irb) we give a more advanced example of how the Fabric Smart Client is used to build a complex demo with Fabric Private Chaincode. \ No newline at end of file diff --git a/samples/deployment/k8s/README.md b/samples/deployment/k8s/README.md index f6370a324..1592ade77 100644 --- a/samples/deployment/k8s/README.md +++ b/samples/deployment/k8s/README.md @@ -124,7 +124,7 @@ If you have installed them somewhere else on your system, please set `FABIC_BIN_ For instance, you can download the binaries and use them by following the commands: ```bash cd $FPC_PATH/samples/deployment/k8s -curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.3.0 1.4.9 -d -s +curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.3.3 1.4.9 -d -s export FABRIC_BIN_DIR=$(pwd)/bin ``` diff --git a/samples/deployment/k8s/orderer-service/orderer0-deployment.yaml b/samples/deployment/k8s/orderer-service/orderer0-deployment.yaml index dec111574..6c5c2e6d4 100644 --- a/samples/deployment/k8s/orderer-service/orderer0-deployment.yaml +++ b/samples/deployment/k8s/orderer-service/orderer0-deployment.yaml @@ -68,7 +68,7 @@ spec: value: /var/hyperledger/orderer/tls/server.key - name: ORDERER_GENERAL_CLUSTER_ROOTCAS value: "[/var/hyperledger/orderer/tls/ca.crt]" - image: hyperledger/fabric-orderer:2.3.0 + image: hyperledger/fabric-orderer:2.3.3 name: orderer ports: - containerPort: 7050 diff --git a/samples/deployment/k8s/orderer-service/orderer1-deployment.yaml b/samples/deployment/k8s/orderer-service/orderer1-deployment.yaml index ecf1bb647..a5f98a276 100644 --- a/samples/deployment/k8s/orderer-service/orderer1-deployment.yaml +++ b/samples/deployment/k8s/orderer-service/orderer1-deployment.yaml @@ -68,7 +68,7 @@ spec: value: /var/hyperledger/orderer/tls/server.key - name: ORDERER_GENERAL_CLUSTER_ROOTCAS value: "[/var/hyperledger/orderer/tls/ca.crt]" - image: hyperledger/fabric-orderer:2.3.0 + image: hyperledger/fabric-orderer:2.3.3 name: orderer ports: - containerPort: 7050 diff --git a/samples/deployment/k8s/orderer-service/orderer2-deployment.yaml b/samples/deployment/k8s/orderer-service/orderer2-deployment.yaml index 819b27399..82bc7f303 100644 --- a/samples/deployment/k8s/orderer-service/orderer2-deployment.yaml +++ b/samples/deployment/k8s/orderer-service/orderer2-deployment.yaml @@ -68,7 +68,7 @@ spec: value: /var/hyperledger/orderer/tls/server.key - name: ORDERER_GENERAL_CLUSTER_ROOTCAS value: "[/var/hyperledger/orderer/tls/ca.crt]" - image: hyperledger/fabric-orderer:2.3.0 + image: hyperledger/fabric-orderer:2.3.3 name: orderer ports: - containerPort: 7050 diff --git a/samples/deployment/k8s/org1/org1-cli-deployment.yaml b/samples/deployment/k8s/org1/org1-cli-deployment.yaml index 55a8a7951..bc975eb64 100644 --- a/samples/deployment/k8s/org1/org1-cli-deployment.yaml +++ b/samples/deployment/k8s/org1/org1-cli-deployment.yaml @@ -52,7 +52,7 @@ spec: configMapKeyRef: name: chaincode-config key: FPC_MRENCLAVE - image: hyperledger/fabric-tools:2.3.0 + image: hyperledger/fabric-tools:2.3.3 name: cli tty: true volumeMounts: diff --git a/samples/deployment/k8s/org1/org1-peer0-deployment.yaml b/samples/deployment/k8s/org1/org1-peer0-deployment.yaml index b63619b47..b6a6d6989 100644 --- a/samples/deployment/k8s/org1/org1-peer0-deployment.yaml +++ b/samples/deployment/k8s/org1/org1-peer0-deployment.yaml @@ -57,7 +57,7 @@ spec: value: 0.0.0.0:9443 - name: CORE_METRICS_PROVIDER value: prometheus - image: hyperledger/fabric-peer:2.3.0 + image: hyperledger/fabric-peer:2.3.3 name: peer0 ports: - containerPort: 7051 diff --git a/samples/deployment/k8s/org2/org2-cli-deployment.yaml b/samples/deployment/k8s/org2/org2-cli-deployment.yaml index b15dfa5cb..315bcc406 100644 --- a/samples/deployment/k8s/org2/org2-cli-deployment.yaml +++ b/samples/deployment/k8s/org2/org2-cli-deployment.yaml @@ -52,7 +52,7 @@ spec: configMapKeyRef: name: chaincode-config key: FPC_MRENCLAVE - image: hyperledger/fabric-tools:2.3.0 + image: hyperledger/fabric-tools:2.3.3 name: cli tty: true volumeMounts: diff --git a/samples/deployment/k8s/org2/org2-peer0-deployment.yaml b/samples/deployment/k8s/org2/org2-peer0-deployment.yaml index eeb32027d..2f38c2623 100644 --- a/samples/deployment/k8s/org2/org2-peer0-deployment.yaml +++ b/samples/deployment/k8s/org2/org2-peer0-deployment.yaml @@ -57,7 +57,7 @@ spec: value: 0.0.0.0:9443 - name: CORE_METRICS_PROVIDER value: prometheus - image: hyperledger/fabric-peer:2.3.0 + image: hyperledger/fabric-peer:2.3.3 name: peer0 ports: - containerPort: 7051 diff --git a/samples/deployment/k8s/org3/org3-cli-deployment.yaml b/samples/deployment/k8s/org3/org3-cli-deployment.yaml index 283421a73..15b3f3817 100644 --- a/samples/deployment/k8s/org3/org3-cli-deployment.yaml +++ b/samples/deployment/k8s/org3/org3-cli-deployment.yaml @@ -52,7 +52,7 @@ spec: configMapKeyRef: name: chaincode-config key: FPC_MRENCLAVE - image: hyperledger/fabric-tools:2.3.0 + image: hyperledger/fabric-tools:2.3.3 name: cli tty: true volumeMounts: diff --git a/samples/deployment/k8s/org3/org3-peer0-deployment.yaml b/samples/deployment/k8s/org3/org3-peer0-deployment.yaml index 650acdf7d..382016f3a 100644 --- a/samples/deployment/k8s/org3/org3-peer0-deployment.yaml +++ b/samples/deployment/k8s/org3/org3-peer0-deployment.yaml @@ -57,7 +57,7 @@ spec: value: 0.0.0.0:9443 - name: CORE_METRICS_PROVIDER value: prometheus - image: hyperledger/fabric-peer:2.3.0 + image: hyperledger/fabric-peer:2.3.3 name: peer0 ports: - containerPort: 7051 diff --git a/samples/deployment/test-network/Makefile b/samples/deployment/test-network/Makefile index 86b8524cb..ea2f38d6a 100644 --- a/samples/deployment/test-network/Makefile +++ b/samples/deployment/test-network/Makefile @@ -33,7 +33,7 @@ ercc-ecc-start: if [ "${SGX_MODE}" = "HW" ]; then \ export HW_EXTENSION="-hw" \ AESMD_PATH="/var/run/aesmd" \ - SGX_DEVICE_PATH=$$(if [ -e "/dev/isgx" ]; then echo "/dev/isgx"; elif [ -e "/dev/sgx" ]; then echo "/dev/sgx"; else echo "none"; fi) && \ + SGX_DEVICE_PATH=$$(if [ -e "/dev/isgx" ]; then echo "/dev/isgx"; elif [ -e "/dev/sgx/enclave" ]; then echo "/dev/sgx/enclave"; else echo "none"; fi) && \ [ "$${SGX_DEVICE_PATH}" != "none" ] || ( echo "ERROR: SGX_MODE is HW but no sgx device found"; exit 1; ) \ fi && \ env CC_ID=${CC_ID} FPC_VERSION=${FPC_VERSION} docker-compose up diff --git a/samples/deployment/test-network/README.md b/samples/deployment/test-network/README.md index 5a7e9c3a2..3903e61c7 100644 --- a/samples/deployment/test-network/README.md +++ b/samples/deployment/test-network/README.md @@ -36,9 +36,9 @@ Next, setup fabric sample network, binaries and docker images. Here we follow th ```bash cd $FPC_PATH/samples/deployment/test-network -git clone https://github.com/hyperledger/fabric-samples -b v2.3.0 +git clone https://github.com/hyperledger/fabric-samples cd $FPC_PATH/samples/deployment/test-network/fabric-samples -curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.3.0 1.4.9 -s +curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.3.3 1.4.9 -s ``` Before we can start the network, we need to update the Fabric peer configuration to enable FPC support. @@ -70,8 +70,8 @@ cd $FPC_PATH/samples/deployment/test-network Let's start the Fabric-Samples test network. ```bash cd $FPC_PATH/samples/deployment/test-network/fabric-samples/test-network -./network.sh up -./network.sh createChannel -c mychannel -ca -cai 1.4.9 -i 2.3.0 +./network.sh up -ca +./network.sh createChannel -c mychannel ``` Next, we install the FPC Enclave Registry and our FPC Chaincode on the network by using the standard Lifecycle commands, diff --git a/samples/deployment/test-network/docker-compose.yml b/samples/deployment/test-network/docker-compose.yml index e9d32d3f7..61419aa67 100644 --- a/samples/deployment/test-network/docker-compose.yml +++ b/samples/deployment/test-network/docker-compose.yml @@ -71,4 +71,4 @@ services: networks: default: external: - name: net_test + name: fabric_test diff --git a/utils/docker/Makefile b/utils/docker/Makefile index a7a0ce549..67524b0fc 100644 --- a/utils/docker/Makefile +++ b/utils/docker/Makefile @@ -30,7 +30,7 @@ DOCKER_DEV_CONTAINER_NAME = fpc-development-${FPC_VERSION} # ------------------------ DOCKER_DAEMON_SOCKET ?= /var/run/docker.sock -SGX_DEVICE_PATH ?= $(shell if [ -e "/dev/isgx" ]; then echo "/dev/isgx"; elif [ -e "/dev/sgx" ]; then echo "/dev/sgx"; fi) +SGX_DEVICE_PATH ?= $(shell if [ -e "/dev/isgx" ]; then echo "/dev/isgx"; elif [ -e "/dev/sgx/enclave" ]; then echo "/dev/sgx/enclave"; fi) SGX_PSW_SOCKET ?= /var/run/aesmd DOCKER_GOPATH=/project diff --git a/utils/docker/base-dev/Dockerfile b/utils/docker/base-dev/Dockerfile index 323be8050..d393d6ce9 100644 --- a/utils/docker/base-dev/Dockerfile +++ b/utils/docker/base-dev/Dockerfile @@ -20,7 +20,7 @@ ARG FPC_VERSION=main FROM hyperledger/fabric-private-chaincode-base-rt:${FPC_VERSION} as common # config/build params -ARG GO_VERSION=1.15.4 +ARG GO_VERSION=1.16.7 ARG NANOPB_VERSION=0.4.3 ARG OPENSSL=1.1.1g ARG SGXSSL=2.10_1.1.1g diff --git a/utils/docker/dev/Dockerfile b/utils/docker/dev/Dockerfile index d61831f3c..4982a0447 100644 --- a/utils/docker/dev/Dockerfile +++ b/utils/docker/dev/Dockerfile @@ -23,7 +23,7 @@ FROM hyperledger/fabric-private-chaincode-base-dev:${FPC_VERSION} # config/build params ARG FABRIC_REPO=https://github.com/hyperledger/fabric.git -ARG FABRIC_VERSION=2.3.0 +ARG FABRIC_VERSION=2.3.3 ARG FABRIC_REL_PATH=src/github.com/hyperledger/fabric ARG FPC_REL_PATH=src/github.com/hyperledger/fabric-private-chaincode diff --git a/utils/docker/dev_peer_cc-builder/Dockerfile b/utils/docker/dev_peer_cc-builder/Dockerfile index d31fe9823..cc6550d53 100644 --- a/utils/docker/dev_peer_cc-builder/Dockerfile +++ b/utils/docker/dev_peer_cc-builder/Dockerfile @@ -53,7 +53,7 @@ ARG SGX_MODE # config/build params ARG FABRIC_REPO=https://github.com/hyperledger/fabric.git -ARG FABRIC_VERSION=2.3.0 +ARG FABRIC_VERSION=2.3.3 ARG FPC_REPO_URL=https://github.com/hyperledger/fabric-private-chaincode.git ARG FPC_REPO_BRANCH_TAG_OR_COMMIT=main ARG GIT_USER_NAME=tester