/* * Authors: * Dmitriy A. Gearasimov <kahovski@gmail.com> * DeM Labs Inc. https://demlabs.net * DeM Labs Open source community https://github.com/demlabsinc * Copyright (c) 2017-2018 * All rights reserved. This file is part of DAP (Deus Applications Prototypes) the open source project DAP (Deus Applicaions Prototypes) 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. DAP 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 DAP based project. If not, see <http://www.gnu.org/licenses/>. */ #include <stdint.h> #include <string.h> #include "dap_common.h" #include "dap_enc_key.h" #include "dap_chain_common.h" #include "dap_sign.h" #include "dap_hash.h" #include "dap_chain_datum_tx.h" #include "dap_chain_datum_tx_in.h" #include "dap_chain_datum_tx_out.h" #include "dap_chain_datum_tx_in_cond.h" #include "dap_chain_datum_tx_out_cond.h" #include "dap_chain_datum_tx_items.h" static size_t dap_chain_tx_in_get_size(const dap_chain_tx_in_t *a_item) { (void) a_item; size_t size = sizeof(dap_chain_tx_in_t); // + item->header.sig_size; return size; } static size_t dap_chain_tx_in_cond_get_size(const dap_chain_tx_in_cond_t *a_item) { UNUSED(a_item); size_t size = sizeof(dap_chain_tx_in_cond_t); return size; } static size_t dap_chain_tx_out_get_size(const dap_chain_tx_out_t *a_item) { (void) a_item; size_t size = sizeof(dap_chain_tx_out_t); return size; } static size_t dap_chain_tx_out_ext_get_size(const dap_chain_tx_out_ext_t *a_item) { (void) a_item; size_t size = sizeof(dap_chain_tx_out_ext_t); return size; } static size_t dap_chain_tx_out_cond_get_size(const dap_chain_tx_out_cond_t *a_item) { return sizeof(dap_chain_tx_out_cond_t) + a_item->params_size; } static size_t dap_chain_tx_pkey_get_size(const dap_chain_tx_pkey_t *a_item) { size_t size = sizeof(dap_chain_tx_pkey_t) + a_item->header.sig_size; return size; } static size_t dap_chain_tx_sig_get_size(const dap_chain_tx_sig_t *item) { size_t size = sizeof(dap_chain_tx_sig_t) + item->header.sig_size; return size; } static size_t dap_chain_tx_token_get_size(const dap_chain_tx_token_t *a_item) { (void) a_item; size_t size = sizeof(dap_chain_tx_token_t); return size; } /** * Get item type * * return type, or TX_ITEM_TYPE_ANY if error */ dap_chain_tx_item_type_t dap_chain_datum_tx_item_get_type(const uint8_t *a_item) { const dap_chain_tx_in_t *l_item_tx_in = (const dap_chain_tx_in_t*) a_item; dap_chain_tx_item_type_t type = (l_item_tx_in) ? l_item_tx_in->header.type : TX_ITEM_TYPE_ANY; return type; } /** * Get item size * * return size, 0 Error */ size_t dap_chain_datum_item_tx_get_size(const uint8_t *a_item) { dap_chain_tx_item_type_t type = dap_chain_datum_tx_item_get_type(a_item); size_t size = 0; switch (type) { case TX_ITEM_TYPE_IN: // Transaction inputs size = dap_chain_tx_in_get_size((const dap_chain_tx_in_t*) a_item); break; case TX_ITEM_TYPE_OUT: // Transaction outputs size = dap_chain_tx_out_get_size((const dap_chain_tx_out_t*) a_item); break; case TX_ITEM_TYPE_OUT_EXT: size = dap_chain_tx_out_ext_get_size((const dap_chain_tx_out_ext_t*) a_item); break; case TX_ITEM_TYPE_RECEIPT: // Receipt size = dap_chain_datum_tx_receipt_get_size((const dap_chain_datum_tx_receipt_t*) a_item); case TX_ITEM_TYPE_IN_COND: // Transaction inputs with condition size = dap_chain_tx_in_cond_get_size((const dap_chain_tx_in_cond_t*) a_item); break; case TX_ITEM_TYPE_OUT_COND: // Transaction output with condition size = dap_chain_tx_out_cond_get_size((const dap_chain_tx_out_cond_t*) a_item); break; case TX_ITEM_TYPE_PKEY: // Transaction public keys size = dap_chain_tx_pkey_get_size((const dap_chain_tx_pkey_t*) a_item); break; case TX_ITEM_TYPE_SIG: // Transaction signatures size = dap_chain_tx_sig_get_size((const dap_chain_tx_sig_t*) a_item); break; case TX_ITEM_TYPE_TOKEN: // token item size = dap_chain_tx_token_get_size((const dap_chain_tx_token_t*) a_item); break; default: return 0; } return size; } /** * Create item dap_chain_tx_token_t * * return item, NULL Error */ dap_chain_tx_token_t* dap_chain_datum_tx_item_token_create(dap_chain_hash_fast_t * a_datum_token_hash,const char * a_ticker) { if(!a_ticker) return NULL; size_t a_ticker_len = strlen(a_ticker); dap_chain_tx_token_t *l_item = DAP_NEW_Z(dap_chain_tx_token_t); l_item->header.type = TX_ITEM_TYPE_TOKEN; memcpy (& l_item->header.token_emission_hash, a_datum_token_hash, sizeof ( *a_datum_token_hash ) ); if(a_ticker_len >= sizeof(l_item->header.ticker)) a_ticker_len = sizeof(l_item->header.ticker) - 1; strncpy(l_item->header.ticker, a_ticker, a_ticker_len); return l_item; } /** * Create item dap_chain_tx_out_t * * return item, NULL Error */ dap_chain_tx_in_t* dap_chain_datum_tx_item_in_create(dap_chain_hash_fast_t *a_tx_prev_hash, uint32_t a_tx_out_prev_idx) { if(!a_tx_prev_hash) return NULL; dap_chain_tx_in_t *l_item = DAP_NEW_Z(dap_chain_tx_in_t); l_item->header.type = TX_ITEM_TYPE_IN; l_item->header.tx_out_prev_idx = a_tx_out_prev_idx; memcpy(&l_item->header.tx_prev_hash, a_tx_prev_hash, sizeof(dap_chain_hash_fast_t)); return l_item; } /** * @brief dap_chain_datum_tx_item_in_cond_create * @param a_pkey_serialized * @param a_pkey_serialized_size * @param a_receipt_idx * @return */ dap_chain_tx_in_cond_t* dap_chain_datum_tx_item_in_cond_create(dap_chain_hash_fast_t *a_tx_prev_hash, uint32_t a_tx_out_prev_idx, uint32_t a_receipt_idx) { if(!a_tx_prev_hash ) return NULL; dap_chain_tx_in_cond_t *l_item = DAP_NEW_Z(dap_chain_tx_in_cond_t); l_item->header.type = TX_ITEM_TYPE_IN_COND; l_item->header.receipt_idx = a_receipt_idx; l_item->header.tx_out_prev_idx = a_tx_out_prev_idx; memcpy(&l_item->header.tx_prev_hash, a_tx_prev_hash,sizeof(l_item->header.tx_prev_hash) ); return l_item; } /** * Create item dap_chain_tx_out_t * * return item, NULL Error */ dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a_addr, uint64_t a_value) { if(!a_addr) return NULL; dap_chain_tx_out_t *l_item = DAP_NEW_Z(dap_chain_tx_out_t); l_item->header.type = TX_ITEM_TYPE_OUT; l_item->header.value = a_value; memcpy(&l_item->addr, a_addr, sizeof(dap_chain_addr_t)); return l_item; } dap_chain_tx_out_ext_t* dap_chain_datum_tx_item_out_ext_create(const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token) { if (!a_addr || !a_token) return NULL; dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t); l_item->header.type = TX_ITEM_TYPE_OUT_EXT; l_item->header.value = a_value; memcpy(&l_item->addr, a_addr, sizeof(dap_chain_addr_t)); strcpy(l_item->token, a_token); return l_item; } /** * Create item dap_chain_tx_out_cond_t * * return item, NULL Error */ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_pay(dap_enc_key_t *a_key, dap_chain_net_srv_uid_t a_srv_uid, uint64_t a_value,uint64_t a_value_max_per_unit, dap_chain_net_srv_price_unit_uid_t a_unit, const void *a_params, size_t a_params_size) { if(!a_key || !a_params) return NULL; size_t l_pub_key_size = 0; uint8_t *l_pub_key = dap_enc_key_serealize_pub_key(a_key, &l_pub_key_size); dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size); l_item->header.item_type = TX_ITEM_TYPE_OUT_COND; l_item->header.value = a_value; l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY; // By default creatre cond for service pay. Rework with smth more flexible l_item->subtype.srv_pay.srv_uid = a_srv_uid; l_item->subtype.srv_pay.unit = a_unit; l_item->subtype.srv_pay.unit_price_max_datoshi = a_value_max_per_unit; dap_hash_fast( l_pub_key, l_pub_key_size, & l_item->subtype.srv_pay.pkey_hash); l_item->params_size = (uint32_t)a_params_size; memcpy(l_item->params, a_params, a_params_size); return l_item; } dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap_chain_net_srv_uid_t a_srv_uid, dap_chain_net_id_t a_net_id, const char *a_token, uint64_t a_value, const void *a_params, uint32_t a_params_size) { if (!a_token) { return NULL; } dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size); l_item->header.item_type = TX_ITEM_TYPE_OUT_COND; l_item->header.value = a_value; l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE; l_item->subtype.srv_xchange.srv_uid = a_srv_uid; l_item->subtype.srv_xchange.net_id = a_net_id; strcpy(l_item->subtype.srv_xchange.token, a_token); l_item->params_size = a_params_size; if (a_params_size) { memcpy(l_item->params, a_params, a_params_size); } return l_item; } dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_stake(dap_chain_net_srv_uid_t a_srv_uid, uint64_t a_value, long double a_fee_value, dap_chain_addr_t *a_fee_addr, const void *a_params, uint32_t a_params_size) { dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size); l_item->header.item_type = TX_ITEM_TYPE_OUT_COND; l_item->header.value = a_value; l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE; l_item->subtype.srv_stake.srv_uid = a_srv_uid; l_item->subtype.srv_stake.fee_value = a_fee_value; memcpy(&l_item->subtype.srv_stake.fee_addr, a_fee_addr, sizeof(dap_chain_addr_t)); l_item->params_size = a_params_size; if (a_params_size) { memcpy(l_item->params, a_params, a_params_size); } return l_item; } /** * Create item dap_chain_tx_sig_t * * return item, NULL Error */ dap_chain_tx_sig_t* dap_chain_datum_tx_item_sign_create(dap_enc_key_t *a_key, const void *a_data, size_t a_data_size) { if(!a_key || !a_data || !a_data_size) return NULL; dap_sign_t *l_chain_sign = dap_sign_create(a_key, a_data, a_data_size, 0); size_t l_chain_sign_size = dap_sign_get_size(l_chain_sign); // sign data if(!l_chain_sign) { return NULL; } dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE(dap_chain_tx_sig_t, sizeof(dap_chain_tx_sig_t) + l_chain_sign_size); l_tx_sig->header.type = TX_ITEM_TYPE_SIG; l_tx_sig->header.sig_size =(uint32_t) l_chain_sign_size; memcpy(l_tx_sig->sig, l_chain_sign, l_chain_sign_size); DAP_DELETE(l_chain_sign); return l_tx_sig; } /** * Get sign from sign item * * return sign, NULL Error */ dap_sign_t* dap_chain_datum_tx_item_sign_get_sig(dap_chain_tx_sig_t *a_tx_sig) { if(!a_tx_sig || !a_tx_sig->header.sig_size) return NULL; return (dap_sign_t*) a_tx_sig->sig; } /** * Get item from transaction * * a_tx [in] transaction * a_item_idx_start[in/out] start index / found index of item in transaction, if 0 then from beginning * a_type[in] type of item being find, if TX_ITEM_TYPE_ANY - any item * a_item_out_size size[out] size of returned item * return item data, NULL Error index or bad format transaction */ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_idx_start, dap_chain_tx_item_type_t a_type, int *a_item_out_size) { if(!a_tx) return NULL; uint32_t l_tx_items_pos = 0, l_tx_items_size = a_tx->header.tx_items_size; int l_item_idx = 0; while(l_tx_items_pos < l_tx_items_size) { uint8_t *l_item = a_tx->tx_items + l_tx_items_pos; int l_item_size = dap_chain_datum_item_tx_get_size(l_item); if(!l_item_size) return NULL; // check index if(!a_item_idx_start || l_item_idx >= *a_item_idx_start) { // check type dap_chain_tx_item_type_t l_type = dap_chain_datum_tx_item_get_type(l_item); if (a_type == TX_ITEM_TYPE_ANY || a_type == l_type || (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT) || (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_COND) || (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_EXT)) { if(a_item_idx_start) *a_item_idx_start = l_item_idx; if(a_item_out_size) *a_item_out_size = l_item_size; return l_item; } } l_tx_items_pos += l_item_size; l_item_idx++; } return NULL; } /** * Get all item from transaction by type * * a_tx [in] transaction * a_item_idx_start[in/out] start index / found index of item in transaction, if 0 then from beginning * a_type[in] type of item being find, if TX_ITEM_TYPE_ANY - any item * a_item_count[out] count of returned item * return item data, NULL Error index or bad format transaction */ dap_list_t* dap_chain_datum_tx_items_get(dap_chain_datum_tx_t *a_tx, dap_chain_tx_item_type_t a_type, int *a_item_count) { dap_list_t *items_list = NULL; int l_items_count = 0, l_item_idx_start = 0; // Get sign item from transaction while(1) { uint8_t *l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx_start, a_type, NULL); if(!l_tx_item) break; items_list = dap_list_append(items_list, l_tx_item); l_items_count++; l_item_idx_start++; } if(a_item_count) *a_item_count = l_items_count; return items_list; } dap_chain_tx_out_cond_t *dap_chain_datum_tx_out_cond_get(dap_chain_datum_tx_t *a_tx, int *a_out_num) { dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, NULL); int l_prev_cond_idx = l_list_out_items ? 0 : -1; dap_chain_tx_out_cond_t *l_res = NULL; for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_prev_cond_idx++) { if (*(uint8_t *)l_list_tmp->data == TX_ITEM_TYPE_OUT_COND) { l_res = l_list_tmp->data; break; } } dap_list_free(l_list_out_items); if (a_out_num) { *a_out_num = l_prev_cond_idx; } return l_res; }