diff --git a/CMakeLists.txt b/CMakeLists.txt index 2cbbc4f0..40fd06f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,15 +12,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY build) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-result -Wreturn-type") -# We have 2 executable build outputs: appbill and hpcore - - -#-------appbill------- - -add_executable(appbill - src/bill/appbill.cpp -) - #-------hpcore------- add_subdirectory(src/killswitch) @@ -83,13 +74,9 @@ target_link_libraries(hpcore sqlite3 ${CMAKE_DL_LIBS} # Needed for stacktrace support ) -add_dependencies(hpcore - appbill -) add_custom_command(TARGET hpcore POST_BUILD # COMMAND strip ./build/hpcore - # COMMAND strip ./build/appbill COMMAND cp ./test/bin/hpws ./test/bin/hpfs ./build/ ) @@ -99,7 +86,7 @@ target_precompile_headers(hpcore PUBLIC src/pchheader.hpp) # Requires docker to be runnable without 'sudo' add_custom_target(docker COMMAND mkdir -p ./test/local-cluster/bin - COMMAND cp ./build/hpcore ./build/appbill ./test/local-cluster/bin/ + COMMAND cp ./build/hpcore ./test/local-cluster/bin/ COMMAND cp ./test/bin/libblake3.so ./test/bin/hpws ./test/bin/hpfs ./test/local-cluster/bin/ COMMAND docker build -t hpcore:latest -f ./test/local-cluster/Dockerfile ./test/local-cluster/bin/ ) diff --git a/examples/c_contract/hotpocket_contract.h b/examples/c_contract/hotpocket_contract.h index 36b62dcf..b3bfb6c3 100644 --- a/examples/c_contract/hotpocket_contract.h +++ b/examples/c_contract/hotpocket_contract.h @@ -148,12 +148,6 @@ struct hp_unl_collection int npl_fd; }; -struct hp_appbill_config -{ - char *mode; - char *bin_args; -}; - struct hp_round_limits_config { size_t user_input_bytes; @@ -176,7 +170,6 @@ struct hp_config char *consensus; char *npl; uint16_t max_input_ledger_offset; - struct hp_appbill_config appbill; struct hp_round_limits_config round_limits; }; @@ -601,8 +594,6 @@ void hp_free_config(struct hp_config *config) __HP_FREE(config->environment); __HP_FREE(config->consensus); __HP_FREE(config->npl); - __HP_FREE(config->appbill.mode); - __HP_FREE(config->appbill.bin_args); __HP_FREE(config); } @@ -720,7 +711,7 @@ struct hp_config *__hp_read_from_patch_file(const int fd) */ int __hp_write_to_patch_file(const int fd, const struct hp_config *config) { - struct iovec iov_vec[5]; + struct iovec iov_vec[4]; // {version: + newline + 4 spaces => 21; const size_t version_len = 21 + strlen(config->version); char version_buf[version_len]; @@ -772,15 +763,6 @@ int __hp_write_to_patch_file(const int fd, const struct hp_config *config) iov_vec[2].iov_base = json_buf; iov_vec[2].iov_len = json_string_len; - // Appbill field valiues. - - const char *appbill_json = " \"appbill\": {\n \"mode\": \"%s\",\n \"bin_args\": \"%s\"\n },\n"; - const size_t appbill_json_len = 67 + strlen(config->appbill.mode) + strlen(config->appbill.bin_args); - char appbill_buf[appbill_json_len]; - sprintf(appbill_buf, appbill_json, config->appbill.mode, config->appbill.bin_args); - iov_vec[3].iov_base = appbill_buf; - iov_vec[3].iov_len = appbill_json_len; - // Round limits field valies. const char *round_limits_json = " \"round_limits\": {\n" @@ -804,11 +786,11 @@ int __hp_write_to_patch_file(const int fd, const struct hp_config *config) sprintf(round_limits_buf, round_limits_json, user_input_bytes_str, user_output_bytes_str, npl_output_bytes_str, proc_cpu_seconds_str, proc_mem_bytes_str, proc_ofd_count_str); - iov_vec[4].iov_base = round_limits_buf; - iov_vec[4].iov_len = round_limits_json_len; + iov_vec[3].iov_base = round_limits_buf; + iov_vec[3].iov_len = round_limits_json_len; if (ftruncate(fd, 0) == -1 || // Clear any previous content in the file. - pwritev(fd, iov_vec, 5, 0) == -1) // Start writing from begining. + pwritev(fd, iov_vec, 4, 0) == -1) // Start writing from begining. return -1; return 0; @@ -886,23 +868,6 @@ void __hp_populate_patch_from_json_object(struct hp_config *config, const struct { __HP_ASSIGN_CHAR_PTR(config->npl, elem); } - else if (strcmp(k->string, "appbill") == 0) - { - struct json_object_s *object = (struct json_object_s *)elem->value->payload; - struct json_object_element_s *sub_ele = object->start; - do - { - if (strcmp(sub_ele->name->string, "mode") == 0) - { - __HP_ASSIGN_CHAR_PTR(config->appbill.mode, sub_ele); - } - else if (strcmp(sub_ele->name->string, "bin_args") == 0) - { - __HP_ASSIGN_CHAR_PTR(config->appbill.bin_args, sub_ele); - } - sub_ele = sub_ele->next; - } while (sub_ele); - } else if (strcmp(k->string, "round_limits") == 0) { struct json_object_s *object = (struct json_object_s *)elem->value->payload; diff --git a/src/bill/appbill.cpp b/src/bill/appbill.cpp deleted file mode 100644 index ca7ae091..00000000 --- a/src/bill/appbill.cpp +++ /dev/null @@ -1,715 +0,0 @@ -/* - App bill default implementation 1 - MSB of return value is reserved for appbill error - bits 1-8 indicate whether or not public keys 0-6 passed appbill check - (to be completed) -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG 0 -#define KEY_SIZE 32 -#define RECORD_SIZE 64 - -#define FILE_BUFFER_SIZE (64*1024*1024) // this will move 0xffff entries at a time - -#define MIN(a,b) (((a)<(b))?(a):(b)) -#define MAX(a,b) (((a)>(b))?(a):(b)) - -#define TABLE_FILE "./state/appbill.table" -#define TABLE_FILE_2 "appbill.table" // if TABLE_FILE can't be found try here - -uint64_t new_balance(uint64_t balance, int64_t to_credit) { - if (to_credit < 0 && -to_credit > balance) { - // catch the wrap around - balance = 0; - } else if (to_credit > 0 && to_credit + balance < balance) { - // and here as well - balance = (uint64_t)-1; - } else { - // normal crediting - balance += to_credit; - } - return balance; -} - -void print_hex(uint8_t* data, int len) { - for (int c = 0; c < len; ++c) - printf("%02hhx", data[c]); -} - -int compar (const void* p1, const void* p2) { - for (uint8_t* c1 = (uint8_t*)p1, * c2 = (uint8_t*)p2; c1 - (uint8_t*)p1 < KEY_SIZE; ++c1, ++c2) - if (*c1 < *c2) return -1; - else if (*c1 > *c2) return +1; - return 0; -} - - -int correct_for_ed_keys(int argc, char** argv, int incr, int offset) { - // correct for ed keys - for (int i = 0; i < argc; i += incr) { - int len = strlen(argv[i + offset]); - if (len == KEY_SIZE*2 + 2 && (argv[i][0] == 'e' || argv[i][0] == 'E') && (argv[i][1] == 'd' || argv[i][1] == 'D')) - argv[i]+=2; - else if (len != KEY_SIZE*2) { - fprintf(stderr, "appbill received an invalid key %s, expected len=%d actual len=%d\n", argv[i], KEY_SIZE*2, len); - return 128; - } - } - return 0; -} - -void key_from_hex(uint8_t* key_in, uint8_t* key_out) { - for (int c = 0; c < 32; ++c) { - uint8_t hn = tolower(key_in[c*2]); - uint8_t ln = tolower(key_in[c*2+1]); - hn = ( hn >= 'a' ? 10 + (hn - 'a') : hn - '0'); - ln = ( ln >= 'a' ? 10 + (ln - 'a') : ln - '0'); - key_out[c] = (hn * 16) + ln; - } -} - -uint64_t uint64_from_bytes(uint8_t* data) { - return - (((uint64_t)(data[0]))<<56) + - (((uint64_t)(data[1]))<<48) + - (((uint64_t)(data[2]))<<40) + - (((uint64_t)(data[3]))<<32) + - (((uint64_t)(data[4]))<<24) + - (((uint64_t)(data[5]))<<16) + - (((uint64_t)(data[6]))<<8) + - (((uint64_t)(data[7]))); -} - - -void uint64_to_bytes(uint8_t* dest, uint64_t x) { - for (int j = 0; j < 8; j++) { - *(dest + (7-j)) = x & 0xff; - x >>= 8; - } -} - - -// returns 1 if found and populates entry_out, 0 if not found -int binary_file_search(FILE* f, uint8_t* key, uint8_t* entry_out, uint64_t* balance_out, size_t* recordno_out, int* error_out) { - - *error_out = 0; - *balance_out = 0; - - // find file size - fseek(f, (size_t)0, SEEK_END); - size_t tablesize = ftell(f); - int recordcount = tablesize / RECORD_SIZE; - - size_t record = recordcount/2; - size_t search_size = (recordcount == 1 ? 1 : record); - - - - uint8_t entry_array[RECORD_SIZE*2]; - uint8_t* entry = entry_array + RECORD_SIZE; - uint8_t* prev_entry = entry_array; - - - while (search_size) { - - if (record == 0) { - // special case, no previous record will be available - fseek(f, 0, SEEK_SET); - int r = fread(entry, 1, RECORD_SIZE, f); - if (r != RECORD_SIZE) { - fprintf(stderr, "failed to read %d bytes\n", RECORD_SIZE); - *error_out = 128; - return 0; - } - memset(prev_entry, 0, RECORD_SIZE); - } else { - fseek(f, (record - 1) * RECORD_SIZE, SEEK_SET); - int r = fread(entry_array, 1, RECORD_SIZE * 2, f); - if (r != RECORD_SIZE*2) { - fprintf(stderr, "failed to read %d bytes\n", RECORD_SIZE*2); - *error_out = 128; - return 0; - } - } - - int search_direction = compar(entry, key); - int check_prev = compar(prev_entry, key); - - if (DEBUG) { - printf("prevrec: %lu\tkey: ", record-1); - print_hex(prev_entry, RECORD_SIZE); - printf("\tsearch dir: %d\n", check_prev); - printf("record: %lu\tkey: ", record); - print_hex(entry, RECORD_SIZE); - printf("\tsearch dir: %d\n", search_direction); - } - - - if (search_direction == 0) { - // get the balance - *balance_out = uint64_from_bytes(entry+32); - if (DEBUG) printf("entry found at record %lu with balance=%lu\n", record, *balance_out); - if (entry_out) - for (int i = 0; i < RECORD_SIZE; ++i) - entry_out[i] = entry[i]; - *recordno_out = record; - return 1; - } - - if (check_prev == 0 && record != 0) { - // get the balance - *balance_out = uint64_from_bytes(prev_entry+32); - if (DEBUG) printf("entry found at record %lu with balance=%lu\n", record-1, *balance_out); - if (entry_out) - for (int i = 0; i < RECORD_SIZE; ++i) - entry_out[i] = prev_entry[i]; - *recordno_out = record-1; - return 1; - } - - if (search_direction != check_prev ) { - // record doesn't exist, it would go between these two records if it did - if (DEBUG) printf("record doesn't exist, would go between\n"); - *recordno_out = record; - return 0; - } - - - search_size /= 2; - - if (search_size < 1) search_size = 1; - - if (search_direction > 0) { - record -= search_size; - } else { - record += search_size; - } - - if (DEBUG) printf("search size: %lu, current record: %lu, check_prev: %d, dir: %d\n", search_size, record, check_prev, search_direction); - - if (record < 0 || record >= recordcount) { - if (DEBUG) - fprintf(stderr, "could not find key record: %lu, recordcount: %d\n", record, recordcount); - if (entry_out) - for (int i = 0; i < RECORD_SIZE; ++i) - entry_out[i] = entry[i]; - *recordno_out = record; - *balance_out = 0; - return 0; - } - - - - *recordno_out = record; - } - - return 0; -} - -// inserts above recordno -// warning: expensive, must copy remaining chunk of file down -int insert_record(FILE* f, uint8_t* entry, size_t recordno) { - - static uint8_t* file_buffer = 0; // we're going to reuse this piece of memory until appbill closes so just alloc once - - if (!file_buffer) - file_buffer = (uint8_t*)malloc(MAX(FILE_BUFFER_SIZE, RECORD_SIZE)); - - if (DEBUG) printf("insert_record called with recno=%lu\n", recordno); - //uint8_t* buffer[FILE_BUFFER_SIZE]; - - size_t offset = recordno * RECORD_SIZE; - - fseek(f, (size_t)0, SEEK_END); - size_t size = ftell(f); - - // inserting 64 bytes at offset - // we need to first compute the short move at the end - - long long tomove = size - offset; - if (tomove <= 0) { - // write the record at the end of the file - if (DEBUG) printf("new write\n"); - return fwrite(entry, RECORD_SIZE, 1, f); - } else { - size_t endpiece = tomove % FILE_BUFFER_SIZE; - - if (DEBUG) printf("endpiece %lu\n", endpiece); - - // the endpiece is always moved, some times there are also no further pieces to move - fseek(f, size - endpiece, SEEK_SET); - fread(file_buffer, 1, endpiece, f); - fseek(f, size - endpiece + RECORD_SIZE, SEEK_SET); - fwrite(file_buffer, 1, endpiece, f); - - size_t cursor = size - endpiece; - - tomove -= endpiece; - - // now if there are any other pieces to move along we can move them - if (size - endpiece >= FILE_BUFFER_SIZE) - for (size_t cursor = size - endpiece - FILE_BUFFER_SIZE; cursor > offset; cursor -= FILE_BUFFER_SIZE) { - if (DEBUG) printf("moving %d sized piece at %lu to %lu - size: %lu - offset: %lu\n", FILE_BUFFER_SIZE, cursor, cursor + RECORD_SIZE, size, offset); - fseek(f, cursor, SEEK_SET); - fread(file_buffer, 1, FILE_BUFFER_SIZE, f); - fseek(f, cursor + RECORD_SIZE, SEEK_SET); - fwrite(file_buffer, 1, FILE_BUFFER_SIZE, f); - } - - // not sure why we need to move this last row down, something is slightly wrong with the math above? - fseek(f, offset, SEEK_SET); - fread(file_buffer, 1, RECORD_SIZE, f); - fseek(f, offset + RECORD_SIZE, SEEK_SET); - fwrite(file_buffer, 1, RECORD_SIZE, f); - - // finally it's safe to emplace our data - fseek(f, offset, SEEK_SET); - return fwrite(entry, 1, RECORD_SIZE, f); - } -} - - -int valid_hex(char* hex, int len) { - char* x = hex; - for (; (x-hex) < len && *x != '\0' && *x != '\n' && *x >= '0' && (*x <= '9' || *x >= 'a' && *x <= 'f' || *x >= 'A' && *x <= 'F'); ++x); - return x-hex == len; -} - -int pass_through_mode(int argc, char** argv) { - // full argc, argv are in tact in this mode - - if (DEBUG) - printf("pass through mode\n"); - - int teepipe[2]; - int error = pipe(teepipe); - if (error) { - fprintf(stderr, "appbill pass through could not create a pipe for teeing fdlist\n"); - return 128; - } - - FILE* teepipeout = fdopen(teepipe[1], "w"); - - // todo: make this all zero copy when someone has time to debug tee and vmsplice readmode - // for now we'll just do a dumb read - - FILE* f = fopen(TABLE_FILE, "rb+"); - if (!f) - f = fopen(TABLE_FILE_2, "rb+"); - - if (!f) { - fprintf(stderr, "could not open %s or %s\n", TABLE_FILE, TABLE_FILE_2); - return 128; - } - - char buf[1024]; - int mode = 0; - int bytes_read = 0; - - int counter = 0; - int toskip = 0; - - uint8_t key[KEY_SIZE]; - - do { - char c = 0; - bytes_read = 0; - while ( (c = getc( stdin )) != EOF && c != ',' && c != '{' && c != '}' && c != '[' && c != ']' && c != '\n' && c != ':' && bytes_read < 1023 ) { - buf[bytes_read++] = c; - putc(c, teepipeout); // make a copy for the next program - } - if (c != EOF) putc(c, teepipeout); // make a copy for the next program - - if (c == EOF) - break; - - if (mode == 2) - continue; - - buf[bytes_read] = '\0'; - - if (mode == 0 && strcmp("\"usrfd\"", buf) == 0) { - mode = 1; - continue; - } else if ( mode == 1 && c == '}' ) { - mode = 2; - continue; - } - - if (buf[0] == '\0' || !mode) - continue; - - ++counter %= 3; - - // this runs if there's an error in the user's public key - if (toskip) { - toskip--; - continue; - } - - - if (DEBUG) - printf("mode=%d counter=%d component `%s`\n", mode, counter%3, buf); - - if (counter == 1) { - // this is the user key - // remove trailing " - if (!buf[strlen(buf)-1] == '"') - continue; - buf[strlen(buf)-1] = '\0'; - - // check the key is valid - if (DEBUG) - printf("key length: %lu, proper length: %d\n", strlen(buf+3), KEY_SIZE*2); - if (DEBUG) - printf("hex: `%s`\n", buf+3); - if (strlen(buf+3) != KEY_SIZE*2 || !valid_hex(buf+3, KEY_SIZE*2)) { - toskip = 2; - if (DEBUG) - printf("invald public key %s\n", buf+3); - continue; - } - - key_from_hex((uint8_t*)buf+3, key); - if (DEBUG) { - printf("parsed key: "); - print_hex(key, KEY_SIZE); - printf("\n"); - } - } else if (counter == 2) { - // this is the user's input fd - - int userfd = 0; - if (!sscanf(buf, "%d", &userfd)) - continue; - - if (DEBUG) printf("mode=2 userfd=%d\n", userfd); - - // there might be some bytes pending on this input, if there are we need to bill for them, one coin per byte - - /*int nbytes = 0; - ioctl(userfd, FIONREAD, &nbytes);*/ - - int64_t to_bill = 0; // and one coin per round for being connected too // no change that to 0 because otherwise malicious nodes can drain accounts! - - //todo: replace all this rubbish with a properly tested zero copy approach - int userpipe[2]; - pipe(userpipe); //todo: handle possible error condition here - FILE* userfile = fdopen(userfd, "r"); - FILE* newuserfile = fdopen(userpipe[1], "w"); - - char x = 0; - while ((x = getc(userfile)) != EOF) { - if (to_bill < (uint64_t)-1) - to_bill++; - putc(x, newuserfile); - } - - fclose(newuserfile); - fclose(userfile); - dup2(userpipe[0], userfd); - - - if (DEBUG) - printf("tobill: %lu\n", to_bill); - - // commence billing - - int error = 0; - uint64_t balance = 0; - size_t recordno = 0; - uint8_t entry[64]; - if (binary_file_search(f, key, entry, &balance, &recordno, &error)) { - // key already exists, update it - if (DEBUG) printf("writing 64 bytes at record:%lu\n", recordno); - fseek(f, recordno*RECORD_SIZE, SEEK_SET); - uint64_t balance = uint64_from_bytes(entry+32); - balance = new_balance(balance, -to_bill); - uint64_to_bytes(entry+32, balance); - fwrite(entry, RECORD_SIZE, 1, f); - } else { - // is user doesn't exist this is an error but we can't do anything about it in passthrough mode so ignore - if (DEBUG) { - printf("user not found key:"); - print_hex(key, KEY_SIZE); - printf("\n"); - } - continue; - } - } - - } while (!feof(stdin)); - - fflush(teepipeout); - - close(teepipe[1]); - dup2(teepipe[0], 0); - - fclose(f); - - execv(argv[1], argv+1); - return 128; -} - - - -int credit_mode(int argc, char** argv) { - // argc,v start from first useful arguments - if (argc == 0 || argc % 2 == 1) { - fprintf(stderr, "appbill credit mode requires args like: public_key amount public key amount\n"); - return 128; - } - - if (correct_for_ed_keys(argc, argv, 2, 0)) - return 128; - - // sanity check our inputs - for (int i = 0; i < argc; i += 2) { - for (char* x = argv[i];; ++x) { - if ( x - argv[i] == KEY_SIZE*2 && *x != '\0' ) { - fprintf(stderr, "appbill was supplied an invalid public key\n"); - return 128; - } - - if (*x >= 'a' && *x <= 'f' || *x >= '0' && *x <= '9' || *x >= 'A' && *x <= 'F') - continue; - - if (*x == '\0') - break; - - fprintf(stderr, "appbill was supplied an invalid public key (not hex) char=%c\n", *x); - return 128; - } - - for (char* x = argv[i+1]; *x; ++x) - if ( ! (*x >= '0' && *x <= '9' || *x == '-') ) { - fprintf(stderr, "appbill was supplied invalid amount to credit, must be decimal integer entry=%s\n", argv[i+1]); - return 128; - } - - int64_t to_credit = 0; - if (!sscanf(argv[i+1], "%ld", &to_credit)) { - fprintf(stderr, "appbill was supplied invalid amount to credit, must be decimal integer entry=%s\n", argv[i+1]); - return 128; - } - } - - FILE* f = fopen(TABLE_FILE, "rb+"); - if (!f) - f = fopen(TABLE_FILE_2, "rb+"); - - if (!f) { - fprintf(stderr, "could not open %s or %s\n", TABLE_FILE, TABLE_FILE_2); - return 128; - } - - // now the expensive bit - for (int i = 0; i < argc; i += 2) { - uint8_t key[32]; - key_from_hex((uint8_t*)argv[i], key); - - int64_t to_credit = 0; - if (!sscanf(argv[i+1], "%ld", &to_credit)) // this has been sanity checked above - continue; - - int error = 0; - uint64_t balance = 0; - size_t recordno = 0; - uint8_t entry[64]; - if (binary_file_search(f, key, entry, &balance, &recordno, &error)) { - // key already exists, update it - if (DEBUG) printf("writing 64 bytes at record:%lu\n", recordno); - fseek(f, recordno*RECORD_SIZE, SEEK_SET); - uint64_t balance = uint64_from_bytes(entry+32); - balance = new_balance(balance, to_credit); - uint64_to_bytes(entry+32, balance); - fwrite(entry, RECORD_SIZE, 1, f); - - } else { - - if (DEBUG) printf("key needs to be inserted\n"); - // key doesn't exist, insert it - uint8_t new_entry[RECORD_SIZE]; - for (int i = 0; i < KEY_SIZE; ++i) - new_entry[i] = key[i]; - uint64_t balance = new_balance(0, to_credit); - - uint64_to_bytes(new_entry+32, balance); - - for (int i = KEY_SIZE + 8; i < RECORD_SIZE; ++i) - new_entry[i] = 0; - - // get the existing entry - fseek(f, recordno * RECORD_SIZE, SEEK_SET); - fread(entry, 1, RECORD_SIZE, f); - - int insert_direction = compar(entry, new_entry); - - insert_record(f, new_entry, recordno + (insert_direction < 0 ? 1 : 0)); - } - - } - - - fclose(f); - return 0; -} - -int check_mode(int argc, char** argv, int print_balances) { - - if (DEBUG) - printf("check mode\n"); - - if (argc > 14 && !print_balances) { - fprintf(stderr, "appbill can only take up to 7 keys at a time\n"); - return 128; - } - - if (argc == 0 || argc % 2 == 1 && !print_balances) { - fprintf(stderr, "appbill check mode requires a public key%s\n", (print_balances ? "" : " and an amount to check against")); - return 128; - } - - - - if (correct_for_ed_keys(argc, argv, (print_balances ? 1 : 2), 0)) - return 128; - - for (int i = 0; i < argc; i+= ( print_balances ? 1 : 2 )) { - // check the pubkey - for (char* x = argv[i];; ++x) { - if ( x - argv[i] == KEY_SIZE*2 && *x != '\0' ) { - fprintf(stderr, "appbill was supplied an invalid public key\n"); - return 128; - } - - if (*x >= 'a' && *x <= 'f' || *x >= '0' && *x <= '9' || *x >= 'A' && *x <= 'F') - continue; - - if (*x == '\0') - break; - - fprintf(stderr, "appbill was supplied an invalid public key (not hex) char=%c\n", *x); - return 128; - } - - if (print_balances) - continue; - - // check the bytecount - for (char* x = argv[i+1]; *x != '\0'; ++x) { - if (*x >= '0' && *x <= '9') - continue; - fprintf(stderr, "appbill was supplied invalid byte count %s\n", argv[i+1]); - return 128; - } - - } - - if (print_balances) - printf("{\n"); - - // open app bill table - - FILE* f = fopen(TABLE_FILE, "rb"); - if (!f) - f = fopen(TABLE_FILE_2, "rb"); - - if (!f) { - fprintf(stderr, "could not open table file at %s or %s\n", TABLE_FILE, TABLE_FILE_2); - return 128; - } - - int bits[7]; - for (int i = 0; i < 7; ++i) - bits[i] = 0; - - // loop keys, check balances - for (int i = 0, j = 0; i < argc; i+=( print_balances ? 1 : 2 ), ++j) { - // convert the argv from hex to binary - uint8_t key[32]; - key_from_hex((uint8_t*)argv[i], key); - - uint32_t bytecount = 0; - if (!print_balances) - sscanf(argv[i+1], "%d", &bytecount); - - int error = 0; - uint64_t balance = 0; - size_t recordno = 0; - if (binary_file_search(f, key, 0, &balance, &recordno, &error)) { - if (j < 7) bits[j] = balance > bytecount; - if (print_balances) { - printf("\t\""); - print_hex(key, KEY_SIZE); - printf("\": %lu%s", balance, (i == argc-1 ? "\n": ",\n")); - } - } - } - - if (print_balances) - printf("}"); - fclose(f); - - if (DEBUG) - for (int i = 0; i < 7; ++i) - printf("bit %d: %d\n", i, bits[i]); - - return bits[0] * 64 + bits[1] * 32 + bits[2] * 16 + bits[3] * 8 + bits[4] * 4 + bits[5] * 2 + bits[6]; -} - -int main(int argc, char** argv) { - - - - // input checks - - int mode = 0; // mode 0 is passthrough [ writes ] - - if (argc >= 2 && strcmp(argv[1], "--credit") == 0) - mode = 1; // mode 1 credit mode [ writes ] - - if (argc >= 2 && strcmp(argv[1], "--check") == 0) - mode = 2; // mode 2 check mode [ read only ] - - if (argc >= 2 && strcmp(argv[1], "--balance") == 0) - mode = 3; // mode 3 balance mode [ read only ] - - - if (mode == 0) { - if (argc < 2) { - fprintf(stderr, "appbill requires an executable to pass execution to as an argument when running in pass through mode\n"); - return 128; - } - return pass_through_mode(argc, argv); - } - - if (argc < 3) { - fprintf(stderr, "appbill was not supplied sufficient arguments\n"); - return 128; - } - - argc-=2; - argv+=2; - - if (mode == 1) - return credit_mode(argc, argv); - - if (mode == 2 || mode == 3) - return check_mode(argc, argv, mode == 3); - - fprintf(stderr, "unknown mode, execution should not reach here\n"); - - return 128; -} \ No newline at end of file diff --git a/src/conf.cpp b/src/conf.cpp index e1b1f783..5f5ac6dd 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -955,11 +955,6 @@ namespace conf jdoc.insert_or_assign("npl", contract.is_npl_public ? PUBLIC : PRIVATE); jdoc.insert_or_assign("max_input_ledger_offset", contract.max_input_ledger_offset); - jsoncons::ojson appbill; - appbill.insert_or_assign("mode", contract.appbill.mode); - appbill.insert_or_assign("bin_args", contract.appbill.bin_args); - jdoc.insert_or_assign("appbill", appbill); - jsoncons::ojson round_limits; round_limits.insert_or_assign("user_input_bytes", contract.round_limits.user_input_bytes); round_limits.insert_or_assign("user_output_bytes", contract.round_limits.user_output_bytes); @@ -1077,10 +1072,6 @@ namespace conf contract.is_npl_public = jdoc["npl"] == PUBLIC; contract.max_input_ledger_offset = jdoc["max_input_ledger_offset"].as(); - jpath = "contract.appbill"; - contract.appbill.mode = jdoc["appbill"]["mode"].as(); - contract.appbill.bin_args = jdoc["appbill"]["bin_args"].as(); - jpath = "contract.round_limits"; contract.round_limits.user_input_bytes = jdoc["round_limits"]["user_input_bytes"].as(); contract.round_limits.user_output_bytes = jdoc["round_limits"]["user_output_bytes"].as(); @@ -1105,13 +1096,7 @@ namespace conf if (!contract.bin_args.empty()) util::split_string(contract.runtime_binexec_args, contract.bin_args, " "); contract.runtime_binexec_args.insert(contract.runtime_binexec_args.begin(), contract.bin_path); - - contract.appbill.runtime_args.clear(); - // Populate runtime app bill args. - if (!contract.appbill.bin_args.empty()) - util::split_string(contract.appbill.runtime_args, contract.appbill.bin_args, " "); - contract.appbill.runtime_args.insert(contract.appbill.runtime_args.begin(), contract.appbill.mode); - + // Uncomment for docker-based execution. // std::string volumearg; // volumearg.append("type=bind,source=").append(ctx.contract_hpfs_dir).append(",target=/hpfs"); diff --git a/src/conf.hpp b/src/conf.hpp index c2396b86..98b5877a 100644 --- a/src/conf.hpp +++ b/src/conf.hpp @@ -145,15 +145,6 @@ namespace conf history_configuration history_config; // Holds history config values. Only applicable if history=custom. }; - struct appbill_config - { - std::string mode; // Binary to execute for appbill. - std::string bin_args; // Any arguments to supply to appbill binary by default. - - // Config element which are initialized in memory (This is not directly loaded from the config file) - std::vector runtime_args; // Appbill execution args used during runtime. - }; - struct round_limits_config { size_t user_input_bytes = 0; // Max contract input bytes per user per round. @@ -188,7 +179,6 @@ namespace conf bool is_consensus_public = false; // If true, consensus are broadcasted to non-unl nodes as well. bool is_npl_public = false; // If true, npl messages are broadcasted to non-unl nodes as well. uint16_t max_input_ledger_offset; // Maximum ledger sequence number offset that can be specified in the input. - appbill_config appbill; round_limits_config round_limits; // Config element which are initialized in memory (This is not directly loaded from the config file) diff --git a/src/msg/usrmsg_common.hpp b/src/msg/usrmsg_common.hpp index dd548390..3a6ca510 100644 --- a/src/msg/usrmsg_common.hpp +++ b/src/msg/usrmsg_common.hpp @@ -101,7 +101,6 @@ namespace msg::usrmsg constexpr const char *REASON_BAD_MSG_FORMAT = "bad_msg_format"; constexpr const char *REASON_INVALID_MSG_TYPE = "invalid_msg_type"; constexpr const char *REASON_BAD_SIG = "bad_sig"; - constexpr const char *REASON_APPBILL_BALANCE_EXCEEDED = "appbill_balance_exceeded"; constexpr const char *REASON_MAX_LEDGER_EXPIRED = "max_ledger_expired"; constexpr const char *REASON_MAX_LEDGER_OFFSET_EXCEEDED = "max_ledger_offset_exceeded"; constexpr const char *REASON_NONCE_EXPIRED = "nonce_expired"; diff --git a/src/sc/sc.cpp b/src/sc/sc.cpp index f2e63766..07669c86 100644 --- a/src/sc/sc.cpp +++ b/src/sc/sc.cpp @@ -192,19 +192,10 @@ namespace sc // Write the contract execution args from HotPocket to the stdin (0) of the contract process. write_contract_args(ctx, user_inputs_fd); - const bool using_appbill = !ctx.args.readonly && !conf::cfg.contract.appbill.mode.empty(); - int execv_len = conf::cfg.contract.runtime_binexec_args.size() + 1; - if (using_appbill) - execv_len += conf::cfg.contract.appbill.runtime_args.size(); - // Fill process args. + int execv_len = conf::cfg.contract.runtime_binexec_args.size() + 1; char *execv_args[execv_len]; int j = 0; - if (using_appbill) - { - for (int i = 0; i < conf::cfg.contract.appbill.runtime_args.size(); i++, j++) - execv_args[i] = conf::cfg.contract.appbill.runtime_args[i].data(); - } for (int i = 0; i < conf::cfg.contract.runtime_binexec_args.size(); i++, j++) execv_args[j] = conf::cfg.contract.runtime_binexec_args[i].data(); diff --git a/src/usr/usr.cpp b/src/usr/usr.cpp index 564ef771..f7c54e4b 100644 --- a/src/usr/usr.cpp +++ b/src/usr/usr.cpp @@ -472,12 +472,6 @@ namespace usr return (nonce_status == 1 ? msg::usrmsg::REASON_NONCE_EXPIRED : msg::usrmsg::REASON_ALREADY_SUBMITTED); } - if (!verify_appbill_check(user_pubkey, new_total_input_size)) - { - LOG_DEBUG << "User input app bill balance exceeded."; - return msg::usrmsg::REASON_APPBILL_BALANCE_EXCEEDED; - } - // Reaching here means the input is successfully validated and we can submit it to consensus. // Copy the input data into the input store. Contract will read the input from this location. @@ -489,69 +483,6 @@ namespace usr return NULL; // Success. No reject reason. } - /** - * Executes the appbill and verifies whether the user has enough account balance to process the provided input. - * @param pubkey User binary pubkey. - * @param input_len Total bytes length of user input. - * @return Whether the user is allowed to process the input or not. - */ - bool verify_appbill_check(std::string_view pubkey, const size_t input_len) - { - // If appbill not enabled always green light the input. - if (conf::cfg.contract.appbill.mode.empty()) - return true; - - // execute appbill in --check mode to verify this user can submit a packet/connection to the network - // todo: this can be made more efficient, appbill --check can process 7 at a time - - // Fill appbill args - const int len = conf::cfg.contract.appbill.runtime_args.size() + 4; - char *execv_args[len]; - for (int i = 0; i < conf::cfg.contract.appbill.runtime_args.size(); i++) - execv_args[i] = conf::cfg.contract.appbill.runtime_args[i].data(); - char option[] = "--check"; - execv_args[len - 4] = option; - // add the hex encoded public key as the last parameter - std::string hexpubkey = util::to_hex(pubkey); - std::string inputsize = std::to_string(input_len); - execv_args[len - 3] = hexpubkey.data(); - execv_args[len - 2] = inputsize.data(); - execv_args[len - 1] = NULL; - - int pid = fork(); - if (pid == 0) - { - // appbill process. - util::fork_detach(); - - // before execution chdir into a valid the latest state data directory that contains an appbill.table - const std::string appbill_dir = sc::contract_fs.rw_dir + sc::STATE_DIR_PATH; - chdir(appbill_dir.c_str()); - int ret = execv(execv_args[0], execv_args); - std::cerr << errno << ": Appbill process execv failed.\n"; - return false; - } - else - { - // app bill in check mode takes a very short period of time to execute, typically 1ms - // so we will blocking wait for it here - int status = 0; - waitpid(pid, &status, 0); //todo: check error conditions here - status = WEXITSTATUS(status); - if (status != 128 && status != 0) - { - // this user's key passed appbill - return true; - } - else - { - // user's key did not pass, do not add to user input candidates - LOG_DEBUG << "Appbill validation failed " << hexpubkey << " return code was " << status; - return false; - } - } - } - /** * Sends any change event notifications to relevant users who are currently connected to the node. */ diff --git a/src/usr/usr.hpp b/src/usr/usr.hpp index 90ae1d11..21e06cf7 100644 --- a/src/usr/usr.hpp +++ b/src/usr/usr.hpp @@ -108,8 +108,6 @@ namespace usr const char *validate_user_input_submission(const std::string &user_pubkey, const usr::extracted_user_input &extracted_input, const uint64_t lcl_seq_no, size_t &total_input_size, std::string &ordered_hash, util::buffer_view &input); - bool verify_appbill_check(std::string_view pubkey, const size_t input_len); - void dispatch_change_events(); } // namespace usr diff --git a/test/docker/Dockerfile.ubt.20.04 b/test/docker/Dockerfile.ubt.20.04 index b5bbdcad..e46626bb 100644 --- a/test/docker/Dockerfile.ubt.20.04 +++ b/test/docker/Dockerfile.ubt.20.04 @@ -11,6 +11,6 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* \ && mkdir /usr/local/bin/hotpocket -COPY hpcore hpfs hpws appbill /usr/local/bin/hotpocket/ +COPY hpcore hpfs hpws /usr/local/bin/hotpocket/ ENTRYPOINT ["/usr/local/bin/hotpocket/hpcore"] diff --git a/test/docker/build.sh b/test/docker/build.sh index 42151626..6e622211 100755 --- a/test/docker/build.sh +++ b/test/docker/build.sh @@ -8,7 +8,7 @@ njsfile="Dockerfile.ubt.20.04-njs" # Prepare build context tmp=$(mktemp -d) -cp $hpcoredir/build/{hpcore,appbill} $hpcoredir/test/bin/{hpfs,hpws,libblake3.so} $tmp/ +cp $hpcoredir/build/hpcore $hpcoredir/test/bin/{hpfs,hpws,libblake3.so} $tmp/ strip $tmp/hpcore # Remove the revision component from hp version to make up the image version. diff --git a/test/local-cluster/Dockerfile b/test/local-cluster/Dockerfile index 659b2870..3882099b 100644 --- a/test/local-cluster/Dockerfile +++ b/test/local-cluster/Dockerfile @@ -1,7 +1,7 @@ # We are going with Hot Pocket NodeJs docker image because sample contracts need NodeJs to run. FROM hotpocketdev/hotpocket:0.5-ubt.20.04-njs.14 -COPY hpcore hpfs hpws appbill /usr/local/bin/hotpocket/ +COPY hpcore hpfs hpws /usr/local/bin/hotpocket/ ENTRYPOINT ["/usr/local/bin/hotpocket/hpcore"] diff --git a/test/local-cluster/cluster-create.sh b/test/local-cluster/cluster-create.sh index 02a7835a..dba8d675 100755 --- a/test/local-cluster/cluster-create.sh +++ b/test/local-cluster/cluster-create.sh @@ -114,11 +114,7 @@ do environment: '', \ roundtime: $roundtime, \ consensus: 'public', \ - npl: 'public', \ - appbill: { \ - mode: '', \ - bin_args: '' \ - } + npl: 'public' }, null, 2)") mesh_json=$(node -p "JSON.stringify({...require('./tmp.json').mesh, \ @@ -148,9 +144,8 @@ do popd > /dev/null 2>&1 - # Copy the contract files and appbill. + # Copy the contract files. eval "cp -r $copyfiles ./node$n/contract_fs/seed/state/" - cp ../bin/appbill ./node$n/contract_fs/seed/state/ done # Function to generate JSON array string while skiping a given index. @@ -210,10 +205,6 @@ do mkdir -p ./node$i/contract_fs/seed/ > /dev/null 2>&1 pushd ./node$i/contract_fs/seed/state/ > /dev/null 2>&1 - - # Load credit balance for user for appbill testing purposes. - >appbill.table - ../../../../../bin/appbill --credit "705bf26354ee4c63c0e5d5d883c07cefc3196d049bd3825f827eb3bc23ead035" 10000 # Copy any more initial state files for testing. # cp ~/my_big_file . diff --git a/test/vm-cluster/cluster.sh b/test/vm-cluster/cluster.sh index fca84925..937105ac 100755 --- a/test/vm-cluster/cluster.sh +++ b/test/vm-cluster/cluster.sh @@ -335,7 +335,6 @@ if [ $mode = "new" ] || [ $mode = "updatebin" ]; then rm -r hpfiles > /dev/null 2>&1 mkdir -p $hpfiles/{bin,ssl,nodejs_contract} strip $hpcore/build/hpcore - strip $hpcore/build/appbill cp $hpcore/build/{hpcore,hpfs,hpws} $hpfiles/bin/ pushd $hpcore/examples/nodejs_contract/ > /dev/null 2>&1 npm install