Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
hive
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
47
Issues
47
List
Boards
Labels
Service Desk
Milestones
Merge Requests
13
Merge Requests
13
Operations
Operations
Incidents
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
hive
hive
Commits
f74d4f3f
Commit
f74d4f3f
authored
Aug 31, 2020
by
Mariusz
Committed by
Bartek Wrona
Aug 31, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Data regarding removed accounts should be hold in a persistent storage
parent
af279f32
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
64 additions
and
102 deletions
+64
-102
libraries/chain/CMakeLists.txt
libraries/chain/CMakeLists.txt
+0
-1
libraries/chain/database.cpp
libraries/chain/database.cpp
+22
-15
libraries/chain/include/hive/chain/database.hpp
libraries/chain/include/hive/chain/database.hpp
+3
-5
libraries/chain/include/hive/chain/hardfork_property_object.hpp
...ies/chain/include/hive/chain/hardfork_property_object.hpp
+12
-3
libraries/chain/include/hive/chain/util/hf23_helper.hpp
libraries/chain/include/hive/chain/util/hf23_helper.hpp
+6
-24
libraries/chain/util/hf23_helper.cpp
libraries/chain/util/hf23_helper.cpp
+0
-10
tests/unit/tests/basic_tests.cpp
tests/unit/tests/basic_tests.cpp
+1
-1
tests/unit/tests/hf23_tests.cpp
tests/unit/tests/hf23_tests.cpp
+20
-42
tests/unit/tests/hf24_tests.cpp
tests/unit/tests/hf24_tests.cpp
+0
-1
No files found.
libraries/chain/CMakeLists.txt
View file @
f74d4f3f
...
...
@@ -32,7 +32,6 @@ add_library( hive_chain
util/smt_token.cpp
util/sps_processor.cpp
util/sps_helper.cpp
util/hf23_helper.cpp
util/delayed_voting.cpp
${
HEADERS
}
...
...
libraries/chain/database.cpp
View file @
f74d4f3f
...
...
@@ -2023,19 +2023,18 @@ void database::lock_account( const account_object& account )
remove
(
*
change_request
);
}
void
database
::
restore_accounts
(
const
hf23_helper
::
hf23_items
&
balances
,
const
std
::
set
<
std
::
string
>&
restored_accounts
)
void
database
::
restore_accounts
(
const
std
::
set
<
std
::
string
>&
restored_accounts
)
{
auto
zero_hive
=
asset
(
0
,
HIVE_SYMBOL
);
auto
zero_hbd
=
asset
(
0
,
HBD_SYMBOL
);
const
auto
&
hardforks
=
get_hardfork_property_object
();
const
auto
&
treasury_account
=
get_treasury
();
auto
treasury_name
=
get_treasury_name
();
for
(
auto
&
name
:
restored_accounts
)
{
auto
found
=
balances
.
find
(
hf23_helper
::
hf23_item
{
name
,
zero_hive
,
zero_hbd
}
);
auto
found
=
hardforks
.
h23_balances
.
find
(
name
);
if
(
found
==
balances
.
end
()
)
if
(
found
==
hardforks
.
h23_
balances
.
end
()
)
{
ilog
(
"The account ${acc} hadn't removed balances, balances can't be restored"
,
(
"acc"
,
name
)
);
continue
;
...
...
@@ -2048,20 +2047,28 @@ void database::restore_accounts( const hf23_helper::hf23_items& balances, const
continue
;
}
adjust_balance
(
treasury_account
,
-
found
->
hbd_balance
);
adjust_balance
(
treasury_account
,
-
found
->
balance
);
adjust_balance
(
treasury_account
,
-
found
->
second
.
hbd_balance
);
adjust_balance
(
treasury_account
,
-
found
->
second
.
balance
);
adjust_balance
(
*
account_ptr
,
found
->
hbd_balance
);
adjust_balance
(
*
account_ptr
,
found
->
balance
);
adjust_balance
(
*
account_ptr
,
found
->
second
.
hbd_balance
);
adjust_balance
(
*
account_ptr
,
found
->
second
.
balance
);
operation
vop
=
hardfork_hive_restore_operation
(
name
,
treasury_name
,
found
->
hbd_balance
,
found
->
balance
);
operation
vop
=
hardfork_hive_restore_operation
(
name
,
treasury_name
,
found
->
second
.
hbd_balance
,
found
->
second
.
balance
);
push_virtual_operation
(
vop
);
ilog
(
"Balances ${hbd} and ${hive} for the account ${acc} were restored"
,
(
"hbd"
,
found
->
hbd_balance
)(
"hive"
,
found
->
balance
)(
"acc"
,
name
)
);
ilog
(
"Balances ${hbd} and ${hive} for the account ${acc} were restored"
,
(
"hbd"
,
found
->
second
.
hbd_balance
)(
"hive"
,
found
->
second
.
balance
)(
"acc"
,
name
)
);
}
}
void
database
::
clear_accounts
(
hf23_helper
::
hf23_items
&
balances
,
const
std
::
set
<
std
::
string
>&
cleared_accounts
)
void
database
::
gather_balance
(
const
std
::
string
&
name
,
const
asset
&
balance
,
const
asset
&
hbd_balance
)
{
modify
(
get_hardfork_property_object
(),
[
&
](
hardfork_property_object
&
hfp
)
{
hfp
.
h23_balances
.
emplace
(
std
::
make_pair
(
name
,
hf23_item
{
balance
,
hbd_balance
}
)
);
}
);
}
void
database
::
clear_accounts
(
const
std
::
set
<
std
::
string
>&
cleared_accounts
)
{
auto
treasury_name
=
get_treasury_name
();
for
(
auto
account_name
:
cleared_accounts
)
...
...
@@ -2073,7 +2080,7 @@ void database::clear_accounts( hf23_helper::hf23_items& balances, const std::set
asset
total_transferred_hbd
,
total_transferred_hive
,
total_converted_vests
,
total_hive_from_vests
;
clear_account
(
*
account_ptr
,
&
total_transferred_hbd
,
&
total_transferred_hive
,
&
total_converted_vests
,
&
total_hive_from_vests
);
hf23_helper
::
gather_balance
(
balances
,
account_name
,
total_transferred_hive
,
total_transferred_hbd
);
gather_balance
(
account_name
,
total_transferred_hive
,
total_transferred_hbd
);
operation
vop
=
hardfork_hive_operation
(
account_name
,
treasury_name
,
total_transferred_hbd
,
total_transferred_hive
,
total_converted_vests
,
total_hive_from_vests
);
...
...
@@ -5941,7 +5948,7 @@ void database::apply_hardfork( uint32_t hardfork )
break
;
case
HIVE_HARDFORK_0_23
:
{
clear_accounts
(
_hf23_items
,
hardforkprotect
::
get_steemit_accounts
()
);
clear_accounts
(
hardforkprotect
::
get_steemit_accounts
()
);
// Reset TAPOS buffer to avoid replay attack
auto
empty_block_id
=
block_id_type
();
...
...
@@ -5956,7 +5963,7 @@ void database::apply_hardfork( uint32_t hardfork )
}
case
HIVE_HARDFORK_1_24
:
{
restore_accounts
(
_hf23_items
,
hardforkprotect
::
get_restored_accounts
()
);
restore_accounts
(
hardforkprotect
::
get_restored_accounts
()
);
set_chain_id
(
HIVE_CHAIN_ID
);
break
;
}
...
...
libraries/chain/include/hive/chain/database.hpp
View file @
f74d4f3f
...
...
@@ -11,7 +11,6 @@
#include <hive/chain/util/advanced_benchmark_dumper.hpp>
#include <hive/chain/util/signal.hpp>
#include <hive/chain/util/hf23_helper.hpp>
#include <hive/protocol/protocol.hpp>
#include <hive/protocol/hardfork.hpp>
...
...
@@ -627,10 +626,11 @@ namespace chain {
#endif
//Restores balances for some accounts, which were cleared by mistake during HF23
void
restore_accounts
(
const
hf23_helper
::
hf23_items
&
balances
,
const
std
::
set
<
std
::
string
>&
restored_accounts
);
void
restore_accounts
(
const
std
::
set
<
std
::
string
>&
restored_accounts
);
//Clears all pending operations on account that involve balance, moves tokens to treasury account
void
clear_accounts
(
hf23_helper
::
hf23_items
&
balances
,
const
std
::
set
<
std
::
string
>&
cleared_accounts
);
void
gather_balance
(
const
std
::
string
&
name
,
const
asset
&
balance
,
const
asset
&
hbd_balance
);
void
clear_accounts
(
const
std
::
set
<
std
::
string
>&
cleared_accounts
);
void
clear_account
(
const
account_object
&
account
,
asset
*
transferred_hbd_ptr
=
nullptr
,
asset
*
transferred_hive_ptr
=
nullptr
,
asset
*
converted_vests_ptr
=
nullptr
,
asset
*
hive_from_vests_ptr
=
nullptr
);
...
...
@@ -789,8 +789,6 @@ namespace chain {
util
::
advanced_benchmark_dumper
_benchmark_dumper
;
index_delegate_map
_index_delegate_map
;
hf23_helper
::
hf23_items
_hf23_items
;
fc
::
signal
<
void
(
const
required_action_notification
&
)
>
_pre_apply_required_action_signal
;
fc
::
signal
<
void
(
const
required_action_notification
&
)
>
_post_apply_required_action_signal
;
...
...
libraries/chain/include/hive/chain/hardfork_property_object.hpp
View file @
f74d4f3f
...
...
@@ -5,17 +5,21 @@
#include <hive/chain/hive_object_types.hpp>
#include <hive/chain/util/hf23_helper.hpp>
namespace
hive
{
namespace
chain
{
using
chainbase
::
t_vector
;
using
chainbase
::
t_flat_map
;
class
hardfork_property_object
:
public
object
<
hardfork_property_object_type
,
hardfork_property_object
>
{
CHAINBASE_OBJECT
(
hardfork_property_object
);
public:
CHAINBASE_DEFAULT_CONSTRUCTOR
(
hardfork_property_object
,
(
processed_hardforks
)
)
CHAINBASE_DEFAULT_CONSTRUCTOR
(
hardfork_property_object
,
(
processed_hardforks
)
(
h23_balances
)
)
using
t_processed_hardforks
=
t_vector
<
fc
::
time_point_sec
>
;
using
t_hf23_items
=
t_flat_map
<
account_name_type
,
hf23_item
>
;
t_processed_hardforks
processed_hardforks
;
uint32_t
last_hardfork
=
0
;
...
...
@@ -23,7 +27,10 @@ namespace hive { namespace chain {
protocol
::
hardfork_version
next_hardfork
;
fc
::
time_point_sec
next_hardfork_time
;
CHAINBASE_UNPACK_CONSTRUCTOR
(
hardfork_property_object
,
(
processed_hardforks
));
//Here are saved balances for given accounts, that were cleared during HF23
t_hf23_items
h23_balances
;
CHAINBASE_UNPACK_CONSTRUCTOR
(
hardfork_property_object
,
(
processed_hardforks
)(
h23_balances
));
};
typedef
multi_index_container
<
...
...
@@ -37,7 +44,9 @@ namespace hive { namespace chain {
}
}
// hive::chain
FC_REFLECT_TYPENAME
(
hive
::
chain
::
hardfork_property_object
::
t_hf23_items
)
FC_REFLECT
(
hive
::
chain
::
hardfork_property_object
,
(
id
)(
processed_hardforks
)(
last_hardfork
)(
current_hardfork_version
)
(
next_hardfork
)(
next_hardfork_time
)
)
(
next_hardfork
)(
next_hardfork_time
)
(
h23_balances
)
)
CHAINBASE_SET_INDEX_TYPE
(
hive
::
chain
::
hardfork_property_object
,
hive
::
chain
::
hardfork_property_index
)
libraries/chain/include/hive/chain/util/hf23_helper.hpp
View file @
f74d4f3f
...
...
@@ -8,31 +8,13 @@ namespace hive { namespace chain {
using
hive
::
protocol
::
asset
;
class
hf23_helper
struct
hf23_item
{
public:
struct
hf23_item
{
std
::
string
name
;
asset
balance
;
asset
hbd_balance
;
};
struct
cmp_hf23_item
{
bool
operator
()(
const
hf23_item
&
a
,
const
hf23_item
&
b
)
const
{
return
std
::
strcmp
(
a
.
name
.
c_str
(),
b
.
name
.
c_str
()
)
<
0
;
}
};
using
hf23_items
=
std
::
set
<
hf23_item
,
cmp_hf23_item
>
;
public:
static
void
gather_balance
(
hf23_items
&
source
,
const
std
::
string
&
name
,
const
asset
&
balance
,
const
asset
&
hbd_balance
);
asset
balance
;
asset
hbd_balance
;
};
}
}
// namespace hive::chain
FC_REFLECT
(
hive
::
chain
::
hf23_item
,
(
balance
)(
hbd_balance
)
)
libraries/chain/util/hf23_helper.cpp
deleted
100644 → 0
View file @
af279f32
#include <hive/chain/util/hf23_helper.hpp>
namespace
hive
{
namespace
chain
{
void
hf23_helper
::
gather_balance
(
hf23_items
&
source
,
const
std
::
string
&
name
,
const
asset
&
balance
,
const
asset
&
hbd_balance
)
{
source
.
emplace
(
hf23_item
{
name
,
balance
,
hbd_balance
}
);
}
}
}
// namespace hive::chain
tests/unit/tests/basic_tests.cpp
View file @
f74d4f3f
...
...
@@ -501,7 +501,7 @@ BOOST_AUTO_TEST_CASE( chain_object_size )
#endif
);
BOOST_CHECK_EQUAL
(
sizeof
(
block_summary_object
),
24
);
//always 64k objects
BOOST_CHECK_EQUAL
(
sizeof
(
hardfork_property_object
),
88
);
BOOST_CHECK_EQUAL
(
sizeof
(
hardfork_property_object
),
120
);
BOOST_CHECK_EQUAL
(
sizeof
(
feed_history_object
),
136
);
//dynamic size worth 7*24 of sizeof(price)
BOOST_CHECK_EQUAL
(
sizeof
(
witness_schedule_object
),
536
);
...
...
tests/unit/tests/hf23_tests.cpp
View file @
f74d4f3f
...
...
@@ -13,7 +13,6 @@
#include <hive/chain/hive_objects.hpp>
#include <hive/chain/util/reward.hpp>
#include <hive/chain/util/hf23_helper.hpp>
#include <hive/plugins/rc/rc_objects.hpp>
#include <hive/plugins/rc/resource_count.hpp>
...
...
@@ -74,7 +73,6 @@ BOOST_AUTO_TEST_CASE( restore_accounts_02 )
return
std
::
strcmp
(
a
.
name
.
c_str
(),
b
.
name
.
c_str
()
)
<
0
;
};
std
::
set
<
tmp_data
,
decltype
(
cmp
)
>
old_balances
(
cmp
);
hf23_helper
::
hf23_items
_balances
;
uint32_t
cnt
=
1
;
for
(
auto
&
account
:
accounts
)
...
...
@@ -91,7 +89,7 @@ BOOST_AUTO_TEST_CASE( restore_accounts_02 )
generate_block
();
}
{
db
->
clear_accounts
(
_balances
,
accounts
);
db
->
clear_accounts
(
accounts
);
for
(
auto
&
account
:
accounts
)
{
...
...
@@ -110,7 +108,7 @@ BOOST_AUTO_TEST_CASE( restore_accounts_02 )
accounts_ex
.
insert
(
"dude"
);
accounts_ex
.
insert
(
"devil"
);
db
->
restore_accounts
(
_balances
,
accounts_ex
);
db
->
restore_accounts
(
accounts_ex
);
auto
itr_old_balances
=
old_balances
.
begin
();
for
(
auto
&
account
:
accounts
)
...
...
@@ -151,8 +149,6 @@ BOOST_AUTO_TEST_CASE( restore_accounts_01 )
FUND
(
"carol"
,
ASSET
(
"3600.000 TESTS"
)
);
FUND
(
"carol"
,
ASSET
(
"3500.000 TBD"
)
);
hf23_helper
::
hf23_items
_hf23_items
;
const
std
::
set
<
std
::
string
>
accounts
{
"alice"
,
"bob"
};
{
...
...
@@ -165,14 +161,14 @@ BOOST_AUTO_TEST_CASE( restore_accounts_01 )
auto
bob_hbd_balance
=
_bob
.
get_hbd_balance
();
{
hf23_helper
::
gather_balance
(
_hf23_items
,
_alice
.
name
,
_alice
.
get_balance
(),
_alice
.
get_hbd_balance
()
);
db
->
gather_balance
(
_alice
.
name
,
_alice
.
get_balance
(),
_alice
.
get_hbd_balance
()
);
db
->
adjust_balance
(
db
->
get_treasury_name
(),
_alice
.
get_balance
()
);
db
->
adjust_balance
(
db
->
get_treasury_name
(),
_alice
.
get_hbd_balance
()
);
db
->
adjust_balance
(
"alice"
,
-
_alice
.
get_balance
()
);
db
->
adjust_balance
(
"alice"
,
-
_alice
.
get_hbd_balance
()
);
}
{
hf23_helper
::
gather_balance
(
_hf23_items
,
_bob
.
name
,
_bob
.
get_balance
(),
_bob
.
get_hbd_balance
()
);
db
->
gather_balance
(
_bob
.
name
,
_bob
.
get_balance
(),
_bob
.
get_hbd_balance
()
);
db
->
adjust_balance
(
db
->
get_treasury_name
(),
_bob
.
get_balance
()
);
db
->
adjust_balance
(
db
->
get_treasury_name
(),
_bob
.
get_hbd_balance
()
);
db
->
adjust_balance
(
"bob"
,
-
_bob
.
get_balance
()
);
...
...
@@ -235,7 +231,7 @@ BOOST_AUTO_TEST_CASE( restore_accounts_01 )
database_fixture
::
validate_database
();
db
->
restore_accounts
(
_hf23_items
,
restored_accounts
);
db
->
restore_accounts
(
restored_accounts
);
auto
&
_alice2
=
db
->
get_account
(
"alice"
);
auto
&
_bob2
=
db
->
get_account
(
"bob"
);
...
...
@@ -255,21 +251,14 @@ BOOST_AUTO_TEST_CASE( restore_accounts_01 )
FC_LOG_AND_RETHROW
()
}
h
f23_helper
::
hf23_item
get_balances
(
const
account_object
&
obj
)
h
ive
::
chain
::
hf23_item
get_balances
(
const
account_object
&
obj
)
{
hf23_helper
::
hf23_item
res
;
res
.
name
=
obj
.
name
;
res
.
balance
=
obj
.
get_balance
();
res
.
hbd_balance
=
obj
.
get_hbd_balance
();
return
res
;
return
hive
::
chain
::
hf23_item
{
obj
.
get_balance
(),
obj
.
get_hbd_balance
()
};
}
bool
cmp_hf23_item
(
const
h
f23_helper
::
hf23_item
&
a
,
const
hf23_helper
::
hf23_item
&
b
)
bool
cmp_hf23_item
(
const
h
ive
::
chain
::
hf23_item
&
a
,
const
hive
::
chain
::
hf23_item
&
b
)
{
return
a
.
name
==
b
.
name
&&
a
.
balance
==
b
.
balance
&&
a
.
hbd_balance
==
b
.
hbd_balance
;
return
a
.
balance
==
b
.
balance
&&
a
.
hbd_balance
==
b
.
hbd_balance
;
}
BOOST_AUTO_TEST_CASE
(
save_test_02
)
...
...
@@ -287,22 +276,18 @@ BOOST_AUTO_TEST_CASE( save_test_02 )
FUND
(
"alice"
,
ASSET
(
"1000.000 TESTS"
)
);
FUND
(
"alice"
,
ASSET
(
"20.000 TBD"
)
);
hf23_helper
::
hf23_items
_hf23_items
;
const
std
::
set
<
std
::
string
>
accounts
{
"alice"
,
"bob"
};
{
hf23_helper
::
gather_balance
(
_hf23_items
,
"alice"
,
get_balance
(
"alice"
),
get_hbd_balance
(
"alice"
)
);
db
->
gather_balance
(
"alice"
,
get_balance
(
"alice"
),
get_hbd_balance
(
"alice"
)
);
}
{
BOOST_REQUIRE_EQUAL
(
_hf23_item
s
.
size
(),
1u
);
BOOST_REQUIRE_EQUAL
(
db
->
get_hardfork_property_object
().
h23_balance
s
.
size
(),
1u
);
auto
alice_balances
=
get_balances
(
db
->
get_account
(
"alice"
)
);
hf23_helper
::
hf23_items
cmp_balances
=
{
alice_balances
};
BOOST_REQUIRE_EQUAL
(
_hf23_items
.
size
(),
cmp_balances
.
size
()
);
BOOST_REQUIRE
(
cmp_hf23_item
(
*
_hf23_items
.
begin
(),
*
cmp_balances
.
begin
()
)
);
BOOST_REQUIRE_EQUAL
(
db
->
get_hardfork_property_object
().
h23_balances
.
size
(),
1u
);
BOOST_REQUIRE
(
cmp_hf23_item
(
db
->
get_hardfork_property_object
().
h23_balances
.
begin
()
->
second
,
alice_balances
)
);
}
database_fixture
::
validate_database
();
...
...
@@ -328,32 +313,25 @@ BOOST_AUTO_TEST_CASE( save_test_01 )
FUND
(
"alice"
,
ASSET
(
"20.000 TBD"
)
);
const
std
::
set
<
std
::
string
>
accounts
{
"alice"
,
"bob"
};
hf23_helper
::
hf23_items
_hf23_items
;
{
vest
(
"alice"
,
"alice"
,
ASSET
(
"10.000 TESTS"
),
alice_private_key
);
vest
(
"bob"
,
"bob"
,
ASSET
(
"10.000 TESTS"
),
bob_private_key
);
hf23_helper
::
gather_balance
(
_hf23_items
,
"alice"
,
get_balance
(
"alice"
),
get_hbd_balance
(
"alice"
)
);
hf23_helper
::
gather_balance
(
_hf23_items
,
"bob"
,
get_balance
(
"bob"
),
get_hbd_balance
(
"bob"
)
);
db
->
gather_balance
(
"alice"
,
get_balance
(
"alice"
),
get_hbd_balance
(
"alice"
)
);
db
->
gather_balance
(
"bob"
,
get_balance
(
"bob"
),
get_hbd_balance
(
"bob"
)
);
}
{
auto
alice_balances
=
get_balances
(
db
->
get_account
(
"alice"
)
);
auto
bob_balances
=
get_balances
(
db
->
get_account
(
"bob"
)
);
hf23_helper
::
hf23_items
cmp_balances
=
{
alice_balances
,
bob_balances
};
BOOST_REQUIRE_EQUAL
(
_hf23_items
.
size
(),
cmp_balances
.
size
()
);
BOOST_REQUIRE_EQUAL
(
db
->
get_hardfork_property_object
().
h23_balances
.
size
(),
2u
);
auto
iter
=
_hf23_items
.
begin
();
auto
cmp_iter
=
cmp_balances
.
begin
();
auto
iter
=
db
->
get_hardfork_property_object
().
h23_balances
.
begin
();
for
(
uint32_t
i
=
0
;
i
<
cmp_balances
.
size
();
++
i
)
{
BOOST_REQUIRE
(
cmp_hf23_item
(
*
iter
,
*
cmp_iter
)
);
++
iter
;
++
cmp_iter
;
}
BOOST_REQUIRE
(
cmp_hf23_item
(
iter
->
second
,
alice_balances
)
);
++
iter
;
BOOST_REQUIRE
(
cmp_hf23_item
(
iter
->
second
,
bob_balances
)
);
}
database_fixture
::
validate_database
();
...
...
tests/unit/tests/hf24_tests.cpp
View file @
f74d4f3f
...
...
@@ -13,7 +13,6 @@
#include <hive/chain/hive_objects.hpp>
#include <hive/chain/util/reward.hpp>
#include <hive/chain/util/hf23_helper.hpp>
#include <hive/plugins/rc/rc_objects.hpp>
#include <hive/plugins/rc/resource_count.hpp>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment