static pse_op_error_t sqlite_update_node(sqlite3_stmt* stat, const uint8_t* blob, uint32_t blob_size, uint32_t id) { pse_op_error_t ret = OP_SUCCESS; int rc; rc = sqlite3_bind_blob(stat, 1, blob, blob_size, NULL); EXIT_IFNOT_SQLITE_OK(rc, error) rc = sqlite3_bind_int(stat, 2, id); EXIT_IFNOT_SQLITE_OK(rc, error) rc = sqlite3_step(stat); if(rc != SQLITE_DONE) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } rc = sqlite3_clear_bindings(stat); EXIT_IFNOT_SQLITE_OK(rc, error) rc = sqlite3_reset(stat); EXIT_IFNOT_SQLITE_OK(rc, error) return OP_SUCCESS; error: return ret; }
pse_op_error_t sqlite_write_db(pse_vmc_hash_tree_cache_t* cache, uint8_t is_for_update_flag, op_leafnode_flag_t* op_flag_info) { PROFILE_START("sqlite_write_db"); int rc; pse_op_error_t ret = OP_SUCCESS; sqlite3_stmt* stat = NULL; sqlite3 *db = NULL; char sql_sentence[512] = {0}; int refid = 0; if( !cache) { PROFILE_END("sqlite_write_db"); return OP_ERROR_INVALID_PARAMETER; } if(is_for_update_flag && !op_flag_info) { PROFILE_END("sqlite_write_db"); return OP_ERROR_INVALID_PARAMETER; } // Backup DB first ret = backup_vmc_db_file(); if(OP_SUCCESS != ret) { pse_vmc_db_state = PSE_VMC_DB_STATE_DOWN; PROFILE_END("sqlite_write_db"); return ret; } ret = sqlite_open_db(&db); if(OP_SUCCESS != ret) { pse_vmc_db_state = PSE_VMC_DB_STATE_DOWN; PROFILE_END("sqlite_write_db"); return ret; } rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL); EXIT_IFNOT_SQLITE_OK(rc, error) if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "update HASH_TREE_NODE_TABLE set node_content=? where ID=?") < 0) { ret = OP_ERROR_INTERNAL; goto error; } rc = sqlite3_prepare_v2(db, sql_sentence, -1, &stat, 0); EXIT_IFNOT_SQLITE_OK(rc, error) // update internal nodes for (uint32_t index = 0; index < INIT_INTERNAL_NODE_NR; index++) { // update ancestors if ((ret = sqlite_update_node(stat, (uint8_t*)&cache->ancestors[index].internal, INTERNAL_NODE_SIZE, cache->ancestors[index].node_id)) != OP_SUCCESS) goto error; // update brothers of ancestors if ((ret = sqlite_update_node(stat, (uint8_t*)&cache->brother_of_ancestors[index].internal, INTERNAL_NODE_SIZE, cache->brother_of_ancestors[index].node_id)) != OP_SUCCESS) goto error; } // update leaf and its brother if ((ret = sqlite_update_node(stat, (uint8_t*)&cache->self.leaf, LEAF_NODE_SIZE, cache->self.node_id)) != OP_SUCCESS) goto error; if ((ret = sqlite_update_node(stat, (uint8_t*)&cache->brother.leaf, LEAF_NODE_SIZE, cache->brother.node_id)) != OP_SUCCESS) goto error; if(is_for_update_flag) { // update USED flag and QUOTA record char mrsigner[65] = {0}; // convert mr_signer to hex string for(uint32_t i=0; i < sizeof(sgx_measurement_t); i++) { char tmp[3]; if(_snprintf_s(tmp, sizeof(tmp), "%02x", ((uint8_t*)(&op_flag_info->mr_signer))[i]) < 0) { ret = OP_ERROR_INTERNAL; goto error; } if(0 != strncat_s(mrsigner, sizeof(mrsigner), tmp, sizeof(tmp))) { ret = OP_ERROR_INTERNAL; goto error; } } switch(op_flag_info->op_type) { case CLR_LEAFNODE_FLAG: // read REFID saved in HASH_TREE_NODE_TABLE before deleting the record. if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "select REFID from HASH_TREE_NODE_TABLE where ID=%d;", cache->self.node_id) < 0) { ret = OP_ERROR_INTERNAL; goto error; } ret = sqlite_query_int_value(db, sql_sentence, &refid); if(OP_SUCCESS != ret && OP_ERROR_SQLITE_NOT_FOUND != ret) { goto error; } // clear REFID and USED flag if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "update HASH_TREE_NODE_TABLE set USED=0 and REFID=0 where ID=%d;", cache->self.node_id) < 0) { ret = OP_ERROR_INTERNAL; goto error; } rc = sqlite3_exec(db, sql_sentence, NULL, NULL, NULL); if(SQLITE_OK != rc) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } if(1 != sqlite3_changes(db)) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } // update QUOTA, counter--; if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "update VMC_QUOTA_TABLE set COUNTER=COUNTER-1 where ID=%d and COUNTER>0;", refid) < 0) { ret = OP_ERROR_INTERNAL; goto error; } rc = sqlite3_exec(db, sql_sentence, NULL, NULL, NULL); if(SQLITE_OK != rc) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } if(1 != sqlite3_changes(db)) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } break; case SET_LEAFNODE_FLAG: // update QUOTA, counter++; if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "update VMC_QUOTA_TABLE set COUNTER=COUNTER+1 where MRSIGNER='%s';", mrsigner) < 0) { ret = OP_ERROR_INTERNAL; goto error; } rc = sqlite3_exec(db, sql_sentence, NULL, NULL, NULL); if(SQLITE_OK != rc) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } rc = sqlite3_changes(db); if(0 == rc) { // the mrsigner isn't in quota table yet, so insert it. if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "insert into VMC_QUOTA_TABLE(MRSIGNER,COUNTER) values('%s', 1);", mrsigner) < 0) { ret = OP_ERROR_INTERNAL; goto error; } rc = sqlite3_exec(db, sql_sentence, NULL, NULL, NULL); if(SQLITE_OK != rc) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } if(1 != sqlite3_changes(db)) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } } else if(1 == rc) { // the mrsigner has been in quota table } else { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } // read refid if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "select ID from VMC_QUOTA_TABLE where MRSIGNER='%s';", mrsigner) < 0) { ret = OP_ERROR_INTERNAL; goto error; } ret = sqlite_query_int_value(db, sql_sentence, &refid); if(OP_SUCCESS != ret && OP_ERROR_SQLITE_NOT_FOUND != ret) { goto error; } // Update HASH_TREE_NODE_TABLE if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "update HASH_TREE_NODE_TABLE set USED=1 where ID=%d;", cache->self.node_id) < 0) { ret = OP_ERROR_INTERNAL; goto error; } rc = sqlite3_exec(db, sql_sentence, NULL, NULL, NULL); if(SQLITE_OK != rc) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } if(1 != sqlite3_changes(db)) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } if (_snprintf_s(sql_sentence, sizeof(sql_sentence), "update HASH_TREE_NODE_TABLE set REFID=%d where ID=%d;", refid, cache->self.node_id) < 0) { ret = OP_ERROR_INTERNAL; goto error; } rc = sqlite3_exec(db, sql_sentence, NULL, NULL, NULL); if(SQLITE_OK != rc) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } if(1 != sqlite3_changes(db)) { ret = OP_ERROR_SQLITE_INTERNAL; goto error; } break; default: ret = OP_ERROR_INVALID_PARAMETER; goto error; } } rc = sqlite3_exec(db, "END TRANSACTION;", NULL, NULL, NULL); EXIT_IFNOT_SQLITE_OK(rc, error) sqlite3_finalize(stat); sqlite3_close_v2(db); PROFILE_END("sqlite_write_db"); return OP_SUCCESS; error: assert(db != NULL); sqlite3_finalize(stat); sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL); sqlite3_close_v2(db); PROFILE_END("sqlite_write_db"); return ret; }
int sqlite_generate_prebuild_db() { sqlite3* db = NULL; int rc; char* errmsg = NULL; int node_type; int start_id, end_id; sqlite3_stmt* stat = NULL; char sql_sentence[512] = {0}; uint8_t* ptr_buf = NULL; uint32_t bufflen; uint8_t* ptr_precalc_node_buff = NULL; int layer; bufflen = (INIT_MAX_HASH_TREE_LAYER-2)*sizeof(hash_tree_internal_node_t) + sizeof(hash_tree_leaf_node_t); ptr_precalc_node_buff = (uint8_t*)malloc(bufflen); if(NULL == ptr_precalc_node_buff) { return -1; } memset(ptr_precalc_node_buff, 0, bufflen); hash_tree_internal_node_t* internal_node = (hash_tree_internal_node_t*)ptr_precalc_node_buff; for(int index=INIT_MAX_HASH_TREE_LAYER-3; index>=0; index--) { if(memcpy_s(internal_node->hash, sizeof(internal_node->hash), &(internal_node_hash_value_table[index][0]), HASH_VALUE_SIZE)) { free(ptr_precalc_node_buff); return -1; } internal_node++; } if(gDb) { db = gDb; } else { rc = sqlite3_open(SQLITE_DB_FILE_NAME, &gDb); if( SQLITE_OK != rc ) { free(ptr_precalc_node_buff); return rc; } db = gDb; } rc = sqlite3_exec( db, "create table VMC_QUOTA_TABLE( ID integer primary key AUTOINCREMENT, MRSIGNER char(64), COUNTER integer)", NULL, NULL, &errmsg ); EXIT_IFNOT_SQLITE_OK(rc) rc = sqlite3_exec( db, "create table HASH_TREE_NODE_TABLE( ID integer primary key, node_content blob, USED integer, REFID integer NULL REFERENCES VMC_QUOTA_TABLE(ID))", NULL, NULL, &errmsg ); EXIT_IFNOT_SQLITE_OK(rc) rc = sqlite3_exec( db, "create table BACKUP_TABLE( ID integer primary key, node_content blob, USED integer, REFID integer)", NULL, NULL, &errmsg ); EXIT_IFNOT_SQLITE_OK(rc) // all nodes in the same layer have the same precalculated value // the merkel hash tree has 12 layers including root layer rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL); EXIT_IFNOT_SQLITE_OK(rc) sprintf(sql_sentence, "insert into HASH_TREE_NODE_TABLE( ID, node_content, USED, REFID) values( ?, ?, 0, NULL)"); rc = sqlite3_prepare_v2(db, sql_sentence, -1, &stat, 0); EXIT_IFNOT_SQLITE_OK(rc) layer = INIT_MAX_HASH_TREE_LAYER - 1; do{ if(INIT_MAX_HASH_TREE_LAYER - 1 == layer) { node_type = HASH_TREE_NODE_TYPE_LEAF; } else { node_type = HASH_TREE_NODE_TYPE_INTERNAL; } start_id = (int)pow((double)2,layer); end_id = (int)pow((double)2,layer+1) - 1; for(int id = start_id; id <= end_id; id++) { rc =sqlite3_bind_int(stat, 1, id); EXIT_IFNOT_SQLITE_OK(rc) switch(node_type) { case HASH_TREE_NODE_TYPE_INTERNAL: ptr_buf = ptr_precalc_node_buff; rc = sqlite3_bind_blob(stat, 2, (hash_tree_internal_node_t*)ptr_buf + layer - 1, sizeof(hash_tree_internal_node_t), NULL ); break; case HASH_TREE_NODE_TYPE_LEAF: rc = sqlite3_bind_blob(stat, 2, ptr_precalc_node_buff + (INIT_MAX_HASH_TREE_LAYER-2)*sizeof(hash_tree_internal_node_t), sizeof(hash_tree_leaf_node_t), NULL ); break; default: goto error; } EXIT_IFNOT_SQLITE_OK(rc) rc = sqlite3_step(stat); if(rc != SQLITE_DONE) { goto error; } rc = sqlite3_clear_bindings(stat); EXIT_IFNOT_SQLITE_OK(rc) rc = sqlite3_reset(stat); EXIT_IFNOT_SQLITE_OK(rc) } layer--; if(layer&0x1) sqlite3_sleep(1); }while(layer>0); rc = sqlite3_exec(db, "END TRANSACTION;", NULL, NULL, NULL); EXIT_IFNOT_SQLITE_OK(rc) rc = sqlite3_finalize(stat); EXIT_IFNOT_SQLITE_OK(rc) stat = NULL; sqlite3_close_v2(db); gDb = NULL; free(ptr_precalc_node_buff); return 0; error: free(ptr_precalc_node_buff); if(db) { sqlite3_finalize(stat); sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL); sqlite3_close_v2(db); gDb = NULL; } return -1; }