Skip to content
Snippets Groups Projects
Commit 08db6bda authored by Dmitriy A. Gerasimov's avatar Dmitriy A. Gerasimov
Browse files

[+] Block consensuses

parent 158a2408
No related branches found
No related tags found
No related merge requests found
Showing
with 684 additions and 0 deletions
cmake_minimum_required(VERSION 2.8)
project (dap_chain_cs_block)
set(DAP_CHAIN_BLOCK_SRCS
dap_chain_block.c
dap_chain_cs_blocks.c
dap_chain_block_cache.c
)
set(DAP_CHAIN_BLOCK_HEADERS
dap_chain_block.h
dap_chain_cs_blocks.h
dap_chain_block_cache.h
)
add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_SRCS} ${DAP_CHAIN_BLOCK_HEADERS})
target_link_libraries(dap_chain_cs_block dap_core dap_crypto dap_chain dap_chain_crypto )
target_include_directories(dap_chain_cs_block INTERFACE .)
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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 "string.h"
#include "dap_common.h"
#include "dap_chain_block.h"
#define LOG_TAG "dap_chain_block"
/**
* @brief dap_chain_block_init
* @return
*/
int dap_chain_block_init()
{
return 0;
}
/**
* @brief dap_chain_block_deinit
*/
void dap_chain_block_deinit()
{
}
/**
* @brief dap_chain_block_new
* @param a_prev_block
* @return
*/
dap_chain_block_t * dap_chain_block_new(dap_chain_hash_t * a_prev_block )
{
dap_chain_block_t * l_block = DAP_NEW_Z_SIZE (dap_chain_block_t,sizeof(l_block->header));
if( l_block == NULL){
log_it(L_CRITICAL, "Can't allocate memory for the new block");
return NULL;
}else{
l_block->header.signature = DAP_CHAIN_BLOCK_SIGNATURE;
l_block->header.version = 1;
l_block->header.timestamp = time(NULL);
if( a_prev_block ){
memcpy(&l_block->header.prev_block,a_prev_block,sizeof(l_block->header.prev_block));
}else{
log_it(L_INFO, "Genesis block produced");
memset(&l_block->header.prev_block,0xff,sizeof(l_block->header.prev_block));
}
l_block->header.size = sizeof(l_block->header);
return l_block;
}
}
/**
* @brief dap_chain_block_create_section
* @param a_block
* @param a_section_type
* @param a_section_data_size
* @return
*/
dap_chain_datum_t * dap_chain_block_create_section(dap_chain_block_t * a_block, uint32_t a_section_offset,
uint16_t a_section_type, uint32_t a_section_data_size )
{
if ( a_block) {
uint32_t l_sections_size = ( a_block->header.size - sizeof(a_block->header) );
if( l_sections_size > a_section_offset ){
if( l_sections_size > (a_section_offset + a_section_data_size ) ) {
dap_chain_datum_t * l_section = (dap_chain_datum_t *) ( a_block->datums +a_section_offset) ;
l_section->header.type_id = a_section_type;
return l_section;
}else{
log_it(L_ERROR, "Section data size %lu is bigger then left for sections in block (%lu)"
,a_section_data_size,l_sections_size - a_section_offset );
return NULL;
}
}else{
log_it(L_ERROR, "Section offset %lu is bigger then section size %lu",a_section_offset,l_sections_size);
return NULL;
}
}else{
log_it(L_ERROR, "Block is NULL");
return NULL;
}
}
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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 <stdlib.h>
#include <time.h>
#include "dap_common.h"
#include "dap_chain_block_cache.h"
#include "dap_chain_datum_coin.h"
#include "dap_chain_datum_tx.h"
#include "dap_chain_datum_tx_in.h"
#include "dap_chain_datum_tx_out.h"
#define LOG_TAG "dap_chain_block_cache"
dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_block_t * a_block)
{
dap_chain_block_cache_t * l_block_cache = DAP_NEW_Z(dap_chain_block_cache_t);
l_block_cache->block = a_block;
log_it(L_DEBUG,"Block cache created");
return l_block_cache;
}
/**
* @brief dap_chain_block_cache_delete
* @param a_block
*/
void dap_chain_block_cache_delete(dap_chain_block_cache_t * a_block_cache)
{
DAP_DELETE(a_block_cache);
log_it(L_DEBUG,"Block cache deleted");
}
/**
* @brief dap_chain_block_cache_dump
* @param a_block_cache
*/
void dap_chain_block_cache_dump(dap_chain_block_cache_t * a_block_cache)
{
if ( a_block_cache ) {
dap_chain_block_t * l_block = a_block_cache->block;
if( l_block ){
char * l_hash_str = dap_chain_hash_to_str_new(&a_block_cache->block_hash);
char * l_prev_hash_str = dap_chain_hash_to_str_new(&l_block->header.prev_block);
char * l_root_sections_str = dap_chain_hash_to_str_new(&l_block->header.root_sections);
log_it(L_INFO, " ** block_hash %s",l_hash_str);
log_it(L_INFO, " ** version %d",l_block->header.version);
log_it(L_INFO, " ** timestamp %s", ctime( (time_t*) &l_block->header.timestamp) );
log_it(L_INFO, " ** difficulty %llu",l_block->header.difficulty);
log_it(L_INFO, " ** nonce %llu",l_block->header.nonce);
log_it(L_INFO, " ** prev_block %s",l_prev_hash_str);
log_it(L_INFO, " ** root_sections %s",l_root_sections_str );
log_it(L_INFO, " ** size %u",l_block->header.size);
log_it(L_INFO, " ** sections[]");
DAP_DELETE(l_hash_str);
DAP_DELETE(l_prev_hash_str);
size_t i, l_sections_size = l_block->header.size - sizeof(l_block->header);
for( i = 0; i< l_sections_size; i++ ){
dap_chain_datum_t * l_datum = (dap_chain_datum_t *) (l_block->datums + i);
switch ( l_datum->header.type_id ) {
case DAP_CHAIN_DATUM_TX:{
dap_chain_datum_tx_t * l_tx = (dap_chain_datum_tx_t *) l_datum->data;
log_it(L_INFO, " ** tx");
log_it(L_INFO, " ** lock_time %s", l_tx->header.lock_time?
ctime( (time_t *) &l_tx->header.lock_time ) : "0x0000000000000000" );
log_it(L_INFO, " ** tx_items_size %u ",l_tx->header.tx_items_size);
/*uint32_t l_data_offset;
for ( l_data_offset = 0; l_data_offset < l_tx->header.tx_items_size; ++l_data_offset ){
}*/
i += sizeof (l_tx->header);
i += l_tx->header.tx_items_size ;
}break;
default:
i = l_sections_size;
}
}
}else{
log_it(L_ERROR,"block in block cache for dump is NULL");
}
}else{
log_it(L_ERROR,"block cache for dump is NULL");
}
}
/**
* @brief dap_chain_block_cache_sections_size_grow
* @param a_block_cache
* @param a_sections_size_grow
*/
dap_chain_block_t* dap_chain_block_cache_sections_size_grow(dap_chain_block_cache_t * a_block_cache,size_t a_sections_size_grow )
{
log_it(L_DEBUG,"Block section size reallocation: grow up +%lu",a_sections_size_grow);
a_block_cache->block->header.size += a_sections_size_grow;
a_block_cache->block=(dap_chain_block_t *) realloc(a_block_cache->block,a_block_cache->block->header.size );
if( a_block_cache->block ){
a_block_cache->sections_size += a_sections_size_grow;
return a_block_cache->block;
}else{
log_it(L_ERROR, "Can't reallocate block!");
return NULL;
}
}
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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 "dap_common.h"
#include "dap_chain_cs_blocks.h"
#include "dap_chain_block.h"
#include "dap_chain_block_cache.h"
#define LOG_TAG "dap_chain_cs_blocks"
typedef struct dap_chain_cs_blocks_pvt
{
dap_chain_cs_blocks_t * blocks;
dap_chain_block_cache_t * block_cache_first; // Mapped area start
dap_chain_block_cache_t * block_cache_last; // Last block in mapped area
uint64_t blocks_count;
uint64_t difficulty;
} dap_chain_cs_blocks_pvt_t;
#define PVT(a) ((dap_chain_cs_blocks_pvt_t *) a->_pvt )
/**
* @brief dap_chain_cs_blocks_init
* @return
*/
int dap_chain_cs_blocks_init()
{
return 0;
}
/**
* @brief dap_chain_cs_blocks_deinit
*/
void dap_chain_cs_blocks_deinit()
{
}
dap_chain_block_cache_t* dap_chain_cs_blocks_allocate_next_block(dap_chain_cs_blocks_t * a_cs_blocks)
{
dap_chain_block_t* l_block = NULL;
dap_chain_block_cache_t* l_block_cache = NULL;
if ( PVT(a_cs_blocks)->block_cache_last )
l_block = dap_chain_block_new( &PVT(a_cs_blocks)->block_cache_last->block_hash );
else
l_block = dap_chain_block_new( NULL );
if( l_block ){
l_block->header.difficulty = PVT(a_cs_blocks)->difficulty;
l_block_cache = dap_chain_block_cache_new(l_block);
return l_block_cache;
}else{
log_it(L_ERROR, "Can't allocate next block!");
return NULL;
}
}
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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/>.
*/
#pragma once
#include <stdalign.h>
#include <stdint.h>
#include <stddef.h>
#include "dap_common.h"
#include "dap_math_ops.h"
#include "dap_hash.h"
#include "dap_chain_common.h"
#include "dap_chain_datum.h"
#include "dap_chain_datum_hashtree_roots.h"
#define DAP_CHAIN_BLOCK_SIGNATURE 0xDA05BF8E
#define DAP_CHAIN_BLOCK_ID_SIZE 4
typedef union dap_chain_block_typeid{
uint8_t data[DAP_CHAIN_BLOCK_ID_SIZE];
} DAP_ALIGN_PACKED dap_chain_block_typeid_t;
/**
* @brief The dap_chain_block struct
*/
typedef struct dap_chain_block{
struct block_header{
uint32_t signature; /// @param signature @brief Magic number, always equels to DAP_CHAIN_BLOCK_SIGNATURE
int32_t version; /// @param version @brief block version (be carefull, signed value, as Bitcoin has)
uint32_t size; /// @param size of the whole block
uint64_t timestamp; /// @param timestamp @brief Block create time timestamp
uint64_t difficulty; /// difficulty level
uint64_t nonce; /// Nonce value to allow header variation for mining
union{
struct{ // Zero-level block without sharding
dap_chain_hash_t prev_block; /// @param prev_block Hash of the previous block
dap_chain_hash_t padding0; //
uint32_t padding1; //
uint64_t padding2; // Always zero (should be well compresed)
};
struct{
dap_chain_hash_t prev_block_0lvl; /// @param prev_block Hash of the previous block
dap_chain_hash_t prev_block_shard; /// @param prev_block Hash of the previous block
uint32_t shard_id; // Shard id
uint64_t nonce2; // Second NonCE for block mining inside the shard
};
};
dap_chain_hash_t root_sections;/// @param root_main Main tree's root for all sections's hashes
} DAP_ALIGN_PACKED header;
uint8_t datums[]; // Sections
} DAP_ALIGN_PACKED dap_chain_block_t;
int dap_chain_block_init();
void dap_chain_block_deinit();
dap_chain_block_t * dap_chain_block_new(dap_chain_hash_t * a_prev_block );
dap_chain_datum_t * dap_chain_block_create_section(dap_chain_block_t * a_block, uint32_t a_section_offset
, uint16_t a_section_type, uint32_t a_section_data_size );
/**
* @brief dap_chain_block_calc_hash
* @param a_block
* @return
*/
static inline void dap_chain_block_hash_calc(dap_chain_block_t * a_block, dap_chain_hash_t * a_hash){
dap_hash(a_block,a_block->header.size,a_hash->raw,
sizeof(a_hash->raw),DAP_HASH_TYPE_SLOW_0);
}
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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/>.
*/
#pragma once
#include "dap_chain_block.h"
#include "dap_hash.h"
typedef struct dap_chain_block_cache{
dap_chain_hash_t block_hash;
uint32_t sections_size;
double block_mine_time;
dap_chain_block_t * block;
} dap_chain_block_cache_t;
dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_block_t * a_block);
void dap_chain_block_cache_delete(dap_chain_block_cache_t * a_block_cache);
dap_chain_block_t* dap_chain_block_cache_sections_size_grow(dap_chain_block_cache_t * a_block_cache,size_t a_sections_size_grow );
void dap_chain_block_cache_dump(dap_chain_block_cache_t * a_block_cache);
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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/>.
*/
#pragma once
#include "dap_chain.h"
#include "dap_chain_block.h"
#include "dap_chain_block_cache.h"
typedef struct dap_chain_cs_blocks
{
dap_chain_t * chain;
void * _pvt;
void * _iheritor;
} dap_chain_cs_blocks_t;
typedef int (*dap_chain_blocks_block_callback_ptr_t)(dap_chain_cs_blocks_t *, dap_chain_block_t *);
int dap_chain_cs_blocks_init();
void dap_chain_cs_blocks_deinit();
dap_chain_block_cache_t* dap_chain_cs_blocks_allocate_next_block(dap_chain_cs_blocks_t * a_cs_blocks);
void dap_chain_cs_blocks_new(dap_chain_t * a_chain);
cmake_minimum_required(VERSION 2.8)
project (dap_chain_cs_block_poa)
set(DAP_CHAIN_BLOCK_CS_POA_SRCS
dap_chain_cs_block_poa.c
)
set(DAP_CHAIN_BLOCK_CS_POA_HEADERS
dap_chain_cs_block_poa.h
)
add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_CS_POA_SRCS} ${DAP_CHAIN_BLOCK_CS_POA_HEADERS})
add_definitions ("-DDAP_CHAIN_BLOCK_CS_POA")
target_link_libraries(dap_chain_cs_block_poa dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_cs_block )
target_include_directories(dap_chain_cs_block_poa INTERFACE .)
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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 "dap_common.h"
#include "dap_chain_cs_block_poa.h"
#include "dap_chain.h"
#include "dap_chain_cs_blocks.h"
#define LOG_TAG "dap_chain_cs_block_poa"
dap_chain_t *s_callback_chain_new();
void s_callback_delete(dap_chain_t * );
void s_callback_blocks(dap_chain_cs_blocks_t *, dap_chain_block_t * );
int dap_chain_cs_block_poa_init()
{
// dap_chain_block_cs_add
return 0;
}
void dap_chain_cs_block_poa_deinit()
{
}
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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/>.
*/
#pragma once
int dap_chain_cs_block_poa_init();
void dap_chain_cs_block_poa_deinit();
cmake_minimum_required(VERSION 2.8)
project (dap_chain_cs_block_pow)
set(DAP_CHAIN_BLOCK_CS_POW_SRCS
dap_chain_cs_block_pow.c
)
set(DAP_CHAIN_BLOCK_CS_POW_HEADERS
dap_chain_cs_block_pow.h
)
add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_CS_POW_SRCS} ${DAP_CHAIN_BLOCK_CS_POW_HEADERS})
target_link_libraries(dap_chain_cs_block_pow dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_cs_block )
target_include_directories(dap_chain_block_cs_pow INTERFACE .)
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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 "dap_common.h"
#include "dap_chain_cs_block_pow.h"
#define LOG_TAG "chain_cs_block_pow"
int dap_chain_cs_block_pow_init()
{
return 0;
}
void dap_chain_cs_block_pow_deinit()
{
}
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* 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/>.
*/
#pragma once
int dap_chain_cs_block_pow_init();
void dap_chain_cs_block_pow_deinit();
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment