-
Roman Khlopkov authored1f6c1a7f
dap_chain_net_anchor.c 18.96 KiB
/*
*
* Authors:
* Frolov Daniil <daniil.frolov@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Copyright (c) 2020, All rights reserved.
This file is part of CellFrame SDK the open source project
CellFrame SDK is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CellFrame SDK is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with any CellFrame SDK based project. If not, see <http://www.gnu.org/licenses/>.
*/
#include <memory.h>
#include <assert.h>
#include "dap_common.h"
#include "dap_sign.h"
#include "dap_pkey.h"
#include "dap_chain.h"
#include "dap_chain_cell.h"
#include "dap_chain_common.h"
#include "dap_chain_ledger.h"
#include "dap_chain_datum_decree.h"
#include "dap_chain_net_srv_stake_pos_delegate.h"
#include "dap_chain_net.h"
#include "dap_chain_net_tx.h"
#include "dap_chain_net_decree.h"
#include "dap_chain_datum_anchor.h"
#include "dap_chain_cs_esbocs.h"
#define LOG_TAG "chain_net_anchor"
typedef struct anchor_table{
dap_hash_fast_t anchor_hash;
dap_chain_datum_anchor_t *anchor;
UT_hash_handle hh;
} anchor_table_t;
// private function prototypes
static bool s_verify_pubkeys(dap_sign_t *a_sign, dap_sign_t **a_decree_signs, size_t a_num_of_decree_sign);
static inline dap_sign_t *s_concate_all_signs_in_array(dap_sign_t *a_in_signs, size_t a_signs_size, size_t *a_sings_count, size_t *a_signs_arr_size);
static bool s_debug_more = false;
int dap_chain_net_anchor_init()
{
s_debug_more = dap_config_get_item_bool_default(g_config, "chain_net", "debug_more", s_debug_more);
return 0;
}
static int s_anchor_verify(dap_chain_net_t *a_net, dap_chain_datum_anchor_t *a_anchor, size_t a_data_size, bool a_load_mode)
{
if (a_data_size < sizeof(dap_chain_datum_anchor_t))
return log_it(L_WARNING, "Anchor size is too small"), -120;
if (dap_chain_datum_anchor_get_size(a_anchor) != a_data_size)
return log_it(L_WARNING, "Anchor size is invalid, %lu != %lu", dap_chain_datum_anchor_get_size(a_anchor), a_data_size), -121;
int ret_val = 0;
size_t l_signs_size = a_anchor->header.signs_size;
//multiple signs reading from datum
dap_sign_t *l_signs_block = (dap_sign_t*)(a_anchor->data_n_sign + a_anchor->header.data_size);
if (!l_signs_size || !l_signs_block)
return log_it(L_WARNING, "Anchor data sign not found"), -100;
// Find unique pkeys in pkeys set from previous step and check that number of signs > min
size_t l_num_of_unique_signs = 0;
dap_sign_t **l_unique_signs = dap_sign_get_unique_signs(l_signs_block, l_signs_size, &l_num_of_unique_signs);
if (!l_num_of_unique_signs || !l_unique_signs)
return log_it(L_WARNING, "No unique signatures!"), -106;
bool l_sign_authorized = false;
size_t l_signs_size_original = a_anchor->header.signs_size;
a_anchor->header.signs_size = 0;
for (size_t i = 0; i < l_num_of_unique_signs; i++) {
dap_chain_net_decree_t *l_net_decree = dap_chain_net_get_net_decree(a_net);
for (dap_list_t *it = l_net_decree->pkeys; it; it = it->next) {
if (dap_pkey_compare_with_sign(it->data, l_unique_signs[i])) {
// TODO make signs verification in s_concate_all_signs_in_array to correctly header.signs_size calculation
size_t l_verify_data_size = a_anchor->header.data_size + sizeof(dap_chain_datum_anchor_t);
if (dap_sign_verify_all(l_unique_signs[i], l_signs_size_original, a_anchor, l_verify_data_size))
continue;
l_sign_authorized = true;
break;
}
}
a_anchor->header.signs_size += dap_sign_get_size(l_unique_signs[i]);
if (l_sign_authorized)
break;
}
DAP_DELETE(l_unique_signs);
a_anchor->header.signs_size = l_signs_size_original;
if (!l_sign_authorized) {
log_it(L_WARNING, "Anchor signs verify failed");
return -108;
}
dap_hash_fast_t l_decree_hash = {};
dap_chain_datum_decree_t *l_decree = NULL;
if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_decree_hash)) != 0) {
log_it(L_WARNING, "Can't get hash from anchor data");
return -106;
}
if (a_load_mode)
return 0;
bool l_is_applied = false;
l_decree = dap_chain_net_decree_get_by_hash(a_net, &l_decree_hash, &l_is_applied);
if (!l_decree) {
log_it(L_WARNING, "Can't get decree by hash %s", dap_hash_fast_to_str_static(&l_decree_hash));
return DAP_CHAIN_CS_VERIFY_CODE_NO_DECREE;
}
if (l_is_applied) {
log_it(L_WARNING, "The decree referred to by the anchor has already been applied");
return -109;
}
return 0;
}
// Public functions
int dap_chain_net_anchor_verify(dap_chain_net_t *a_net, dap_chain_datum_anchor_t *a_anchor, size_t a_data_size)
{
return s_anchor_verify(a_net, a_anchor, a_data_size, false);
}
int dap_chain_net_anchor_load(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain, dap_hash_fast_t *a_anchor_hash)
{
int ret_val = 0;
if (!a_anchor || !a_chain)
{
log_it(L_WARNING, "Invalid arguments. a_decree and a_chain must be not NULL");
return -107;
}
dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
dap_chain_net_decree_t *l_net_decree = dap_chain_net_get_net_decree(l_net);
if (!l_net_decree)
{
log_it(L_WARNING, "Decree is not inited!");
return -108;
}
if ((ret_val = s_anchor_verify(l_net, a_anchor, dap_chain_datum_anchor_get_size(a_anchor), true)) != 0)
{
log_it(L_WARNING, "Anchor is not pass verification!");
return ret_val;
}
dap_chain_hash_fast_t l_hash = {0};
if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_hash)) != 0)
{
log_it(L_WARNING, "Can not find datum hash in anchor data");
return -109;
}
if ((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain)) != 0){
debug_if(s_debug_more, L_WARNING, "Decree applying failed");
return ret_val;
}
anchor_table_t **l_anchors = dap_chain_net_get_anchors(l_net);
anchor_table_t *l_new_anchor = DAP_NEW_Z(anchor_table_t);
l_new_anchor->anchor_hash = *a_anchor_hash;
l_new_anchor->anchor = a_anchor;
HASH_ADD(hh, *l_anchors, anchor_hash, sizeof(l_new_anchor->anchor_hash), l_new_anchor);
return ret_val;
}
dap_chain_datum_anchor_t * s_find_previous_anchor(dap_hash_fast_t *a_old_anchor_hash, dap_chain_net_t *a_net)
{
if (!a_old_anchor_hash || !a_net){
log_it(L_ERROR,"Params are NULL");
return NULL;
}
dap_chain_net_t *l_net = a_net;
dap_chain_datum_anchor_t * l_ret_anchor = NULL;
dap_chain_datum_anchor_t *l_old_anchor = NULL;
anchor_table_t **l_anchors_ptr = dap_chain_net_get_anchors(l_net);
anchor_table_t *l_anchor = NULL;
HASH_FIND(hh, *l_anchors_ptr, a_old_anchor_hash, sizeof(*a_old_anchor_hash), l_anchor);
if (!l_old_anchor){
log_it(L_WARNING,"Can not find anchor");
return NULL;
}
l_old_anchor = l_anchor->anchor;
dap_hash_fast_t l_old_decrere_hash = {};
if (dap_chain_datum_anchor_get_hash_from_data(l_old_anchor, &l_old_decrere_hash) != 0)
return NULL;
dap_chain_datum_decree_t *l_old_decree = dap_chain_net_decree_get_by_hash(l_net, &l_old_decrere_hash, NULL);
uint16_t l_old_decree_type = l_old_decree->header.type;
uint16_t l_old_decree_subtype = l_old_decree->header.sub_type;
anchor_table_t *l_anchors = HASH_LAST(*l_anchors_ptr);
for(; l_anchors; l_anchors = l_anchors->hh.prev){
size_t l_datums_count = 0;
dap_chain_datum_anchor_t *l_curr_anchor = l_anchors->anchor;
dap_hash_fast_t l_hash = {};
if (dap_chain_datum_anchor_get_hash_from_data(l_curr_anchor, &l_hash) != 0)
continue;
bool l_is_applied = false;
dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(l_net, &l_hash, &l_is_applied);
if (!l_decree)
continue;
if (l_decree->header.type == l_old_decree_type && l_old_decree_type == DAP_CHAIN_DATUM_DECREE_TYPE_COMMON &&
l_old_decree_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE &&
l_decree->header.sub_type == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE){
dap_chain_addr_t l_addr_old, l_addr_new = {};
if (dap_chain_datum_decree_get_stake_signing_addr(l_old_decree, &l_addr_old)){
continue;
}
if (dap_chain_datum_decree_get_stake_signing_addr(l_decree, &l_addr_new)){
continue;
}
if(dap_chain_addr_compare(&l_addr_old, &l_addr_new)){
l_ret_anchor = l_curr_anchor;
dap_chain_net_decree_reset_applied(l_net, &l_hash);
break;
}
} else if (l_decree->header.type == l_old_decree_type && l_decree->header.sub_type == l_old_decree_subtype){
// check addr if l_decree type is stake approve
l_ret_anchor = l_curr_anchor;
dap_chain_net_decree_reset_applied(l_net, &l_hash);
break;
}
if (l_ret_anchor)
break;
}
return l_ret_anchor;
}
void s_delete_anchor(dap_chain_net_t *a_net, dap_hash_fast_t *a_anchor_hash)
{
anchor_table_t **l_anchors_ptr = dap_chain_net_get_anchors(a_net);
anchor_table_t *l_anchor = NULL;
HASH_FIND(hh, *l_anchors_ptr, a_anchor_hash, sizeof(*a_anchor_hash), l_anchor);
if(l_anchor){
HASH_DEL(*l_anchors_ptr, l_anchor);
DAP_DEL_Z(l_anchor);
}
}
int dap_chain_net_anchor_unload(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain, dap_hash_fast_t *a_anchor_hash)
{
int ret_val = 0;
if (!a_anchor || !a_chain)
{
log_it(L_WARNING,"Invalid arguments. a_decree and a_chain must be not NULL");
return -107;
}
dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
if (!dap_chain_net_get_net_decree(l_net))
{
log_it(L_WARNING,"Decree is not inited!");
return -108;
}
ret_val = s_anchor_verify(l_net, a_anchor, dap_chain_datum_anchor_get_size(a_anchor), true);
if (ret_val != 0)
{
log_it(L_WARNING,"Decree is not pass verification!");
return ret_val;
}
dap_hash_fast_t l_hash = {};
if (dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_hash) != 0)
return -110;
dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(l_net, &l_hash, NULL);
if (!l_decree)
return -111;
if(l_decree->header.type == DAP_CHAIN_DATUM_DECREE_TYPE_COMMON){
switch (l_decree->header.sub_type)
{
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_FEE:{
dap_chain_net_decree_reset_applied(l_net, &l_hash);
dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor_hash, l_net);
s_delete_anchor(l_net, a_anchor_hash);
if (l_new_anchor){// if previous anchor is founded apply it
dap_chain_hash_fast_t l_hash = {0};
if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){
log_it(L_WARNING,"Can not find datum hash in anchor data");
return -109;
}
if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){
log_it(L_WARNING,"Decree applying failed");
return ret_val;
}
} else {
dap_chain_addr_t a_addr = c_dap_chain_addr_blank;
if (!dap_chain_net_tx_set_fee(a_chain->net_id, uint256_0, a_addr)){
log_it(L_ERROR, "Can't set fee value for network %s", dap_chain_net_by_id(a_chain->net_id)->pub.name);
ret_val = -100;
}
}
}
break;
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE:{
// Invalidate canceled stake
dap_chain_addr_t l_signing_addr = {};
if ((ret_val = dap_chain_datum_decree_get_stake_signing_addr(l_decree, &l_signing_addr)) != 0){
log_it(L_WARNING,"Can't get signing address from decree.");
return -105;
}
dap_chain_net_srv_stake_key_invalidate(&l_signing_addr);
dap_chain_net_decree_reset_applied(l_net, &l_hash);
s_delete_anchor(l_net, a_anchor_hash);
}
break;
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE:{
// Find previous anchor with this stake approve and apply it
dap_chain_net_decree_reset_applied(l_net, &l_hash);
dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor_hash, l_net);
s_delete_anchor(l_net, a_anchor_hash);
if (l_new_anchor){// if previous anchor is founded apply it
dap_chain_hash_fast_t l_hash = {0};
if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){
log_it(L_WARNING,"Can not find datum hash in anchor data");
return -109;
}
if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){
log_it(L_WARNING,"Decree applying failed");
return ret_val;
}
}
}
break;
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_MIN_VALUE:{
dap_chain_net_decree_reset_applied(l_net, &l_hash);
dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor_hash, l_net);
s_delete_anchor(l_net, a_anchor_hash);
if (l_new_anchor){// if previous anchor is founded apply it
dap_chain_hash_fast_t l_hash = {0};
if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){
log_it(L_WARNING,"Can not find datum hash in anchor data");
return -109;
}
if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){
log_it(L_WARNING,"Decree applying failed");
return ret_val;
}
} else {
dap_chain_addr_t a_addr = {};
dap_chain_net_srv_stake_set_allowed_min_value(a_chain->net_id, dap_chain_coins_to_balance("1.0"));
}
}
break;
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_MIN_VALIDATORS_COUNT:{
dap_chain_net_decree_reset_applied(l_net, &l_hash);
dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor_hash, l_net);
s_delete_anchor(l_net, a_anchor_hash);
if (l_new_anchor){// if previous anchor is founded apply it
dap_chain_hash_fast_t l_hash = {0};
if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){
log_it(L_WARNING,"Can not find datum hash in anchor data");
return -109;
}
if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){
log_it(L_WARNING,"Decree applying failed");
return ret_val;
}
} else {
dap_chain_esbocs_set_min_validators_count(a_chain, 0);
}
}
break;
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_REWARD:{
// find previous anchor with rewarrd and apply it
dap_chain_net_decree_reset_applied(l_net, &l_hash);
dap_chain_net_remove_last_reward(dap_chain_net_by_id(a_chain->net_id));
s_delete_anchor(l_net, a_anchor_hash);
}
break;
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_OWNERS:
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_OWNERS_MIN:
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN:
case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN:
ret_val = -1;
default:
break;
}
} else if(l_decree->header.type == DAP_CHAIN_DATUM_DECREE_TYPE_SERVICE){
}
return ret_val;
}
// Private functions
static bool s_verify_pubkeys (dap_sign_t *a_sign, dap_sign_t **a_decree_signs, size_t a_num_of_decree_sign)
{
bool ret_val = false;
for(size_t i = 0; i < a_num_of_decree_sign; i++)
{
if (!memcmp(a_sign->pkey_n_sign, a_decree_signs[i]->pkey_n_sign, a_sign->header.sign_pkey_size))
{
ret_val = true;
break;
}
}
return ret_val;
}
static inline dap_sign_t *s_concate_all_signs_in_array(dap_sign_t *a_in_signs, size_t a_signs_size, size_t *a_sings_count, size_t *a_signs_arr_size)
{
if (!a_in_signs)
{
log_it(L_WARNING,"Bad arguments");
return NULL;
}
// Concate all signs in array
uint32_t l_signs_count = 0;
size_t l_signs_offset = dap_sign_get_size(a_in_signs);
size_t l_signs_arr_size = 0;
dap_sign_t *l_signs_arr = DAP_NEW_Z_SIZE(dap_sign_t, l_signs_offset);
memcpy(l_signs_arr, a_in_signs, l_signs_offset);
l_signs_arr_size += l_signs_offset;
l_signs_count++;
while (l_signs_offset < a_signs_size)
{
dap_sign_t *cur_sign = (dap_sign_t *)((byte_t*)a_in_signs + l_signs_offset);
size_t l_sign_size = dap_sign_get_size(cur_sign);
if (l_sign_size > a_signs_size)
{
log_it(L_WARNING,"Sign size greather than decree datum signs size. May be data is corrupted.");
DAP_DELETE(l_signs_arr);
return NULL;
}
dap_sign_t *l_signs_arr_temp = (dap_sign_t *)DAP_REALLOC(l_signs_arr, l_signs_arr_size + l_sign_size);
if (!l_signs_arr_temp)
{
log_it(L_WARNING,"Memory allocate fail");
DAP_DELETE(l_signs_arr);
return NULL;
}
l_signs_arr = l_signs_arr_temp;
memcpy((byte_t *)l_signs_arr + l_signs_arr_size, cur_sign, l_sign_size);
l_signs_arr_size += l_sign_size;
l_signs_offset += l_sign_size;
l_signs_count++;
}
if (a_sings_count)
*a_sings_count = l_signs_count;
if(a_signs_arr_size)
*a_signs_arr_size = l_signs_arr_size;
return l_signs_arr;
}