diff --git a/libraries/chain/include/eosio/chain/contract_table_objects.hpp b/libraries/chain/include/eosio/chain/contract_table_objects.hpp index baf549a2b1..51c06d6812 100644 --- a/libraries/chain/include/eosio/chain/contract_table_objects.hpp +++ b/libraries/chain/include/eosio/chain/contract_table_objects.hpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -282,6 +284,35 @@ namespace config { } // namespace config +namespace detail { + template<> + struct snapshot_row_traits { + using value_type = key_value_object; + using snapshot_type = snapshot_key_value_object; + + static snapshot_key_value_object to_snapshot_row(const key_value_object& value, const chainbase::database&) { + snapshot_key_value_object ret; + + ret.primary_key = value.primary_key; + ret.payer = value.payer; + if(value.value.size()) { + ret.value.resize(value.value.size()); + memcpy(ret.value.data(), value.value.data(), value.value.size()); + } + return ret; + }; + + static void from_snapshot_row(snapshot_key_value_object&& row, key_value_object& value, chainbase::database&) { + value.primary_key = row.primary_key; + value.payer = row.payer; + if(row.value.size()) + value.value.resize_and_fill(row.value.size(), [&](char* data, std::size_t size) { + memcpy(data, row.value.data(), size); + }); + } + }; +} + } } // namespace eosio::chain CHAINBASE_SET_INDEX_TYPE(eosio::chain::table_id_object, eosio::chain::table_id_multi_index) diff --git a/libraries/chain/include/eosio/chain/database_utils.hpp b/libraries/chain/include/eosio/chain/database_utils.hpp index a3d6948080..e039d12198 100644 --- a/libraries/chain/include/eosio/chain/database_utils.hpp +++ b/libraries/chain/include/eosio/chain/database_utils.hpp @@ -91,6 +91,42 @@ namespace eosio { namespace chain { fc::raw::unpack(ds, static_cast(b)); return ds; } + +namespace detail { + struct snapshot_key_value_object { + template + friend Stream& operator>>(Stream& ds, snapshot_key_value_object& o) { + fc::raw::unpack(ds, o.primary_key); + fc::raw::unpack(ds, o.payer); + + fc::unsigned_int sz; + fc::raw::unpack(ds, sz); + if(sz) { + o.value.resize(sz); + ds.read(o.value.data(), sz); + } + + return ds; + } + + template + friend Stream& operator<<(Stream& ds, const snapshot_key_value_object& o) { + fc::raw::pack(ds, o.primary_key); + fc::raw::pack(ds, o.payer); + + fc::raw::pack(ds, fc::unsigned_int(o.value.size())); + if(o.value.size()) + ds.write(o.value.data(), o.value.size()); + + return ds; + } + + uint64_t primary_key; + account_name payer; + std::vector value; + }; +} + } } namespace fc { @@ -197,6 +233,20 @@ namespace fc { from_variant(v, _v); sv = eosio::chain::shared_vector(_v.begin(), _v.end(), sv.get_allocator()); } + + inline + void to_variant(const eosio::chain::detail::snapshot_key_value_object& a, fc::variant& v) { + v = fc::mutable_variant_object("primary_key", a.primary_key) + ("payer", a.payer) + ("value", base64_encode(a.value.data(), a.value.size())); + } + + inline + void from_variant(const fc::variant& v, eosio::chain::detail::snapshot_key_value_object& a) { + from_variant(v["primary_key"], a.primary_key); + from_variant(v["payer"], a.payer); + a.value = base64_decode(v["value"].as_string()); + } } namespace chainbase { diff --git a/libraries/state_history/include/eosio/state_history/serialization.hpp b/libraries/state_history/include/eosio/state_history/serialization.hpp index af4a71e125..b39698291c 100644 --- a/libraries/state_history/include/eosio/state_history/serialization.hpp +++ b/libraries/state_history/include/eosio/state_history/serialization.hpp @@ -119,6 +119,13 @@ datastream& operator<<(datastream& ds, const eosio::state_history::big_v return ds; } +template +datastream& operator<<(datastream& ds, const eosio::state_history::row_pair& rp) { + fc::raw::pack(ds, rp.first); + history_pack_big_bytes(ds, rp.second); + return ds; +} + template inline void history_pack_varuint64(datastream& ds, uint64_t val) { do { @@ -136,6 +143,12 @@ void history_pack_big_bytes(datastream& ds, const eosio::chain::bytes& v) { ds.write(&v.front(), v.size()); } +template +void history_pack_big_bytes(datastream& ds, const eosio::chain::shared_blob& b) { + fc::raw::pack(ds, unsigned_int((uint32_t)b.size())); + ds.write(b.data(), b.size()); +} + template void history_pack_big_bytes(datastream& ds, const std::optional& v) { fc::raw::pack(ds, v.has_value()); @@ -223,7 +236,7 @@ datastream& operator<<(datastream& ds, const history_context_wrapper_sta fc::raw::pack(ds, as_type(obj.context.table.to_uint64_t())); fc::raw::pack(ds, as_type(obj.obj.primary_key)); fc::raw::pack(ds, as_type(obj.obj.payer.to_uint64_t())); - fc::raw::pack(ds, as_type(obj.obj.value)); + history_pack_big_bytes(ds, obj.obj.value); return ds; } diff --git a/libraries/state_history/include/eosio/state_history/types.hpp b/libraries/state_history/include/eosio/state_history/types.hpp index a5f74de9ef..e86275ad8d 100644 --- a/libraries/state_history/include/eosio/state_history/types.hpp +++ b/libraries/state_history/include/eosio/state_history/types.hpp @@ -17,6 +17,13 @@ struct big_vector_wrapper { T obj; }; +struct row_pair { + row_pair() {} + row_pair(const bool f, const bytes& s) : first(f), second(s){} + bool first = false; + bytes second; +}; + struct partial_transaction { fc::time_point_sec expiration = {}; uint16_t ref_block_num = {}; @@ -66,7 +73,7 @@ struct augmented_transaction_trace { struct table_delta { fc::unsigned_int struct_version = 0; std::string name{}; - state_history::big_vector_wrapper>> rows{}; + state_history::big_vector_wrapper> rows{}; }; struct block_position { diff --git a/unittests/state_history_tests.cpp b/unittests/state_history_tests.cpp index b1089da989..51f78df9c0 100644 --- a/unittests/state_history_tests.cpp +++ b/unittests/state_history_tests.cpp @@ -29,6 +29,18 @@ bool operator==(const eosio::checksum256& lhs, const transaction_id_type& rhs) { namespace eosio::state_history { +template +datastream& operator>>(datastream& ds, row_pair& rp) { + fc::raw::unpack(ds, rp.first); + fc::unsigned_int sz; + fc::raw::unpack(ds, sz); + if(sz) { + rp.second.resize(sz); + ds.read(rp.second.data(), sz); + } + return ds; +} + template datastream& operator>>(datastream& ds, eosio::state_history::big_vector_wrapper& obj) { fc::unsigned_int sz;