diff --git a/cmake/gitinfo.cmake b/cmake/gitinfo.cmake index 6752a4734..5f45def7e 100644 --- a/cmake/gitinfo.cmake +++ b/cmake/gitinfo.cmake @@ -79,7 +79,7 @@ macro(get_git_info) file(APPEND ${VersionInc} "const std::string TOP_GIT_BRANCH = \"${TOP_GIT_BRANCH}\";\n") file(APPEND ${VersionInc} "const std::string TOP_GIT_HASH = \"${TOP_GIT_HASH}\";\n") file(APPEND ${VersionInc} "const std::string TOP_GIT_DATE = \"${TOP_GIT_DATE}\";\n") - file(APPEND ${VersionInc} "const std::string TOP_GIT_LOG_LATEST = ${TOP_GIT_LOG_LATEST};\n") # multiline + file(APPEND ${VersionInc} "const std::string TOP_GIT_LOG_LATEST = \"${TOP_GIT_LOG_LATEST}\";\n") # multiline file(APPEND ${VersionInc} "const std::string TOP_GIT_SUBMODULE = \"${TOP_GIT_SUBMODULE}\";\n") file(APPEND ${VersionInc} "const std::string TOP_BUILD_DATE = __DATE__;\n") file(APPEND ${VersionInc} "const std::string TOP_BUILD_TIME = __TIME__;\n") diff --git a/src/libraries/xapplication/src/xapplication.cpp b/src/libraries/xapplication/src/xapplication.cpp index 99ea1d6fa..c6c012de7 100644 --- a/src/libraries/xapplication/src/xapplication.cpp +++ b/src/libraries/xapplication/src/xapplication.cpp @@ -284,11 +284,11 @@ void xtop_application::on_election_data_updated(data::election::xelection_result } if (!updated_election_data2.empty()) { - auto outdated_xips_pair = m_vnode_manager->handle_election_data(updated_election_data2); - for (const auto & xip : outdated_xips_pair.first) { + auto const outdated_xips_pair = m_vnode_manager->handle_election_data(updated_election_data2); + for (auto const & xip : outdated_xips_pair.first) { m_elect_main->GetElectManager()->OnElectQuit(xip); } - for (const auto & xip : outdated_xips_pair.second) { + for (auto const & xip : outdated_xips_pair.second) { // m_cons_mgr->destroy({xip.raw_low_part(), xip.raw_high_part()}); m_txpool_service_mgr->destroy({xip.raw_low_part(), xip.raw_high_part()}); } diff --git a/src/libraries/xelect/src/xelect_client_process.cpp b/src/libraries/xelect/src/xelect_client_process.cpp index 257192671..d4591556b 100644 --- a/src/libraries/xelect/src/xelect_client_process.cpp +++ b/src/libraries/xelect/src/xelect_client_process.cpp @@ -228,7 +228,6 @@ void xelect_client_process::update_election_status(common::xlogic_time_t current auto const update_exchange_interval = nonconsensus_group_update_interval; // for mainnet & bounty #endif process_election_contract(common::xaccount_address_t{sys_contract_rec_elect_exchange_addr}, current_time, update_exchange_interval); - // } } { diff --git a/src/libraries/xvnode/src/xvnode_manager.cpp b/src/libraries/xvnode/src/xvnode_manager.cpp index 8fe654f99..55317d05f 100644 --- a/src/libraries/xvnode/src/xvnode_manager.cpp +++ b/src/libraries/xvnode/src/xvnode_manager.cpp @@ -119,7 +119,7 @@ std::pair, std::vector> xtop_vnode_m xwarn("[vnode mgr] vnode (%p) at address %s will outdate at logic time %" PRIu64, vnode.get(), vnode->address().to_string().c_str(), vnode->outdate_time()); } - xwarn("[vnode mgr] vnode at address %s is outdated", cluster_address.to_string().c_str()); + // xwarn("[vnode mgr] vnode at address %s is outdated", cluster_address.to_string().c_str()); common::xip2_t xip{ cluster_address.network_id(), cluster_address.zone_id(), @@ -127,7 +127,7 @@ std::pair, std::vector> xtop_vnode_m cluster_address.group_id(), outdated_group->group_size(), outdated_group->associated_blk_height()}; - purely_outdated_xips.push_back(std::move(xip)); + purely_outdated_xips.push_back(xip); } if (faded_group != nullptr && faded_group->contains(account_address)) { @@ -187,7 +187,7 @@ std::pair, std::vector> xtop_vnode_m common::xip2_t xip{cluster_address.network_id(), cluster_address.zone_id(), cluster_address.cluster_id(), cluster_address.group_id()}; - logical_outdated_xips.push_back(std::move(xip)); + logical_outdated_xips.push_back(xip); } } diff --git a/src/libraries/xvnode/xvnode_manager.h b/src/libraries/xvnode/xvnode_manager.h index 8c501180e..bb2834c74 100644 --- a/src/libraries/xvnode/xvnode_manager.h +++ b/src/libraries/xvnode/xvnode_manager.h @@ -128,7 +128,7 @@ class xtop_vnode_manager : public xvnode_manager_face_t xwarn("[vnode mgr] vnode (%p) at address %s starts at logic time %" PRIu64 " current logic time %" PRIu64 " %s", vnode.get(), - vnode->address().to_string().c_str(), + vnode->address().to_string().c_str(), vnode->start_time(), time, vnode->address().xip2().to_string().c_str()); diff --git a/src/xtools/xscripts/xip_decoder.py b/src/xtools/xscripts/xip_decoder.py index 099b969ce..b670ef1e6 100644 --- a/src/xtools/xscripts/xip_decoder.py +++ b/src/xtools/xscripts/xip_decoder.py @@ -84,9 +84,9 @@ def main(argv): if zone_id == 0: if cluster_id == 1: if 1 <= group_id < 64: - print("\taddress type: auditor") + print("\taddress type: consensus.auditor") elif 64 <= group_id < 127: - print("\taddress type: validator") + print("\taddress type: consensus.validator") else: print("\taddress type: unknown cluster id") elif zone_id == 1: @@ -108,7 +108,13 @@ def main(argv): elif zone_id == 3: print("\taddress type: frozen") elif zone_id == 4: - print("\taddress type: evm") + if cluster_id == 1: + if 1 <= group_id < 64: + print("\taddress type: evm.auditor") + elif 64 <= group_id < 127: + print("\taddress type: evm.validator") + else: + print("\taddress type: unknown cluster id") elif zone_id == 5: print("\taddress type: relay") elif zone_id == 13: diff --git a/src/xtopcom/xbasic/xbitset.h b/src/xtopcom/xbasic/xbitset.h index 54faad16c..e7fd3c1d7 100644 --- a/src/xtopcom/xbasic/xbitset.h +++ b/src/xtopcom/xbasic/xbitset.h @@ -43,11 +43,11 @@ class xtop_bitset { public: constexpr xtop_bitset() = default; - xtop_bitset(xtop_bitset const &) = default; - xtop_bitset(xtop_bitset&&) = default; - xtop_bitset& operator=(xtop_bitset const &) = default; - xtop_bitset& operator=(xtop_bitset&&) = default; - ~xtop_bitset() = default; + //xtop_bitset(xtop_bitset const &) = default; + //xtop_bitset(xtop_bitset&&) = default; + //xtop_bitset& operator=(xtop_bitset const &) = default; + //xtop_bitset& operator=(xtop_bitset&&) = default; + //~xtop_bitset() = default; using reference = typename std::bitset::reference; @@ -70,7 +70,7 @@ class xtop_bitset { } if (!is_hex_string_without_prefix(str_view)) { - ec = error::xbasic_errc_t::invalid_hex_string; + ec = error::xbasic_errc_t::invalid_hex_string; return {}; } @@ -99,11 +99,13 @@ class xtop_bitset { return {}; } - std::string tmp; if (sb == xsignificant_bit_t::lsb0) { - tmp = std::string{std::begin(str_view), std::end(str_view)}; + auto tmp = std::string{std::begin(str_view), std::end(str_view)}; std::reverse(std::begin(tmp), std::end(tmp)); str_view = xstring_view_t{tmp}; + + str_view = str_view.substr(str_view.size() - std::min(N, str_view.size())); + return {std::bitset{str_view.data(), str_view.size()}}; } str_view = str_view.substr(str_view.size() - std::min(N, str_view.size())); diff --git a/src/xtopcom/xcommon/rlp.h b/src/xtopcom/xcommon/rlp.h index 34fb7eb84..b4a3acefb 100644 --- a/src/xtopcom/xcommon/rlp.h +++ b/src/xtopcom/xcommon/rlp.h @@ -417,6 +417,8 @@ class RLP /// Decodes data, remainder from RLP encoded data static DecodedItem decode(xbytes_t const & input); static DecodedItem decode_once(xbytes_t const & input); + static DecodedItem decode_once(xbytes_t const & input, std::error_code & ec); + static DecodedItem decode_list_once(xbytes_t const & input, std::error_code & ec); static DecodedItem decode_list(xbytes_t const & input, std::error_code & ec); static DecodedItem decode(xbytes_t const & input, std::error_code & ec); @@ -613,6 +615,76 @@ extern xbytes_t RLPEmptyList; /// Human readable version of RLP. std::ostream& operator<<(std::ostream& _out, RLP const& _d); +enum class xenum_rlp_object_type { + invalid, + bytes, + list +}; +using xrlp_object_type_t = xenum_rlp_object_type; + +struct xtop_rlp_object; +using xrlp_object_t = xtop_rlp_object; + +struct xtop_rlp_bytes { + std::size_t size{0}; + xbyte_t const * ptr; +}; + +struct xtop_rlp_list { + std::size_t size{0}; + xrlp_object_t * ptr; + +}; + +//struct xtop_rlp_decoded_raw { +// +//}; + +struct xtop_rlp_decoded_raw { + std::size_t offset{0}; + std::size_t length{0}; + xrlp_object_type_t type{xenum_rlp_object_type::invalid}; + + xtop_rlp_decoded_raw() = default; + xtop_rlp_decoded_raw(std::size_t offset, std::size_t length, xrlp_object_type_t type); +}; +using xrlp_decoded_raw_t = xtop_rlp_decoded_raw; + +class xtop_rlp_decoder { +public: + static void decode(xspan_t rlp_encoded_bytes, std::vector & result, std::error_code & ec); + +private: + static auto parse_length(xspan_t rlp_encoded_bytes, std::error_code & ec) -> xrlp_decoded_raw_t; + static auto to_integer(xspan_t rlp_encoded_bytes, std::error_code & ec) -> std::uint64_t; + static auto decode_list(xspan_t rlp_encoded_bytes, std::error_code & ec) -> std::vector; +}; +using xrlp_object_parser_t = xtop_rlp_decoder; + +class xtop_rlp_encoder { +public: + static auto encode(xbyte_t const * data, std::size_t length) -> xbytes_t; + static auto encode(char const * data, std::size_t length) -> xbytes_t; + + static auto encode(std::uint64_t integer) -> xbytes_t; + static auto encode(u256 const & number) -> xbytes_t; + + template + static auto encode(T const & object) -> xbytes_t { + xbytes_t bytes = object.encode(); + + auto result = encode_length(bytes.size(), 0xC0); + std::copy(std::begin(bytes), std::end(bytes), std::back_inserter(result)); + + return result; + } + +private: + static auto encode_length(std::size_t length, std::uint8_t offset) -> xbytes_t; + static auto to_big_ending(uint64_t integer) -> xbytes_t; + static auto to_big_endian(u256 const & number) -> xbytes_t; +}; +using xrlp_encoder_t = xtop_rlp_encoder; } } diff --git a/src/xtopcom/xcommon/src/rlp.cpp b/src/xtopcom/xcommon/src/rlp.cpp index c6320441c..85e262346 100644 --- a/src/xtopcom/xcommon/src/rlp.cpp +++ b/src/xtopcom/xcommon/src/rlp.cpp @@ -679,6 +679,134 @@ RLP::DecodedItem RLP::decode(xbytes_t const & input, std::error_code & ec) { return item; } +RLP::DecodedItem RLP::decode_once(xbytes_t const & input, std::error_code & ec) { + assert(!ec); + + RLP::DecodedItem item; + if (input.empty()) { + xwarn("RLP::decode failed, can't decode empty rlp data"); + ec = common::error::xerrc_t::rlp_input_empty; + return {}; + } + + auto const input_len = input.size(); + auto const prefix = input[0]; + if (prefix <= 0x7f) { + // 00--7f: a single byte whose value is in the [0x00, 0x7f] range, that byte is its own RLP encoding. + item.decoded.push_back(xbytes_t{input[0]}); + item.remainder = sub_data(input, 1); + return item; + } + + if (prefix <= 0xb7) { + // 80--b7: short string + // string is 0-55 bytes long. A single byte with value 0x80 plus the length of the string followed by the string + // The range of the first byte is [0x80, 0xb7] + + // empty string + if (prefix == 0x80) { + item.decoded.emplace_back(xbytes_t()); + item.remainder = sub_data(input, 1); + return item; + } + + const size_t str_len = prefix - 0x80; + if (str_len == 1 && input[1] <= 0x7f) { + ec = common::error::xerrc_t::rlp_invalid_encoded_data; + xwarn("RLP::decode failed, single byte below 128 must be encoded as itself"); + return {}; + } + + if (input_len < (1 + str_len)) { + ec = common::error::xerrc_t::rlp_invalid_encoded_data; + xwarn("RLP::decode failed, invalid short string, length %" PRIu64, str_len); + return {}; + } + item.decoded.push_back(sub_data(input, 1, str_len)); + item.remainder = sub_data(input, 1 + str_len); + + return item; + } + if (prefix <= 0xbf) { + // b8--bf: long string + const auto len_of_str_len = static_cast(prefix - 0xb7); + const auto str_len = static_cast(parseVarInt(len_of_str_len, input, 1)); + if (input_len < len_of_str_len || input_len < (1 + len_of_str_len + str_len)) { + ec = common::error::xerrc_t::rlp_invalid_encoded_data; + xwarn("Invalid rlp encoding length, length %zu", str_len); + return {}; + } + auto data = sub_data(input, 1 + len_of_str_len, str_len); + item.decoded.push_back(std::move(data)); + item.remainder = sub_data(input, 1 + len_of_str_len + str_len); + return item; + } + if (prefix <= 0xf7) { + // c0--f7: a list between 0-55 bytes long + const auto list_len = static_cast(prefix - 0xc0); + if (input_len < (1 + list_len)) { + ec = common::error::xerrc_t::rlp_invalid_encoded_data; + xwarn("Invalid rlp string length, length %zu", list_len); + return {}; + } + // empty list + if (list_len == 0) { + item.remainder = sub_data(input, 1); + return item; + } + auto data = sub_data(input, 1, list_len); + item.decoded.push_back(std::move(data)); + item.remainder = sub_data(input, 1 + list_len); + return item; + } + + // f8--ff + const auto len_of_list_len = static_cast(prefix - 0xf7); + const auto list_len = static_cast(parseVarInt(len_of_list_len, input, 1)); + if (list_len < 56) { + ec = common::error::xerrc_t::rlp_invalid_encoded_data; + xwarn("RLP::decode failed, length below 56 must be encoded in one byte"); + return {}; + } + if (input_len < len_of_list_len || input_len < (1 + len_of_list_len + list_len)) { + ec = common::error::xerrc_t::rlp_invalid_encoded_data; + xwarn("Invalid rlp list length, length %zu", list_len); + return {}; + } + + auto data = sub_data(input, 1 + len_of_list_len, list_len); + item.decoded.push_back(std::move(data)); + item.remainder = sub_data(input, 1 + len_of_list_len + list_len); + return item; +} + +RLP::DecodedItem RLP::decode_list_once(xbytes_t const & input, std::error_code & ec) { + RLP::DecodedItem item; + auto remainder = input; + while (true) { + auto list_item = RLP::decode_once(remainder, ec); + if (ec) { + xwarn("RLP::decode_list_once failed, error code: %s", ec.message().c_str()); + break; + } + + if (!list_item.decoded.empty()) { + for (auto & decoded : list_item.decoded) { + item.decoded.emplace_back(std::move(decoded)); + } + } else { + item.decoded.emplace_back(); + } + + if (list_item.remainder.empty()) { + break; + } + + remainder = std::move(list_item.remainder); + } + return item; +} + RLPStream& RLPStream::appendRaw(bytesConstRef _s, size_t _itemCount) { m_out.insert(m_out.end(), _s.begin(), _s.end()); @@ -834,5 +962,153 @@ std::ostream& operator<<(std::ostream& _out, RLP const& _d) } +auto xtop_rlp_decoder::to_integer(xspan_t const rlp_encoded_bytes, std::error_code & ec) -> std::uint64_t { + assert(!ec); + + if (rlp_encoded_bytes.empty()) { + ec = common::error::xerrc_t::rlp_input_empty; + return 0; + } + + if (rlp_encoded_bytes.size() == 1) { + return static_cast(rlp_encoded_bytes[0]); + } + + std::uint64_t ret = 0; + for (xbyte_t const num : rlp_encoded_bytes) { + ret <<= 8; + ret += static_cast(num); + } + + return ret; +} + +auto xtop_rlp_decoder::parse_length(xspan_t const rlp_encoded_bytes, std::error_code & ec) -> xrlp_decoded_raw_t { + assert(!ec); + + auto const input = rlp_encoded_bytes; + + if (input.empty()) { + ec = common::error::xerrc_t::rlp_input_empty; + return {}; + } + + std::size_t const length = input.size(); + std::size_t const prefix = input[0]; + if (prefix <= 0x7F) { + return xrlp_decoded_raw_t{0, 1, xrlp_object_type_t::bytes}; + } + + if (prefix <= 0xB7 and length > prefix - 0x80) { + return xrlp_decoded_raw_t{1, static_cast(prefix - 0x80), xrlp_object_type_t::bytes}; + } + + if (prefix <= 0xBF and length > prefix - 0xB7 and length > prefix - 0xB7 + to_integer(input.subspan(1, prefix - 0xB7), ec) && !ec) { + std::size_t const length_of_bytes_length = prefix - 0xB7; + std::size_t const bytes_length = static_cast(to_integer(input.subspan(1, length_of_bytes_length), ec)); + + if (ec) { + return {}; + } + + return xrlp_decoded_raw_t{1 + length_of_bytes_length, bytes_length, xrlp_object_type_t::bytes}; + } + + if (prefix <= 0xF7 and length > prefix - 0xC0) { + return xrlp_decoded_raw_t{1, static_cast(prefix - 0xC0), xrlp_object_type_t::list}; + } + + if (length > prefix - 0xF7 and length > prefix - 0xF7 + to_integer(input.subspan(1, prefix - 0xF7), ec) && !ec) { + std::size_t const length_of_list_length = prefix - 0xF7; + std::size_t const list_length = static_cast(to_integer(input.subspan(1, length_of_list_length), ec)); + + if (ec) { + return {}; + } + + return xrlp_decoded_raw_t{1 + length_of_list_length, list_length, xrlp_object_type_t::list}; + } + + ec = common::error::xerrc_t::rlp_invalid_encoded_data; + return {}; +} + +xtop_rlp_decoded_raw::xtop_rlp_decoded_raw(std::size_t const offset, std::size_t const length, xrlp_object_type_t const type) : offset(offset), length(length), type(type) { + assert(type == xrlp_object_type_t::bytes || type == xrlp_object_type_t::list); + assert(offset + length >= offset); +} + +void xtop_rlp_decoder::decode(xspan_t rlp_encoded_bytes, std::vector & result, std::error_code & ec) { + assert(!ec); + if (rlp_encoded_bytes.empty()) { + return; + } + + auto const rlp_object = parse_length(rlp_encoded_bytes, ec); + if (ec) { + return; + } + + result.push_back(rlp_object); + decode(rlp_encoded_bytes.subspan(rlp_object.offset + rlp_object.length), result, ec); +} + +auto xtop_rlp_encoder::encode(xbyte_t const * data, std::size_t const length) -> xbytes_t { + if (length == 1 && data[0] < 0x80) { + return {data[0]}; + } + + xbytes_t encoded = encode_length(length, 0x80); + + encoded.insert(encoded.end(), data, data + length); + return encoded; +} + +auto xtop_rlp_encoder::encode(char const * data, std::size_t const length) -> xbytes_t { + return encode(reinterpret_cast(data), length); +} + +auto xtop_rlp_encoder::encode(std::uint64_t const integer) -> xbytes_t { + auto const bytes = to_big_endian(integer); + return encode(bytes.data(), bytes.size()); +} + +auto xtop_rlp_encoder::encode(u256 const & number) -> xbytes_t { + auto const bytes = to_big_endian(number); + return encode(bytes.data(), bytes.size()); +} + +auto xtop_rlp_encoder::encode_length(std::size_t const length, std::uint8_t const offset) -> xbytes_t { + if (length < 56) { + return {static_cast(length + offset)}; + } + + auto length_bytes = to_big_endian(length); + + auto const length_length = length_bytes.size(); + + xbytes_t result(length_length + 1); + result[0] = static_cast(length_length + offset + 55); + + std::copy(length_bytes.begin(), length_bytes.end(), result.begin() + 1); + + return result; +} + +auto xtop_rlp_encoder::to_big_ending(uint64_t const integer) -> xbytes_t { + if (integer == 0) { + return {}; + } + return toCompactBigEndian(integer); +} + +auto xtop_rlp_encoder::to_big_endian(u256 const & number) -> xbytes_t { + if (number == 0) { + return {}; + } + return toCompactBigEndian(number); +} + + } } \ No newline at end of file diff --git a/src/xtopcom/xcommon/src/xip.cpp b/src/xtopcom/xcommon/src/xip.cpp index 1116499bf..a7db7e72b 100644 --- a/src/xtopcom/xcommon/src/xip.cpp +++ b/src/xtopcom/xcommon/src/xip.cpp @@ -916,4 +916,12 @@ xslot_id_t const xtop_broadcast_id::slot{xbroadcast_slot_id_value}; #endif +bool in_the_same_group(xip_t const lhs, xip_t const rhs) noexcept { + return lhs.network_id() == rhs.network_id() && lhs.zone_id() == rhs.zone_id() && lhs.cluster_id() == rhs.cluster_id() && lhs.group_id() == rhs.group_id(); +} + +bool in_the_same_group(xip2_t const lhs, xip2_t const rhs) noexcept { + return in_the_same_group(lhs.xip(), rhs.xip()); +} + NS_END2 diff --git a/src/xtopcom/xcommon/xcommon.h b/src/xtopcom/xcommon/xcommon.h index 9e63f9c3f..dd42580e1 100644 --- a/src/xtopcom/xcommon/xcommon.h +++ b/src/xtopcom/xcommon/xcommon.h @@ -3,19 +3,25 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once + #include "xbase/xns_macro.h" #include +#include + NS_BEG1(top) // block special heights using xblock_number_t = uint64_t; -static const xblock_number_t LatestConnectBlock = (xblock_number_t)-3; -static const xblock_number_t LatestBlock = (xblock_number_t)-2; -static const xblock_number_t PendingBlock = (xblock_number_t)-1; -constexpr const char* BlockHeightLatest = "latest"; -constexpr const char* BlockHeightEarliest = "earliest"; -constexpr const char* BlockHeightPending = "pending"; +XINLINE_CONSTEXPR xblock_number_t LatestConnectBlock = static_cast(-3); +XINLINE_CONSTEXPR xblock_number_t LatestBlock = static_cast(-2); +XINLINE_CONSTEXPR xblock_number_t PendingBlock = static_cast(-1); + +XINLINE_CONSTEXPR char const * BlockHeightLatest = "latest"; +XINLINE_CONSTEXPR char const * BlockHeightEarliest = "earliest"; +XINLINE_CONSTEXPR char const * BlockHeightPending = "pending"; + +XINLINE_CONSTEXPR std::size_t ETH_ADDRESS_LENGTH{20}; NS_END1 diff --git a/src/xtopcom/xcommon/xip.h b/src/xtopcom/xcommon/xip.h index 03b88b8ff..b136b5079 100644 --- a/src/xtopcom/xcommon/xip.h +++ b/src/xtopcom/xcommon/xip.h @@ -723,6 +723,9 @@ xgroup_id_t const & broadcast() noexcept; template <> xslot_id_t const & broadcast() noexcept; +bool in_the_same_group(xip_t lhs, xip_t rhs) noexcept; +bool in_the_same_group(xip2_t lhs, xip2_t rhs) noexcept; + NS_END2 NS_BEG1(std) diff --git a/src/xtopcom/xdata/xsystem_contract/xdata_structures.h b/src/xtopcom/xdata/xsystem_contract/xdata_structures.h index 67f8f1932..de976e488 100644 --- a/src/xtopcom/xdata/xsystem_contract/xdata_structures.h +++ b/src/xtopcom/xdata/xsystem_contract/xdata_structures.h @@ -80,6 +80,9 @@ XINLINE_CONSTEXPR char const * XPROPERTY_ALL_HASHES = "@162"; XINLINE_CONSTEXPR char const * XPROPERTY_HEADERS = "@163"; XINLINE_CONSTEXPR char const * XPROPERTY_HEADERS_SUMMARY = "@164"; XINLINE_CONSTEXPR char const * XPROPERTY_RESET_FLAG = "@165"; +XINLINE_CONSTEXPR char const * XPROPERTY_PRE_LAST_VALIDATOR_SET = "@166"; +XINLINE_CONSTEXPR char const * XPROPERTY_LAST_VALIDATOR_SET = "@167"; +XINLINE_CONSTEXPR char const * XPROPERTY_RECENT_SNAPSHOTS = "@168"; XINLINE_CONSTEXPR char const * XPROPERTY_RELAY_ELECT_PACK_HEIGHT = "@170"; XINLINE_CONSTEXPR char const * XPROPERTY_RELAY_WRAP_PHASE = "@171"; diff --git a/src/xtopcom/xevm_common/src/xabi_decoder.cpp b/src/xtopcom/xevm_common/src/xabi_decoder.cpp index 1d781fec6..1905fbb43 100644 --- a/src/xtopcom/xevm_common/src/xabi_decoder.cpp +++ b/src/xtopcom/xevm_common/src/xabi_decoder.cpp @@ -268,4 +268,5 @@ xbytes_t xtop_abi_decoder::extract(std::error_code & ec) const { return decode_bytes(ec); } + NS_END2 diff --git a/src/xtopcom/xevm_common/src/xconfig.cpp b/src/xtopcom/xevm_common/src/xconfig.cpp new file mode 100644 index 000000000..b4c90d684 --- /dev/null +++ b/src/xtopcom/xevm_common/src/xconfig.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "xevm_common/xcrosschain/xbsc/xconfig.h" + +NS_BEG4(top, evm, crosschain, bsc) + +xchain_config_t const bsc_chain_config{ + 56, // chain id + + 0, // homestead block + + 0, // dao fork block + false, // dao fork support + + 0, // eip150 block + {}, // eip150 hash + + 0, // eip155 block + 0, // eip158 block + + 0, // byzantium block + 0, // constantinople block + 0, // petersburg block + 0, // istanbul block + 0, // muir_glacier block + 31302048, // berlin block + 0, // yolo_v3 block + 0, // catalyst block + 31302048, // london block + 0, // arrow_glacier block + 0, // merge_fork block + + 0, // terminal_total_difficulty + + 0, // ramanujan block + 0, // niels block + 5184000, // mirror_sync block + 13082000, // bruno block + 18907621, // euler block + 21962149, // nano block + 22107423, // moran block + 23846001, // gibbs block + 27281024, // planck block + + 29020050, // luban block + 30720096, // plato block + 31302048, // hertz block + + {3, 200}, // parlia config +}; + + +NS_END4 diff --git a/src/xtopcom/xevm_common/src/xerror.cpp b/src/xtopcom/xevm_common/src/xerror.cpp index 51844b1d0..d4422b13f 100644 --- a/src/xtopcom/xevm_common/src/xerror.cpp +++ b/src/xtopcom/xevm_common/src/xerror.cpp @@ -91,6 +91,18 @@ static char const * errc_to_string(int code) { case xenum_errc::invalid_public_key_size: return "invalid public key size"; + case xenum_errc::invalid_bsc_epoch_data: + return "invalid bsc epoch data"; + + case xenum_errc::invalid_bsc_extra_data: + return "invalid bsc extra data"; + + case xenum_errc::bsc_header_before_luban: + return "bsc header before luban"; + + case xenum_errc::bsc_not_epoch_header: + return "bsc not epoch header"; + default: // NOLINT(clang-diagnostic-covered-switch-default) assert(false); return "unknown evm common error"; @@ -101,10 +113,6 @@ std::error_code make_error_code(xerrc_t const errc) noexcept { return std::error_code{static_cast(errc), evm_common_category()}; } -std::error_condition make_error_condition(xerrc_t const errc) noexcept { - return std::error_condition{static_cast(errc), evm_common_category()}; -} - std::error_category const & evm_common_category() { static class xtop_evm_common_category final : public std::error_category { public: diff --git a/src/xtopcom/xevm_common/src/xeth_header.cpp b/src/xtopcom/xevm_common/src/xeth_header.cpp index fbfec94ed..fde9afa6c 100644 --- a/src/xtopcom/xevm_common/src/xeth_header.cpp +++ b/src/xtopcom/xevm_common/src/xeth_header.cpp @@ -26,12 +26,16 @@ #include "xbasic/xhex.h" #include "xcommon/rlp.h" +#include "xcrypto/xckey.h" +#include "xevm_common/xcrosschain/xbsc/xconfig.h" #include "xevm_common/xerror/xerror.h" #include "xutility/xhash.h" #include #include +using namespace top::evm::crosschain::bsc; + NS_BEG2(top, evm_common) bool xeth_header_t::operator==(xeth_header_t const & rhs) const { @@ -39,7 +43,7 @@ bool xeth_header_t::operator==(xeth_header_t const & rhs) const { (this->transactions_root == rhs.transactions_root) && (this->receipts_root == rhs.receipts_root) && (this->bloom == rhs.bloom) && (this->difficulty == rhs.difficulty) && (this->number == rhs.number) && (this->gas_limit == rhs.gas_limit) && (this->gas_used == rhs.gas_used) && (this->time == rhs.time) && (this->extra == rhs.extra) && (this->mix_digest == rhs.mix_digest) && (this->nonce == rhs.nonce) && (this->base_fee_per_gas == rhs.base_fee_per_gas) && - (this->withdrawals_root == rhs.withdrawals_root); + (this->withdrawals_root == rhs.withdrawals_root) && (this->blob_gas_used == rhs.blob_gas_used) && (this->excess_blob_gas == rhs.excess_blob_gas); } xh256_t xeth_header_t::calc_hash(bool const partial) const { @@ -131,6 +135,16 @@ xbytes_t xeth_header_t::encode_rlp(bool const partial) const { out.insert(out.end(), tmp.begin(), tmp.end()); } + if (blob_gas_used.has_value()) { + auto tmp = RLP::encode(blob_gas_used.value()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + + if (excess_blob_gas.has_value()) { + auto tmp = RLP::encode(excess_blob_gas.value()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + return RLP::encodeList(out); } @@ -232,6 +246,14 @@ void xeth_header_t::decode_rlp(xbytes_t const & bytes, std::error_code & ec) { withdrawals_root = xh256_t{xspan_t{l.decoded[16]}}; } + if (l.decoded.size() >= 18) { + blob_gas_used = evm_common::fromBigEndian(l.decoded[17]); + } + + if (l.decoded.size() >= 19) { + excess_blob_gas = evm_common::fromBigEndian(l.decoded[18]); + } + { xbytes_t rlp_bytes = bytes; auto const & encoded_bytes = encode_rlp(); @@ -325,4 +347,96 @@ bool xeth_header_info_t::decode_rlp(xbytes_t const & input) { return true; } +static uint256_t seal_hash(xeth_header_t const & header, bigint const & chainid) { + xbytes_t out; + { + auto tmp = RLP::encode(static_cast(chainid)); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.parent_hash.asBytes()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.uncle_hash.asBytes()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.miner.to_bytes()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.state_root.asBytes()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.transactions_root.asBytes()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.receipts_root.asBytes()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.bloom.asBytes()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(static_cast(header.difficulty)); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.number); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.gas_limit); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.gas_used); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.time); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + xbytes_t extra{header.extra.begin(), header.extra.begin() + (header.extra.size() - EXTRA_SEAL)}; + auto tmp = RLP::encode(extra); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.mix_digest.asBytes()); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + { + auto tmp = RLP::encode(header.nonce); + out.insert(out.end(), tmp.begin(), tmp.end()); + } + auto value = RLP::encodeList(out); + return utl::xkeccak256_t::digest(value.data(), value.size()); +} + +static common::xeth_address_t ecrecover(xeth_header_t const & header, bigint const & chainid, std::error_code & ec) { + if (header.extra.size() < EXTRA_SEAL) { + xwarn("[ecrecover] header.extra size %zu < extraSeal %lu", header.extra.size(), EXTRA_SEAL); + return {}; + } + + uint8_t sig_array[65] = {0}; + sig_array[0] = header.extra.back(); + std::memcpy(sig_array + 1, header.extra.data() + header.extra.size() - EXTRA_SEAL, 64); + utl::xecdsasig_t sig(sig_array); + + uint8_t pubkey[65] = {0}; + auto const hash = seal_hash(header, chainid); + if (false == utl::xsecp256k1_t::get_publickey_from_signature_directly(sig, hash, pubkey)) { + xwarn("[ecrecover] get_publickey_from_signature_directly failed, extra: %s, seal_hash: %s", to_hex(header.extra).c_str(), to_hex(to_bytes(hash)).c_str()); + return {}; + } + auto digest = to_bytes(utl::xkeccak256_t::digest(&pubkey[1], sizeof(pubkey) - 1)); + return common::xeth_address_t::build_from(std::next(std::begin(digest), 12), std::end(digest), ec); +} + NS_END2 diff --git a/src/xtopcom/xevm_common/src/xheco_eip1559.cpp b/src/xtopcom/xevm_common/src/xheco_eip1559.cpp index c07091f4d..dcb578c21 100644 --- a/src/xtopcom/xevm_common/src/xheco_eip1559.cpp +++ b/src/xtopcom/xevm_common/src/xheco_eip1559.cpp @@ -1,30 +1,30 @@ -#include "xevm_common/xcrosschain/xheco_eip1559.h" - -#include "xcommon/common.h" -#include "xevm_common/xcrosschain/xeth_header.h" -#include "xevm_common/xcrosschain/xheco_gaslimit.h" - -#include - -NS_BEG3(top, evm_common, heco) -static uint64_t calc_base_fee(xeth_header_t const &) { - return 0; -} - -bool verify_eip1559_header(xeth_header_t const & parent_header, xeth_header_t const & header) { - assert(parent_header.base_fee_per_gas.has_value()); - - auto const & parent_gas_limit = parent_header.gas_limit; - if (!heco::verify_gaslimit(parent_gas_limit, header.gas_limit)) { - xwarn("[xtop_evm_eth_bridge_contract::verifyEip1559Header] gaslimit mismatch, new: %s, old: %s", header.gas_limit.str().c_str(), parent_header.gas_limit.str().c_str()); - return false; - } - auto const expected_base_fee = calc_base_fee(parent_header); - if (header.base_fee_per_gas.value() != expected_base_fee) { - xwarn("[xtop_evm_eth_bridge_contract::verifyEip1559Header] wrong basefee: %" PRIu64 ", should be: %" PRIu64, header.base_fee_per_gas.value(), expected_base_fee); - return false; - } - return true; -} - -NS_END3 +//#include "xevm_common/xcrosschain/xheco_eip1559.h" +// +//#include "xcommon/common.h" +//#include "xevm_common/xcrosschain/xeth_header.h" +//#include "xevm_common/xcrosschain/xheco_gaslimit.h" +// +//#include +// +//NS_BEG3(top, evm_common, heco) +//static uint64_t calc_base_fee(xeth_header_t const &) { +// return 0; +//} +// +//bool verify_eip1559_header(xeth_header_t const & parent_header, xeth_header_t const & header) { +// assert(parent_header.base_fee_per_gas.has_value()); +// +// auto const & parent_gas_limit = parent_header.gas_limit; +// if (!heco::verify_gaslimit(parent_gas_limit, header.gas_limit)) { +// xwarn("[xtop_evm_eth_bridge_contract::verifyEip1559Header] gaslimit mismatch, new: %s, old: %s", header.gas_limit.str().c_str(), parent_header.gas_limit.str().c_str()); +// return false; +// } +// auto const expected_base_fee = calc_base_fee(parent_header); +// if (header.base_fee_per_gas.value() != expected_base_fee) { +// xwarn("[xtop_evm_eth_bridge_contract::verifyEip1559Header] wrong basefee: %" PRIu64 ", should be: %" PRIu64, header.base_fee_per_gas.value(), expected_base_fee); +// return false; +// } +// return true; +//} +// +//NS_END3 diff --git a/src/xtopcom/xevm_common/src/xheco_gaslimit.cpp b/src/xtopcom/xevm_common/src/xheco_gaslimit.cpp index a696a5175..9115e6e15 100644 --- a/src/xtopcom/xevm_common/src/xheco_gaslimit.cpp +++ b/src/xtopcom/xevm_common/src/xheco_gaslimit.cpp @@ -1,30 +1,30 @@ -#include "xevm_common/xcrosschain/xheco_gaslimit.h" - -#include "xbase/xbase.h" -#include "xcommon/common.h" - -NS_BEG3(top, evm_common, heco) - -constexpr uint64_t GasLimitBoundDivisor = 1024; -constexpr uint64_t MinGasLimit = 5000; - -bool verify_gaslimit(const u256 parent_gas_limit, const u256 header_gas_limit) { - // Verify that the gas limit remains within allowed bounds - bigint diff = bigint(parent_gas_limit) - bigint(header_gas_limit); - if (diff < 0) { - diff *= -1; - } - bigint limit = parent_gas_limit / GasLimitBoundDivisor; - if (uint64_t(diff) >= limit) { - xwarn("[xtop_evm_eth_bridge_contract::verifyGaslimit] diff: %lu >= limit: %s", uint64_t(diff), limit.str().c_str()); - return false; - } - - if (header_gas_limit < MinGasLimit) { - xwarn("[xtop_evm_eth_bridge_contract::verifyGaslimit] headerGasLimit: %s too small < %lu", header_gas_limit.str().c_str(), MinGasLimit); - return false; - } - return true; -} - -NS_END3 +//#include "xevm_common/xcrosschain/xheco_gaslimit.h" +// +//#include "xbase/xbase.h" +//#include "xcommon/common.h" +// +//NS_BEG3(top, evm_common, heco) +// +//constexpr uint64_t GasLimitBoundDivisor = 1024; +//constexpr uint64_t MinGasLimit = 5000; +// +//bool verify_gaslimit(const u256 parent_gas_limit, const u256 header_gas_limit) { +// // Verify that the gas limit remains within allowed bounds +// bigint diff = bigint(parent_gas_limit) - bigint(header_gas_limit); +// if (diff < 0) { +// diff *= -1; +// } +// bigint limit = parent_gas_limit / GasLimitBoundDivisor; +// if (uint64_t(diff) >= limit) { +// xwarn("[xtop_evm_eth_bridge_contract::verifyGaslimit] diff: %lu >= limit: %s", uint64_t(diff), limit.str().c_str()); +// return false; +// } +// +// if (header_gas_limit < MinGasLimit) { +// xwarn("[xtop_evm_eth_bridge_contract::verifyGaslimit] headerGasLimit: %s too small < %lu", header_gas_limit.str().c_str(), MinGasLimit); +// return false; +// } +// return true; +//} +// +//NS_END3 diff --git a/src/xtopcom/xevm_common/src/xsnapshot.cpp b/src/xtopcom/xevm_common/src/xsnapshot.cpp new file mode 100644 index 000000000..0879b2036 --- /dev/null +++ b/src/xtopcom/xevm_common/src/xsnapshot.cpp @@ -0,0 +1,91 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "xevm_common/xcrosschain/xbsc/xsnapshot.h" +#include "xevm_common/xerror/xerror.h" + +NS_BEG4(top, evm, crosschain, bsc) + +auto xtop_snapshot::new_snapshot(uint64_t const number, + xh256_t const & hash, + std::vector const & validators, + std::vector const & vote_addresses, + std::error_code & ec) -> xtop_snapshot { + assert(!ec); + + xtop_snapshot snapshot; + if (vote_addresses.size() != validators.size()) { + ec = top::evm_common::error::xerrc_t::invalid_bsc_epoch_data; + return snapshot; + } + + + snapshot.number_ = number; + snapshot.hash_ = hash; + + size_t i = 0; + for (; i < validators.size(); ++i) { + auto const & v = validators[i]; + + snapshot.validators_[v].index = 0; + snapshot.validators_[v].vote_address = vote_addresses[i]; + } + + i = 0; + for (auto & v : snapshot.validators()) { + v.second.index = static_cast(++i); + } + + return snapshot; +} + +auto xtop_snapshot::number() const noexcept-> uint64_t { + return number_; +} + +auto xtop_snapshot::hash() const noexcept -> xh256_t const& { + return hash_; +} + +auto xtop_snapshot::validators() const noexcept -> std::map const & { + return validators_; +} + +auto xtop_snapshot::validators() noexcept -> std::map & { + return validators_; +} + +auto xtop_snapshot::recents() const noexcept -> std::map const & { + return recents_; +} + +auto xtop_snapshot::recents() noexcept -> std::map & { + return recents_; +} + +auto xtop_snapshot::recent_fork_hashes() const noexcept -> std::map const & { + return recent_fork_hashes_; +} + +auto xtop_snapshot::recent_fork_hashes() noexcept -> std::map & { + return recent_fork_hashes_; +} + +auto xtop_snapshot::attestation() const noexcept -> xvote_data_t const & { + return attestation_; +} + +auto xtop_snapshot::empty() const noexcept -> bool { + return hash_.empty(); +} + +auto xtop_snapshot::encode(std::error_code & ec) const -> xbytes_t { + return {}; +} + +auto xtop_snapshot::decode(xbytes_t const & bytes, std::error_code & ec) -> void { +} + +NS_END4 + diff --git a/src/xtopcom/xevm_common/src/xutility.cpp b/src/xtopcom/xevm_common/src/xutility.cpp new file mode 100644 index 000000000..a087355fe --- /dev/null +++ b/src/xtopcom/xevm_common/src/xutility.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include "xevm_common/xcrosschain/xbsc/xutility.h" +#include "xevm_common/xerror/xerror.h" +#include "xcommon/rlp.h" + +NS_BEG4(top, evm, crosschain, bsc) + +// getValidatorBytesFromHeader returns the validators bytes extracted from the header's extra field if exists. +// The validators bytes would be contained only in the epoch block's header, and its each validator bytes length is fixed. +// On luban fork, we introduce vote attestation into the header's extra field, so extra format is different from before. +// Before luban fork: |---Extra Vanity---|---Validators Bytes (or Empty)---|---Extra Seal---| +// After luban fork: |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---| +auto get_validator_bytes_from_header(evm_common::xeth_header_t const & header, + xchain_config_t const & chain_config, + xparlia_config_t const & parlia_config) -> xbytes_t { + if (header.extra.size() <= EXTRA_VANITY + EXTRA_SEAL) { + return {}; + } + + if (!chain_config.is_luban(header.number)) { + return {}; + } + + if (header.number % parlia_config.epoch != 0) { + return {}; + } + + auto const num = static_cast(header.extra[EXTRA_VANITY]); + if (num == 0 || header.extra.size() <= EXTRA_VANITY + EXTRA_SEAL + num * VALIDATOR_BYTES_LENGTH) { + return {}; + } + + auto const start = std::next(std::begin(header.extra), static_cast(EXTRA_VANITY + VALIDATOR_NUMBER_SIZE)); + auto const end = std::next(start, static_cast(num * VALIDATOR_BYTES_LENGTH)); + + return xbytes_t{start, end}; +} + +auto get_vote_attestation_from_header(evm_common::xeth_header_t const & header, + xchain_config_t const & chain_config, + xparlia_config_t const & parlia_config, + std::error_code & ec) -> xvote_attestation_t { + assert(!ec); + if (header.extra.size() <= EXTRA_VANITY + EXTRA_SEAL) { + ec = evm_common::error::xerrc_t::invalid_bsc_extra_data; + return {}; + } + + if (!chain_config.is_luban(header.number)) { + ec = evm_common::error::xerrc_t::bsc_header_before_luban; + return {}; + } + + xbytes_t attesttion_bytes; + if (header.number % parlia_config.epoch != 0) { + auto const b = std::next(std::begin(header.extra), static_cast(EXTRA_VANITY)); + auto const e = std::next(std::end(header.extra), -static_cast(EXTRA_SEAL)); + attesttion_bytes = xbytes_t{b, e}; + } else { + auto const num = static_cast(header.extra[EXTRA_VANITY]); + if (header.extra.size() <= EXTRA_VANITY + EXTRA_SEAL + VALIDATOR_NUMBER_SIZE + num * VALIDATOR_BYTES_LENGTH) { + ec = evm_common::error::xerrc_t::invalid_bsc_extra_data; + return {}; + } + + auto const b = std::next(std::begin(header.extra), static_cast(EXTRA_VANITY + VALIDATOR_NUMBER_SIZE + num * VALIDATOR_BYTES_LENGTH)); + auto const e = std::next(std::end(header.extra), -static_cast(EXTRA_SEAL)); + attesttion_bytes = xbytes_t{b, e}; + } + + // auto const & decoded_item = evm_common::RLP::decode_list(attesttion_bytes, ec); + xvote_attestation_t attestation; + assert(false); + return attestation; +} + +NS_END4 diff --git a/src/xtopcom/xevm_common/src/xvalidators_snapshot.cpp b/src/xtopcom/xevm_common/src/xvalidators_snapshot.cpp index 3115905a6..21bc87d11 100644 --- a/src/xtopcom/xevm_common/src/xvalidators_snapshot.cpp +++ b/src/xtopcom/xevm_common/src/xvalidators_snapshot.cpp @@ -1,502 +1,502 @@ -// Copyright (c) 2023-present Telos Foundation & contributors -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "xevm_common/xcrosschain/xvalidators_snapshot.h" - -#include "xbasic/xhex.h" -#include "xcrypto/xckey.h" -#include "xcommon/rlp.h" -#include "xutility/xhash.h" - -#include - -NS_BEG2(top, evm_common) -constexpr uint64_t extraVanity = 32; -constexpr uint64_t extraSeal = 64 + 1; -constexpr uint64_t epoch = 200; - -static uint256_t seal_hash(xeth_header_t const & header) { - xbytes_t out; - { - auto tmp = RLP::encode(header.parent_hash.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.uncle_hash.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.miner.to_bytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.state_root.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.transactions_root.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.receipts_root.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.bloom.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(static_cast(header.difficulty)); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.number); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.gas_limit); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.gas_used); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.time); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - xbytes_t extra{header.extra.begin(), std::next(header.extra.begin(), static_cast(header.extra.size() - extraSeal))}; - auto tmp = RLP::encode(extra); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.mix_digest.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.nonce); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - auto const value = RLP::encodeList(out); - return utl::xkeccak256_t::digest(value.data(), value.size()); -} - -static uint256_t seal_hash(xeth_header_t const & header, bigint const & chainid) { - xbytes_t out; - { - auto tmp = RLP::encode(static_cast(chainid)); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.parent_hash.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.uncle_hash.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.miner.to_bytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.state_root.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.transactions_root.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.receipts_root.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.bloom.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(static_cast(header.difficulty)); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.number); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.gas_limit); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.gas_used); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.time); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - xbytes_t extra{header.extra.begin(), header.extra.begin() + (header.extra.size() - extraSeal)}; - auto tmp = RLP::encode(extra); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.mix_digest.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(header.nonce); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - auto value = RLP::encodeList(out); - return utl::xkeccak256_t::digest(value.data(), value.size()); -} - -static common::xeth_address_t ecrecover(xeth_header_t const & header, std::error_code & ec) { - if (header.extra.size() < extraSeal) { - xwarn("[ecrecover] header.extra size %zu < extraSeal %lu", header.extra.size(), extraSeal); - return {}; - } - - uint8_t sig_array[65] = {0}; - sig_array[0] = header.extra.back(); - std::memcpy(sig_array + 1, header.extra.data() + header.extra.size() - extraSeal, 64); - utl::xecdsasig_t sig(sig_array); - - uint8_t pubkey[65] = {0}; - auto const hash = seal_hash(header); - if (false == utl::xsecp256k1_t::get_publickey_from_signature_directly(sig, hash, pubkey)) { - xwarn("[ecrecover] get_publickey_from_signature_directly failed, extra: %s, seal_hash: %s", to_hex(header.extra).c_str(), to_hex(to_bytes(hash)).c_str()); - return {}; - } - auto digest = to_bytes(utl::xkeccak256_t::digest(&pubkey[1], sizeof(pubkey) - 1)); - return common::xeth_address_t::build_from(std::next(std::begin(digest), 12), std::end(digest), ec); -} - -static common::xeth_address_t ecrecover(xeth_header_t const & header, bigint const & chainid, std::error_code & ec) { - if (header.extra.size() < extraSeal) { - xwarn("[ecrecover] header.extra size %zu < extraSeal %lu", header.extra.size(), extraSeal); - return {}; - } - - uint8_t sig_array[65] = {0}; - sig_array[0] = header.extra.back(); - std::memcpy(sig_array + 1, header.extra.data() + header.extra.size() - extraSeal, 64); - utl::xecdsasig_t sig(sig_array); - - uint8_t pubkey[65] = {0}; - auto const hash = seal_hash(header, chainid); - if (false == utl::xsecp256k1_t::get_publickey_from_signature_directly(sig, hash, pubkey)) { - xwarn("[ecrecover] get_publickey_from_signature_directly failed, extra: %s, seal_hash: %s", to_hex(header.extra).c_str(), to_hex(to_bytes(hash)).c_str()); - return {}; - } - auto digest = to_bytes(utl::xkeccak256_t::digest(&pubkey[1], sizeof(pubkey) - 1)); - return common::xeth_address_t::build_from(std::next(std::begin(digest), 12), std::end(digest), ec); -} - -bool xvalidators_snapshot_t::init_with_epoch(xeth_header_t const & header) { - if (header.number % epoch != 0) { - xwarn("[xvalidators_snapshot_t::init_with_epoch] not epoch header"); - return false; - } - number = static_cast(header.number); - hash = header.calc_hash(); - xbytes_t new_validators_bytes{header.extra.begin() + extraVanity, header.extra.end() - extraSeal}; - if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { - xwarn("[xvalidators_snapshot_t::init_with_epoch] new_validators_bytes size error: %zu", new_validators_bytes.size()); - return false; - } - auto const new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); - for (uint32_t i = 0; i < new_validators_num; ++i) { - auto b = common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), - std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size()))); - validators.insert(b); - } - - return true; -} - -bool xvalidators_snapshot_t::init_with_double_epoch(xeth_header_t const & header1, xeth_header_t const & header2) { - if (header1.number % epoch != 0 || header2.number % epoch != 0) { - xwarn("[xvalidators_snapshot_t::init_with_epoch] not epoch header"); - return false; - } - { - number = static_cast(header1.number); - hash = header1.calc_hash(); - xbytes_t new_validators_bytes{header1.extra.begin() + extraVanity, header1.extra.end() - extraSeal}; - if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { - xwarn("[xvalidators_snapshot_t::init_with_epoch] new_validators_bytes size error: %zu", new_validators_bytes.size()); - return false; - } - auto new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); - for (uint32_t i = 0; i < new_validators_num; ++i) { - auto b = common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), - std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size()))); - last_validators.insert(b); - } - } - { - number = static_cast(header2.number); - hash = header2.calc_hash(); - xbytes_t new_validators_bytes{header2.extra.begin() + extraVanity, header2.extra.end() - extraSeal}; - if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { - xwarn("[xvalidators_snapshot_t::init_with_epoch] new_validators_bytes size error: %zu", new_validators_bytes.size()); - return false; - } - auto const new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); - for (uint32_t i = 0; i < new_validators_num; ++i) { - auto b = common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), - std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size()))); - validators.insert(b); - } - } - - return true; -} - -bool xvalidators_snapshot_t::apply(xeth_header_t const & header, bool const check_inturn) { - std::error_code ec; - - auto const height = header.number; - if (height != number + 1) { - xwarn("[xvalidators_snapshot_t::apply] number mismatch %" PRIu64 ", %" PRIu64, height, number + 1); - return false; - } - auto limit = validators.size() / 2 + 1; - if (height >= limit) { - recents.erase(height - limit); - } - auto const validator = ecrecover(header, ec); - if (ec) { - xwarn("[xvalidators_snapshot_t::apply] ecrecover failed: category %s errc %d msg %s", ec.category().name(), ec.value(), ec.message().c_str()); - return false; - } - - xinfo("[xvalidators_snapshot_t::apply] number: %" PRIu64 ", validator: %s", height, validator.to_hex_string().c_str()); - - if (!validators.count(validator)) { - xwarn("[xvalidators_snapshot_t::apply] validator %s not in validators", validator.to_hex_string().c_str()); - return false; - } - if (validator != header.miner) { - xwarn("[xvalidators_snapshot_t::apply] validator %s is not miner %s", validator.to_hex_string().c_str(), header.miner.to_hex_string().c_str()); - return false; - } - for (auto const & r : recents) { - if (r.second == validator) { - xwarn("[xvalidators_snapshot_t::apply] validator %s is in recent", validator.to_hex_string().c_str()); - return false; - } - } - recents[static_cast(height)] = validator; - if (height > 0 && height % epoch == 0) { - xbytes_t new_validators_bytes{header.extra.begin() + extraVanity, header.extra.end() - extraSeal}; - if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { - xwarn("[xvalidators_snapshot_t::apply] new_validators_bytes size error: %zu", new_validators_bytes.size()); - return false; - } - auto const new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); - std::set new_validators; - for (uint32_t i = 0; i < new_validators_num; ++i) { - new_validators.insert(common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), - std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size())))); - } - limit = new_validators.size() / 2 + 1; - for (auto i = 0u; i < validators.size() / 2 - new_validators.size() / 2; i++) { - recents.erase(height - limit - i); - } - validators = new_validators; - } - number += 1; - - bigint const diff_in_turn = 2; - bigint const diff_no_turn = 1; - if (check_inturn) { - auto const turn = inturn(number, validator, false); - if (turn && header.difficulty != diff_in_turn) { - xwarn("[xvalidators_snapshot_t::apply] check inturn failed, turn: %d, difficulty: %s", turn, header.difficulty.str().c_str()); - return false; - } - if (!turn && header.difficulty != diff_no_turn) { - xwarn("[xvalidators_snapshot_t::apply] check inturn failed, turn: %d, difficulty: %s", turn, header.difficulty.str().c_str()); - return false; - } - } - - hash = header.calc_hash(); - return true; -} - -bool xvalidators_snapshot_t::apply_with_chainid(xeth_header_t const & header, bigint const & chainid, bool const check_inturn) { - auto const height = header.number; - if (height != number + 1) { - xwarn("[xvalidators_snapshot_t::apply_with_chainid] number mismatch %" PRIu64 ", %" PRIu64, height, number + 1); - return false; - } - auto limit = validators.size() / 2 + 1; - if (height >= limit) { - recents.erase(height - limit); - } - std::error_code ec; - auto const validator = ecrecover(header, chainid, ec); - if (ec) { - xwarn("[xvalidators_snapshot_t::apply_with_chainid] ecrecover failed: category %s errc %d msg %s", ec.category().name(), ec.value(), ec.message().c_str()); - return false; - } - xinfo("[xvalidators_snapshot_t::apply_with_chainid] number: %" PRIu64 ", validator: %s", height, validator.to_hex_string().c_str()); - - auto const pos = height % 200; - if (pos >= 1 && pos <= 10) { - if (!last_validators.count(validator)) { - xwarn("[xvalidators_snapshot_t::apply_with_chainid] validator %s not in last_validators", validator.to_hex_string().c_str()); - return false; - } - } else { - if (!validators.count(validator)) { - xwarn("[xvalidators_snapshot_t::apply_with_chainid] validator %s not in validators", validator.to_hex_string().c_str()); - return false; - } - } - if (validator != header.miner) { - xwarn("[xvalidators_snapshot_t::apply_with_chainid] validator %s is not miner %s", validator.to_hex_string().c_str(), header.miner.to_hex_string().c_str()); - return false; - } - for (auto const & r : recents) { - if (r.second == validator) { - xwarn("[xvalidators_snapshot_t::apply_with_chainid] validator %s is in recent", validator.to_hex_string().c_str()); - return false; - } - } - recents[static_cast(height)] = validator; - if (height > 0 && height % epoch == 0) { - xbytes_t new_validators_bytes{header.extra.begin() + extraVanity, header.extra.end() - extraSeal}; - if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { - xwarn("[xvalidators_snapshot_t::apply_with_chainid] new_validators_bytes size error: %zu", new_validators_bytes.size()); - return false; - } - auto const new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); - std::set new_validators; - for (uint32_t i = 0; i < new_validators_num; ++i) { - // new_validators.insert(xbytes_t{new_validators_bytes.begin() + i * common::xeth_address_t::size(), new_validators_bytes.begin() + (i + 1) * common::xeth_address_t::size()}); - new_validators.insert(common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), - std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size())))); - } - limit = new_validators.size() / 2 + 1; - for (auto i = 0u; i < validators.size() / 2 - new_validators.size() / 2; i++) { - recents.erase(height - limit - i); - } - last_validators = validators; - validators = new_validators; - } - number += 1; - - bigint const diff_in_turn = 2; - bigint const diff_no_turn = 1; - if (check_inturn) { - bool turn{false}; - if (pos >= 0 && pos <= 10) { - turn = inturn(number, validator, true); - } else { - turn = inturn(number, validator, false); - } - if (turn && header.difficulty != diff_in_turn) { - xwarn("[xvalidators_snapshot_t::apply] check inturn failed, turn: %d, difficulty: %s", turn, header.difficulty.str().c_str()); - return false; - } - if (!turn && header.difficulty != diff_no_turn) { - xwarn("[xvalidators_snapshot_t::apply] check inturn failed, turn: %d, difficulty: %s", turn, header.difficulty.str().c_str()); - return false; - } - } - - hash = header.calc_hash(); - return true; -} - -bool xvalidators_snapshot_t::inturn(uint64_t const num, common::xeth_address_t const & validator, bool const use_old) const { - std::vector addrs; - if (use_old) { - for (auto const & address : last_validators) { - addrs.push_back(address); - } - } else { - for (auto const & address : validators) { - addrs.push_back(address); - } - } - - std::sort(addrs.begin(), addrs.end()); - uint32_t index{0}; - for (; index < addrs.size(); ++index) { - if (addrs[index] == validator) { - break; - } - } - assert(index < addrs.size()); - return (num % addrs.size()) == index; -} - -h256 xvalidators_snapshot_t::digest() const { - RLPStream stream; - stream << number << hash << validators; - for (auto const & p : recents) { - stream << p.first; - stream << p.second; - } - auto const & v = stream.out(); - auto const hash_value = utl::xkeccak256_t::digest(v.data(), v.size()); - return h256(hash_value.data(), h256::ConstructFromPointer); -} - -void xvalidators_snapshot_t::print() const { - printf("number: %lu\n", number); - printf("hash: %s\n", hash.hex().c_str()); - printf("validators:\n"); - for (auto const & address : validators) { - printf("%s\n", address.to_hex_string().c_str()); - } - printf("recents:\n"); - for (auto const & recent : recents) { - printf("%lu:%s\n", recent.first, recent.second.to_hex_string().c_str()); - } - printf("digest: %s\n", digest().hex().c_str()); -} - -xvalidators_snap_info_t::xvalidators_snap_info_t(h256 const & snap_hash, h256 const & parent_hash, uint64_t const number) : snap_hash(snap_hash), parent_hash(parent_hash), number(number) { -} - -xbytes_t xvalidators_snap_info_t::encode_rlp() const { - xbytes_t out; - { - auto tmp = RLP::encode(snap_hash.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(parent_hash.asBytes()); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - { - auto tmp = RLP::encode(static_cast(number)); - out.insert(out.end(), tmp.begin(), tmp.end()); - } - return RLP::encodeList(out); -} - -bool xvalidators_snap_info_t::decode_rlp(xbytes_t const & input) { - auto l = RLP::decodeList(input); - if (l.decoded.size() != 3) { - return false; - } - if (!l.remainder.empty()) { - return false; - } - snap_hash = xh256_t{xspan_t{l.decoded[0]}}; - parent_hash = xh256_t{xspan_t{l.decoded[1]}}; - number = static_cast(evm_common::fromBigEndian(l.decoded[2])); - return true; -} - -NS_END2 +//// Copyright (c) 2023-present Telos Foundation & contributors +//// Distributed under the MIT software license, see the accompanying +//// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +//#include "xevm_common/xcrosschain/xvalidators_snapshot.h" +// +//#include "xbasic/xhex.h" +//#include "xcrypto/xckey.h" +//#include "xcommon/rlp.h" +//#include "xutility/xhash.h" +// +//#include +// +//NS_BEG2(top, evm_common) +//constexpr uint64_t extraVanity = 32; +//constexpr uint64_t extraSeal = 64 + 1; +//constexpr uint64_t epoch = 200; +// +//static uint256_t seal_hash(xeth_header_t const & header) { +// xbytes_t out; +// { +// auto tmp = RLP::encode(header.parent_hash.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.uncle_hash.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.miner.to_bytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.state_root.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.transactions_root.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.receipts_root.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.bloom.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(static_cast(header.difficulty)); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.number); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.gas_limit); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.gas_used); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.time); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// xbytes_t extra{header.extra.begin(), std::next(header.extra.begin(), static_cast(header.extra.size() - extraSeal))}; +// auto tmp = RLP::encode(extra); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.mix_digest.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.nonce); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// auto const value = RLP::encodeList(out); +// return utl::xkeccak256_t::digest(value.data(), value.size()); +//} +// +//static uint256_t seal_hash(xeth_header_t const & header, bigint const & chainid) { +// xbytes_t out; +// { +// auto tmp = RLP::encode(static_cast(chainid)); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.parent_hash.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.uncle_hash.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.miner.to_bytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.state_root.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.transactions_root.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.receipts_root.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.bloom.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(static_cast(header.difficulty)); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.number); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.gas_limit); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.gas_used); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.time); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// xbytes_t extra{header.extra.begin(), header.extra.begin() + (header.extra.size() - extraSeal)}; +// auto tmp = RLP::encode(extra); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.mix_digest.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(header.nonce); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// auto value = RLP::encodeList(out); +// return utl::xkeccak256_t::digest(value.data(), value.size()); +//} +// +//static common::xeth_address_t ecrecover(xeth_header_t const & header, std::error_code & ec) { +// if (header.extra.size() < extraSeal) { +// xwarn("[ecrecover] header.extra size %zu < extraSeal %lu", header.extra.size(), extraSeal); +// return {}; +// } +// +// uint8_t sig_array[65] = {0}; +// sig_array[0] = header.extra.back(); +// std::memcpy(sig_array + 1, header.extra.data() + header.extra.size() - extraSeal, 64); +// utl::xecdsasig_t sig(sig_array); +// +// uint8_t pubkey[65] = {0}; +// auto const hash = seal_hash(header); +// if (false == utl::xsecp256k1_t::get_publickey_from_signature_directly(sig, hash, pubkey)) { +// xwarn("[ecrecover] get_publickey_from_signature_directly failed, extra: %s, seal_hash: %s", to_hex(header.extra).c_str(), to_hex(to_bytes(hash)).c_str()); +// return {}; +// } +// auto digest = to_bytes(utl::xkeccak256_t::digest(&pubkey[1], sizeof(pubkey) - 1)); +// return common::xeth_address_t::build_from(std::next(std::begin(digest), 12), std::end(digest), ec); +//} +// +//static common::xeth_address_t ecrecover(xeth_header_t const & header, bigint const & chainid, std::error_code & ec) { +// if (header.extra.size() < extraSeal) { +// xwarn("[ecrecover] header.extra size %zu < extraSeal %lu", header.extra.size(), extraSeal); +// return {}; +// } +// +// uint8_t sig_array[65] = {0}; +// sig_array[0] = header.extra.back(); +// std::memcpy(sig_array + 1, header.extra.data() + header.extra.size() - extraSeal, 64); +// utl::xecdsasig_t sig(sig_array); +// +// uint8_t pubkey[65] = {0}; +// auto const hash = seal_hash(header, chainid); +// if (false == utl::xsecp256k1_t::get_publickey_from_signature_directly(sig, hash, pubkey)) { +// xwarn("[ecrecover] get_publickey_from_signature_directly failed, extra: %s, seal_hash: %s", to_hex(header.extra).c_str(), to_hex(to_bytes(hash)).c_str()); +// return {}; +// } +// auto digest = to_bytes(utl::xkeccak256_t::digest(&pubkey[1], sizeof(pubkey) - 1)); +// return common::xeth_address_t::build_from(std::next(std::begin(digest), 12), std::end(digest), ec); +//} +// +//bool xvalidators_snapshot_t::init_with_epoch(xeth_header_t const & header) { +// if (header.number % epoch != 0) { +// xwarn("[xvalidators_snapshot_t::init_with_epoch] not epoch header"); +// return false; +// } +// number = static_cast(header.number); +// hash = header.calc_hash(); +// xbytes_t new_validators_bytes{header.extra.begin() + extraVanity, header.extra.end() - extraSeal}; +// if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { +// xwarn("[xvalidators_snapshot_t::init_with_epoch] new_validators_bytes size error: %zu", new_validators_bytes.size()); +// return false; +// } +// auto const new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); +// for (uint32_t i = 0; i < new_validators_num; ++i) { +// auto b = common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), +// std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size()))); +// validators.insert(b); +// } +// +// return true; +//} +// +//bool xvalidators_snapshot_t::init_with_double_epoch(xeth_header_t const & header1, xeth_header_t const & header2) { +// if (header1.number % epoch != 0 || header2.number % epoch != 0) { +// xwarn("[xvalidators_snapshot_t::init_with_epoch] not epoch header"); +// return false; +// } +// { +// number = static_cast(header1.number); +// hash = header1.calc_hash(); +// xbytes_t new_validators_bytes{header1.extra.begin() + extraVanity, header1.extra.end() - extraSeal}; +// if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { +// xwarn("[xvalidators_snapshot_t::init_with_epoch] new_validators_bytes size error: %zu", new_validators_bytes.size()); +// return false; +// } +// auto new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); +// for (uint32_t i = 0; i < new_validators_num; ++i) { +// auto b = common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), +// std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size()))); +// last_validators.insert(b); +// } +// } +// { +// number = static_cast(header2.number); +// hash = header2.calc_hash(); +// xbytes_t new_validators_bytes{header2.extra.begin() + extraVanity, header2.extra.end() - extraSeal}; +// if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { +// xwarn("[xvalidators_snapshot_t::init_with_epoch] new_validators_bytes size error: %zu", new_validators_bytes.size()); +// return false; +// } +// auto const new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); +// for (uint32_t i = 0; i < new_validators_num; ++i) { +// auto b = common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), +// std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size()))); +// validators.insert(b); +// } +// } +// +// return true; +//} +// +//bool xvalidators_snapshot_t::apply(xeth_header_t const & header, bool const check_inturn) { +// std::error_code ec; +// +// auto const height = header.number; +// if (height != number + 1) { +// xwarn("[xvalidators_snapshot_t::apply] number mismatch %" PRIu64 ", %" PRIu64, height, number + 1); +// return false; +// } +// auto limit = validators.size() / 2 + 1; +// if (height >= limit) { +// recents.erase(height - limit); +// } +// auto const validator = ecrecover(header, ec); +// if (ec) { +// xwarn("[xvalidators_snapshot_t::apply] ecrecover failed: category %s errc %d msg %s", ec.category().name(), ec.value(), ec.message().c_str()); +// return false; +// } +// +// xinfo("[xvalidators_snapshot_t::apply] number: %" PRIu64 ", validator: %s", height, validator.to_hex_string().c_str()); +// +// if (!validators.count(validator)) { +// xwarn("[xvalidators_snapshot_t::apply] validator %s not in validators", validator.to_hex_string().c_str()); +// return false; +// } +// if (validator != header.miner) { +// xwarn("[xvalidators_snapshot_t::apply] validator %s is not miner %s", validator.to_hex_string().c_str(), header.miner.to_hex_string().c_str()); +// return false; +// } +// for (auto const & r : recents) { +// if (r.second == validator) { +// xwarn("[xvalidators_snapshot_t::apply] validator %s is in recent", validator.to_hex_string().c_str()); +// return false; +// } +// } +// recents[static_cast(height)] = validator; +// if (height > 0 && height % epoch == 0) { +// xbytes_t new_validators_bytes{header.extra.begin() + extraVanity, header.extra.end() - extraSeal}; +// if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { +// xwarn("[xvalidators_snapshot_t::apply] new_validators_bytes size error: %zu", new_validators_bytes.size()); +// return false; +// } +// auto const new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); +// std::set new_validators; +// for (uint32_t i = 0; i < new_validators_num; ++i) { +// new_validators.insert(common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), +// std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size())))); +// } +// limit = new_validators.size() / 2 + 1; +// for (auto i = 0u; i < validators.size() / 2 - new_validators.size() / 2; i++) { +// recents.erase(height - limit - i); +// } +// validators = new_validators; +// } +// number += 1; +// +// bigint const diff_in_turn = 2; +// bigint const diff_no_turn = 1; +// if (check_inturn) { +// auto const turn = inturn(number, validator, false); +// if (turn && header.difficulty != diff_in_turn) { +// xwarn("[xvalidators_snapshot_t::apply] check inturn failed, turn: %d, difficulty: %s", turn, header.difficulty.str().c_str()); +// return false; +// } +// if (!turn && header.difficulty != diff_no_turn) { +// xwarn("[xvalidators_snapshot_t::apply] check inturn failed, turn: %d, difficulty: %s", turn, header.difficulty.str().c_str()); +// return false; +// } +// } +// +// hash = header.calc_hash(); +// return true; +//} +// +//bool xvalidators_snapshot_t::apply_with_chainid(xeth_header_t const & header, bigint const & chainid, bool const check_inturn) { +// auto const height = header.number; +// if (height != number + 1) { +// xwarn("[xvalidators_snapshot_t::apply_with_chainid] number mismatch %" PRIu64 ", %" PRIu64, height, number + 1); +// return false; +// } +// auto limit = validators.size() / 2 + 1; +// if (height >= limit) { +// recents.erase(height - limit); +// } +// std::error_code ec; +// auto const validator = ecrecover(header, chainid, ec); +// if (ec) { +// xwarn("[xvalidators_snapshot_t::apply_with_chainid] ecrecover failed: category %s errc %d msg %s", ec.category().name(), ec.value(), ec.message().c_str()); +// return false; +// } +// xinfo("[xvalidators_snapshot_t::apply_with_chainid] number: %" PRIu64 ", validator: %s", height, validator.to_hex_string().c_str()); +// +// auto const pos = height % 200; +// if (pos >= 1 && pos <= 10) { +// if (!last_validators.count(validator)) { +// xwarn("[xvalidators_snapshot_t::apply_with_chainid] validator %s not in last_validators", validator.to_hex_string().c_str()); +// return false; +// } +// } else { +// if (!validators.count(validator)) { +// xwarn("[xvalidators_snapshot_t::apply_with_chainid] validator %s not in validators", validator.to_hex_string().c_str()); +// return false; +// } +// } +// if (validator != header.miner) { +// xwarn("[xvalidators_snapshot_t::apply_with_chainid] validator %s is not miner %s", validator.to_hex_string().c_str(), header.miner.to_hex_string().c_str()); +// return false; +// } +// for (auto const & r : recents) { +// if (r.second == validator) { +// xwarn("[xvalidators_snapshot_t::apply_with_chainid] validator %s is in recent", validator.to_hex_string().c_str()); +// return false; +// } +// } +// recents[static_cast(height)] = validator; +// if (height > 0 && height % epoch == 0) { +// xbytes_t new_validators_bytes{header.extra.begin() + extraVanity, header.extra.end() - extraSeal}; +// if (new_validators_bytes.size() % common::xeth_address_t::size() != 0) { +// xwarn("[xvalidators_snapshot_t::apply_with_chainid] new_validators_bytes size error: %zu", new_validators_bytes.size()); +// return false; +// } +// auto const new_validators_num = new_validators_bytes.size() / common::xeth_address_t::size(); +// std::set new_validators; +// for (uint32_t i = 0; i < new_validators_num; ++i) { +// // new_validators.insert(xbytes_t{new_validators_bytes.begin() + i * common::xeth_address_t::size(), new_validators_bytes.begin() + (i + 1) * common::xeth_address_t::size()}); +// new_validators.insert(common::xeth_address_t::build_from(std::next(std::begin(new_validators_bytes), static_cast(i * common::xeth_address_t::size())), +// std::next(std::begin(new_validators_bytes), static_cast((i + 1) * common::xeth_address_t::size())))); +// } +// limit = new_validators.size() / 2 + 1; +// for (auto i = 0u; i < validators.size() / 2 - new_validators.size() / 2; i++) { +// recents.erase(height - limit - i); +// } +// last_validators = validators; +// validators = new_validators; +// } +// number += 1; +// +// bigint const diff_in_turn = 2; +// bigint const diff_no_turn = 1; +// if (check_inturn) { +// bool turn{false}; +// if (pos >= 0 && pos <= 10) { +// turn = inturn(number, validator, true); +// } else { +// turn = inturn(number, validator, false); +// } +// if (turn && header.difficulty != diff_in_turn) { +// xwarn("[xvalidators_snapshot_t::apply] check inturn failed, turn: %d, difficulty: %s", turn, header.difficulty.str().c_str()); +// return false; +// } +// if (!turn && header.difficulty != diff_no_turn) { +// xwarn("[xvalidators_snapshot_t::apply] check inturn failed, turn: %d, difficulty: %s", turn, header.difficulty.str().c_str()); +// return false; +// } +// } +// +// hash = header.calc_hash(); +// return true; +//} +// +//bool xvalidators_snapshot_t::inturn(uint64_t const num, common::xeth_address_t const & validator, bool const use_old) const { +// std::vector addrs; +// if (use_old) { +// for (auto const & address : last_validators) { +// addrs.push_back(address); +// } +// } else { +// for (auto const & address : validators) { +// addrs.push_back(address); +// } +// } +// +// std::sort(addrs.begin(), addrs.end()); +// uint32_t index{0}; +// for (; index < addrs.size(); ++index) { +// if (addrs[index] == validator) { +// break; +// } +// } +// assert(index < addrs.size()); +// return (num % addrs.size()) == index; +//} +// +//h256 xvalidators_snapshot_t::digest() const { +// RLPStream stream; +// stream << number << hash << validators; +// for (auto const & p : recents) { +// stream << p.first; +// stream << p.second; +// } +// auto const & v = stream.out(); +// auto const hash_value = utl::xkeccak256_t::digest(v.data(), v.size()); +// return h256(hash_value.data(), h256::ConstructFromPointer); +//} +// +//void xvalidators_snapshot_t::print() const { +// printf("number: %lu\n", number); +// printf("hash: %s\n", hash.hex().c_str()); +// printf("validators:\n"); +// for (auto const & address : validators) { +// printf("%s\n", address.to_hex_string().c_str()); +// } +// printf("recents:\n"); +// for (auto const & recent : recents) { +// printf("%lu:%s\n", recent.first, recent.second.to_hex_string().c_str()); +// } +// printf("digest: %s\n", digest().hex().c_str()); +//} +// +//xvalidators_snap_info_t::xvalidators_snap_info_t(h256 const & snap_hash, h256 const & parent_hash, uint64_t const number) : snap_hash(snap_hash), parent_hash(parent_hash), number(number) { +//} +// +//xbytes_t xvalidators_snap_info_t::encode_rlp() const { +// xbytes_t out; +// { +// auto tmp = RLP::encode(snap_hash.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(parent_hash.asBytes()); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// { +// auto tmp = RLP::encode(static_cast(number)); +// out.insert(out.end(), tmp.begin(), tmp.end()); +// } +// return RLP::encodeList(out); +//} +// +//bool xvalidators_snap_info_t::decode_rlp(xbytes_t const & input) { +// auto l = RLP::decodeList(input); +// if (l.decoded.size() != 3) { +// return false; +// } +// if (!l.remainder.empty()) { +// return false; +// } +// snap_hash = xh256_t{xspan_t{l.decoded[0]}}; +// parent_hash = xh256_t{xspan_t{l.decoded[1]}}; +// number = static_cast(evm_common::fromBigEndian(l.decoded[2])); +// return true; +//} +// +//NS_END2 diff --git a/src/xtopcom/xevm_common/src/xvote.cpp b/src/xtopcom/xevm_common/src/xvote.cpp new file mode 100644 index 000000000..e4ea4dfa1 --- /dev/null +++ b/src/xtopcom/xevm_common/src/xvote.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "xevm_common/xcrosschain/xbsc/xvote.h" +#include "xcommon/rlp.h" +#include "xevm_common/xerror/xerror.h" +#include "xevm_common/xcommon.h" +#include "xutility/xhash.h" + +NS_BEG4(top, evm, crosschain, bsc) +xtop_vote_data::xtop_vote_data(std::uint64_t source_number, xh256_t const & source_hash, std::uint64_t target_number, xh256_t const & target_hash) + : source_number_{source_number}, source_hash_{source_hash}, target_number_{target_number}, target_hash_{target_hash} { +} + +auto xtop_vote_data::source_number() const noexcept -> std::uint64_t { + return source_number_; +} + +auto xtop_vote_data::source_hash() const noexcept -> xh256_t const & { + return source_hash_; +} + +auto xtop_vote_data::target_number() const noexcept -> std::uint64_t { + return target_number_; +} + +auto xtop_vote_data::target_hash() const noexcept -> xh256_t const& { + return target_hash_; +} + +auto xtop_vote_data::encode_rlp() const -> xbytes_t { + xbytes_t out; + + auto bytes = evm_common::RLP::encode(source_number()); + out.insert(out.end(), bytes.begin(), bytes.end()); + + bytes = evm_common::RLP::encode(source_hash()); + out.insert(out.end(), bytes.begin(), bytes.end()); + + bytes = evm_common::RLP::encode(target_number()); + out.insert(out.end(), bytes.begin(), bytes.end()); + + bytes = evm_common::RLP::encode(target_hash()); + out.insert(out.end(), bytes.begin(), bytes.end()); + + out = evm_common::RLP::encodeList(out); + return out; +} + + + +auto xtop_vote_data::hash() const -> xh256_t { + xbytes_t const & value = encode_rlp(); + auto const hash_value = utl::xkeccak256_t::digest(value.data(), value.size()); + return xh256_t{hash_value.data(), xh256_t::ConstructFromPointer}; +} + +auto xtop_vote_attestation::decode_rlp(xbytes_t const & bytes, std::error_code & ec) -> void { + assert(!ec); + + auto const & l = evm_common::RLP::decode_list(bytes, ec); + if (ec) { + xwarn("%s, decode_rlp failed, ec: {}", __func__, ec.message().c_str()); + return; + } + + if (l.decoded.size() != 4) { + ec = evm_common::error::xerrc_t::rlp_list_size_not_match; + xwarn("%s, decode_rlp failed, expected 4 fields in xvote_attestation, got %zu", __func__, l.decoded.size()); + return; + } + + vote_address_set = evm_common::fromBigEndian(l.decoded[0]); + + if (l.decoded[1].size() != common::BLS_SIGNATURE_LEN) { + ec = evm_common::error::xerrc_t::rlp_bytes_invalid; + xwarn("%s, decode_rlp failed, invalid BLS signature length: %sz", __func__, l.decoded[1].size()); + return; + } +} + + +NS_END4 diff --git a/src/xtopcom/xevm_common/xabi_decoder.h b/src/xtopcom/xevm_common/xabi_decoder.h index 013239e68..c1a6383f4 100644 --- a/src/xtopcom/xevm_common/xabi_decoder.h +++ b/src/xtopcom/xevm_common/xabi_decoder.h @@ -10,8 +10,10 @@ #include "xcommon/xeth_address.h" #include "xcommon/common.h" #include "xcommon/common_data.h" +#include "xcrosschain/xeth_header.h" #include "xevm_common/xerror/xerror.h" + #include #include #include diff --git a/src/xtopcom/xevm_common/xcommon.h b/src/xtopcom/xevm_common/xcommon.h new file mode 100644 index 000000000..ddfa86103 --- /dev/null +++ b/src/xtopcom/xevm_common/xcommon.h @@ -0,0 +1,20 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "xbasic/xfixed_bytes.h" + +#include + +NS_BEG3(top, evm, common) + +XINLINE_CONSTEXPR size_t BLS_PUBLIC_KEY_LEN{48}; +XINLINE_CONSTEXPR size_t BLS_SIGNATURE_LEN{96}; + +using xbls_publick_key_t = xfixed_bytes_t; +using xbls_signature_t = xfixed_bytes_t; + + +NS_END3 diff --git a/src/xtopcom/xevm_common/xcrosschain/xbsc/xconfig.h b/src/xtopcom/xevm_common/xcrosschain/xbsc/xconfig.h new file mode 100644 index 000000000..ab958eca6 --- /dev/null +++ b/src/xtopcom/xevm_common/xcrosschain/xbsc/xconfig.h @@ -0,0 +1,90 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "xbasic/xfixed_hash.h" +#include "xcommon/xcommon.h" +#include "xevm_common/xcommon.h" + +#include +#include + +NS_BEG4(top, evm, crosschain, bsc) + +XINLINE_CONSTEXPR uint64_t BLOB_TX_MAX_BLOB_GAS_PER_BLOCK{1 << 19}; +XINLINE_CONSTEXPR uint64_t BLOB_TX_TARGET_BLOB_GAS_PER_BLOCK{1 << 18}; +XINLINE_CONSTEXPR uint64_t BLOB_TX_BLOB_GAS_PER_BLOB{1 << 17}; + +constexpr auto is_forked(uint64_t const s, uint64_t const head) noexcept -> bool { + return (std::numeric_limits::max() != s) && (std::numeric_limits::max() != head) && (s <= head); +} + +struct xtop_parlia_config { + uint64_t period; + uint64_t epoch; +}; +using xparlia_config_t = xtop_parlia_config; + +struct xtop_chain_config { + uint64_t chain_id; + + uint64_t homestead_block; + + uint64_t dao_fork_block; + bool dao_fork_support; + + uint64_t eip150_block; + xh256_t eip150_hash; + + uint64_t eip155_block; + uint64_t eip158_block; + + uint64_t byzantium_block; + uint64_t constantinople_block; + uint64_t petersburg_block; + uint64_t istanbul_block; + uint64_t muir_glacier_block; + uint64_t berlin_block; + uint64_t yolo_v3_block; + uint64_t catalyst_block; + uint64_t london_block; + uint64_t arrow_glacier_block; + uint64_t merge_fork_block; + + uint64_t terminal_total_difficulty; + + uint64_t ramanujan_block; + uint64_t niels_block; + uint64_t mirror_sync_block; + uint64_t bruno_block; + uint64_t euler_block; + uint64_t nano_block; + uint64_t moran_block; + uint64_t gibbs_block; + uint64_t planck_block; + uint64_t luban_block; + uint64_t plato_block; + uint64_t hertz_block; + + xparlia_config_t parlia_config; + + auto is_london(uint64_t const number) const noexcept -> bool { + return /*is_forked(london_block, number);*/ true; + } + + auto is_luban(uint64_t const number) const noexcept -> bool { + return /*is_forked(luban_block, number);*/ true; + } +}; +using xchain_config_t = xtop_chain_config; + +extern xchain_config_t const bsc_chain_config; + +XINLINE_CONSTEXPR size_t EXTRA_VANITY{32}; +XINLINE_CONSTEXPR size_t EXTRA_SEAL{65}; +XINLINE_CONSTEXPR size_t VALIDATOR_BYTES_LENGTH{ETH_ADDRESS_LENGTH + evm::common::BLS_PUBLIC_KEY_LEN}; +XINLINE_CONSTEXPR size_t VALIDATOR_NUMBER_SIZE{1}; + +NS_END4 diff --git a/src/xtopcom/xevm_common/xcrosschain/xbsc/xsnapshot.h b/src/xtopcom/xevm_common/xcrosschain/xbsc/xsnapshot.h new file mode 100644 index 000000000..75843f3a1 --- /dev/null +++ b/src/xtopcom/xevm_common/xcrosschain/xbsc/xsnapshot.h @@ -0,0 +1,54 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "xevm_common/xcrosschain/xeth_header.h" +#include "xevm_common/xcommon.h" +#include "xevm_common/xcrosschain/xbsc/xvote.h" + +#include + +NS_BEG4(top, evm, crosschain, bsc) + +struct xtop_validator_info { + int32_t index{0}; // the index should offset by 1. + common::xbls_publick_key_t vote_address; +}; +using xvalidator_info_t = xtop_validator_info; + +class xtop_snapshot { +private: + uint64_t number_{0}; // block number where the snapshot was created. + xh256_t hash_{}; // block hash where the snapshot was created. + std::map validators_{}; // set of authorized validators at this moment. + std::set last_validators_{}; + std::map recents_{}; // set of recent validators for spam protection. + std::map recent_fork_hashes_{}; // set of recent fork hashes. + xvote_data_t attestation_{}; // attestation for fast finality, but `Source` used as `Finalized`. + +public: + static auto new_snapshot(uint64_t number, + xh256_t const & hash, + std::vector const & validators, + std::vector const & vote_addresses, + std::error_code & ec) -> xtop_snapshot; + + auto number() const noexcept -> uint64_t; + auto hash() const noexcept -> xh256_t const &; + auto validators() const noexcept -> std::map const &; + auto validators() noexcept -> std::map &; + auto recents() const noexcept -> std::map const &; + auto recents() noexcept -> std::map &; + auto recent_fork_hashes() const noexcept -> std::map const &; + auto recent_fork_hashes() noexcept -> std::map &; + auto attestation() const noexcept -> xvote_data_t const &; + auto empty() const noexcept -> bool; + + auto encode(std::error_code & ec) const -> xbytes_t; + void decode(xbytes_t const & bytes, std::error_code & ec); +}; +using xsnapshot_t = xtop_snapshot; + +NS_END4 diff --git a/src/xtopcom/xevm_common/xcrosschain/xbsc/xutility.h b/src/xtopcom/xevm_common/xcrosschain/xbsc/xutility.h new file mode 100644 index 000000000..1692c02de --- /dev/null +++ b/src/xtopcom/xevm_common/xcrosschain/xbsc/xutility.h @@ -0,0 +1,27 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "xbasic/xbytes.h" +#include "xevm_common/xcrosschain/xeth_header.h" +#include "xevm_common/xcrosschain/xbsc/xconfig.h" +#include "xevm_common/xcrosschain/xbsc/xvote.h" + +#include + +NS_BEG4(top, evm, crosschain, bsc) + +auto get_validator_bytes_from_header(evm_common::xeth_header_t const & header, + xchain_config_t const & chain_config, + xparlia_config_t const & parlia_config) -> xbytes_t; + +auto get_vote_attestation_from_header(evm_common::xeth_header_t const & header, + xchain_config_t const & chain_config, + xparlia_config_t const & parlia_config, + std::error_code & ec) -> xvote_attestation_t; + +//auto verify_vote_attestation() + +NS_END4 diff --git a/src/xtopcom/xevm_common/xcrosschain/xbsc/xvote.h b/src/xtopcom/xevm_common/xcrosschain/xbsc/xvote.h new file mode 100644 index 000000000..2246c57db --- /dev/null +++ b/src/xtopcom/xevm_common/xcrosschain/xbsc/xvote.h @@ -0,0 +1,52 @@ +// Copyright (c) 2023-present Telos Foundation & contributors +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include "xbasic/xbitset.h" +#include "xbasic/xbytes.h" +#include "xbasic/xfixed_hash.h" +#include "xbasic/xoptional.hpp" +#include "xevm_common/xcommon.h" + +#include + +NS_BEG4(top, evm, crosschain, bsc) + +constexpr size_t MAX_ATTESTATION_EXTRA_SIZE = 256; + +class xtop_vote_data { +private: + std::uint64_t source_number_{0}; + xh256_t source_hash_{}; + std::uint64_t target_number_{0}; + xh256_t target_hash_{}; + +public: + xtop_vote_data() = default; + xtop_vote_data(std::uint64_t source_number, xh256_t const & source_hash, std::uint64_t target_number, xh256_t const & target_hash); + + auto source_number() const noexcept -> std::uint64_t; + auto source_hash() const noexcept -> xh256_t const &; + auto target_number() const noexcept -> std::uint64_t; + auto target_hash() const noexcept -> xh256_t const &; + + auto encode_rlp() const -> xbytes_t; + auto decode_rlp(xbytes_t const & input, std::error_code & ec) -> void; + + auto hash() const -> xh256_t; +}; +using xvote_data_t = xtop_vote_data; + +struct xtop_vote_attestation { + uint64_t vote_address_set{}; + evm::common::xbls_signature_t aggregate_signature; + optional data; + xbytes_t extra; + + auto decode_rlp(xbytes_t const & bytes, std::error_code & ec) -> void; +}; +using xvote_attestation_t = xtop_vote_attestation; + +NS_END4 diff --git a/src/xtopcom/xevm_common/xcrosschain/xeth_header.h b/src/xtopcom/xevm_common/xcrosschain/xeth_header.h index a7c7e8235..9139a6868 100644 --- a/src/xtopcom/xevm_common/xcrosschain/xeth_header.h +++ b/src/xtopcom/xevm_common/xcrosschain/xeth_header.h @@ -39,6 +39,8 @@ struct xeth_header_t { // base_fee was added by EIP-1559 and is ignored in legacy headers. optional base_fee_per_gas; optional withdrawals_root; + optional blob_gas_used; + optional excess_blob_gas; mutable xh256_t hash; mutable xh256_t partial_hash; @@ -77,4 +79,6 @@ struct xeth_header_info_t { bigint number; }; +common::xeth_address_t ecrecover(xeth_header_t const & header, std::error_code & ec); + NS_END2 diff --git a/src/xtopcom/xevm_common/xerror/xerror.h b/src/xtopcom/xevm_common/xerror/xerror.h index 9bf0c31eb..1d6b73b8d 100644 --- a/src/xtopcom/xevm_common/xerror/xerror.h +++ b/src/xtopcom/xevm_common/xerror/xerror.h @@ -37,11 +37,14 @@ enum class xenum_errc { rlp_bytes_invalid, rlp_list_size_not_match, invalid_public_key_size, + invalid_bsc_epoch_data, + invalid_bsc_extra_data, + bsc_header_before_luban, + bsc_not_epoch_header }; using xerrc_t = xenum_errc; std::error_code make_error_code(xerrc_t errc) noexcept; -std::error_condition make_error_condition(xerrc_t errc) noexcept; std::error_category const & evm_common_category(); @@ -52,7 +55,4 @@ NS_BEG1(std) template <> struct is_error_code_enum : std::true_type {}; -template <> -struct is_error_condition_enum : std::true_type {}; - NS_END1 diff --git a/src/xtopcom/xevm_contract_runtime/src/xerror.cpp b/src/xtopcom/xevm_contract_runtime/src/xerror.cpp index 25ddb5f34..4cfdfadb6 100644 --- a/src/xtopcom/xevm_contract_runtime/src/xerror.cpp +++ b/src/xtopcom/xevm_contract_runtime/src/xerror.cpp @@ -19,6 +19,39 @@ static char const * const errc_to_string(int code) { case xerrc_t::precompiled_contract_erc20_burn: return "precompiled contract erc20 burn failed"; + case xenum_errc::bsc_unknown_ancestor: + return "bsc: unknown ancestor"; + + case xenum_errc::bsc_snapshot_not_found: + return "bsc: snapshot not found"; + + case xenum_errc::bsc_invalid_gas_limit: + return "bsc: invalid gas limit"; + + case xenum_errc::bsc_invalid_gas_used: + return "bsc: invalid gas used"; + + case xenum_errc::bsc_invalid_extra_data: + return "bsc: invalid extra data"; + + case xenum_errc::bsc_invalid_attestation: + return "bsc: invalid attestation"; + + case xenum_errc::bsc_header_missing_excess_blob_gas: + return "bsc: header is missing excessBlobGas"; + + case xenum_errc::bsc_header_missing_blob_gas_used: + return "bsc: header is missing blobGasUsed"; + + case xenum_errc::bsc_blob_gas_used_exceeds_maximum_allowance: + return "bsc: blob gas used exceeds maximum allowance"; + + case xenum_errc::bsc_blob_gas_used_not_a_multiple_of_blob_gas_per_blob: + return "bsc: blob gas used is not a multiple of blob gas per blob"; + + case xenum_errc::bsc_invalid_excess_blob_gas: + return "bsc: invalid excess blob gas"; + default: return "unknown contract vm error"; } diff --git a/src/xtopcom/xevm_contract_runtime/src/xevm_bsc_client_contract.cpp b/src/xtopcom/xevm_contract_runtime/src/xevm_bsc_client_contract.cpp index a0a6491e7..d73da245d 100644 --- a/src/xtopcom/xevm_contract_runtime/src/xevm_bsc_client_contract.cpp +++ b/src/xtopcom/xevm_contract_runtime/src/xevm_bsc_client_contract.cpp @@ -5,13 +5,15 @@ #include "xevm_contract_runtime/sys_contract/xevm_bsc_client_contract.h" #include "xbasic/endianness.h" +#include "xcommon/common_data.h" #include "xcommon/xaccount_address.h" #include "xcommon/xeth_address.h" #include "xdata/xdata_common.h" #include "xdata/xsystem_contract/xdata_structures.h" -#include "xcommon/common_data.h" #include "xevm_common/xabi_decoder.h" +#include "xevm_common/xcrosschain/xbsc/xutility.h" #include "xevm_common/xcrosschain/xeth_header.h" +#include "xevm_contract_runtime/xerror/xerror.h" #if defined(XCXX20) #include @@ -22,20 +24,20 @@ using namespace top::evm_common; +using namespace top::evm::crosschain::bsc; + NS_BEG4(top, contract_runtime, evm, sys_contract) constexpr uint64_t confirm_num = 15; -constexpr uint64_t validator_num = 21; +constexpr uint64_t VALIDATOR_NUM = 21; constexpr uint64_t hash_reserve_num = 40000; constexpr uint64_t block_reserve_num = 500; constexpr uint64_t epoch = 200; -constexpr uint64_t extra_vanity = 32; -constexpr uint64_t extra_seal = 64 + 1; constexpr uint64_t address_length = 20; constexpr uint64_t max_gas_limit = 0x7fffffffffffffff; -constexpr uint64_t min_gas_limit = 5000; -constexpr uint64_t gas_limit_bound_divisor = 256; +constexpr uint64_t MIN_GAS_LIMIT = 5000; +constexpr uint64_t GAS_LIMIT_BOUND_DIVISOR = 256; constexpr uint64_t bsc_chainid = 56; auto static empty_unclehash = static_cast(from_hex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")); @@ -61,55 +63,59 @@ bool xtop_evm_bsc_client_contract::init(xbytes_t const & rlp_bytes, state_ptr st } headers.emplace_back(header); } - // min 12 + 1 to construnct state - if (headers.size() < (validator_num / 2 + 1) + 1 + 1) { + + // two epoch headers + VALIDATOR_NUM / 2 headers + if (headers.size() < (VALIDATOR_NUM / 2 + 1) + 1) { xwarn("[xtop_evm_bsc_client_contract::init] not enough headers"); return false; } - xvalidators_snapshot_t snap; - if (!snap.init_with_double_epoch(headers[0], headers[1])) { - xwarn("[xtop_evm_bsc_client_contract::init] new_epoch_snapshot error"); - return false; - } - for (size_t i = 0; i < headers.size(); ++i) { - if (i == 0) { - continue; - } - auto const & h = headers[i]; - if (i != 1) { - if (!snap.apply_with_chainid(h, bsc_chainid, false)) { - xwarn("[xtop_evm_bsc_client_contract::init] apply_with_chainid failed"); - return false; - } - } - auto snap_hash = snap.digest(); - auto header_hash = h.calc_hash(); - // step 3: store with no check - xinfo("[xtop_evm_bsc_client_contract::init] header dump: %s, snap_hash: %s", h.dump().c_str(), snap_hash.hex().c_str()); - if (!set_last_hash(header_hash, state)) { - xwarn("[xtop_evm_bsc_client_contract::init] set_last_hash failed, hash: %s", header_hash.hex().c_str()); - return false; - } - if (!set_effective_hash(h.number, header_hash, state)) { - xwarn("[xtop_evm_bsc_client_contract::init] set_effective_hash failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); - return false; - } - if (!set_hashes(h.number, {header_hash}, state)) { - xwarn("[xtop_evm_bsc_client_contract::init] set_hash failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); - return false; - } - if (!set_header(header_hash, h, state)) { - xwarn("[xtop_evm_bsc_client_contract::init] set_header failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); - return false; - } - xvalidators_snap_info_t snap_info{snap_hash, h.parent_hash, h.number}; - if (!set_snap_info(header_hash, snap_info, state)) { - xwarn("[xtop_evm_bsc_client_contract::init] set_snap_info failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); - return false; - } - } + //xsnapshot_t last_snapshot = xsnapshot_t::new_snapshot(headers[0].number, headers[0].hash); + + //xvalidators_snapshot_t snap; + //if (!snap.init_with_double_epoch(headers[0], headers[1])) { + // xwarn("[xtop_evm_bsc_client_contract::init] new_epoch_snapshot error"); + // return false; + //} + + //for (size_t i = 0; i < headers.size(); ++i) { + // if (i == 0) { + // continue; + // } + // auto const & h = headers[i]; + // if (i != 1) { + // if (!snap.apply_with_chainid(h, bsc_chainid, false)) { + // xwarn("[xtop_evm_bsc_client_contract::init] apply_with_chainid failed"); + // return false; + // } + // } + // auto snap_hash = snap.digest(); + // auto header_hash = h.calc_hash(); + // // step 3: store with no check + // xinfo("[xtop_evm_bsc_client_contract::init] header dump: %s, snap_hash: %s", h.dump().c_str(), snap_hash.hex().c_str()); + // if (!set_last_hash(header_hash, state)) { + // xwarn("[xtop_evm_bsc_client_contract::init] set_last_hash failed, hash: %s", header_hash.hex().c_str()); + // return false; + // } + // if (!set_effective_hash(h.number, header_hash, state)) { + // xwarn("[xtop_evm_bsc_client_contract::init] set_effective_hash failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); + // return false; + // } + // if (!set_hashes(h.number, {header_hash}, state)) { + // xwarn("[xtop_evm_bsc_client_contract::init] set_hash failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); + // return false; + // } + // if (!set_header(header_hash, h, state)) { + // xwarn("[xtop_evm_bsc_client_contract::init] set_header failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); + // return false; + // } + // xvalidators_snap_info_t snap_info{snap_hash, h.parent_hash, h.number}; + // if (!set_snap_info(header_hash, snap_info, state)) { + // xwarn("[xtop_evm_bsc_client_contract::init] set_snap_info failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); + // return false; + // } + //} xinfo("[xtop_evm_bsc_client_contract::init] init success"); return true; @@ -146,33 +152,33 @@ bool xtop_evm_bsc_client_contract::sync(xbytes_t const & rlp_bytes, state_ptr st xinfo("[xtop_evm_bsc_client_contract::sync] header dump: %s", header.dump().c_str()); xvalidators_snapshot_t snap; - uint32_t const validator_num_index = 1; + constexpr uint32_t validator_num_index = 1; snap.number = header.number - 1; snap.hash = header.parent_hash; - auto validator_num = evm_common::fromBigEndian(item.decoded[validator_num_index]); + auto const validators_num = evm_common::fromBigEndian(item.decoded[validator_num_index]); // check decoded_size with recent_num - if (decoded_size < validator_num + validator_num_index + 1 + 1) { + if (decoded_size < validators_num + validator_num_index + 1 + 1) { xwarn("[xtop_evm_bsc_client_contract::sync] sync param error"); return false; } - uint32_t const validators_index = validator_num_index + 1; - for (uint64_t i = 0; i < validator_num; ++i) { + constexpr uint32_t validators_index = validator_num_index + 1; + for (uint64_t i = 0; i < validators_num; ++i) { snap.validators.insert(common::xeth_address_t::build_from(item.decoded[i + validators_index])); } - uint32_t const last_validator_num_index = validator_num + validator_num_index + 1; - auto last_validator_num = evm_common::fromBigEndian(item.decoded[last_validator_num_index]); + uint64_t const last_validator_num_index = validators_num + validator_num_index + 1; + auto const last_validator_num = evm_common::fromBigEndian(item.decoded[last_validator_num_index]); if (decoded_size < last_validator_num_index + 1 + last_validator_num) { xwarn("[xtop_evm_bsc_client_contract::sync] sync param error"); return false; } - uint32_t const last_validators_index = last_validator_num_index + 1; + uint64_t const last_validators_index = last_validator_num_index + 1; for (uint64_t i = 0; i < last_validator_num; ++i) { snap.last_validators.insert(common::xeth_address_t::build_from(item.decoded[i + last_validators_index])); } - uint32_t const recent_num_index = last_validator_num + last_validator_num_index + 1; - auto recent_num = evm_common::fromBigEndian(item.decoded[recent_num_index]); + uint64_t const recent_num_index = last_validator_num + last_validator_num_index + 1; + auto const recent_num = evm_common::fromBigEndian(item.decoded[recent_num_index]); if (decoded_size < recent_num_index + 1 + recent_num) { xwarn("[xtop_evm_bsc_client_contract::sync] sync param error"); return false; @@ -278,119 +284,163 @@ bool xtop_evm_bsc_client_contract::is_confirmed(u256 const height, xbytes_t cons } bool xtop_evm_bsc_client_contract::verify(xeth_header_t const & prev_header, xeth_header_t const & new_header, xvalidators_snapshot_t & snap, state_ptr state) const { - if (new_header.extra.size() < extra_vanity) { - xwarn("[xtop_evm_bsc_client_contract::verify] header extra size error: %lu, should < %lu", new_header.extra.size(), extra_vanity); + if (new_header.extra.size() < EXTRA_VANITY) { + xwarn("xtop_evm_bsc_client_contract::verify: header extra missing EXTRA_VANITY. extra size %" PRIu64, new_header.extra.size()); return false; } - if (new_header.extra.size() < extra_vanity + extra_seal) { - xwarn("[xtop_evm_bsc_client_contract::verify] header extra miss signature: %lu, should < %lu", new_header.extra.size(), extra_vanity + extra_seal); + + if (new_header.extra.size() < EXTRA_VANITY + EXTRA_SEAL) { + xwarn("xtop_evm_bsc_client_contract::verify: header extra missing signature. extra size %" PRIu64, new_header.extra.size()); return false; } - bool is_epoch = (new_header.number % epoch == 0); - uint64_t validators_bytes = new_header.extra.size() - extra_vanity - extra_seal; - if (!is_epoch && validators_bytes != 0) { - xwarn("[xtop_evm_bsc_client_contract::verify] not epoch but has validators_bytes"); + + std::error_code ec; + + bool const is_epoch = new_header.number % epoch == 0; + auto const signers_bytes = + get_validator_bytes_from_header(new_header, bsc_chain_config, bsc_chain_config.parlia_config); + if (ec) { + xwarn("xtop_evm_bsc_client_contract::verify: get_validator_bytes_from_header failed, msg: %s", ec.message().c_str()); return false; } - if (is_epoch && validators_bytes % address_length != 0) { - xwarn("[xtop_evm_bsc_client_contract::verify] validators_bytes length error: %lu", validators_bytes); + + // Ensure that the extra-data contains a signer list on checkpoint, but none otherwise + if (!is_epoch && !signers_bytes.empty()) { + xwarn("xtop_evm_bsc_client_contract::verify: extra validators"); return false; } + + if (is_epoch && signers_bytes.empty()) { + xwarn("xtop_evm_bsc_client_contract::verify: invalid span validators"); + return false; + } + + // Ensure that the mix digest is zero as we don't have fork protection currently if (new_header.mix_digest != h256(0)) { - xwarn("[xtop_evm_bsc_client_contract::verify] mix_digest not 0: %lu", new_header.mix_digest.hex().c_str()); + xwarn("xtop_evm_bsc_client_contract::verify: invalid mix digest. %s", new_header.mix_digest.hex().c_str()); return false; } + + // Ensure that the block doesn't contain any uncles which are meaningless in PoA if (new_header.uncle_hash != empty_unclehash) { - xwarn("[xtop_evm_bsc_client_contract::verify] uncle_hash mismatch: %s, should be: %s", new_header.uncle_hash.hex().c_str(), empty_unclehash.hex().c_str()); + xwarn("xtop_evm_bsc_client_contract::verify: invalid uncle hash. %s, should be: %s", new_header.uncle_hash.hex().c_str(), empty_unclehash.hex().c_str()); + return false; + } + + if (new_header.number > 0) { + if (new_header.difficulty == 0) { + xwarn("xtop_evm_bsc_client_contract::verify: invalid difficulty. block number %" PRIu64, new_header.number); + return false; + } + } + + if (!verify_fork_hashes(top::evm::crosschain::bsc::bsc_chain_config, new_header, false)) { + xwarn("xtop_evm_bsc_client_contract::verify: verify_fork_hashes failed"); + return false; + } + + if (prev_header.number + 1 != new_header.number || prev_header.hash != new_header.parent_hash) { + xwarn("xtop_evm_bsc_client_contract::verify: unknown ancestor. parent hash and number from current header: %s:%" PRIu64 ", specified parent hash and number: %s:" PRIu64, new_header.parent_hash.hex().c_str(), new_header.number - 1, prev_header.hash.hex().c_str(), prev_header.number); + return false; + } + + if (!top::evm::crosschain::bsc::bsc_chain_config.is_london(new_header.number)) { + xwarn("xtop_evm_bsc_client_contract::verify: not london fork"); + return false; + } + + if (!verify_eip1559_header(top::evm::crosschain::bsc::bsc_chain_config, prev_header, new_header)) { + xwarn("xtop_evm_bsc_client_contract::verify: verify_eip1559_header failed"); return false; } + if (new_header.gas_limit > max_gas_limit) { - xwarn("[xtop_evm_bsc_client_contract::verify] gaslimit too big: %s > %lu", new_header.gas_limit.str().c_str(), max_gas_limit); + xwarn("xtop_evm_bsc_client_contract::verify: gaslimit too big: %s > %lu", new_header.gas_limit.str().c_str(), max_gas_limit); return false; } if (new_header.gas_used > new_header.gas_limit) { - xwarn("[xtop_evm_bsc_client_contract::verify] gasUsed: %s > gasLimit: %s", new_header.gas_used.str().c_str(), new_header.gas_limit.str().c_str()); + xwarn("xtop_evm_bsc_client_contract::verify: gasUsed: %s > gasLimit: %s", new_header.gas_used.str().c_str(), new_header.gas_limit.str().c_str()); return false; } auto diff = prev_header.gas_limit - new_header.gas_limit; if (diff < 0) { diff *= -1; } - auto const limit = prev_header.gas_limit / gas_limit_bound_divisor; - if (diff >= limit || new_header.gas_limit < min_gas_limit) { - xwarn("[xtop_evm_bsc_client_contract::verify] invalid gas limit: have %s, want %s + %s", + auto const limit = prev_header.gas_limit / GAS_LIMIT_BOUND_DIVISOR; + if (diff >= limit || new_header.gas_limit < MIN_GAS_LIMIT) { + xwarn("xtop_evm_bsc_client_contract::verify: invalid gas limit: have %s, want %s + %s", new_header.gas_limit.str().c_str(), prev_header.gas_limit.str().c_str(), diff.str().c_str()); return false; } if (new_header.number != prev_header.number + 1) { - xwarn("[xtop_evm_bsc_client_contract::verify] height mismatch, new: %" PRIu64 ", old: %" PRIu64, new_header.number, prev_header.number); + xwarn("xtop_evm_bsc_client_contract::verify: height mismatch, new: %" PRIu64 ", old: %" PRIu64, new_header.number, prev_header.number); return false; } - h256 last_hash = get_last_hash(state); + h256 const last_hash = get_last_hash(state); xvalidators_snap_info_t last_info; if (!get_snap_info(last_hash, last_info, state)) { - xwarn("[xtop_evm_bsc_client_contract::verify] get_header_info failed, hash: %s", last_hash.hex().c_str()); - return false; - } - auto snap_hash = snap.digest(); - if (last_info.snap_hash != snap_hash) { - xwarn("[xtop_evm_bsc_client_contract::verify] snap hash mismatch: %s", last_info.snap_hash.hex().c_str(), snap_hash.hex().c_str()); - return false; - } - if (!snap.apply_with_chainid(new_header, bsc_chainid, true)) { - xwarn("[xtop_evm_bsc_client_contract::verify] snap apply_with_chainid failed"); + xwarn("xtop_evm_bsc_client_contract::verify: get_header_info failed, hash: %s", last_hash.hex().c_str()); return false; } + //auto const snap_hash = snap.digest(); + //if (last_info.snap_hash != snap_hash) { + // xwarn("xtop_evm_bsc_client_contract::verify: snap hash mismatch: %s", last_info.snap_hash.hex().c_str(), snap_hash.hex().c_str()); + // return false; + //} + //if (!snap.apply_with_chainid(new_header, bsc_chainid, true)) { + // xwarn("xtop_evm_bsc_client_contract::verify: snap apply_with_chainid failed"); + // return false; + //} return true; } bool xtop_evm_bsc_client_contract::record(xeth_header_t const & header, xvalidators_snapshot_t const & snap, state_ptr state) { - h256 header_hash = header.calc_hash(); - h256 last_hash = get_last_hash(state); - xvalidators_snap_info_t last_info; - if (!get_snap_info(last_hash, last_info, state)) { - xwarn("[xtop_evm_bsc_client_contract::record] get_header_info failed, hash: %s", last_hash.hex().c_str()); - return false; - } - if (header.number + block_reserve_num < last_info.number) { - xwarn("[xtop_evm_bsc_client_contract::record] header is too old height: %" PRIu64 ", hash: %s, now height: %s", - header.number, - header_hash.hex().c_str(), - last_info.number.str().c_str()); - return false; - } - xvalidators_snap_info_t parent_info; - if (!get_snap_info(header.parent_hash, parent_info, state)) { - xwarn("[xtop_evm_bsc_client_contract::record] get parent header_info failed, hash: %s", header.parent_hash.hex().c_str()); - return false; - } - auto all_hashes = get_hashes(header.number, state); - if (all_hashes.count(header_hash)) { - xwarn("[xtop_evm_bsc_client_contract::record] header existed, hash: %s", header_hash.hex().c_str()); - return false; - } - all_hashes.insert(header_hash); - if (!set_hashes(header.number, all_hashes, state)) { - xwarn("[xtop_evm_bsc_client_contract::record] set hashes failed, height: %" PRIu64, header.number); - return false; - } - if (!set_header(header_hash, header, state)) { - xwarn("[xtop_evm_bsc_client_contract::record] set header failed, hash: %s", header_hash.hex().c_str()); - return false; - } - xvalidators_snap_info_t info{snap.digest(), header.parent_hash, header.number}; - if (!set_snap_info(header.calc_hash(), info, state)) { - xwarn("[xtop_evm_bsc_client_contract::record] set_header_info failed, height: %" PRIu64 ", hash: %s", header.number, header.calc_hash().hex().c_str()); - return false; - } - if (!rebuild(header, last_info, info, state)) { - xwarn("[xtop_evm_bsc_client_contract::record] rebuild failed"); - return false; - } - release(header.number, state); + //h256 header_hash = header.calc_hash(); + //h256 last_hash = get_last_hash(state); + //xvalidators_snap_info_t last_info; + //if (!get_snap_info(last_hash, last_info, state)) { + // xwarn("[xtop_evm_bsc_client_contract::record] get_header_info failed, hash: %s", last_hash.hex().c_str()); + // return false; + //} + //if (header.number + block_reserve_num < last_info.number) { + // xwarn("[xtop_evm_bsc_client_contract::record] header is too old height: %" PRIu64 ", hash: %s, now height: %s", + // header.number, + // header_hash.hex().c_str(), + // last_info.number.str().c_str()); + // return false; + //} + //xvalidators_snap_info_t parent_info; + //if (!get_snap_info(header.parent_hash, parent_info, state)) { + // xwarn("[xtop_evm_bsc_client_contract::record] get parent header_info failed, hash: %s", header.parent_hash.hex().c_str()); + // return false; + //} + //auto all_hashes = get_hashes(header.number, state); + //if (all_hashes.count(header_hash)) { + // xwarn("[xtop_evm_bsc_client_contract::record] header existed, hash: %s", header_hash.hex().c_str()); + // return false; + //} + //all_hashes.insert(header_hash); + //if (!set_hashes(header.number, all_hashes, state)) { + // xwarn("[xtop_evm_bsc_client_contract::record] set hashes failed, height: %" PRIu64, header.number); + // return false; + //} + //if (!set_header(header_hash, header, state)) { + // xwarn("[xtop_evm_bsc_client_contract::record] set header failed, hash: %s", header_hash.hex().c_str()); + // return false; + //} + //xvalidators_snap_info_t info{snap.digest(), header.parent_hash, header.number}; + //if (!set_snap_info(header.calc_hash(), info, state)) { + // xwarn("[xtop_evm_bsc_client_contract::record] set_header_info failed, height: %" PRIu64 ", hash: %s", header.number, header.calc_hash().hex().c_str()); + // return false; + //} + //if (!rebuild(header, last_info, info, state)) { + // xwarn("[xtop_evm_bsc_client_contract::record] rebuild failed"); + // return false; + //} + //release(header.number, state); return true; } @@ -504,25 +554,25 @@ bool xtop_evm_bsc_client_contract::remove_header(h256 const hash, state_ptr stat } bool xtop_evm_bsc_client_contract::get_snap_info(h256 const hash, xvalidators_snap_info_t & header_info, state_ptr state) const { - auto k = hash.asBytes(); - auto info_str = state->map_get(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()}); - if (info_str.empty()) { - xwarn("[xtop_evm_bsc_client_contract::get_snap_info] get_header not exist, hash: %s", hash.hex().c_str()); - return false; - } - if (header_info.decode_rlp({std::begin(info_str), std::end(info_str)}) == false) { - xwarn("[xtop_evm_bsc_client_contract::get_snap_info] decode_header failed, hash: %s", hash.hex().c_str()); - return false; - } + //auto k = hash.asBytes(); + //auto info_str = state->map_get(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()}); + //if (info_str.empty()) { + // xwarn("[xtop_evm_bsc_client_contract::get_snap_info] get_header not exist, hash: %s", hash.hex().c_str()); + // return false; + //} + //if (header_info.decode_rlp({std::begin(info_str), std::end(info_str)}) == false) { + // xwarn("[xtop_evm_bsc_client_contract::get_snap_info] decode_header failed, hash: %s", hash.hex().c_str()); + // return false; + //} return true; } bool xtop_evm_bsc_client_contract::set_snap_info(h256 const hash, xvalidators_snap_info_t const & snap_info, state_ptr state) { - auto k = hash.asBytes(); - auto v = snap_info.encode_rlp(); - if (0 != state->map_set(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()}, {v.begin(), v.end()})) { - return false; - } + //auto k = hash.asBytes(); + //auto v = snap_info.encode_rlp(); + //if (0 != state->map_set(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()}, {v.begin(), v.end()})) { + // return false; + //} return true; } @@ -595,20 +645,17 @@ bool xtop_evm_bsc_client_contract::remove_hashes(bigint const height, state_ptr return true; } -h256 xtop_evm_bsc_client_contract::get_last_hash(state_ptr state) const { +h256 xtop_evm_bsc_client_contract::get_last_hash(state_ptr const & state) const { auto hash_str = state->string_get(data::system_contract::XPROPERTY_LAST_HASH); if (hash_str.empty()) { - return h256(); + return h256{}; } - return static_cast(xbytes_t{std::begin(hash_str), std::end(hash_str)}); + return h256{xbytes_t{std::begin(hash_str), std::end(hash_str)}}; } -bool xtop_evm_bsc_client_contract::set_last_hash(h256 const hash, state_ptr state) { +bool xtop_evm_bsc_client_contract::set_last_hash(h256 const & hash, state_ptr const & state) { auto bytes = hash.asBytes(); - if (0 != state->string_set(data::system_contract::XPROPERTY_LAST_HASH, {bytes.begin(), bytes.end()})) { - return false; - } - return true; + return 0 == state->string_set(data::system_contract::XPROPERTY_LAST_HASH, {bytes.begin(), bytes.end()}); } int xtop_evm_bsc_client_contract::get_flag(state_ptr state) const { @@ -626,4 +673,520 @@ bool xtop_evm_bsc_client_contract::set_flag(state_ptr state) { return true; } +bool xtop_evm_bsc_client_contract::verify_fork_hashes(xchain_config_t const & chain_config, xeth_header_t const & header, bool const uncle) { + if (uncle) { + return true; + } + + if (chain_config.eip150_block > 0 && header.number == chain_config.eip150_block) { + if (chain_config.eip150_hash != xh256_t{0} && chain_config.eip150_hash != header.hash) { + return false; + } + } + + return true; +} + +bool xtop_evm_bsc_client_contract::verify_eip1559_header(xchain_config_t const & chain_config, + xeth_header_t const & parent, + xeth_header_t const & header) { + if (!header.base_fee_per_gas.has_value()) { + xwarn("xtop_evm_bsc_client_contract::verify_eip1559_header: header is missing baseFee"); + return false; + } + + uint64_t const expected_base_fee = calc_base_fee(chain_config, parent); + + if (header.base_fee_per_gas.value() != expected_base_fee) { + xwarn("xtop_evm_bsc_client_contract::verify_eip1559_header: base fee mismatch: %" PRIu64 ", %" PRIu64, header.base_fee_per_gas.value(), expected_base_fee); + return false; + } + + return true; +} + +void xtop_evm_bsc_client_contract::verify_eip4844_header(xeth_header_t const & parent, xeth_header_t const & header, std::error_code & ec) { + assert(!ec); + + if (!header.excess_blob_gas.has_value()) { + ec = top::evm_runtime::error::xerrc_t::bsc_header_missing_excess_blob_gas; + return; + } + + if (!header.blob_gas_used.has_value()) { + ec = top::evm_runtime::error::xerrc_t::bsc_header_missing_blob_gas_used; + return; + } + + if (header.blob_gas_used.value() > BLOB_TX_MAX_BLOB_GAS_PER_BLOCK) { + ec = top::evm_runtime::error::xerrc_t::bsc_blob_gas_used_exceeds_maximum_allowance; + return; + } + + if (header.blob_gas_used.value() % BLOB_TX_BLOB_GAS_PER_BLOB != 0) { + ec = top::evm_runtime::error::xerrc_t::bsc_blob_gas_used_not_a_multiple_of_blob_gas_per_blob; + return; + } + + uint64_t parent_excess_blob_gas = 0; + uint64_t parent_blob_gas_used = 0; + if (parent.excess_blob_gas.has_value()) { + parent_excess_blob_gas = parent.excess_blob_gas.value(); + parent_blob_gas_used = parent.blob_gas_used.value(); + } + + auto const excess_blob_gas = parent_excess_blob_gas + parent_blob_gas_used; + auto const expected_excess_blob_gas = excess_blob_gas < BLOB_TX_TARGET_BLOB_GAS_PER_BLOCK ? 0u : excess_blob_gas - BLOB_TX_TARGET_BLOB_GAS_PER_BLOCK; + if (header.excess_blob_gas.value() != expected_excess_blob_gas) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_excess_blob_gas; + } +} + +uint64_t xtop_evm_bsc_client_contract::calc_base_fee(xchain_config_t const &, xeth_header_t const &) { + return 0; +} + +// verifyCascadingFields verifies all the header fields that are not standalone, +// rather depend on a batch of previous headers. The caller may optionally pass +// in a batch of parents (ascending order) to avoid looking those up from the +// database. This is useful for concurrently verifying a batch of new headers. +bool xtop_evm_bsc_client_contract::verify_cascading_fields(xchain_config_t const & chain_config, + xeth_header_t const & header, + xspan_t parents, + state_ptr state, + std::error_code & ec) const { + assert(!ec); + + if (header.number == 0) { + return true; + } + + auto const & parent = get_parent(header, parents, state, ec); + if (ec) { + xerror("%s: get_parent failed, msg: %s", __func__, ec.message().c_str()); + return false; + } + + constexpr uint64_t capacity = 0x7fffffffffffffffull; + if (header.gas_limit > capacity) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_gas_limit; + xerror("xtop_evm_bsc_client_contract::verify_cascading_fields: invalid gas limit: have %" PRIu64 ", max %" PRIu64, header.gas_limit.convert_to(), capacity); + return false; + } + + if (header.gas_used > header.gas_limit) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_gas_used; + xwarn("xtop_evm_bsc_client_contract::verify_cascading_fields: invalid gas used: have %" PRIu64 ", gas limit %" PRIu64, header.gas_used.convert_to(), header.gas_limit.convert_to()); + return false; + } + + // Verify that the gas limit remains within allowed bounds + auto diff = parent.gas_limit - header.gas_limit; + if (diff < 0) { + diff *= -1; + } + auto const limit = parent.gas_limit / GAS_LIMIT_BOUND_DIVISOR; + + if (diff.convert_to() >= limit || header.gas_limit < MIN_GAS_LIMIT) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_gas_limit; + xwarn("xtop_evm_bsc_client_contract::verify_cascading_fields: invalid gas limit: have %" PRIu64 ", want %" PRIu64 " += %" PRIu64 "-1", + header.gas_limit.convert_to(), + parent.gas_limit.convert_to(), + limit.convert_to()); + return false; + } + + verify_vote_attestation(chain_config, header, parents, state, ec); + if (ec) { + xerror("%s: Verify vote attestation failed. ec: %s", __func__, ec.message().c_str()); + return false; + } + + // return verify_seal(); + return true; +} + +void xtop_evm_bsc_client_contract::verify_vote_attestation(xchain_config_t const & chain_config, + xeth_header_t const & header, + xspan_t parents, + state_ptr state, + std::error_code & ec) const { + assert(!ec); + auto const attestation = get_vote_attestation_from_header(header, chain_config, ec); + if (ec) { + xerror("%s: get_vote_attestation_from_header failed, msg: %s", __func__, ec.message().c_str()); + return; + } + + /* + * if (attestation.empty()) { + * return; + * } + */ + + if (!attestation.data.has_value()) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_attestation; + xerror("%s: invalid attestation, vote data is null", __func__); + return; + } + + if (attestation.extra.size() > MAX_ATTESTATION_EXTRA_SIZE) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_attestation; + xerror("%s: invalid attestation, too large extra length %" PRIu64, __func__, attestation.extra.size()); + return; + } + + xeth_header_t const & parent = get_parent(header, parents, state, ec); + if (ec) { + xerror("%s: get_parent failed, msg: %s", __func__, ec.message().c_str()); + return; + } + + auto const target_number = attestation.data.value().target_number(); + auto const target_hash = attestation.data.value().target_hash(); + if (target_number != parent.number || target_hash != parent.hash) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_attestation; + xerror("%s: invalid attestation, target mismatch, expected block: %" PRIu64 ", hash: %s; real block: %" PRIu64 ", hash: %s", + __func__, + parent.number, + parent.hash.hex().c_str(), + target_number, + target_hash.hex().c_str()); + return; + } + + auto const parent_attestation = get_vote_attestation_from_header(parent, chain_config, ec); + if (ec) { + xerror("%s: get_vote_attestation_from_header failed on parent header, msg: %s", __func__, ec.message().c_str()); + return; + } + auto const source_number = attestation.data.value().source_number(); + auto const source_hash = attestation.data.value().source_hash(); + uint64_t justified_block_number = parent_attestation.data.value().target_number(); + xh256_t justified_block_hash = parent_attestation.data.value().target_hash(); + + if (source_number != justified_block_number || source_hash != justified_block_hash) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_attestation; + xerror("%s: invalid attestation, source mismatch, expected block: %" PRIu64 ", hash: %s; real block: %" PRIu64 ", hash: %s", + justified_block_number, + justified_block_hash.hex().c_str(), + source_number, + source_hash.hex().c_str()); + return; + } + + if (!parents.empty()) { + parents = parents.first(parents.size() - 1); + } + + xsnapshot_t snapshot; // = snapshot(number, hash, parents); + if (ec) { + return; + } + + auto const validators = snapshot.validators(); + std::bitset const validators_bitset{attestation.vote_address_set}; + if (validators_bitset.count() > validators.size()) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_attestation; + xerror("%s: invalid attestation, vote number larger than validators number", __func__); + return; + } + + +} + +void xtop_evm_bsc_client_contract::get_justified_number_and_hash(xeth_header_t const & header, + state_ptr const & state, + uint64_t & justified_number, + xh256_t & justified_hash, + std::error_code & ec) const { + assert(!ec); + // auto snapshot = snapshot(); + xsnapshot_t snapshot; + + justified_number = snapshot.attestation().target_number(); + justified_hash = snapshot.attestation().target_hash(); +} + + +xvote_attestation_t xtop_evm_bsc_client_contract::get_vote_attestation_from_header(xeth_header_t const & header, xchain_config_t const & chain_config, std::error_code & ec) const { + assert(!ec); + + xvote_attestation_t attestation; + if (header.extra.size() <= EXTRA_VANITY + EXTRA_SEAL) { + return attestation; + } + + xbytes_t attestation_bytes; + if (header.number % epoch == 0) { + auto const begin = std::next(std::begin(header.extra), static_cast(EXTRA_VANITY)); + auto const end = std::next(std::end(header.extra), -static_cast(EXTRA_SEAL)); + + attestation_bytes = xbytes_t{begin, end}; + return attestation; + } + + int const num = static_cast(header.extra[EXTRA_VANITY]); + if (header.extra.size() <= EXTRA_VANITY + EXTRA_SEAL + VALIDATOR_NUMBER_SIZE + num * VALIDATOR_BYTES_LENGTH) { + return attestation; + } + + auto const begin = std::next(std::begin(header.extra), static_cast(EXTRA_VANITY + VALIDATOR_NUMBER_SIZE + num * VALIDATOR_BYTES_LENGTH)); + auto const end = std::next(std::end(header.extra), -static_cast(EXTRA_SEAL)); + + attestation_bytes = xbytes_t{begin, end}; + + attestation.decode_rlp(attestation_bytes, ec); + if (ec) { + ec = top::evm_runtime::error::xerrc_t::bsc_invalid_extra_data; + xerror("%s: decode_rlp failed, msg: %s", __func__, ec.message().c_str()); + return attestation; + } + + return attestation; +} + +bool xtop_evm_bsc_client_contract::verify_headers(std::vector const & headers, state_ptr state) const { + for (size_t i = 0; i < headers.size(); ++i) { + if (!verify_header(headers[i], xspan_t{headers.data(), i}, state)) { + return false; + } + } + + return true; +} + +bool xtop_evm_bsc_client_contract::verify_header(xeth_header_t const & header, xspan_t const parents, state_ptr state) const { + if (header.number == 0) { + xerror("%s: block number invalid.", __func__); + return false; + } + + if (header.extra.size() < EXTRA_VANITY) { + xerror("%s: header extra missing EXTRA_VANITY.", __func__); + return false; + } + + if (header.extra.size() < EXTRA_VANITY + EXTRA_SEAL) { + xerror("%s: header extra missing signature.", __func__); + return false; + } + + // check extra data + uint64_t const number = header.number; + bool const is_epoch = number % epoch == 0; + std::error_code ec; + + // Ensure that the extra-data contains a signer list on checkpoint, but none otherwise + auto const & signers_bytes = get_validator_bytes_from_header(header, bsc_chain_config, bsc_chain_config.parlia_config); + + if (!is_epoch && !signers_bytes.empty()) { + xerror("%s: extra validators.", __func__); + return false; + } + + if (is_epoch && signers_bytes.empty()) { + xerror("%s: invalid span validators.", __func__); + return false; + } + + // Ensure that the mix digest is zero as we don't have fork protection currently + if (header.mix_digest != xh256_t{}) { + xerror("%s: invalid mix digest.", __func__); + return false; + } + + // Ensure that the block doesn't contain any uncles which are meaningless in PoA + if (header.uncle_hash != empty_unclehash) { + xerror("%s: invalid uncle hash.", __func__); + return false; + } + + if (header.number > 0) { + if (header.difficulty == 0) { + xerror("%s: invalid difficulty.", __func__); + return false; + } + } + + auto const parent = get_parent(header, parents, state, ec); + if (ec) { + xerror("%s: get_parent failed, msg: %s", __func__, ec.message().c_str()); + return false; + } + + if (!verify_eip1559_header(bsc_chain_config, parent, header)) { + xerror("%s: verify_eip1559_header failed.", __func__); + return false; + } + + if (header.withdrawals_root.has_value()) { + xerror("%s: invalid withdrawals root: have %s, expected null", __func__, header.withdrawals_root.value().hex().c_str()); + return false; + } + + // Ethereum cancun fork + // https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/cancun.md + // https://forum.bnbchain.org/t/bnb-chain-upgrades-mainnet/936#future-4 + // Future + // StateExpiry + // Parallel EVM + // Dynamic GasFee + // Segmented Archive State Maintenance + // Safe Hard Fork With Transition Period ? + // Part of Cancun Upgrade: + // https://forum.bnbchain.org/t/bnb-chain-upgrades-mainnet/936#kepler-ideas-collecting-5 + + verify_eip4844_header(parent, header, ec); + if (ec) { + return false; + } + + return verify_cascading_fields(bsc_chain_config, header, parents, state, ec); +} + +xeth_header_t xtop_evm_bsc_client_contract::get_parent(xeth_header_t const & header, xspan_t parents, state_ptr state, std::error_code & ec) const { + xeth_header_t parent; + assert(!ec); + + if (!parents.empty()) { + parent = parents.back(); + } else { + if (!get_header(header.parent_hash, parent, state)) { + ec = evm_runtime::error::xerrc_t::bsc_unknown_ancestor; + } + } + + return parent; +} + +/// +/// snapshot retrieves the authorization snapshot at a given point in time. +/// !!! be careful +/// the block with `number` and `hash` is just the last element of `parents`, +/// unlike other interfaces such as verifyCascadingFields, `parents` are real parents +/// +/// extra notes: +/// 1. `number is the last element of `parents`' number +/// 2. `hash` is the last element of `parents`' hash +/// +/// snapshot at the number +/// snapshot at the hash +/// the parent headers when calling this API +/// world state object +/// error code +/// true for success, false for the other +xsnapshot_t xtop_evm_bsc_client_contract::snapshot(uint64_t number, xh256_t const & hash, xspan_t parents, state_ptr state, std::error_code & ec) const { + std::vector headers; + xsnapshot_t snap; + + while (snap.empty()) { + snap = get_recent_snapshot(hash, state, ec); + if (!ec) { + break; + } + + + } + + return snap; +} + +xsnapshot_t xtop_evm_bsc_client_contract::get_recent_snapshot(xh256_t const & snapshot_hash, state_ptr & state, std::error_code & ec) const { + assert(!ec); + { + auto const snapshot_it = recent_snapshots_.find(snapshot_hash); + if (snapshot_it != recent_snapshots_.end()) { + return top::get(*snapshot_it); + } + } + + xsnapshot_t snapshot; + std::string snapshot_bytes = state->map_get(data::system_contract::XPROPERTY_RECENT_SNAPSHOTS, {std::begin(snapshot_hash), std::end(snapshot_hash)}); + if (snapshot_bytes.empty()) { + ec = evm_runtime::error::xerrc_t::bsc_snapshot_not_found; + return snapshot; + } + + snapshot.decode({std::begin(snapshot_bytes), std::end(snapshot_bytes)}, ec); + if (ec) { + xerror("%s: decode snapshot failed, msg: %s", __func__, ec.message().c_str()); + return snapshot; + } + + recent_snapshots_.insert({snapshot_hash, snapshot}); + + return snapshot; +} + +void xtop_evm_bsc_client_contract::add_recent_snapshot(xsnapshot_t const & snapshot, state_ptr & state, std::error_code & ec) { + assert(!ec); + auto const & hash = snapshot.hash(); + + std::string const key{std::begin(hash), std::end(hash)}; + + auto const & bytes = snapshot.encode(ec); + if (ec) { + xerror("%s: encode snapshot failed, msg: %s", __func__, ec.message().c_str()); + return; + } + std::string const value{std::begin(bytes), std::end(bytes)}; + + state->map_set(data::system_contract::XPROPERTY_RECENT_SNAPSHOTS, key, value); + + recent_snapshots_.insert({hash, snapshot}); +} + +void xtop_evm_bsc_client_contract::del_recent_snapshot(xh256_t const & snapshot_hash, state_ptr & state, std::error_code & ec) { + assert(!ec); + std::string const key{std::begin(snapshot_hash), std::end(snapshot_hash)}; + state->map_remove(data::system_contract::XPROPERTY_RECENT_SNAPSHOTS, key); + + { + auto const snapshot_it = recent_snapshots_.find(snapshot_hash); + if (snapshot_it != recent_snapshots_.end()) { + recent_snapshots_.erase(snapshot_it); + } + } +} + + +xsnapshot_t xtop_evm_bsc_client_contract::last_validator_set(state_ptr & state, std::error_code & ec) const { + xsnapshot_t snapshot; + return snapshot; +} + +void xtop_evm_bsc_client_contract::last_validator_set(top::evm::crosschain::bsc::xsnapshot_t const & snapshot, state_ptr & state, std::error_code & ec) { + +} + +xsnapshot_t xtop_evm_bsc_client_contract::pre_last_validator_set(state_ptr & state, std::error_code & ec) const { + xsnapshot_t snapshot; + return snapshot; +} + +void xtop_evm_bsc_client_contract::pre_last_validator_set(top::evm::crosschain::bsc::xsnapshot_t const & snapshot, state_ptr & state, std::error_code & ec) { + assert(!ec); + + auto const & hash = snapshot.hash(); + std::string const key{std::begin(hash), std::end(hash)}; + + auto const & bytes = snapshot.encode(ec); + if (ec) { + xerror("%s: encode snapshot failed, msg: %s", __func__, ec.message().c_str()); + return; + } + std::string const value{std::begin(bytes), std::end(bytes)}; + + state->map_set(data::system_contract::XPROPERTY_PRE_LAST_VALIDATOR_SET, key, value); +} + +void xtop_evm_bsc_client_contract::verify_seal(xeth_header_t const & header, xspan_t parents, std::error_code & ec) const { + assert(!ec); + + //auto const number = header.number; + //xsnapshot_t snapshot; +} + + NS_END4 diff --git a/src/xtopcom/xevm_contract_runtime/src/xevm_contract_manager.cpp b/src/xtopcom/xevm_contract_runtime/src/xevm_contract_manager.cpp index ce34fe7a9..c64d28b37 100644 --- a/src/xtopcom/xevm_contract_runtime/src/xevm_contract_manager.cpp +++ b/src/xtopcom/xevm_contract_runtime/src/xevm_contract_manager.cpp @@ -14,7 +14,7 @@ #include "xevm_contract_runtime/sys_contract/xevm_bsc_client_contract.h" #include "xevm_contract_runtime/sys_contract/xevm_eth2_client_contract.h" #include "xevm_contract_runtime/sys_contract/xevm_eth_bridge_contract.h" -#include "xevm_contract_runtime/sys_contract/xevm_heco_client_contract.h" +// #include "xevm_contract_runtime/sys_contract/xevm_heco_client_contract.h" #if defined(XCXX20) #include "xevm_runner/proto/ubuntu/proto_precompile.pb.h" #else @@ -32,7 +32,7 @@ xtop_evm_contract_manager::xtop_evm_contract_manager() { add_sys_contract(evm_usdt_contract_address, top::make_unique()); add_sys_contract(evm_eth_bridge_contract_address, top::make_unique()); add_sys_contract(evm_bsc_client_contract_address, top::make_unique()); - add_sys_contract(evm_heco_client_contract_address, top::make_unique()); + // add_sys_contract(evm_heco_client_contract_address, top::make_unique()); #ifdef ETH2_SEPOLIA add_sys_contract(evm_eth2_client_contract_address, top::make_unique(contract_runtime::evm::sys_contract::xeth2_client_net_t::eth2_net_sepolia)); #else diff --git a/src/xtopcom/xevm_contract_runtime/src/xevm_heco_client_contract.cpp b/src/xtopcom/xevm_contract_runtime/src/xevm_heco_client_contract.cpp index 3800cbb9b..1ed63ca95 100644 --- a/src/xtopcom/xevm_contract_runtime/src/xevm_heco_client_contract.cpp +++ b/src/xtopcom/xevm_contract_runtime/src/xevm_heco_client_contract.cpp @@ -1,609 +1,609 @@ -// Copyright (c) 2017-present Telos Foundation & contributors -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "xevm_contract_runtime/sys_contract/xevm_heco_client_contract.h" - -#include "xbasic/endianness.h" -#include "xcommon/xaccount_address.h" -#include "xcommon/xeth_address.h" -#include "xdata/xdata_common.h" -#include "xdata/xsystem_contract/xdata_structures.h" -#include "xcommon/common_data.h" -#include "xevm_common/xabi_decoder.h" -#include "xevm_common/xcrosschain/xeth_header.h" -#include "xevm_common/xcrosschain/xheco_config.h" -#include "xevm_common/xcrosschain/xheco_eip1559.h" - -#if defined(XCXX20) -#include -#else -#include -#endif -#include - -using namespace top::evm_common; - -NS_BEG4(top, contract_runtime, evm, sys_contract) - -constexpr uint64_t confirm_num = 15; -constexpr uint64_t validator_num = 21; -constexpr uint64_t hash_reserve_num = 40000; -constexpr uint64_t block_reserve_num = 500; - -constexpr uint64_t epoch = 200; -constexpr uint64_t extra_vanity = 32; -constexpr uint64_t extra_seal = 64 + 1; -constexpr uint64_t address_length = 20; -constexpr uint64_t max_gas_limit = 0x7fffffffffffffff; - -auto static empty_unclehash = static_cast(from_hex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")); - -bool xtop_evm_heco_client_contract::init(xbytes_t const & rlp_bytes, state_ptr state) { - // step 1: check init - if (get_last_hash(state) != h256()) { - xwarn("[xtop_evm_heco_client_contract::init] init already"); - return false; - } - // step 2: decode - auto left_bytes = rlp_bytes; - std::vector headers; - std::error_code ec; - while (!left_bytes.empty()) { - auto item = RLP::decode_once(left_bytes); - left_bytes = item.remainder; - xeth_header_t header; - header.decode_rlp(item.decoded[0], ec); - if (ec) { - xwarn("xtop_evm_heco_client_contract::init, xeth_header_t::decode_rlp failed, msg %s", ec.message().c_str()); - return false; - } - headers.emplace_back(header); - } - // min 12 to construnct state - if (headers.size() < (validator_num / 2 + 1) + 1) { - xwarn("[xtop_evm_heco_client_contract::init] not enough headers"); - return false; - } - - xvalidators_snapshot_t snap; - if (!snap.init_with_epoch(headers[0])) { - xwarn("[xtop_evm_heco_client_contract::init] new_epoch_snapshot error"); - return false; - } - - for (size_t i = 0; i < headers.size(); ++i) { - auto const & h = headers[i]; - if (i != 0) { - if (!snap.apply(h, false)) { - xwarn("[xtop_evm_heco_client_contract::init] apply failed"); - return false; - } - } - auto snap_hash = snap.digest(); - auto header_hash = h.calc_hash(); - // step 3: store with no check - xinfo("[xtop_evm_heco_client_contract::init] header dump: %s, snap_hash: %s", h.dump().c_str(), snap_hash.hex().c_str()); - if (!set_last_hash(header_hash, state)) { - xwarn("[xtop_evm_heco_client_contract::init] set_last_hash failed, hash: %s", header_hash.hex().c_str()); - return false; - } - if (!set_effective_hash(h.number, header_hash, state)) { - xwarn("[xtop_evm_heco_client_contract::init] set_effective_hash failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); - return false; - } - if (!set_hashes(h.number, {header_hash}, state)) { - xwarn("[xtop_evm_heco_client_contract::init] set_hash failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); - return false; - } - if (!set_header(header_hash, h, state)) { - xwarn("[xtop_evm_heco_client_contract::init] set_header failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); - return false; - } - xvalidators_snap_info_t snap_info{snap_hash, h.parent_hash, h.number}; - if (!set_snap_info(header_hash, snap_info, state)) { - xwarn("[xtop_evm_heco_client_contract::init] set_snap_info failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); - return false; - } - } - - xinfo("[xtop_evm_heco_client_contract::init] init success"); - return true; -} - -bool xtop_evm_heco_client_contract::sync(xbytes_t const & rlp_bytes, state_ptr state) { - // step 1: check init - if (get_last_hash(state) == h256()) { - xwarn("[xtop_evm_heco_client_contract::sync] not init yet"); - return false; - } - - auto left_bytes = rlp_bytes; - std::error_code ec; - while (!left_bytes.empty()) { - // step 2: decode - auto item = RLP::decode(left_bytes); - auto decoded_size = item.decoded.size(); - if (decoded_size < 2) { - xwarn("[xtop_evm_heco_client_contract::sync] sync param error"); - return false; - } - left_bytes = std::move(item.remainder); - xeth_header_t header; - { - auto item_header = RLP::decode_once(item.decoded[0]); - auto header_bytes = item_header.decoded[0]; - header.decode_rlp(header_bytes, ec); - if (ec) { - xwarn("xtop_evm_heco_client_contract::sync, xeth_header_t::decode_rlp failed, msg %s", ec.message().c_str()); - return false; - } - } - xinfo("[xtop_evm_heco_client_contract::sync] header dump: %s", header.dump().c_str()); - - xvalidators_snapshot_t snap; - uint32_t const validator_num_index = 1; - snap.number = header.number - 1; - snap.hash = header.parent_hash; - auto validator_num = evm_common::fromBigEndian(item.decoded[validator_num_index]); - // check decoded_size with recent_num - if (decoded_size < validator_num + validator_num_index + 1 + 1) { - xwarn("[xtop_evm_heco_client_contract::sync] sync param error"); - return false; - } - uint32_t const validators_index = validator_num_index + 1; - for (uint64_t i = 0; i < validator_num; ++i) { - snap.validators.insert(common::xeth_address_t::build_from(item.decoded[i + validators_index])); - } - uint32_t const recent_num_index = validator_num + validator_num_index + 1; - auto recent_num = evm_common::fromBigEndian(item.decoded[recent_num_index]); - if (decoded_size < recent_num_index + 1 + recent_num) { - xwarn("[xtop_evm_heco_client_contract::sync] sync param error"); - return false; - } - uint32_t const recents_index = recent_num_index + 1; - for (uint64_t i = 0; i < recent_num; ++i) { - auto k = evm_common::fromBigEndian(item.decoded[recents_index + i * 2]); - snap.recents[k] = common::xeth_address_t::build_from(item.decoded[recents_index + i * 2 + 1]); - } - - xeth_header_t parent_header; - if (!get_header(header.parent_hash, parent_header, state)) { - xwarn("[xtop_evm_heco_client_contract::sync] get parent header failed, hash: %s", header.parent_hash.hex().c_str()); - return false; - } - // step 5: verify header - if (!verify(parent_header, header, snap, state)) { - xwarn("[xtop_evm_heco_client_contract::sync] verify header failed"); - return false; - } - // step 6: record - if (!record(header, snap, state)) { - xwarn("[xtop_evm_heco_client_contract::sync] record header failed"); - return false; - } - } - xinfo("[xtop_evm_heco_client_contract::sync] sync success"); - return true; -} - -bool xtop_evm_heco_client_contract::reset(state_ptr state) { - if (get_flag(state) != 0) { - xwarn("[xtop_evm_heco_client_contract::reset] flag not 0"); - return false; - } - state->map_clear(data::system_contract::XPROPERTY_EFFECTIVE_HASHES); - state->map_clear(data::system_contract::XPROPERTY_ALL_HASHES); - state->map_clear(data::system_contract::XPROPERTY_HEADERS); - state->map_clear(data::system_contract::XPROPERTY_HEADERS_SUMMARY); - set_last_hash(h256(), state); - return true; -} - -bool xtop_evm_heco_client_contract::disable_reset(state_ptr state) { - return set_flag(state); -} - -bigint xtop_evm_heco_client_contract::get_height(state_ptr state) const { - h256 last_hash = get_last_hash(state); - xvalidators_snap_info_t info; - if (!get_snap_info(last_hash, info, state)) { - xwarn("[xtop_evm_heco_client_contract::get_height] get header info failed, hash: %s", last_hash.hex().c_str()); - return 0; - } - xinfo("[xtop_evm_heco_client_contract::get_height] height: %s", info.number.str().c_str()); - return info.number; -} - -xheader_status_t xtop_evm_heco_client_contract::query_height(u256 const height, state_ptr state) const { - auto now_height = get_height(state); - if (now_height == 0) { - return xheader_status_t::header_not_confirmed; - } - if (now_height >= height + hash_reserve_num) { - return xheader_status_t::header_overdue; - } - if (now_height <= height + confirm_num) { - return xheader_status_t::header_not_confirmed; - } - return xheader_status_t::header_confirmed; -} - -bool xtop_evm_heco_client_contract::is_known(u256 const height, xbytes_t const & hash_bytes, state_ptr state) const { - h256 hash = static_cast(hash_bytes); - auto hashes = get_hashes(height, state); - if (!hashes.count(hash)) { - xwarn("[xtop_evm_heco_client_contract::is_known] not found, height: %s, hash: %s", height.str().c_str(), hash.hex().c_str()); - return false; - } - xinfo("[xtop_evm_heco_client_contract::is_known] is known, height: %s, hash: %s", height.str().c_str(), hash.hex().c_str()); - return true; -} - -bool xtop_evm_heco_client_contract::is_confirmed(u256 const height, xbytes_t const & hash_bytes, state_ptr state) const { - h256 hash = static_cast(hash_bytes); - h256 origin_hash = get_effective_hash(height, state); - if (hash != origin_hash) { - xwarn("[xtop_evm_heco_client_contract::is_confirmed] hash mismatch: %s, %s", hash.hex().c_str(), origin_hash.hex().c_str()); - return false; - } - h256 last_hash = get_last_hash(state); - xvalidators_snap_info_t info; - if (!get_snap_info(last_hash, info, state)) { - xwarn("[xtop_evm_heco_client_contract::is_confirmed] get header info failed, hash: %s", last_hash.hex().c_str()); - return false; - } - if (height + confirm_num > info.number) { - xwarn("[xtop_evm_heco_client_contract::is_confirmed] height not confirmed: %s, %s, limit: %d", info.number.str().c_str(), height.str().c_str(), confirm_num); - return false; - } - xinfo("[xtop_evm_heco_client_contract::is_confirmed] is_confirmed: %s", hash.hex().c_str()); - return true; -} - -bool xtop_evm_heco_client_contract::verify(xeth_header_t const & prev_header, xeth_header_t const & new_header, xvalidators_snapshot_t & snap, state_ptr state) const { - if (new_header.extra.size() < extra_vanity) { - xwarn("[xtop_evm_heco_client_contract::verify] header extra size error: %lu, should < %lu", new_header.extra.size(), extra_vanity); - return false; - } - if (new_header.extra.size() < extra_vanity + extra_seal) { - xwarn("[xtop_evm_heco_client_contract::verify] header extra miss signature: %lu, should < %lu", new_header.extra.size(), extra_vanity + extra_seal); - return false; - } - bool is_epoch = (new_header.number % epoch == 0); - uint64_t validators_bytes = new_header.extra.size() - extra_vanity - extra_seal; - if (!is_epoch && validators_bytes != 0) { - xwarn("[xtop_evm_heco_client_contract::verify] not epoch but has validators_bytes"); - return false; - } - if (is_epoch && validators_bytes % address_length != 0) { - xwarn("[xtop_evm_heco_client_contract::verify] validators_bytes length error: %lu", validators_bytes); - return false; - } - if (new_header.mix_digest != h256(0)) { - xwarn("[xtop_evm_heco_client_contract::verify] mix_digest not 0: %lu", new_header.mix_digest.hex().c_str()); - return false; - } - if (new_header.uncle_hash != empty_unclehash) { - xwarn("[xtop_evm_heco_client_contract::verify] uncle_hash mismatch: %s, should be: %s", new_header.uncle_hash.hex().c_str(), empty_unclehash.hex().c_str()); - return false; - } - if (new_header.gas_limit > max_gas_limit) { - xwarn("[xtop_evm_heco_client_contract::verify] gaslimit too big: %s > %lu", new_header.gas_limit.str().c_str(), max_gas_limit); - return false; - } - if (new_header.gas_used > new_header.gas_limit) { - xwarn("[xtop_evm_heco_client_contract::verify] gasUsed: %s > gasLimit: %s", new_header.gas_used.str().c_str(), new_header.gas_limit.str().c_str()); - return false; - } - if (!heco::config::is_london(new_header.number)) { - xwarn("[xtop_evm_heco_client_contract::verify] not london fork"); - return false; - } - if (!heco::verify_eip1559_header(prev_header, new_header)) { - xwarn("[xtop_evm_heco_client_contract::verify] verifyEip1559Header failed, new: %s, old: %s", new_header.gas_limit.str().c_str(), prev_header.gas_limit.str().c_str()); - return false; - } - if (new_header.number != prev_header.number + 1) { - xwarn("[xtop_evm_heco_client_contract::verify] height mismatch, new: %" PRIu64 ", old: %" PRIu64, new_header.number, prev_header.number); - return false; - } - - h256 last_hash = get_last_hash(state); - xvalidators_snap_info_t last_info; - if (!get_snap_info(last_hash, last_info, state)) { - xwarn("[xtop_evm_heco_client_contract::verify] get_header_info failed, hash: %s", last_hash.hex().c_str()); - return false; - } - auto snap_hash = snap.digest(); - if (last_info.snap_hash != snap_hash) { - xwarn("[xtop_evm_heco_client_contract::verify] snap hash mismatch: %s", last_info.snap_hash.hex().c_str(), snap_hash.hex().c_str()); - return false; - } - if (!snap.apply(new_header, true)) { - xwarn("[xtop_evm_heco_client_contract::verify] snap apply failed"); - return false; - } - return true; -} - -bool xtop_evm_heco_client_contract::record(xeth_header_t const & header, xvalidators_snapshot_t const & snap, state_ptr state) { - h256 header_hash = header.calc_hash(); - h256 last_hash = get_last_hash(state); - xvalidators_snap_info_t last_info; - if (!get_snap_info(last_hash, last_info, state)) { - xwarn("[xtop_evm_heco_client_contract::record] get_header_info failed, hash: %s", last_hash.hex().c_str()); - return false; - } - if (header.number + block_reserve_num < last_info.number) { - xwarn("[xtop_evm_heco_client_contract::record] header is too old height: %" PRIu64 ", hash: %s, now height: %s", - header.number, - header_hash.hex().c_str(), - last_info.number.str().c_str()); - return false; - } - xvalidators_snap_info_t parent_info; - if (!get_snap_info(header.parent_hash, parent_info, state)) { - xwarn("[xtop_evm_heco_client_contract::record] get parent header_info failed, hash: %s", header.parent_hash.hex().c_str()); - return false; - } - auto all_hashes = get_hashes(header.number, state); - if (all_hashes.count(header_hash)) { - xwarn("[xtop_evm_heco_client_contract::record] header existed, hash: %s", header_hash.hex().c_str()); - return false; - } - all_hashes.insert(header_hash); - if (!set_hashes(header.number, all_hashes, state)) { - xwarn("[xtop_evm_heco_client_contract::record] set hashes failed, height: %" PRIu64, header.number); - return false; - } - if (!set_header(header_hash, header, state)) { - xwarn("[xtop_evm_heco_client_contract::record] set header failed, hash: %s", header_hash.hex().c_str()); - return false; - } - xvalidators_snap_info_t info{snap.digest(), header.parent_hash, header.number}; - if (!set_snap_info(header.calc_hash(), info, state)) { - xwarn("[xtop_evm_heco_client_contract::record] set_header_info failed, height: %" PRIu64 ", hash: %s", header.number, header.calc_hash().hex().c_str()); - return false; - } - if (!rebuild(header, last_info, info, state)) { - xwarn("[xtop_evm_heco_client_contract::record] rebuild failed"); - return false; - } - release(header.number, state); - return true; -} - -bool xtop_evm_heco_client_contract::rebuild(xeth_header_t const & header, xvalidators_snap_info_t const & last_info, xvalidators_snap_info_t const & cur_info, state_ptr state) { - if (last_info.number > cur_info.number) { - for (bigint i = cur_info.number + 1; i <= last_info.number; ++i) { - remove_effective_hash(i, state); - } - } - auto header_hash = header.calc_hash(); - if (!set_last_hash(header_hash, state)) { - xwarn("[xtop_evm_heco_client_contract::record] set_last_hash failed, hash: %s", header_hash.hex().c_str()); - return false; - } - if (!set_effective_hash(header.number, header_hash, state)) { - xwarn("[xtop_evm_heco_client_contract::init] set_effective_hash failed, height: %" PRIu64 ", hash: %s", header.number, header_hash.hex().c_str()); - return false; - } - bigint height = header.number - 1; - auto current_hash = cur_info.parent_hash; - for (;;) { - if (height == 0) { - break; - } - if (get_effective_hash(height, state) == current_hash) { - break; - } - if (!set_effective_hash(height, current_hash, state)) { - xwarn("[xtop_evm_heco_client_contract::init] set_effective_hash failed, height: %s, hash: %s", height.str().c_str(), current_hash.hex().c_str()); - return false; - } - xvalidators_snap_info_t info; - if (get_snap_info(current_hash, info, state)) { - current_hash = info.parent_hash; - } else { - break; - } - height -= 1; - } - return true; -} - -void xtop_evm_heco_client_contract::release(bigint const number, state_ptr state) { - xeth_header_t header; - bigint difficulty; - h256 hash; - if (number > block_reserve_num) { - bigint n = number - block_reserve_num; - for (;;) { - auto hashes = get_hashes(n, state); - if (hashes.empty()) { - break; - } - for (auto h : hashes) { - remove_snap_info(h, state); - remove_header(h, state); - } - remove_hashes(n, state); - if (n == 0) { - break; - } - n -= 1; - } - } - if (number > hash_reserve_num) { - bigint n = number - hash_reserve_num; - for (;;) { - if (get_effective_hash(n, state) == h256()) { - break; - } - remove_effective_hash(n, state); - if (n == 0) { - break; - } - n -= 1; - } - } -} - -bool xtop_evm_heco_client_contract::get_header(h256 const hash, xeth_header_t & header, state_ptr state) const { - auto k = hash.asBytes(); - auto header_str = state->map_get(data::system_contract::XPROPERTY_HEADERS, {k.begin(), k.end()}); - if (header_str.empty()) { - xwarn("[xtop_evm_heco_client_contract::get_header] get_header not exist, hash: %s", hash.hex().c_str()); - return false; - } - std::error_code ec; - header.decode_rlp({std::begin(header_str), std::end(header_str)}, ec); - if (ec) { - xwarn("[xtop_evm_heco_client_contract::get_header] decode_header failed, hash: %s, msg %s", hash.hex().c_str(), ec.message().c_str()); - return false; - } - return true; -} - -bool xtop_evm_heco_client_contract::set_header(h256 const hash, xeth_header_t const & header, state_ptr state) { - auto k = hash.asBytes(); - auto v = header.encode_rlp(); - if (0 != state->map_set(data::system_contract::XPROPERTY_HEADERS, {k.begin(), k.end()}, {v.begin(), v.end()})) { - return false; - } - return true; -} - -bool xtop_evm_heco_client_contract::remove_header(h256 const hash, state_ptr state) { - auto k = hash.asBytes(); - if (0 != state->map_remove(data::system_contract::XPROPERTY_HEADERS, {k.begin(), k.end()})) { - return false; - } - return true; -} - -bool xtop_evm_heco_client_contract::get_snap_info(h256 const hash, xvalidators_snap_info_t & header_info, state_ptr state) const { - auto k = hash.asBytes(); - auto info_str = state->map_get(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()}); - if (info_str.empty()) { - xwarn("[xtop_evm_heco_client_contract::get_snap_info] get_header not exist, hash: %s", hash.hex().c_str()); - return false; - } - if (header_info.decode_rlp({std::begin(info_str), std::end(info_str)}) == false) { - xwarn("[xtop_evm_heco_client_contract::get_snap_info] decode_header failed, hash: %s", hash.hex().c_str()); - return false; - } - return true; -} - -bool xtop_evm_heco_client_contract::set_snap_info(h256 const hash, xvalidators_snap_info_t const & snap_info, state_ptr state) { - auto k = hash.asBytes(); - auto v = snap_info.encode_rlp(); - if (0 != state->map_set(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()}, {v.begin(), v.end()})) { - return false; - } - return true; -} - -bool xtop_evm_heco_client_contract::remove_snap_info(h256 const hash, state_ptr state) { - auto k = hash.asBytes(); - if (0 != state->map_remove(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()})) { - return false; - } - return true; -} - -h256 xtop_evm_heco_client_contract::get_effective_hash(bigint const height, state_ptr state) const { - auto k = evm_common::toBigEndian(static_cast(height)); - auto hash_str = state->map_get(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, {k.begin(), k.end()}); - if (hash_str.empty()) { - return h256(); - } - return static_cast(xbytes_t{std::begin(hash_str), std::end(hash_str)}); -} - -bool xtop_evm_heco_client_contract::set_effective_hash(bigint const height, h256 const hash, state_ptr state) { - auto k = evm_common::toBigEndian(static_cast(height)); - auto v = hash.asBytes(); - if (0 != state->map_set(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, {k.begin(), k.end()}, {v.begin(), v.end()})) { - return false; - } - return true; -} - -bool xtop_evm_heco_client_contract::remove_effective_hash(bigint const height, state_ptr state) { - auto k = evm_common::toBigEndian(static_cast(height)); - if (0 != state->map_remove(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, {k.begin(), k.end()})) { - return false; - } - return true; -} - -std::set xtop_evm_heco_client_contract::get_hashes(bigint const height, state_ptr state) const { - auto k = evm_common::toBigEndian(static_cast(height)); - auto str = state->map_get(data::system_contract::XPROPERTY_ALL_HASHES, {k.begin(), k.end()}); - if (str.empty()) { - return {}; - } - std::set hashes; - auto item = RLP::decodeList({std::begin(str), std::end(str)}); - for (auto bytes : item.decoded) { - hashes.insert(static_cast(bytes)); - } - return hashes; -} - -bool xtop_evm_heco_client_contract::set_hashes(bigint const height, std::set const & hashes, state_ptr state) { - auto k = evm_common::toBigEndian(static_cast(height)); - xbytes_t v; - for (auto h : hashes) { - auto bytes = RLP::encode(h.asBytes()); - v.insert(v.end(), bytes.begin(), bytes.end()); - } - if (0 != state->map_set(data::system_contract::XPROPERTY_ALL_HASHES, {k.begin(), k.end()}, {v.begin(), v.end()})) { - return false; - } - return true; -} - -bool xtop_evm_heco_client_contract::remove_hashes(bigint const height, state_ptr state) { - auto k = evm_common::toBigEndian(static_cast(height)); - if (0 != state->map_remove(data::system_contract::XPROPERTY_ALL_HASHES, {k.begin(), k.end()})) { - return false; - } - return true; -} - -h256 xtop_evm_heco_client_contract::get_last_hash(state_ptr state) const { - auto hash_str = state->string_get(data::system_contract::XPROPERTY_LAST_HASH); - if (hash_str.empty()) { - return h256(); - } - return static_cast(xbytes_t{std::begin(hash_str), std::end(hash_str)}); -} - -bool xtop_evm_heco_client_contract::set_last_hash(h256 const hash, state_ptr state) { - auto bytes = hash.asBytes(); - if (0 != state->string_set(data::system_contract::XPROPERTY_LAST_HASH, {bytes.begin(), bytes.end()})) { - return false; - } - return true; -} - -int xtop_evm_heco_client_contract::get_flag(state_ptr state) const { - auto flag_str = state->string_get(data::system_contract::XPROPERTY_RESET_FLAG); - if (flag_str.empty()) { - return -1; - } - return from_string(flag_str); -} - -bool xtop_evm_heco_client_contract::set_flag(state_ptr state) { - if (0 != state->string_set(data::system_contract::XPROPERTY_RESET_FLAG, top::to_string(1))) { - return false; - } - return true; -} - -NS_END4 +//// Copyright (c) 2017-present Telos Foundation & contributors +//// Distributed under the MIT software license, see the accompanying +//// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +//#include "xevm_contract_runtime/sys_contract/xevm_heco_client_contract.h" +// +//#include "xbasic/endianness.h" +//#include "xcommon/xaccount_address.h" +//#include "xcommon/xeth_address.h" +//#include "xdata/xdata_common.h" +//#include "xdata/xsystem_contract/xdata_structures.h" +//#include "xcommon/common_data.h" +//#include "xevm_common/xabi_decoder.h" +//#include "xevm_common/xcrosschain/xeth_header.h" +//#include "xevm_common/xcrosschain/xheco_config.h" +//#include "xevm_common/xcrosschain/xheco_eip1559.h" +// +//#if defined(XCXX20) +//#include +//#else +//#include +//#endif +//#include +// +//using namespace top::evm_common; +// +//NS_BEG4(top, contract_runtime, evm, sys_contract) +// +//constexpr uint64_t confirm_num = 15; +//constexpr uint64_t validator_num = 21; +//constexpr uint64_t hash_reserve_num = 40000; +//constexpr uint64_t block_reserve_num = 500; +// +//constexpr uint64_t epoch = 200; +//constexpr uint64_t extra_vanity = 32; +//constexpr uint64_t extra_seal = 64 + 1; +//constexpr uint64_t address_length = 20; +//constexpr uint64_t max_gas_limit = 0x7fffffffffffffff; +// +//auto static empty_unclehash = static_cast(from_hex("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")); +// +//bool xtop_evm_heco_client_contract::init(xbytes_t const & rlp_bytes, state_ptr state) { +// // step 1: check init +// if (get_last_hash(state) != h256()) { +// xwarn("[xtop_evm_heco_client_contract::init] init already"); +// return false; +// } +// // step 2: decode +// auto left_bytes = rlp_bytes; +// std::vector headers; +// std::error_code ec; +// while (!left_bytes.empty()) { +// auto item = RLP::decode_once(left_bytes); +// left_bytes = item.remainder; +// xeth_header_t header; +// header.decode_rlp(item.decoded[0], ec); +// if (ec) { +// xwarn("xtop_evm_heco_client_contract::init, xeth_header_t::decode_rlp failed, msg %s", ec.message().c_str()); +// return false; +// } +// headers.emplace_back(header); +// } +// // min 12 to construnct state +// if (headers.size() < (validator_num / 2 + 1) + 1) { +// xwarn("[xtop_evm_heco_client_contract::init] not enough headers"); +// return false; +// } +// +// xvalidators_snapshot_t snap; +// if (!snap.init_with_epoch(headers[0])) { +// xwarn("[xtop_evm_heco_client_contract::init] new_epoch_snapshot error"); +// return false; +// } +// +// for (size_t i = 0; i < headers.size(); ++i) { +// auto const & h = headers[i]; +// if (i != 0) { +// if (!snap.apply(h, false)) { +// xwarn("[xtop_evm_heco_client_contract::init] apply failed"); +// return false; +// } +// } +// auto snap_hash = snap.digest(); +// auto header_hash = h.calc_hash(); +// // step 3: store with no check +// xinfo("[xtop_evm_heco_client_contract::init] header dump: %s, snap_hash: %s", h.dump().c_str(), snap_hash.hex().c_str()); +// if (!set_last_hash(header_hash, state)) { +// xwarn("[xtop_evm_heco_client_contract::init] set_last_hash failed, hash: %s", header_hash.hex().c_str()); +// return false; +// } +// if (!set_effective_hash(h.number, header_hash, state)) { +// xwarn("[xtop_evm_heco_client_contract::init] set_effective_hash failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); +// return false; +// } +// if (!set_hashes(h.number, {header_hash}, state)) { +// xwarn("[xtop_evm_heco_client_contract::init] set_hash failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); +// return false; +// } +// if (!set_header(header_hash, h, state)) { +// xwarn("[xtop_evm_heco_client_contract::init] set_header failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); +// return false; +// } +// xvalidators_snap_info_t snap_info{snap_hash, h.parent_hash, h.number}; +// if (!set_snap_info(header_hash, snap_info, state)) { +// xwarn("[xtop_evm_heco_client_contract::init] set_snap_info failed, height: %" PRIu64 ", hash: %s", h.number, header_hash.hex().c_str()); +// return false; +// } +// } +// +// xinfo("[xtop_evm_heco_client_contract::init] init success"); +// return true; +//} +// +//bool xtop_evm_heco_client_contract::sync(xbytes_t const & rlp_bytes, state_ptr state) { +// // step 1: check init +// if (get_last_hash(state) == h256()) { +// xwarn("[xtop_evm_heco_client_contract::sync] not init yet"); +// return false; +// } +// +// auto left_bytes = rlp_bytes; +// std::error_code ec; +// while (!left_bytes.empty()) { +// // step 2: decode +// auto item = RLP::decode(left_bytes); +// auto decoded_size = item.decoded.size(); +// if (decoded_size < 2) { +// xwarn("[xtop_evm_heco_client_contract::sync] sync param error"); +// return false; +// } +// left_bytes = std::move(item.remainder); +// xeth_header_t header; +// { +// auto item_header = RLP::decode_once(item.decoded[0]); +// auto header_bytes = item_header.decoded[0]; +// header.decode_rlp(header_bytes, ec); +// if (ec) { +// xwarn("xtop_evm_heco_client_contract::sync, xeth_header_t::decode_rlp failed, msg %s", ec.message().c_str()); +// return false; +// } +// } +// xinfo("[xtop_evm_heco_client_contract::sync] header dump: %s", header.dump().c_str()); +// +// xvalidators_snapshot_t snap; +// uint32_t const validator_num_index = 1; +// snap.number = header.number - 1; +// snap.hash = header.parent_hash; +// auto validator_num = evm_common::fromBigEndian(item.decoded[validator_num_index]); +// // check decoded_size with recent_num +// if (decoded_size < validator_num + validator_num_index + 1 + 1) { +// xwarn("[xtop_evm_heco_client_contract::sync] sync param error"); +// return false; +// } +// uint32_t const validators_index = validator_num_index + 1; +// for (uint64_t i = 0; i < validator_num; ++i) { +// snap.validators.insert(common::xeth_address_t::build_from(item.decoded[i + validators_index])); +// } +// uint32_t const recent_num_index = validator_num + validator_num_index + 1; +// auto recent_num = evm_common::fromBigEndian(item.decoded[recent_num_index]); +// if (decoded_size < recent_num_index + 1 + recent_num) { +// xwarn("[xtop_evm_heco_client_contract::sync] sync param error"); +// return false; +// } +// uint32_t const recents_index = recent_num_index + 1; +// for (uint64_t i = 0; i < recent_num; ++i) { +// auto k = evm_common::fromBigEndian(item.decoded[recents_index + i * 2]); +// snap.recents[k] = common::xeth_address_t::build_from(item.decoded[recents_index + i * 2 + 1]); +// } +// +// xeth_header_t parent_header; +// if (!get_header(header.parent_hash, parent_header, state)) { +// xwarn("[xtop_evm_heco_client_contract::sync] get parent header failed, hash: %s", header.parent_hash.hex().c_str()); +// return false; +// } +// // step 5: verify header +// if (!verify(parent_header, header, snap, state)) { +// xwarn("[xtop_evm_heco_client_contract::sync] verify header failed"); +// return false; +// } +// // step 6: record +// if (!record(header, snap, state)) { +// xwarn("[xtop_evm_heco_client_contract::sync] record header failed"); +// return false; +// } +// } +// xinfo("[xtop_evm_heco_client_contract::sync] sync success"); +// return true; +//} +// +//bool xtop_evm_heco_client_contract::reset(state_ptr state) { +// if (get_flag(state) != 0) { +// xwarn("[xtop_evm_heco_client_contract::reset] flag not 0"); +// return false; +// } +// state->map_clear(data::system_contract::XPROPERTY_EFFECTIVE_HASHES); +// state->map_clear(data::system_contract::XPROPERTY_ALL_HASHES); +// state->map_clear(data::system_contract::XPROPERTY_HEADERS); +// state->map_clear(data::system_contract::XPROPERTY_HEADERS_SUMMARY); +// set_last_hash(h256(), state); +// return true; +//} +// +//bool xtop_evm_heco_client_contract::disable_reset(state_ptr state) { +// return set_flag(state); +//} +// +//bigint xtop_evm_heco_client_contract::get_height(state_ptr state) const { +// h256 last_hash = get_last_hash(state); +// xvalidators_snap_info_t info; +// if (!get_snap_info(last_hash, info, state)) { +// xwarn("[xtop_evm_heco_client_contract::get_height] get header info failed, hash: %s", last_hash.hex().c_str()); +// return 0; +// } +// xinfo("[xtop_evm_heco_client_contract::get_height] height: %s", info.number.str().c_str()); +// return info.number; +//} +// +//xheader_status_t xtop_evm_heco_client_contract::query_height(u256 const height, state_ptr state) const { +// auto now_height = get_height(state); +// if (now_height == 0) { +// return xheader_status_t::header_not_confirmed; +// } +// if (now_height >= height + hash_reserve_num) { +// return xheader_status_t::header_overdue; +// } +// if (now_height <= height + confirm_num) { +// return xheader_status_t::header_not_confirmed; +// } +// return xheader_status_t::header_confirmed; +//} +// +//bool xtop_evm_heco_client_contract::is_known(u256 const height, xbytes_t const & hash_bytes, state_ptr state) const { +// h256 hash = static_cast(hash_bytes); +// auto hashes = get_hashes(height, state); +// if (!hashes.count(hash)) { +// xwarn("[xtop_evm_heco_client_contract::is_known] not found, height: %s, hash: %s", height.str().c_str(), hash.hex().c_str()); +// return false; +// } +// xinfo("[xtop_evm_heco_client_contract::is_known] is known, height: %s, hash: %s", height.str().c_str(), hash.hex().c_str()); +// return true; +//} +// +//bool xtop_evm_heco_client_contract::is_confirmed(u256 const height, xbytes_t const & hash_bytes, state_ptr state) const { +// h256 hash = static_cast(hash_bytes); +// h256 origin_hash = get_effective_hash(height, state); +// if (hash != origin_hash) { +// xwarn("[xtop_evm_heco_client_contract::is_confirmed] hash mismatch: %s, %s", hash.hex().c_str(), origin_hash.hex().c_str()); +// return false; +// } +// h256 last_hash = get_last_hash(state); +// xvalidators_snap_info_t info; +// if (!get_snap_info(last_hash, info, state)) { +// xwarn("[xtop_evm_heco_client_contract::is_confirmed] get header info failed, hash: %s", last_hash.hex().c_str()); +// return false; +// } +// if (height + confirm_num > info.number) { +// xwarn("[xtop_evm_heco_client_contract::is_confirmed] height not confirmed: %s, %s, limit: %d", info.number.str().c_str(), height.str().c_str(), confirm_num); +// return false; +// } +// xinfo("[xtop_evm_heco_client_contract::is_confirmed] is_confirmed: %s", hash.hex().c_str()); +// return true; +//} +// +//bool xtop_evm_heco_client_contract::verify(xeth_header_t const & prev_header, xeth_header_t const & new_header, xvalidators_snapshot_t & snap, state_ptr state) const { +// if (new_header.extra.size() < extra_vanity) { +// xwarn("[xtop_evm_heco_client_contract::verify] header extra size error: %lu, should < %lu", new_header.extra.size(), extra_vanity); +// return false; +// } +// if (new_header.extra.size() < extra_vanity + extra_seal) { +// xwarn("[xtop_evm_heco_client_contract::verify] header extra miss signature: %lu, should < %lu", new_header.extra.size(), extra_vanity + extra_seal); +// return false; +// } +// bool is_epoch = (new_header.number % epoch == 0); +// uint64_t validators_bytes = new_header.extra.size() - extra_vanity - extra_seal; +// if (!is_epoch && validators_bytes != 0) { +// xwarn("[xtop_evm_heco_client_contract::verify] not epoch but has validators_bytes"); +// return false; +// } +// if (is_epoch && validators_bytes % address_length != 0) { +// xwarn("[xtop_evm_heco_client_contract::verify] validators_bytes length error: %lu", validators_bytes); +// return false; +// } +// if (new_header.mix_digest != h256(0)) { +// xwarn("[xtop_evm_heco_client_contract::verify] mix_digest not 0: %lu", new_header.mix_digest.hex().c_str()); +// return false; +// } +// if (new_header.uncle_hash != empty_unclehash) { +// xwarn("[xtop_evm_heco_client_contract::verify] uncle_hash mismatch: %s, should be: %s", new_header.uncle_hash.hex().c_str(), empty_unclehash.hex().c_str()); +// return false; +// } +// if (new_header.gas_limit > max_gas_limit) { +// xwarn("[xtop_evm_heco_client_contract::verify] gaslimit too big: %s > %lu", new_header.gas_limit.str().c_str(), max_gas_limit); +// return false; +// } +// if (new_header.gas_used > new_header.gas_limit) { +// xwarn("[xtop_evm_heco_client_contract::verify] gasUsed: %s > gasLimit: %s", new_header.gas_used.str().c_str(), new_header.gas_limit.str().c_str()); +// return false; +// } +// if (!heco::config::is_london(new_header.number)) { +// xwarn("[xtop_evm_heco_client_contract::verify] not london fork"); +// return false; +// } +// if (!heco::verify_eip1559_header(prev_header, new_header)) { +// xwarn("[xtop_evm_heco_client_contract::verify] verifyEip1559Header failed, new: %s, old: %s", new_header.gas_limit.str().c_str(), prev_header.gas_limit.str().c_str()); +// return false; +// } +// if (new_header.number != prev_header.number + 1) { +// xwarn("[xtop_evm_heco_client_contract::verify] height mismatch, new: %" PRIu64 ", old: %" PRIu64, new_header.number, prev_header.number); +// return false; +// } +// +// h256 last_hash = get_last_hash(state); +// xvalidators_snap_info_t last_info; +// if (!get_snap_info(last_hash, last_info, state)) { +// xwarn("[xtop_evm_heco_client_contract::verify] get_header_info failed, hash: %s", last_hash.hex().c_str()); +// return false; +// } +// auto snap_hash = snap.digest(); +// if (last_info.snap_hash != snap_hash) { +// xwarn("[xtop_evm_heco_client_contract::verify] snap hash mismatch: %s", last_info.snap_hash.hex().c_str(), snap_hash.hex().c_str()); +// return false; +// } +// if (!snap.apply(new_header, true)) { +// xwarn("[xtop_evm_heco_client_contract::verify] snap apply failed"); +// return false; +// } +// return true; +//} +// +//bool xtop_evm_heco_client_contract::record(xeth_header_t const & header, xvalidators_snapshot_t const & snap, state_ptr state) { +// h256 header_hash = header.calc_hash(); +// h256 last_hash = get_last_hash(state); +// xvalidators_snap_info_t last_info; +// if (!get_snap_info(last_hash, last_info, state)) { +// xwarn("[xtop_evm_heco_client_contract::record] get_header_info failed, hash: %s", last_hash.hex().c_str()); +// return false; +// } +// if (header.number + block_reserve_num < last_info.number) { +// xwarn("[xtop_evm_heco_client_contract::record] header is too old height: %" PRIu64 ", hash: %s, now height: %s", +// header.number, +// header_hash.hex().c_str(), +// last_info.number.str().c_str()); +// return false; +// } +// xvalidators_snap_info_t parent_info; +// if (!get_snap_info(header.parent_hash, parent_info, state)) { +// xwarn("[xtop_evm_heco_client_contract::record] get parent header_info failed, hash: %s", header.parent_hash.hex().c_str()); +// return false; +// } +// auto all_hashes = get_hashes(header.number, state); +// if (all_hashes.count(header_hash)) { +// xwarn("[xtop_evm_heco_client_contract::record] header existed, hash: %s", header_hash.hex().c_str()); +// return false; +// } +// all_hashes.insert(header_hash); +// if (!set_hashes(header.number, all_hashes, state)) { +// xwarn("[xtop_evm_heco_client_contract::record] set hashes failed, height: %" PRIu64, header.number); +// return false; +// } +// if (!set_header(header_hash, header, state)) { +// xwarn("[xtop_evm_heco_client_contract::record] set header failed, hash: %s", header_hash.hex().c_str()); +// return false; +// } +// xvalidators_snap_info_t info{snap.digest(), header.parent_hash, header.number}; +// if (!set_snap_info(header.calc_hash(), info, state)) { +// xwarn("[xtop_evm_heco_client_contract::record] set_header_info failed, height: %" PRIu64 ", hash: %s", header.number, header.calc_hash().hex().c_str()); +// return false; +// } +// if (!rebuild(header, last_info, info, state)) { +// xwarn("[xtop_evm_heco_client_contract::record] rebuild failed"); +// return false; +// } +// release(header.number, state); +// return true; +//} +// +//bool xtop_evm_heco_client_contract::rebuild(xeth_header_t const & header, xvalidators_snap_info_t const & last_info, xvalidators_snap_info_t const & cur_info, state_ptr state) { +// if (last_info.number > cur_info.number) { +// for (bigint i = cur_info.number + 1; i <= last_info.number; ++i) { +// remove_effective_hash(i, state); +// } +// } +// auto header_hash = header.calc_hash(); +// if (!set_last_hash(header_hash, state)) { +// xwarn("[xtop_evm_heco_client_contract::record] set_last_hash failed, hash: %s", header_hash.hex().c_str()); +// return false; +// } +// if (!set_effective_hash(header.number, header_hash, state)) { +// xwarn("[xtop_evm_heco_client_contract::init] set_effective_hash failed, height: %" PRIu64 ", hash: %s", header.number, header_hash.hex().c_str()); +// return false; +// } +// bigint height = header.number - 1; +// auto current_hash = cur_info.parent_hash; +// for (;;) { +// if (height == 0) { +// break; +// } +// if (get_effective_hash(height, state) == current_hash) { +// break; +// } +// if (!set_effective_hash(height, current_hash, state)) { +// xwarn("[xtop_evm_heco_client_contract::init] set_effective_hash failed, height: %s, hash: %s", height.str().c_str(), current_hash.hex().c_str()); +// return false; +// } +// xvalidators_snap_info_t info; +// if (get_snap_info(current_hash, info, state)) { +// current_hash = info.parent_hash; +// } else { +// break; +// } +// height -= 1; +// } +// return true; +//} +// +//void xtop_evm_heco_client_contract::release(bigint const number, state_ptr state) { +// xeth_header_t header; +// bigint difficulty; +// h256 hash; +// if (number > block_reserve_num) { +// bigint n = number - block_reserve_num; +// for (;;) { +// auto hashes = get_hashes(n, state); +// if (hashes.empty()) { +// break; +// } +// for (auto h : hashes) { +// remove_snap_info(h, state); +// remove_header(h, state); +// } +// remove_hashes(n, state); +// if (n == 0) { +// break; +// } +// n -= 1; +// } +// } +// if (number > hash_reserve_num) { +// bigint n = number - hash_reserve_num; +// for (;;) { +// if (get_effective_hash(n, state) == h256()) { +// break; +// } +// remove_effective_hash(n, state); +// if (n == 0) { +// break; +// } +// n -= 1; +// } +// } +//} +// +//bool xtop_evm_heco_client_contract::get_header(h256 const hash, xeth_header_t & header, state_ptr state) const { +// auto k = hash.asBytes(); +// auto header_str = state->map_get(data::system_contract::XPROPERTY_HEADERS, {k.begin(), k.end()}); +// if (header_str.empty()) { +// xwarn("[xtop_evm_heco_client_contract::get_header] get_header not exist, hash: %s", hash.hex().c_str()); +// return false; +// } +// std::error_code ec; +// header.decode_rlp({std::begin(header_str), std::end(header_str)}, ec); +// if (ec) { +// xwarn("[xtop_evm_heco_client_contract::get_header] decode_header failed, hash: %s, msg %s", hash.hex().c_str(), ec.message().c_str()); +// return false; +// } +// return true; +//} +// +//bool xtop_evm_heco_client_contract::set_header(h256 const hash, xeth_header_t const & header, state_ptr state) { +// auto k = hash.asBytes(); +// auto v = header.encode_rlp(); +// if (0 != state->map_set(data::system_contract::XPROPERTY_HEADERS, {k.begin(), k.end()}, {v.begin(), v.end()})) { +// return false; +// } +// return true; +//} +// +//bool xtop_evm_heco_client_contract::remove_header(h256 const hash, state_ptr state) { +// auto k = hash.asBytes(); +// if (0 != state->map_remove(data::system_contract::XPROPERTY_HEADERS, {k.begin(), k.end()})) { +// return false; +// } +// return true; +//} +// +//bool xtop_evm_heco_client_contract::get_snap_info(h256 const hash, xvalidators_snap_info_t & header_info, state_ptr state) const { +// auto k = hash.asBytes(); +// auto info_str = state->map_get(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()}); +// if (info_str.empty()) { +// xwarn("[xtop_evm_heco_client_contract::get_snap_info] get_header not exist, hash: %s", hash.hex().c_str()); +// return false; +// } +// if (header_info.decode_rlp({std::begin(info_str), std::end(info_str)}) == false) { +// xwarn("[xtop_evm_heco_client_contract::get_snap_info] decode_header failed, hash: %s", hash.hex().c_str()); +// return false; +// } +// return true; +//} +// +//bool xtop_evm_heco_client_contract::set_snap_info(h256 const hash, xvalidators_snap_info_t const & snap_info, state_ptr state) { +// auto k = hash.asBytes(); +// auto v = snap_info.encode_rlp(); +// if (0 != state->map_set(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()}, {v.begin(), v.end()})) { +// return false; +// } +// return true; +//} +// +//bool xtop_evm_heco_client_contract::remove_snap_info(h256 const hash, state_ptr state) { +// auto k = hash.asBytes(); +// if (0 != state->map_remove(data::system_contract::XPROPERTY_HEADERS_SUMMARY, {k.begin(), k.end()})) { +// return false; +// } +// return true; +//} +// +//h256 xtop_evm_heco_client_contract::get_effective_hash(bigint const height, state_ptr state) const { +// auto k = evm_common::toBigEndian(static_cast(height)); +// auto hash_str = state->map_get(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, {k.begin(), k.end()}); +// if (hash_str.empty()) { +// return h256(); +// } +// return static_cast(xbytes_t{std::begin(hash_str), std::end(hash_str)}); +//} +// +//bool xtop_evm_heco_client_contract::set_effective_hash(bigint const height, h256 const hash, state_ptr state) { +// auto k = evm_common::toBigEndian(static_cast(height)); +// auto v = hash.asBytes(); +// if (0 != state->map_set(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, {k.begin(), k.end()}, {v.begin(), v.end()})) { +// return false; +// } +// return true; +//} +// +//bool xtop_evm_heco_client_contract::remove_effective_hash(bigint const height, state_ptr state) { +// auto k = evm_common::toBigEndian(static_cast(height)); +// if (0 != state->map_remove(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, {k.begin(), k.end()})) { +// return false; +// } +// return true; +//} +// +//std::set xtop_evm_heco_client_contract::get_hashes(bigint const height, state_ptr state) const { +// auto k = evm_common::toBigEndian(static_cast(height)); +// auto str = state->map_get(data::system_contract::XPROPERTY_ALL_HASHES, {k.begin(), k.end()}); +// if (str.empty()) { +// return {}; +// } +// std::set hashes; +// auto item = RLP::decodeList({std::begin(str), std::end(str)}); +// for (auto bytes : item.decoded) { +// hashes.insert(static_cast(bytes)); +// } +// return hashes; +//} +// +//bool xtop_evm_heco_client_contract::set_hashes(bigint const height, std::set const & hashes, state_ptr state) { +// auto k = evm_common::toBigEndian(static_cast(height)); +// xbytes_t v; +// for (auto h : hashes) { +// auto bytes = RLP::encode(h.asBytes()); +// v.insert(v.end(), bytes.begin(), bytes.end()); +// } +// if (0 != state->map_set(data::system_contract::XPROPERTY_ALL_HASHES, {k.begin(), k.end()}, {v.begin(), v.end()})) { +// return false; +// } +// return true; +//} +// +//bool xtop_evm_heco_client_contract::remove_hashes(bigint const height, state_ptr state) { +// auto k = evm_common::toBigEndian(static_cast(height)); +// if (0 != state->map_remove(data::system_contract::XPROPERTY_ALL_HASHES, {k.begin(), k.end()})) { +// return false; +// } +// return true; +//} +// +//h256 xtop_evm_heco_client_contract::get_last_hash(state_ptr state) const { +// auto hash_str = state->string_get(data::system_contract::XPROPERTY_LAST_HASH); +// if (hash_str.empty()) { +// return h256(); +// } +// return static_cast(xbytes_t{std::begin(hash_str), std::end(hash_str)}); +//} +// +//bool xtop_evm_heco_client_contract::set_last_hash(h256 const hash, state_ptr state) { +// auto bytes = hash.asBytes(); +// if (0 != state->string_set(data::system_contract::XPROPERTY_LAST_HASH, {bytes.begin(), bytes.end()})) { +// return false; +// } +// return true; +//} +// +//int xtop_evm_heco_client_contract::get_flag(state_ptr state) const { +// auto flag_str = state->string_get(data::system_contract::XPROPERTY_RESET_FLAG); +// if (flag_str.empty()) { +// return -1; +// } +// return from_string(flag_str); +//} +// +//bool xtop_evm_heco_client_contract::set_flag(state_ptr state) { +// if (0 != state->string_set(data::system_contract::XPROPERTY_RESET_FLAG, top::to_string(1))) { +// return false; +// } +// return true; +//} +// +//NS_END4 diff --git a/src/xtopcom/xevm_contract_runtime/sys_contract/xevm_bsc_client_contract.h b/src/xtopcom/xevm_contract_runtime/sys_contract/xevm_bsc_client_contract.h index 268b21a4a..e3fabb5b3 100644 --- a/src/xtopcom/xevm_contract_runtime/sys_contract/xevm_bsc_client_contract.h +++ b/src/xtopcom/xevm_contract_runtime/sys_contract/xevm_bsc_client_contract.h @@ -5,6 +5,9 @@ #pragma once #include "xdata/xnative_contract_address.h" +#include "xevm_common/xcrosschain/xbsc/xconfig.h" +#include "xevm_common/xcrosschain/xbsc/xsnapshot.h" +#include "xevm_common/xcrosschain/xbsc/xvote.h" #include "xevm_common/xcrosschain/xeth_header.h" #include "xevm_common/xcrosschain/xvalidators_snapshot.h" #include "xevm_contract_runtime/xevm_sys_crosschain_contract_face.h" @@ -29,13 +32,15 @@ class xtop_evm_bsc_client_contract : public xtop_evm_crosschain_syscontract_face bool disable_reset(state_ptr state); private: + mutable std::unordered_map recent_snapshots_; + bool verify(const xeth_header_t & prev_header, const xeth_header_t & new_header, xvalidators_snapshot_t & snap, state_ptr state) const; bool record(const xeth_header_t & header, const xvalidators_snapshot_t & snap, state_ptr state); bool rebuild(const xeth_header_t & header, const xvalidators_snap_info_t & last_info, const xvalidators_snap_info_t & cur_info, state_ptr state); void release(const bigint number, state_ptr state); // last hash @160 - h256 get_last_hash(state_ptr state) const; - bool set_last_hash(const h256 hash, state_ptr state); + h256 get_last_hash(state_ptr const & state) const; + bool set_last_hash(h256 const & hash, state_ptr const & state); // effective hashes @161 h256 get_effective_hash(const bigint height, state_ptr state) const; bool set_effective_hash(const bigint height, const h256 hash, state_ptr state); @@ -55,6 +60,43 @@ class xtop_evm_bsc_client_contract : public xtop_evm_crosschain_syscontract_face // flag @165 int get_flag(state_ptr state) const; bool set_flag(state_ptr state); + + // get/set pre last snapshot @166 + top::evm::crosschain::bsc::xsnapshot_t pre_last_validator_set(state_ptr & state, std::error_code & ec) const; + void pre_last_validator_set(top::evm::crosschain::bsc::xsnapshot_t const & snapshot, state_ptr & state, std::error_code & ec); + + // get/set last snapshot @167 + top::evm::crosschain::bsc::xsnapshot_t last_validator_set(state_ptr & state, std::error_code & ec) const; + void last_validator_set(top::evm::crosschain::bsc::xsnapshot_t const & snapshot, state_ptr & state, std::error_code & ec); + + // get/set recent snapshot @168 + top::evm::crosschain::bsc::xsnapshot_t get_recent_snapshot(xh256_t const & snapshot_hash, state_ptr & state, std::error_code & ec) const; + void add_recent_snapshot(top::evm::crosschain::bsc::xsnapshot_t const & snapshot, state_ptr & state, std::error_code & ec); + void del_recent_snapshot(xh256_t const & snapshot_hash, state_ptr & state, std::error_code & ec); + + static bool verify_fork_hashes(top::evm::crosschain::bsc::xchain_config_t const & chain_config, xeth_header_t const & header, bool uncle); + static bool verify_eip1559_header(top::evm::crosschain::bsc::xchain_config_t const & chain_config, xeth_header_t const & parent, xeth_header_t const & header); + static void verify_eip4844_header(xeth_header_t const & parent, xeth_header_t const & header, std::error_code & ec); + static uint64_t calc_base_fee(top::evm::crosschain::bsc::xchain_config_t const &, xeth_header_t const &); + bool verify_cascading_fields(top::evm::crosschain::bsc::xchain_config_t const & chain_config, + xeth_header_t const & header, + xspan_t parents, + state_ptr state, + std::error_code & ec) const; + bool verify_headers(std::vector const & headers, state_ptr state) const; + bool verify_header(xeth_header_t const & header, xspan_t parents, state_ptr state) const; + xeth_header_t get_parent(xeth_header_t const & header, xspan_t parents, state_ptr state, std::error_code & ec) const; + top::evm::crosschain::bsc::xsnapshot_t snapshot(uint64_t number, xh256_t const & hash, xspan_t parents, state_ptr state, std::error_code & ec) const; + void verify_vote_attestation(top::evm::crosschain::bsc::xchain_config_t const & chain_config, + xeth_header_t const & header, + xspan_t parents, + state_ptr state, + std::error_code & ec) const; + top::evm::crosschain::bsc::xvote_attestation_t get_vote_attestation_from_header(xeth_header_t const & header, + top::evm::crosschain::bsc::xchain_config_t const & chain_config, + std::error_code & ec) const; + void get_justified_number_and_hash(xeth_header_t const & header, state_ptr const & state, uint64_t & justified_number, xh256_t & justified_hash, std::error_code & ec) const; + void verify_seal(xeth_header_t const & header, xspan_t parents, std::error_code & ec) const; }; using xevm_bsc_client_contract_t = xtop_evm_bsc_client_contract; diff --git a/src/xtopcom/xevm_contract_runtime/sys_contract/xevm_heco_client_contract.h b/src/xtopcom/xevm_contract_runtime/sys_contract/xevm_heco_client_contract.h index d637908d3..99ca211e0 100644 --- a/src/xtopcom/xevm_contract_runtime/sys_contract/xevm_heco_client_contract.h +++ b/src/xtopcom/xevm_contract_runtime/sys_contract/xevm_heco_client_contract.h @@ -1,61 +1,61 @@ -// Copyright (c) 2017-present Telos Foundation & contributors -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#pragma once - -#include "xdata/xnative_contract_address.h" -#include "xevm_common/xcrosschain/xeth_header.h" -#include "xevm_common/xcrosschain/xvalidators_snapshot.h" -#include "xevm_contract_runtime/xevm_sys_crosschain_contract_face.h" - -NS_BEG4(top, contract_runtime, evm, sys_contract) - -using evm_common::xvalidators_snapshot_t; -using evm_common::xvalidators_snap_info_t; - -class xtop_evm_heco_client_contract : public xtop_evm_crosschain_syscontract_face { -public: - xtop_evm_heco_client_contract() = default; - ~xtop_evm_heco_client_contract() override = default; - - bool init(const xbytes_t & rlp_bytes, state_ptr state); - bool sync(const xbytes_t & rlp_bytes, state_ptr state); - bool is_known(const u256 height, const xbytes_t & hash_bytes, state_ptr state) const; - bool is_confirmed(const u256 height, const xbytes_t & hash_bytes, state_ptr state) const; - bigint get_height(state_ptr state) const; - xheader_status_t query_height(const u256 height, state_ptr state) const; - bool reset(state_ptr state); - bool disable_reset(state_ptr state); - -private: - bool verify(const xeth_header_t & prev_header, const xeth_header_t & new_header, xvalidators_snapshot_t & snap, state_ptr state) const; - bool record(const xeth_header_t & header, const xvalidators_snapshot_t & snap, state_ptr state); - bool rebuild(const xeth_header_t & header, const xvalidators_snap_info_t & last_info, const xvalidators_snap_info_t & cur_info, state_ptr state); - void release(const bigint number, state_ptr state); - // last hash @160 - h256 get_last_hash(state_ptr state) const; - bool set_last_hash(const h256 hash, state_ptr state); - // effective hashes @161 - h256 get_effective_hash(const bigint height, state_ptr state) const; - bool set_effective_hash(const bigint height, const h256 hash, state_ptr state); - bool remove_effective_hash(const bigint height, state_ptr state); - // all hashes @162 - std::set get_hashes(const bigint height, state_ptr state) const; - bool set_hashes(const bigint height, const std::set & hashes, state_ptr state); - bool remove_hashes(const bigint height, state_ptr state); - // all headers @163 - bool get_header(const h256 hash, xeth_header_t & header, state_ptr state) const; - bool set_header(const h256 hash, const xeth_header_t & header, state_ptr state); - bool remove_header(const h256 hash, state_ptr state); - // headers info @164 - bool get_snap_info(const h256 hash, xvalidators_snap_info_t & snap_info, state_ptr state) const; - bool set_snap_info(const h256 hash, const xvalidators_snap_info_t & snap_info, state_ptr state); - bool remove_snap_info(const h256 hash, state_ptr state); - // flag @165 - int get_flag(state_ptr state) const; - bool set_flag(state_ptr state); -}; -using xevm_heco_client_contract_t = xtop_evm_heco_client_contract; - -NS_END4 +//// Copyright (c) 2017-present Telos Foundation & contributors +//// Distributed under the MIT software license, see the accompanying +//// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +//#pragma once +// +//#include "xdata/xnative_contract_address.h" +//#include "xevm_common/xcrosschain/xeth_header.h" +//#include "xevm_common/xcrosschain/xvalidators_snapshot.h" +//#include "xevm_contract_runtime/xevm_sys_crosschain_contract_face.h" +// +//NS_BEG4(top, contract_runtime, evm, sys_contract) +// +//using evm_common::xvalidators_snapshot_t; +//using evm_common::xvalidators_snap_info_t; +// +//class xtop_evm_heco_client_contract : public xtop_evm_crosschain_syscontract_face { +//public: +// xtop_evm_heco_client_contract() = default; +// ~xtop_evm_heco_client_contract() override = default; +// +// bool init(const xbytes_t & rlp_bytes, state_ptr state); +// bool sync(const xbytes_t & rlp_bytes, state_ptr state); +// bool is_known(const u256 height, const xbytes_t & hash_bytes, state_ptr state) const; +// bool is_confirmed(const u256 height, const xbytes_t & hash_bytes, state_ptr state) const; +// bigint get_height(state_ptr state) const; +// xheader_status_t query_height(const u256 height, state_ptr state) const; +// bool reset(state_ptr state); +// bool disable_reset(state_ptr state); +// +//private: +// bool verify(const xeth_header_t & prev_header, const xeth_header_t & new_header, xvalidators_snapshot_t & snap, state_ptr state) const; +// bool record(const xeth_header_t & header, const xvalidators_snapshot_t & snap, state_ptr state); +// bool rebuild(const xeth_header_t & header, const xvalidators_snap_info_t & last_info, const xvalidators_snap_info_t & cur_info, state_ptr state); +// void release(const bigint number, state_ptr state); +// // last hash @160 +// h256 get_last_hash(state_ptr state) const; +// bool set_last_hash(const h256 hash, state_ptr state); +// // effective hashes @161 +// h256 get_effective_hash(const bigint height, state_ptr state) const; +// bool set_effective_hash(const bigint height, const h256 hash, state_ptr state); +// bool remove_effective_hash(const bigint height, state_ptr state); +// // all hashes @162 +// std::set get_hashes(const bigint height, state_ptr state) const; +// bool set_hashes(const bigint height, const std::set & hashes, state_ptr state); +// bool remove_hashes(const bigint height, state_ptr state); +// // all headers @163 +// bool get_header(const h256 hash, xeth_header_t & header, state_ptr state) const; +// bool set_header(const h256 hash, const xeth_header_t & header, state_ptr state); +// bool remove_header(const h256 hash, state_ptr state); +// // headers info @164 +// bool get_snap_info(const h256 hash, xvalidators_snap_info_t & snap_info, state_ptr state) const; +// bool set_snap_info(const h256 hash, const xvalidators_snap_info_t & snap_info, state_ptr state); +// bool remove_snap_info(const h256 hash, state_ptr state); +// // flag @165 +// int get_flag(state_ptr state) const; +// bool set_flag(state_ptr state); +//}; +//using xevm_heco_client_contract_t = xtop_evm_heco_client_contract; +// +//NS_END4 diff --git a/src/xtopcom/xevm_contract_runtime/xerror/xerror.h b/src/xtopcom/xevm_contract_runtime/xerror/xerror.h index 8f1afadaf..cb0042067 100644 --- a/src/xtopcom/xevm_contract_runtime/xerror/xerror.h +++ b/src/xtopcom/xevm_contract_runtime/xerror/xerror.h @@ -16,6 +16,18 @@ enum class xenum_errc { precompiled_contract_erc20_mint, precompiled_contract_erc20_burn, + + bsc_unknown_ancestor, + bsc_snapshot_not_found, + bsc_invalid_gas_limit, + bsc_invalid_gas_used, + bsc_invalid_extra_data, + bsc_invalid_attestation, + bsc_header_missing_excess_blob_gas, + bsc_header_missing_blob_gas_used, + bsc_blob_gas_used_exceeds_maximum_allowance, + bsc_blob_gas_used_not_a_multiple_of_blob_gas_per_blob, + bsc_invalid_excess_blob_gas, }; using xerrc_t = xenum_errc; diff --git a/src/xtopcom/xrpc/xrule_manager.h b/src/xtopcom/xrpc/xrule_manager.h index 1b00d7f2c..cb4b5fbc6 100644 --- a/src/xtopcom/xrpc/xrule_manager.h +++ b/src/xtopcom/xrpc/xrule_manager.h @@ -34,8 +34,6 @@ NS_BEG2(top, xrpc) using filter_handler = std::function; -#define ADDRESS_LENGTH 35 - class xfilter_manager { public: xfilter_manager(); diff --git a/src/xtopcom/xstatestore/xstatestore_face.h b/src/xtopcom/xstatestore/xstatestore_face.h index c91980ddf..70a66f707 100644 --- a/src/xtopcom/xstatestore/xstatestore_face.h +++ b/src/xtopcom/xstatestore/xstatestore_face.h @@ -60,9 +60,9 @@ class xstatestore_face_t { virtual bool accountindex_cache_unbroken(base::xvblock_t * table_block) const = 0; virtual bool get_accountindex_by_recent_blocks_cache(common::xaccount_address_t const & account_address, base::xvblock_t * table_block, base::xaccount_index_t & account_index) const = 0; virtual bool get_accountindex(const std::string& table_height, common::xaccount_address_t const & account_address, base::xaccount_index_t & account_index) const = 0; - virtual bool get_accountindex(xblock_number_t number, common::xtable_address_t const & table_address, common::xaccount_address_t const & account_address, base::xaccount_index_t & account_index) const = 0; - virtual bool get_accountindex(xblock_number_t number, common::xaccount_address_t const & account_address, base::xaccount_index_t & account_index) const = 0; - virtual data::xaccountstate_ptr_t get_accountstate(xblock_number_t number, common::xaccount_address_t const & account_address) const = 0; + virtual bool get_accountindex(top::xblock_number_t number, common::xtable_address_t const & table_address, common::xaccount_address_t const & account_address, base::xaccount_index_t & account_index) const = 0; + virtual bool get_accountindex(top::xblock_number_t number, common::xaccount_address_t const & account_address, base::xaccount_index_t & account_index) const = 0; + virtual data::xaccountstate_ptr_t get_accountstate(top::xblock_number_t number, common::xaccount_address_t const & account_address) const = 0; virtual std::vector> get_all_accountindex(base::xvblock_t * table_block, std::error_code & ec) const = 0; virtual base::xvblock_ptr_t get_unit_block(xblock_number_t number, common::xaccount_address_t const & account_address) const = 0; diff --git a/src/xtopcom/xunit_service/src/xcons_service.cpp b/src/xtopcom/xunit_service/src/xcons_service.cpp index 6fd8832d0..8e017fc6c 100644 --- a/src/xtopcom/xunit_service/src/xcons_service.cpp +++ b/src/xtopcom/xunit_service/src/xcons_service.cpp @@ -57,6 +57,8 @@ bool xcons_service_t::unreg(const xvip2_t & xip) { bool xcons_service_t::destroy(const xvip2_t & xip) { xunit_info("xcons_service_t::destroy %s this=%p", xcons_utl::xip_to_hex(xip).c_str(), this); m_dispatcher->destroy(xip); + auto network_proxy = m_para->get_resources()->get_network(); + network_proxy->unlisten(xip, get_msg_category()); running_ = false; return true; } diff --git a/src/xtopcom/xunit_service/src/xnetwork_proxy.cpp b/src/xtopcom/xunit_service/src/xnetwork_proxy.cpp index e5bc813f7..b0fabdf8b 100644 --- a/src/xtopcom/xunit_service/src/xnetwork_proxy.cpp +++ b/src/xtopcom/xunit_service/src/xnetwork_proxy.cpp @@ -201,24 +201,57 @@ bool xnetwork_proxy::unlisten(const xvip2_t & addr, common::xmessage_category_t xkinfo("[xunitservice] network unlisten %s msg:%x %p", xcons_utl::xip_to_hex(addr).c_str(), category, this); { std::lock_guard lock(m_mutex); + auto iter = m_networks.find(addr); if (iter != m_networks.end()) { - auto network = iter->second; + auto const & network = iter->second; // unregister virtual network message callback network->unregister_message_ready_notify(category); + } else { + for (iter = m_networks.begin(); iter != m_networks.end(); ++iter) { + auto & network_xip = iter->first; + common::xip2_t const group_xip2 = common::xip2_t{network_xip}.group_xip2(); + xvip2_t network_group_xip = {group_xip2.raw_low_part(), group_xip2.raw_high_part()}; + if (xcons_utl::xip_equals(addr, network_group_xip)) { + auto const & network = iter->second; + network->unregister_message_ready_notify(category); + break; + } + } } + // erase bridge callback auto listen_iter = m_reactors.find(addr); if (listen_iter != m_reactors.end()) { // add category to callback map auto & cb_map = listen_iter->second; - auto cb_iter = cb_map.find(category); + auto const cb_iter = cb_map.find(category); if (cb_iter != cb_map.end()) { cb_map.erase(cb_iter); } if (cb_map.empty()) { m_reactors.erase(listen_iter); } + } else { + for (listen_iter = m_reactors.begin(); listen_iter != m_reactors.end();) { + auto & reactor_xip = listen_iter->first; + common::xip2_t const group_xip2 = common::xip2_t{reactor_xip}.group_xip2(); + xvip2_t reactor_group_xip = {group_xip2.raw_low_part(), group_xip2.raw_high_part()}; + if (xcons_utl::xip_equals(addr, reactor_group_xip)) { + auto & cb_map = listen_iter->second; + auto const cb_iter = cb_map.find(category); + if (cb_iter != cb_map.end()) { + cb_map.erase(cb_iter); + } + if (cb_map.empty()) { + listen_iter = m_reactors.erase(listen_iter); + } else { + ++listen_iter; + } + } else { + ++listen_iter; + } + } } } return true; diff --git a/src/xtopcom/xvm/xcontract/xcontract_register.h b/src/xtopcom/xvm/xcontract/xcontract_register.h index 147ddf2ad..90c202869 100644 --- a/src/xtopcom/xvm/xcontract/xcontract_register.h +++ b/src/xtopcom/xvm/xcontract/xcontract_register.h @@ -19,49 +19,49 @@ using std::shared_ptr; * @brief contract register * */ -class xcontract_register { -public: - - /** - * @brief get the registered contract map object - * - * @return std::unordered_map>& - */ - static std::unordered_map>& get_contract_map() { - static std::unordered_map> contract_map; - return contract_map; - } - - /** - * @brief Construct a new xcontract register object - * - * @param name the contract name - * @param contract_ptr the contract object ptr - */ - xcontract_register(const string& name, shared_ptr contract_ptr) { - printf("%s\n", name.c_str()); - get_contract_map()[name]= contract_ptr; - } - - /** - * @brief Get the contract object - * - * @param name the contract name - * @return shared_ptr - */ - static shared_ptr get_contract(const std::string& name) { - auto contract = get_contract_map().find(name); - if (contract != get_contract_map().end()) { - return contract->second; - } - return nullptr; - } -}; - -#define REGISTER_NAME_CONTRACT(...) OVERLOADED_MACRO(REGISTER_NAME_CONTRACT, __VA_ARGS__) - -#define REGISTER_NAME_CONTRACT2(name, contract) static xcontract_register COMBINE_NAME(__contract_, __COUNTER__) (name, std::make_shared()) - -#define REGISTER_NAME_CONTRACT3(name, contract, helper) static xcontract_register COMBINE_NAME(__contract_, __COUNTER__) (name, std::make_shared(helper)) +//class xcontract_register { +//public: +// +// /** +// * @brief get the registered contract map object +// * +// * @return std::unordered_map>& +// */ +// static std::unordered_map>& get_contract_map() { +// static std::unordered_map> contract_map; +// return contract_map; +// } +// +// /** +// * @brief Construct a new xcontract register object +// * +// * @param name the contract name +// * @param contract_ptr the contract object ptr +// */ +// xcontract_register(const string& name, shared_ptr contract_ptr) { +// printf("%s\n", name.c_str()); +// get_contract_map()[name]= contract_ptr; +// } +// +// /** +// * @brief Get the contract object +// * +// * @param name the contract name +// * @return shared_ptr +// */ +// static shared_ptr get_contract(const std::string& name) { +// auto contract = get_contract_map().find(name); +// if (contract != get_contract_map().end()) { +// return contract->second; +// } +// return nullptr; +// } +//}; +// +//#define REGISTER_NAME_CONTRACT(...) OVERLOADED_MACRO(REGISTER_NAME_CONTRACT, __VA_ARGS__) +// +//#define REGISTER_NAME_CONTRACT2(name, contract) static xcontract_register COMBINE_NAME(__contract_, __COUNTER__) (name, std::make_shared()) +// +//#define REGISTER_NAME_CONTRACT3(name, contract, helper) static xcontract_register COMBINE_NAME(__contract_, __COUNTER__) (name, std::make_shared(helper)) NS_END3 diff --git a/src/xtopcom/xvm/xsystem_contracts/xelection/xelect_consensus_group_contract.h b/src/xtopcom/xvm/xsystem_contracts/xelection/xelect_consensus_group_contract.h index d00d54cc8..0d1cb8837 100644 --- a/src/xtopcom/xvm/xsystem_contracts/xelection/xelect_consensus_group_contract.h +++ b/src/xtopcom/xvm/xsystem_contracts/xelection/xelect_consensus_group_contract.h @@ -35,15 +35,15 @@ class xtop_election_awared_data final { ~xtop_election_awared_data() = default; xtop_election_awared_data(common::xnode_id_t const & account, - uint64_t const stake, - uint64_t const comprehensive_stake, + uint64_t stake, + uint64_t comprehensive_stake, xpublic_key_t const & public_key, common::xminer_type_t miner_type, bool genesis, uint64_t raw_credit_score); xtop_election_awared_data(common::xnode_id_t const & account, - uint64_t const stake, + uint64_t stake, xpublic_key_t const & public_key, common::xminer_type_t miner_type, bool genesis, @@ -123,9 +123,9 @@ class xtop_elect_consensus_group_contract : public xelect_group_contract_t { bool elect_group(common::xzone_id_t const & zid, common::xcluster_id_t const & cid, common::xgroup_id_t const & gid, - common::xlogic_time_t const election_timestamp, - common::xlogic_time_t const start_time, - std::uint64_t const random_seed, + common::xlogic_time_t election_timestamp, + common::xlogic_time_t start_time, + std::uint64_t random_seed, xrange_t const & group_size_range, data::election::xstandby_network_result_t const & standby_network_result, data::election::xelection_network_result_t & election_network_result) override; @@ -137,7 +137,7 @@ class xtop_elect_consensus_group_contract : public xelect_group_contract_t { common::xzone_id_t const & zid, common::xcluster_id_t const & cid, common::xgroup_id_t const & gid, - common::xnode_type_t const node_type, + common::xnode_type_t node_type, data::election::xelection_group_result_t & election_group_result) const; /** @@ -148,7 +148,7 @@ class xtop_elect_consensus_group_contract : public xelect_group_contract_t { common::xzone_id_t const & zid, common::xcluster_id_t const & cid, common::xgroup_id_t const & gid, - common::xnode_type_t const node_type, + common::xnode_type_t node_type, data::election::xelection_group_result_t & election_group_result) const; /** @@ -167,9 +167,9 @@ class xtop_elect_consensus_group_contract : public xelect_group_contract_t { bool do_normal_election(common::xzone_id_t const & zid, common::xcluster_id_t const & cid, common::xgroup_id_t const & gid, - common::xnode_type_t const node_type, - common::xminer_type_t const role_type, - std::uint64_t const random_seed, + common::xnode_type_t node_type, + common::xminer_type_t role_type, + std::uint64_t random_seed, xrange_t const & group_size_range, data::election::xstandby_result_t const & standby_result, data::election::xelection_group_result_t & current_group_nodes); @@ -180,7 +180,7 @@ class xtop_elect_consensus_group_contract : public xelect_group_contract_t { * @param zid Zone id * @param cid Cluster id * @param gid Group id - * @param node_type + * @param node_type Node type * @param random_seed Random seed for FTS algorithm internally used by election process * @param shrink_size current_group_size minus max_group_size * @param standby_result Standby pool @@ -191,8 +191,8 @@ class xtop_elect_consensus_group_contract : public xelect_group_contract_t { bool do_shrink_election(common::xzone_id_t const & zid, common::xcluster_id_t const & cid, common::xgroup_id_t const & gid, - common::xnode_type_t const node_type, - std::uint64_t const random_seed, + common::xnode_type_t node_type, + std::uint64_t random_seed, std::size_t shrink_size, data::election::xstandby_result_t const & standby_result, data::election::xelection_group_result_t & current_group_nodes) const; diff --git a/tests/xevm_contract_runtime/test_evm_bsc_client_contract.cpp b/tests/xevm_contract_runtime/test_evm_bsc_client_contract.cpp index eb070d134..208cbbe1f 100644 --- a/tests/xevm_contract_runtime/test_evm_bsc_client_contract.cpp +++ b/tests/xevm_contract_runtime/test_evm_bsc_client_contract.cpp @@ -1,148 +1,148 @@ -#include "tests/xevm_contract_runtime/test_evm_eth_bridge_contract_fixture.h" -#include "xbasic/xhex.h" -#include "xcommon/rlp.h" -#include "xevm_common/xabi_decoder.h" -#include "xevm_common/xcrosschain/xvalidators_snapshot.h" -#include "xevm_contract_runtime/sys_contract/xevm_bsc_client_contract.h" - -#define private public -#include "xevm_common/xcrosschain/xeth_header.h" -#include "xevm_contract_runtime/xevm_sys_contract_face.h" - -namespace top { -namespace tests { - -using namespace contract_runtime::evm::sys_contract; -using namespace evm_common; - -class xbsc_contract_fixture_t : public testing::Test { -public: - xbsc_contract_fixture_t() { - } - - void init() { - auto bstate = make_object_ptr( - evm_eth_bridge_contract_address.to_string(), (uint64_t)0, (uint64_t)0, std::string(), std::string(), (uint64_t)0, (uint32_t)0, (uint16_t)0); - auto canvas = make_object_ptr(); - bstate->new_string_map_var(data::system_contract::XPROPERTY_HEADERS, canvas.get()); - bstate->new_string_map_var(data::system_contract::XPROPERTY_HEADERS_SUMMARY, canvas.get()); - bstate->new_string_map_var(data::system_contract::XPROPERTY_ALL_HASHES, canvas.get()); - bstate->new_string_map_var(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, canvas.get()); - bstate->new_string_var(data::system_contract::XPROPERTY_LAST_HASH, canvas.get()); - auto bytes = (evm_common::h256(0)).asBytes(); - bstate->load_string_var(data::system_contract::XPROPERTY_LAST_HASH)->reset({bytes.begin(), bytes.end()}, canvas.get()); - contract_state = std::make_shared(bstate.get(), bstate.get()); - statectx = top::make_unique(contract_state); - statectx_observer = make_observer(statectx.get()); - context.address = common::xtop_eth_address::build_from("ff00000000000000000000000000000000000003"); - context.caller = common::xtop_eth_address::build_from("f8a1e199c49c2ae2682ecc5b4a8838b39bab1a38"); - } - - void SetUp() override { - init(); - } - - void TearDown() override { - } - - contract_runtime::evm::sys_contract::xevm_bsc_client_contract_t contract; - data::xunitstate_ptr_t contract_state; - std::unique_ptr statectx; - observer_ptr statectx_observer; - contract_runtime::evm::sys_contract_context context; -}; - -#include "tests/xevm_contract_runtime/test_evm_bsc_client_contract_data.cpp" - -// TEST(test, test) { -// auto rlp_bytes = from_hex(heco_sync_17276012_hex); -// // auto decode_items = RLP::decode(rlp_bytes); -// // printf("%lu, %lu\n", decode_items.decoded.size(), decode_items.remainder.size()); - -// auto left_bytes = std::move(rlp_bytes); -// while (left_bytes.size() != 0) { -// RLP::DecodedItem item = RLP::decode(left_bytes); -// auto decoded_size = item.decoded.size(); -// if (decoded_size < 4) { -// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); -// return; -// } -// left_bytes = std::move(item.remainder); -// xeth_header_t header; -// { -// auto item_header = RLP::decode_once(item.decoded[0]); -// auto header_bytes = item_header.decoded[0]; -// if (header.decode_rlp(header_bytes) == false) { -// xwarn("[xtop_evm_eth_bridge_contract::sync] decode header error"); -// return; -// } -// } -// header.print(); - -// auto validator_num = static_cast(evm_common::fromBigEndian(item.decoded[1])); -// if (decoded_size < validator_num + 2 + 1) { -// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); -// return; -// } - -// heco::xheco_snapshot_t snap; -// snap.number = static_cast(header.number - 1); -// snap.hash = header.parent_hash; -// for (uint64_t i = 0; i < validator_num; ++i) { -// snap.validators.insert(item.decoded[i + 2]); -// printf("validator: %s\n", to_hex(item.decoded[i + 2]).c_str()); -// } - -// auto recent_num = static_cast(evm_common::fromBigEndian(item.decoded[1 + validator_num + 1])); -// if (decoded_size < validator_num + 2 + 1 + recent_num) { -// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); -// return; -// } - -// for (uint64_t i = 0; i < recent_num; ++i) { -// uint64_t k = static_cast(evm_common::fromBigEndian(item.decoded[1 + validator_num + 1 + 1 + i * 2])); -// snap.recents[k] = item.decoded[1 + validator_num + 1 + 1 + i * 2 + 1]; -// printf("recents: %lu, %s\n", k, to_hex(item.decoded[1 + validator_num + 1 + 1 + i * 2 + 1]).c_str()); -// } -// snap.print(); -// } -// } - -// TODO: delete +//#include "tests/xevm_contract_runtime/test_evm_eth_bridge_contract_fixture.h" +//#include "xbasic/xhex.h" +//#include "xcommon/rlp.h" +//#include "xevm_common/xabi_decoder.h" +//#include "xevm_common/xcrosschain/xvalidators_snapshot.h" +//#include "xevm_contract_runtime/sys_contract/xevm_bsc_client_contract.h" +// +//#define private public +//#include "xevm_common/xcrosschain/xeth_header.h" +//#include "xevm_contract_runtime/xevm_sys_contract_face.h" +// +//namespace top { +//namespace tests { +// +//using namespace contract_runtime::evm::sys_contract; +//using namespace evm_common; +// +//class xbsc_contract_fixture_t : public testing::Test { +//public: +// xbsc_contract_fixture_t() { +// } +// +// void init() { +// auto bstate = make_object_ptr( +// evm_eth_bridge_contract_address.to_string(), (uint64_t)0, (uint64_t)0, std::string(), std::string(), (uint64_t)0, (uint32_t)0, (uint16_t)0); +// auto canvas = make_object_ptr(); +// bstate->new_string_map_var(data::system_contract::XPROPERTY_HEADERS, canvas.get()); +// bstate->new_string_map_var(data::system_contract::XPROPERTY_HEADERS_SUMMARY, canvas.get()); +// bstate->new_string_map_var(data::system_contract::XPROPERTY_ALL_HASHES, canvas.get()); +// bstate->new_string_map_var(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, canvas.get()); +// bstate->new_string_var(data::system_contract::XPROPERTY_LAST_HASH, canvas.get()); +// auto bytes = (evm_common::h256(0)).asBytes(); +// bstate->load_string_var(data::system_contract::XPROPERTY_LAST_HASH)->reset({bytes.begin(), bytes.end()}, canvas.get()); +// contract_state = std::make_shared(bstate.get(), bstate.get()); +// statectx = top::make_unique(contract_state); +// statectx_observer = make_observer(statectx.get()); +// context.address = common::xtop_eth_address::build_from("ff00000000000000000000000000000000000003"); +// context.caller = common::xtop_eth_address::build_from("f8a1e199c49c2ae2682ecc5b4a8838b39bab1a38"); +// } +// +// void SetUp() override { +// init(); +// } +// +// void TearDown() override { +// } +// +// contract_runtime::evm::sys_contract::xevm_bsc_client_contract_t contract; +// data::xunitstate_ptr_t contract_state; +// std::unique_ptr statectx; +// observer_ptr statectx_observer; +// contract_runtime::evm::sys_contract_context context; +//}; +// +//#include "tests/xevm_contract_runtime/test_evm_bsc_client_contract_data.cpp" +// +// //TEST(test, test) { +// // auto rlp_bytes = from_hex(heco_sync_17276012_hex); +// // // auto decode_items = RLP::decode(rlp_bytes); +// // // printf("%lu, %lu\n", decode_items.decoded.size(), decode_items.remainder.size()); +// +// // auto left_bytes = std::move(rlp_bytes); +// // while (left_bytes.size() != 0) { +// // RLP::DecodedItem item = RLP::decode(left_bytes); +// // auto decoded_size = item.decoded.size(); +// // if (decoded_size < 4) { +// // xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); +// // return; +// // } +// // left_bytes = std::move(item.remainder); +// // xeth_header_t header; +// // { +// // auto item_header = RLP::decode_once(item.decoded[0]); +// // auto header_bytes = item_header.decoded[0]; +// // if (header.decode_rlp(header_bytes) == false) { +// // xwarn("[xtop_evm_eth_bridge_contract::sync] decode header error"); +// // return; +// // } +// // } +// // header.print(); +// +// // auto validator_num = static_cast(evm_common::fromBigEndian(item.decoded[1])); +// // if (decoded_size < validator_num + 2 + 1) { +// // xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); +// // return; +// // } +// +// // heco::xheco_snapshot_t snap; +// // snap.number = static_cast(header.number - 1); +// // snap.hash = header.parent_hash; +// // for (uint64_t i = 0; i < validator_num; ++i) { +// // snap.validators.insert(item.decoded[i + 2]); +// // printf("validator: %s\n", to_hex(item.decoded[i + 2]).c_str()); +// // } +// +// // auto recent_num = static_cast(evm_common::fromBigEndian(item.decoded[1 + validator_num + 1])); +// // if (decoded_size < validator_num + 2 + 1 + recent_num) { +// // xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); +// // return; +// // } +// +// // for (uint64_t i = 0; i < recent_num; ++i) { +// // uint64_t k = static_cast(evm_common::fromBigEndian(item.decoded[1 + validator_num + 1 + 1 + i * 2])); +// // snap.recents[k] = item.decoded[1 + validator_num + 1 + 1 + i * 2 + 1]; +// // printf("recents: %lu, %s\n", k, to_hex(item.decoded[1 + validator_num + 1 + 1 + i * 2 + 1]).c_str()); +// // } +// // snap.print(); +// // } +// //} +// +//// TODO: delete // TEST_F(xbsc_contract_fixture_t, test_bsc_init) { // auto bytes = top::from_hex(bsc_init_20250000_hex); // EXPECT_TRUE(contract.init(bytes, contract_state)); // } - -TEST_F(xbsc_contract_fixture_t, test_parse_validators) { - const char * header_hex = "f90403a0c18af239fc81de948d4f7785b1ea8c70eaa23283a1ca29f7bfbd164f91d37201a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794be807dddb074639cd9fa61b47676c064fc50d62ca0cce0dfc134ef9611ed22535b05e1ff39ada7eef0613f62311b11e8af31243225a034000ae64d1693c21abfdce1af136c2b2ebfea48626add1a911a08642830d532a0bc20983deafc6035dd81cf7fea6aff00d6a06e2b2c1db78236e3b97123a9c849b9010000a222890b00c03030240001920c04e014000010e610a5a444300000281045a24080144201801012efe020d190c04032007900d106b00d60e10320402b3f00801e04882055301818013000080501502162100c000cc408908a04320298080000409014ec0e472018904b80c40508892288604042ce84848682240018880004297a04100124090d4000c21210285608a78c651407000a0409011009730027882002394100110952c03610a0218a0a880472000912090083a51208200005620828602c691208064d2722a048001a00d0c0b2429106e90170b109414b831000e0a12070542804434960d1c4848100ca920140027461a1000854200201380008309102840134fd908404c54a9b834ef0368462f07be6b90205d88301010b846765746888676f312e31332e34856c696e75780000005d43d2fd2465176c461afb316ebc773c61faee85a6515daa295e26495cef6f69dfa69911d9d8e4f3bbadb89b2b3a6c089311b478bf629c29d790a7a6db3fc1b92d4c407bbe49438ed859fe965b140dcf1aab71a93f349bbafec1551819b8be1efea2fc46ca749aa161dd481a114a2e761c554b641742c973867899d3685b1ded8013785d6623cc18d214320b6bb6475970f657164e5b75689b64b7fd1fa275f334f28e1872b61c6014342d914470ec7ac2975be345796c2b7ae2f5b9e386cd1b50a4550696d957cb4900f03a8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec739f8ccdafcc39f3c7d6ebf637c9151673cbc36b88a6f79b60359f141df90a0c745125b131caaffd12aacf6a8119f7e11623b5a43da638e91f669a130fac0e15a038eedfc68ba3c35c73fed5be4a07afb5be807dddb074639cd9fa61b47676c064fc50d62ce2d3a739effcd3a99387d015e260eefac72ebea1e9ae3261a475a27bb1028f140bc2a7c843318afdea0a6e3c511bbd10f4519ece37dc24887e11b55dee226379db83cffc681495730c11fdde79ba4c0cef0274e31810c9df02f98fafde0f841f4e66a1cd5f0b40e8f4d4c857f4ea521ab99410c2a3d370e1f9f38fc5fa195eb3ed7707fc2f3fd6541d5041cbd30ee63f1aced286eefe989742716965d9927ca0d09e635b01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"; - auto bytes = top::from_hex(header_hex); - xeth_header_t header; - header.decode_rlp(bytes); - xvalidators_snapshot_t snap; - EXPECT_TRUE(snap.init_with_epoch(header)); - for (auto v : snap.validators) { - printf("%s\n", v.to_hex_string().c_str()); - } -} - -char const * init_error_hex = "0xf90403a004004c5e9a630b79eb53a9330f1db5516e696b37939e6c16bc6d576a9c2f4e2ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347947ae2f5b9e386cd1b50a4550696d957cb4900f03aa06f05252cf338cb174ef46bf08694ea5840e877f6175ca83da84884d9df7d9eb7a05f7ebfbc2e8173aca9381d7a2be5e0f27e5dd5533fbb7c8f58c8478ee0db99afa01cb53ebec99f61785f66f505e1125c681cada89cf1ff222d2d3e4b9cfcf0dcabb901004aa002011440135032d4003880349408010c030ae0448000e013040844180830438297084c8100050a98000829235020221420401a8680a2630e104f326002005000168845413800093c808980280aa86298010953400597225606519881030249ac28a54bfa0033844320d18c881d212b08002408b2448a86040a1952a101285c000321029315622888368209518810056d4c8b140205886014105902df60698380c16030808471222841c11aa04600442c80614784000506ae18222602682001300c0622420142404822401a241e40266033ec0140431725084e4a10dbb000c0511523a0c188e00382209809158800212811089ca6824812c1103181a009950284016ea1d084084fda76836c411284639fd11db90205d983010112846765746889676f312e31372e3133856c696e757800005b7663b52465176c461afb316ebc773c61faee85a6515daa295e26495cef6f69dfa69911d9d8e4f3bbadb89b2d4c407bbe49438ed859fe965b140dcf1aab71a93f349bbafec1551819b8be1efea2fc46ca749aa161dd481a114a2e761c554b641742c973867899d3685b1ded8013785d6623cc18d214320b6bb6475970f657164e5b75689b64b7fd1fa275f334f28e1872b61c6014342d914470ec7ac2975be345796c2b7ae2f5b9e386cd1b50a4550696d957cb4900f03a8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a6f79b60359f141df90a0c745125b131caaffd12ac0e15a038eedfc68ba3c35c73fed5be4a07afb5b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b4dd66d7c2c7e57f628210187192fb89d4b99dd4be807dddb074639cd9fa61b47676c064fc50d62ccc8e6d00c17eb431350c6c50d8b8f05176b90b11d1d6bf74282782b0b3eb1413c901d6ecf02e8e28e9ae3261a475a27bb1028f140bc2a7c843318afdea0a6e3c511bbd10f4519ece37dc24887e11b55dee226379db83cffc681495730c11fdde79ba4c0cef0274e31810c9df02f98fafde0f841f4e66a1cdd539b90275d3acaf234ebb7c6c4255d050f0e106b5df0abc8ec502c69c41c8c7462ea969f2c73ff563111d1439634192c240c6e3b5219939721b3892c2a7423000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0084568f6edef5dabf3411d8b9111f8223c698b2b35fc1f07f21a8df8ca0d0956a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a0872650568946f7b2038a3fdede4b429f877ce0fa7da802cea11b0bed9244fce5a019dcbc248159cdc168f8bfc3dd762b670c828bbdebd63977c778f9b3513faf44a0a9f83e19f3470bab2e071515088f0f189817f20401dddd18fbd889759e7029d7b9010040b2074b80de1a140b0438c491926008b64a235151446480745111c50487c53a020894088410151e82298e0084611000210084000aa640a0664c062a182e2a080c048028800ba249019304d9c3a102bc661d0009434428a323f61029a8b0042c02042db20ee330434629ca1080088f130a8000400068de4d5046569134c10ca210040b260888920047a19f11214450089d762485540e02ea2d3a407000f03020120025421a401018664526da4e91542048f480582b22005b5cf8090b6120000421206c070094524206222049000212022c7221a011c800119286082e400cf140091a1222a453a46b230ac2902b4020c04ab0043a180a92dd024a1f324ab58a900284016ea1d18408582a4f837c6b0984639fd120b861d683010112846765746886676f312e3139856c696e757800000000005b7663b5ceb94a368df9745376169819aed6854589878eb45818e78715676d1576aed6a72ebf594d74596b1c606855cce31ed1d43bfe2176ae8c48197553924dfc6287bb00a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea07a28cfeb30370f061445f01d532e54176f947b5e6e8b4618a05615159945bc6aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794a6f79b60359f141df90a0c745125b131caaffd12a08a99982afb361c30f6057ee604d6a8973014f37c265a1c0e0e63d116dc8cf674a044f01f6a940f3088b413025712e94287274542b15bbad0625ea209fa4dcb18ffa0b7ea2d73cc3a563319cd10b2813c17cbcbc1259112f11967b0b4767278a1436bb90100c8308290c7d018102224d404b01ae8203100022080212400201000009100b03004002444b482100e4304202110008422a5021142000080044800422e00602a11149400424201000591221428e68001a0223ea299885248c295063a4888100985000030280ac200111205000480320c44aa01886088c085c06066f25888a70c0114c888a517050ba8009014a40057500a0475840554062b8801092064011409260a82450b190a1032ab8c40a93bce4cc0482200a000040305904060082182286a65020d0b001202624002244b6030121121d32dec211840198102108a214ef0a800385c0905d380488b02888d414a000050a0041c0046016a09020e1208a042000284016ea1d284084fd226839ac16d84639fd123b861d883010112846765746888676f312e31392e32856c696e75780000005b7663b5c849b541ab8ecb37db64630ca3c6851f63e70014f61b724386dc38aa2543be1d0420e6dea4fb039066330e50699f4d7319f60ef9546dbf5249a2fd606fe76a0e01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0d88c9f59017e6b76f9086d8a22c1b10997c394974d9ad963a568214fc4b768d1a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ac0e15a038eedfc68ba3c35c73fed5be4a07afb5a032938bf8078064107e010b320ca7d66f5019a85330d8b2f8b946c73a2f7758f5a07fd18ff3d5678b41c91cc77c00005ce79edadaa3bbe2564265624efcd5127f75a0d7b5b36e2f318c6662556c28ff0c2b6157cd8d884b1ded46828feb60d153e1f1b901005270ce100444f694861e6244825a4484500013569004b4097854b16006000032c6221540d60714103964b072d1140410f811901814ea200243f8310ab42407800820149210b00120011a010b80a210a4a4180139434c2883b44c030c8809011080861ca08e820c60d803b848c4020c728f400af188c057148924735140859e009110f1283811020905e11c014c68190924240c9517073728091008440a8a88222302804110a900b119067020069a4308d40a080004042885020020c822020049a0000612018c0146210042198266722022d02320414800118618840b01abf121003202160041804c4100b4514745200040802e0068098a780200183303b744300284016ea1d384084782558376019084639fd126b861d983010112846765746889676f312e31372e3133856c696e757800005b7663b5323e80a2e03007c94b5965e69a102ab6921913ef831245ba33681804d3b2ce03660546277036892ce3609f06a7e35c0f726f5c82cb8b03e47cb6504a743e844a01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0cd3e35664d2c8a73fbe77cf6f8036763d75a96b63fa539a393cecce05ab4ee16a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b218c5d6af1f979ac42bc68d98a5a0d796c6ab01a0574870e05d7a85d847b82b86a81735f7d32aff5b8d11697d173f358196aaffc1a05a0d61cc0df65887ab237c7c0884c0ffd473021fa6830621f825293f05741f0ba01dd653ff9bd8487d22274d8eb1dfe9fbc403eecc2798296104c7b9ac88e40367b9010082720b009f080a14024c10b5a402108090492e4c1cd4a18022120a092040c53d4002a6812c081000f3e88053240060731800444204a00223722cf10e882402088a08274502160004014c9438a12928256819a68b415748a3d7040a00aaa22400080018268a030d70212024048858599bae0442c084c887200065a05b008d08c1867101ba04b019ec45a31140001758283074458516b0ac183530c8416893bc3026801400110002484840304913d645baee82402337ba250121f012182404188a018100070006c362491501180482128420162025d94444179603306e162ae44140500a20ac41487a110810880581000508840c28690592e80200336280e5489c0284016ea1d484083f3ad4837fc47e84639fd129b861d883010112846765746888676f312e31392e32856c696e75780000005b7663b57d995f67870ca39809195a97d1b6725afd7675ac13de9aa0075bc0b362a06a4474337e12d62709df28b2bd83813d901f88ea6ebecb759db4b6854375b200573301a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0188382c8555fa1aaf257c4055f4ede55192cbf82009df72d6ce96d9533394890a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b4dd66d7c2c7e57f628210187192fb89d4b99dd4a0c2b96414c2c110af9316832f1c491952f4be5425d5f96982850604186a2266e9a04b9d40b71f851c0b9f42cce80676c2bab39b8c09dd18ca39a70620400e8bcbe6a0f4940e144bd9d46fd5cbab8c5e63f1730075aca17e8a68ccf7cf46840b23250db90100c02a3781a3cd1e1122e4a8ae801f91b01000825a504724087a3523061012c1380412e55e9694121162348000c48108d418092990ab345a104709435e24a01b02d02034504ea282852d3270ac83a000f239db115a6a4a388220ed0912e8506f00238b09a14aa709829c5474b242042cb18f2082c944cb4e440025e23114894c0510840b24ea5104638da83c039c410a1c253f2d0554062738a104b368008604aea712c041a410001748894e4132ae70dc4210020a118a0815134d346d2513c20a3352240a46d01143dc0642bd51431a6d2115352181438558a611524b5108e8a5addba06165d18cc8f11026248f2946c231984c091c0cb56e0335fb2668a028340284016ea1d5840836fb9b83e0e05a84639fd12cb861d983010112846765746889676f312e31372e3133856c696e757800005b7663b55a4527d7d43f88487798555643364d3376d9b94a31826498304cd8633f72faa96edec4c2471c01dab3e7acefaa8cf2718bb5fc358ff758c986a982853fbd7e9b00a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0211a0aa45ddc02992a14df5914307c2541b275571d1fb9b1e70f14d6328461dba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794be807dddb074639cd9fa61b47676c064fc50d62ca00c72c47f58cdbc93d96c0de42170fcd493a6c8f52dbf2a48007a056d98355202a021f2b3fcea5f7aaa8f20e33ba67e2cf9443cef9c677b1539e2647882e2ab452ca0e9b86284169565b52f7992bd854c166fa4b8502913365b2cea7c8c2690f6834db90100c56412220b1836164a55846ecc701100600c0718545235003035a425b113917a6114d64881801000c8159030e40052214200914888171a20464cd94b32af3200a483a2c030d1e6614d3029c9a1a028e430d92448135028c214b56b42e8a8da44220806a54baa2e953c0b19009142ac802f1b08ea250135468827013800eb48401182c22c015268a2e2bc96d0dc40be41042f6d86142302ac3309be5900a03028be8220401c91b0100d00cb7142e00e50166c1805040a900522ec00bfe242000000862502081c4fc31000520901425641ad402124037f505386421d4e100ae8a8297875c90d77d26821021042cba7218409800ec889d8b01802020a0201ed58aa0284016ea1d684083f329583908df484639fd12fb861d983010112846765746889676f312e31372e3133856c696e757800005b7663b55a3b2bd95822c241ee047708ae9ca2c605eb36a16fcd1a971443b1255ea98ee216086a9e92bb52848f99ce0afcd5485bde47075e64778c2f66a949f0d22504df01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0656268cd8e612dbe4fd3eb4d546cbc3b71e57ac396c5b9b975488e7a1236f86da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794cc8e6d00c17eb431350c6c50d8b8f05176b90b11a01f8fde897379b878743526153c0af60b3c1915b89c339f7bd7a35523bd33ab1ba079140c5af546f5f7e9f8765fb33b3d44d89a440e7682d87223ecc3e61c0676bba0a0a00bddb60fa91d4d17b97f9b68f497bbb44a7c61646e19f5e49cfb48af76bdb901008624073c1e0012304680502c8802212f710404041025a0042111000c010100400000456a402130502314885180805692a8ac0000882800145210610801a500063094231810002981452a082a89084d382030300108c628a0a43d040c8c000a2d801032341a960c0241000100b8885aa10822604485341c000664d61300314c04110042000c01800800e015130102181222259f051480062c2912e0410d068922264290faf88ba818200434a262ee2348e5ca4025030411591a117103201a212821120442101a005e0c400809581012102101410c406427319606b092a42ae821c01000c00109014207411210050400025ac80c405848c978020b801680e14a8f0284016ea1d7840836f3648359aa1884639fd132b861d983010112846765746889676f312e31372e3133856c696e757800005b7663b53ee87f6349403fe40204bc647cd517aab53651cdc29e5f69e811c4f176f3b28e6d801e90dddc695a8e8e531c5d2406c86e930592ea1361c32dd2d167c85afdf600a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0332078fc0d3bd8e4d9bbaa6251a03677ececf98b37d0ac0a182eed90d251164ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ce2fd7544e0b2cc94692d4a704debef7bcb61328a034d2ef3160a06d3ed862bda817d1b40e40e9210c650e3b4890e5b9f825ac5db0a00173f511d8856e3297fb80a051f2a991138ff57f482ad8cc467d2412ca0e4656a03b6d792432099652a390fcf9b3c6d1db1046044ab49aa2689e3c90b28a13320db9010060751f40c74c165a42053025a0931518a0235bd2bcc165c02c518112980c3fd024a24560f48c5240a3260f2a345d8f20aa830ab9a87b18335f8c23d69d367948b03220a30120876b6135156e99a360b8709af22914545ebac43666aaca0b2c4253183c314f2a7e21036f39e584208c8e4f6560f1a1e8663c0e240e19143d6f7f1459901046cb717007a09e5524e6dc21942f45a59e3b430c11984b4147825a2327a743f51deff4327e90542797cf4200484470e9e19b0f4579182ba5600629283124bd060199316607c9b5ef86427b3260669b4685293d18dec010cf3daae9211039f70b9f9d80d95b71741201c8818650889e044b1863e1866a0f4283a94a160284016ea1d884083f2a5683a4a32884639fd135b861d983010112846765746889676f312e31372e3133856c696e757800005b7663b5706db41fb5cecd664ec85f66a718966a8cb423622390c8a0e87a83ae361e911c6bdc2743193c954726e45dc445b1c5a3fc51614d8a6c0decff75e8269c2544c200a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea02f601b318ec4cc1de09aca45a409c235c60803a2983c7b740f1a825d36a5bb0ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794d1d6bf74282782b0b3eb1413c901d6ecf02e8e28a0feb91adbc056648743b59e5f46d9f4a6c2cdb652f23999da4fd1388d875442aba0148fabbfff39d0bb08f5efa897790057890688c27b07381ea21993773be3e574a00f13f82271037170b0939fb870890b163f233b80ca4e4d7bcee0dd059c1e77c7b90100482003900204439ac0041342ca7002408808226c1c168d002015008400a09164030006e18ce0141047b8a2f08066228085944080827aca00560ef10010a44a880210ec008000c5938130d10cad9015b4e01237e1025e20b2807400088e194f01004519281fa644620205815200000cab1ab00011a40c34140825a23964034610118b20000e01202804a4108080c1010064240401c5400a2eec05014911cd6a3222030e504608f0137c06241322db2100430022010082b50904403131614a610927120006100340435083020dc8a23a0026652b0a22c0cc10a259a042081aec211c1006110861d0504d0430008101040842182018680a844a069392020020489c0284016ea1d9840836eb2d83892bd484639fd138b861d883010112846765746888676f312e31392e32856c696e75780000005b7663b5c2df77037264db29bb3198dd7c518f11e4adac7dbea2bfd8784b874cbe0b9839039eacec0e2ba7641dad877de2043861d9562ebec29373b988c2b2ae74505e3f01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0bb9615180b11613d317044cc7e5f1b1473a2cc0541d5b36a42ab694a45a21adca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794e9ae3261a475a27bb1028f140bc2a7c843318afda06f7c5ddc54c1be027726e976042e00a04d551e9e3a8bb7011a11c3732fc16ff2a048c8c4de185849c03a5ff3ed8c630a42ff5ec1076275ecbde98213410e19a6d6a0255cba0529c2c9fa0d387086173489959b38524073822d50110fc4f04740e1d7b9010022214f016d0c1230522d001a81d280407018005cdc31810215d48820814101c00510544206228044d3b5845080860d7208e28ad00c3aa28a7b0c15424664e2029282a4020a292801412908c9c1bd03b2757d5048135420f3a48508008c20904080085b346b02a723a009190049029d851a2b007085880e8050665030000544845261b04e76590c6924e61e88a2d70008062d95c55e042c2c281992c1809a383aab8800001d8ad07a6a003239d3ca4142441e6920220207814c207080265a906821404422000a844a410042290a765602394c614bc589e819238104e6883fe8a3c0bc311503259469011c30000560002742852818436b4558828a488612f5589c0284016ea1da84083f2217837e6d4384639fd13bb861d983010112846765746889676f312e31372e3133856c696e757800005b7663b5a3fbb1383e889a9547b8b3d191de304707a35776593a974d3c8247aacfa2cc683482ce53a13996a036d5991b993c0cd5c3f0b047bd59c0c1e28c28f19ff83db401a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea013dbf66808dcb4d75f4c441c314327ef20d98bd57cd3b1a6323cca0969aec72fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ef0274e31810c9df02f98fafde0f841f4e66a1cda030d3b7e629a22f8f0644337fc7f6b597d0a09feb7b035c84ca8374997ed8bc0ba02bb37cab13137ebb70b85d69c6f6d4ead9f103878d8c130f3f6df0f172300b81a0eea403aabc4e4606157333a91a0767ea51a10b4fd82c8a133f3ce744a0c2c5c9b901006f24021445009730500e28d48006110050143206192c844020140ac82810813715020660e42b1018031014510002c250a00a1000420040305028030e00ec3a888a00035e04110a4597708088808840272818cc0f15540ea291a41602cc000400da091a2daaca2410200822cee001a8258e067042848226020425417040174500141011000ca1511806a096400400c8b306740405c622066839082046001a0a21ab0220012709005862403540628b0164a20600804ca0014360d9200c2402d829a1804822046040424402100310c2320826504020410c111167a3046b804ae02118503c4c49015840010410828112030048084c28c9cb4c481466836c002000040284016ea1db84084761388387781084639fd13eb861d883010112846765746888676f312e31382e32856c696e75780000005b7663b57c4fa9f941052ca2e7d1e1f07fdff9478bd9782e5849494beaa701a4a580e7c528f13d2bdac116022a2fe6adb66f077e2f560cbe511dc8342c4c7a984370552200a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"; - -TEST_F(xbsc_contract_fixture_t, test_init_error) { - auto const extra_hex = "0xd983010112846765746889676f312e31372e3133856c696e757800005b7663b50bac492386862ad3df4b666bc096b0505bb694da2465176c461afb316ebc773c61faee85a6515daa295e26495cef6f69dfa69911d9d8e4f3bbadb89b2d4c407bbe49438ed859fe965b140dcf1aab71a93f349bbafec1551819b8be1efea2fc46ca749aa161dd481a114a2e761c554b641742c973867899d3685b1ded8013785d6623cc18d214320b6bb6475972b61c6014342d914470ec7ac2975be345796c2b73564052d8e469ed0721c4e53379dc3c912289307ae2f5b9e386cd1b50a4550696d957cb4900f03a8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a6f79b60359f141df90a0c745125b131caaffd12ac0e15a038eedfc68ba3c35c73fed5be4a07afb5b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b4dd66d7c2c7e57f628210187192fb89d4b99dd4be807dddb074639cd9fa61b47676c064fc50d62ccc8e6d00c17eb431350c6c50d8b8f05176b90b11ce2fd7544e0b2cc94692d4a704debef7bcb61328d1d6bf74282782b0b3eb1413c901d6ecf02e8e28e9ae3261a475a27bb1028f140bc2a7c843318afdef0274e31810c9df02f98fafde0f841f4e66a1cde65173e67ad6055ed95d06a951e68b409809834183e59c65399bd74e50598d2c2ec062ff5cbf618ed049280624b90132c557042c7d5df8ba58a29564ef1980b901"; - auto const extra_bytes = from_hex(std::string{extra_hex}); - auto const init_error = from_hex(init_error_hex); - - auto const item = RLP::decode_once(init_error); - xeth_header_t header; - std::error_code ec; - header.decode_rlp(item.decoded[0], ec); - assert(!ec); - header.extra = extra_bytes; - auto b = header.encode_rlp(); - b += init_error; - EXPECT_TRUE(contract.init(b, contract_state)); -} - -} -} +// +//TEST_F(xbsc_contract_fixture_t, test_parse_validators) { +// const char * header_hex = "f90403a0c18af239fc81de948d4f7785b1ea8c70eaa23283a1ca29f7bfbd164f91d37201a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794be807dddb074639cd9fa61b47676c064fc50d62ca0cce0dfc134ef9611ed22535b05e1ff39ada7eef0613f62311b11e8af31243225a034000ae64d1693c21abfdce1af136c2b2ebfea48626add1a911a08642830d532a0bc20983deafc6035dd81cf7fea6aff00d6a06e2b2c1db78236e3b97123a9c849b9010000a222890b00c03030240001920c04e014000010e610a5a444300000281045a24080144201801012efe020d190c04032007900d106b00d60e10320402b3f00801e04882055301818013000080501502162100c000cc408908a04320298080000409014ec0e472018904b80c40508892288604042ce84848682240018880004297a04100124090d4000c21210285608a78c651407000a0409011009730027882002394100110952c03610a0218a0a880472000912090083a51208200005620828602c691208064d2722a048001a00d0c0b2429106e90170b109414b831000e0a12070542804434960d1c4848100ca920140027461a1000854200201380008309102840134fd908404c54a9b834ef0368462f07be6b90205d88301010b846765746888676f312e31332e34856c696e75780000005d43d2fd2465176c461afb316ebc773c61faee85a6515daa295e26495cef6f69dfa69911d9d8e4f3bbadb89b2b3a6c089311b478bf629c29d790a7a6db3fc1b92d4c407bbe49438ed859fe965b140dcf1aab71a93f349bbafec1551819b8be1efea2fc46ca749aa161dd481a114a2e761c554b641742c973867899d3685b1ded8013785d6623cc18d214320b6bb6475970f657164e5b75689b64b7fd1fa275f334f28e1872b61c6014342d914470ec7ac2975be345796c2b7ae2f5b9e386cd1b50a4550696d957cb4900f03a8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec739f8ccdafcc39f3c7d6ebf637c9151673cbc36b88a6f79b60359f141df90a0c745125b131caaffd12aacf6a8119f7e11623b5a43da638e91f669a130fac0e15a038eedfc68ba3c35c73fed5be4a07afb5be807dddb074639cd9fa61b47676c064fc50d62ce2d3a739effcd3a99387d015e260eefac72ebea1e9ae3261a475a27bb1028f140bc2a7c843318afdea0a6e3c511bbd10f4519ece37dc24887e11b55dee226379db83cffc681495730c11fdde79ba4c0cef0274e31810c9df02f98fafde0f841f4e66a1cd5f0b40e8f4d4c857f4ea521ab99410c2a3d370e1f9f38fc5fa195eb3ed7707fc2f3fd6541d5041cbd30ee63f1aced286eefe989742716965d9927ca0d09e635b01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"; +// auto bytes = top::from_hex(header_hex); +// xeth_header_t header; +// header.decode_rlp(bytes); +// xvalidators_snapshot_t snap; +// EXPECT_TRUE(snap.init_with_epoch(header)); +// for (auto v : snap.validators) { +// printf("%s\n", v.to_hex_string().c_str()); +// } +//} +// +//char const * init_error_hex = "0xf90403a004004c5e9a630b79eb53a9330f1db5516e696b37939e6c16bc6d576a9c2f4e2ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347947ae2f5b9e386cd1b50a4550696d957cb4900f03aa06f05252cf338cb174ef46bf08694ea5840e877f6175ca83da84884d9df7d9eb7a05f7ebfbc2e8173aca9381d7a2be5e0f27e5dd5533fbb7c8f58c8478ee0db99afa01cb53ebec99f61785f66f505e1125c681cada89cf1ff222d2d3e4b9cfcf0dcabb901004aa002011440135032d4003880349408010c030ae0448000e013040844180830438297084c8100050a98000829235020221420401a8680a2630e104f326002005000168845413800093c808980280aa86298010953400597225606519881030249ac28a54bfa0033844320d18c881d212b08002408b2448a86040a1952a101285c000321029315622888368209518810056d4c8b140205886014105902df60698380c16030808471222841c11aa04600442c80614784000506ae18222602682001300c0622420142404822401a241e40266033ec0140431725084e4a10dbb000c0511523a0c188e00382209809158800212811089ca6824812c1103181a009950284016ea1d084084fda76836c411284639fd11db90205d983010112846765746889676f312e31372e3133856c696e757800005b7663b52465176c461afb316ebc773c61faee85a6515daa295e26495cef6f69dfa69911d9d8e4f3bbadb89b2d4c407bbe49438ed859fe965b140dcf1aab71a93f349bbafec1551819b8be1efea2fc46ca749aa161dd481a114a2e761c554b641742c973867899d3685b1ded8013785d6623cc18d214320b6bb6475970f657164e5b75689b64b7fd1fa275f334f28e1872b61c6014342d914470ec7ac2975be345796c2b7ae2f5b9e386cd1b50a4550696d957cb4900f03a8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a6f79b60359f141df90a0c745125b131caaffd12ac0e15a038eedfc68ba3c35c73fed5be4a07afb5b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b4dd66d7c2c7e57f628210187192fb89d4b99dd4be807dddb074639cd9fa61b47676c064fc50d62ccc8e6d00c17eb431350c6c50d8b8f05176b90b11d1d6bf74282782b0b3eb1413c901d6ecf02e8e28e9ae3261a475a27bb1028f140bc2a7c843318afdea0a6e3c511bbd10f4519ece37dc24887e11b55dee226379db83cffc681495730c11fdde79ba4c0cef0274e31810c9df02f98fafde0f841f4e66a1cdd539b90275d3acaf234ebb7c6c4255d050f0e106b5df0abc8ec502c69c41c8c7462ea969f2c73ff563111d1439634192c240c6e3b5219939721b3892c2a7423000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0084568f6edef5dabf3411d8b9111f8223c698b2b35fc1f07f21a8df8ca0d0956a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a0872650568946f7b2038a3fdede4b429f877ce0fa7da802cea11b0bed9244fce5a019dcbc248159cdc168f8bfc3dd762b670c828bbdebd63977c778f9b3513faf44a0a9f83e19f3470bab2e071515088f0f189817f20401dddd18fbd889759e7029d7b9010040b2074b80de1a140b0438c491926008b64a235151446480745111c50487c53a020894088410151e82298e0084611000210084000aa640a0664c062a182e2a080c048028800ba249019304d9c3a102bc661d0009434428a323f61029a8b0042c02042db20ee330434629ca1080088f130a8000400068de4d5046569134c10ca210040b260888920047a19f11214450089d762485540e02ea2d3a407000f03020120025421a401018664526da4e91542048f480582b22005b5cf8090b6120000421206c070094524206222049000212022c7221a011c800119286082e400cf140091a1222a453a46b230ac2902b4020c04ab0043a180a92dd024a1f324ab58a900284016ea1d18408582a4f837c6b0984639fd120b861d683010112846765746886676f312e3139856c696e757800000000005b7663b5ceb94a368df9745376169819aed6854589878eb45818e78715676d1576aed6a72ebf594d74596b1c606855cce31ed1d43bfe2176ae8c48197553924dfc6287bb00a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea07a28cfeb30370f061445f01d532e54176f947b5e6e8b4618a05615159945bc6aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794a6f79b60359f141df90a0c745125b131caaffd12a08a99982afb361c30f6057ee604d6a8973014f37c265a1c0e0e63d116dc8cf674a044f01f6a940f3088b413025712e94287274542b15bbad0625ea209fa4dcb18ffa0b7ea2d73cc3a563319cd10b2813c17cbcbc1259112f11967b0b4767278a1436bb90100c8308290c7d018102224d404b01ae8203100022080212400201000009100b03004002444b482100e4304202110008422a5021142000080044800422e00602a11149400424201000591221428e68001a0223ea299885248c295063a4888100985000030280ac200111205000480320c44aa01886088c085c06066f25888a70c0114c888a517050ba8009014a40057500a0475840554062b8801092064011409260a82450b190a1032ab8c40a93bce4cc0482200a000040305904060082182286a65020d0b001202624002244b6030121121d32dec211840198102108a214ef0a800385c0905d380488b02888d414a000050a0041c0046016a09020e1208a042000284016ea1d284084fd226839ac16d84639fd123b861d883010112846765746888676f312e31392e32856c696e75780000005b7663b5c849b541ab8ecb37db64630ca3c6851f63e70014f61b724386dc38aa2543be1d0420e6dea4fb039066330e50699f4d7319f60ef9546dbf5249a2fd606fe76a0e01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0d88c9f59017e6b76f9086d8a22c1b10997c394974d9ad963a568214fc4b768d1a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ac0e15a038eedfc68ba3c35c73fed5be4a07afb5a032938bf8078064107e010b320ca7d66f5019a85330d8b2f8b946c73a2f7758f5a07fd18ff3d5678b41c91cc77c00005ce79edadaa3bbe2564265624efcd5127f75a0d7b5b36e2f318c6662556c28ff0c2b6157cd8d884b1ded46828feb60d153e1f1b901005270ce100444f694861e6244825a4484500013569004b4097854b16006000032c6221540d60714103964b072d1140410f811901814ea200243f8310ab42407800820149210b00120011a010b80a210a4a4180139434c2883b44c030c8809011080861ca08e820c60d803b848c4020c728f400af188c057148924735140859e009110f1283811020905e11c014c68190924240c9517073728091008440a8a88222302804110a900b119067020069a4308d40a080004042885020020c822020049a0000612018c0146210042198266722022d02320414800118618840b01abf121003202160041804c4100b4514745200040802e0068098a780200183303b744300284016ea1d384084782558376019084639fd126b861d983010112846765746889676f312e31372e3133856c696e757800005b7663b5323e80a2e03007c94b5965e69a102ab6921913ef831245ba33681804d3b2ce03660546277036892ce3609f06a7e35c0f726f5c82cb8b03e47cb6504a743e844a01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0cd3e35664d2c8a73fbe77cf6f8036763d75a96b63fa539a393cecce05ab4ee16a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b218c5d6af1f979ac42bc68d98a5a0d796c6ab01a0574870e05d7a85d847b82b86a81735f7d32aff5b8d11697d173f358196aaffc1a05a0d61cc0df65887ab237c7c0884c0ffd473021fa6830621f825293f05741f0ba01dd653ff9bd8487d22274d8eb1dfe9fbc403eecc2798296104c7b9ac88e40367b9010082720b009f080a14024c10b5a402108090492e4c1cd4a18022120a092040c53d4002a6812c081000f3e88053240060731800444204a00223722cf10e882402088a08274502160004014c9438a12928256819a68b415748a3d7040a00aaa22400080018268a030d70212024048858599bae0442c084c887200065a05b008d08c1867101ba04b019ec45a31140001758283074458516b0ac183530c8416893bc3026801400110002484840304913d645baee82402337ba250121f012182404188a018100070006c362491501180482128420162025d94444179603306e162ae44140500a20ac41487a110810880581000508840c28690592e80200336280e5489c0284016ea1d484083f3ad4837fc47e84639fd129b861d883010112846765746888676f312e31392e32856c696e75780000005b7663b57d995f67870ca39809195a97d1b6725afd7675ac13de9aa0075bc0b362a06a4474337e12d62709df28b2bd83813d901f88ea6ebecb759db4b6854375b200573301a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0188382c8555fa1aaf257c4055f4ede55192cbf82009df72d6ce96d9533394890a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b4dd66d7c2c7e57f628210187192fb89d4b99dd4a0c2b96414c2c110af9316832f1c491952f4be5425d5f96982850604186a2266e9a04b9d40b71f851c0b9f42cce80676c2bab39b8c09dd18ca39a70620400e8bcbe6a0f4940e144bd9d46fd5cbab8c5e63f1730075aca17e8a68ccf7cf46840b23250db90100c02a3781a3cd1e1122e4a8ae801f91b01000825a504724087a3523061012c1380412e55e9694121162348000c48108d418092990ab345a104709435e24a01b02d02034504ea282852d3270ac83a000f239db115a6a4a388220ed0912e8506f00238b09a14aa709829c5474b242042cb18f2082c944cb4e440025e23114894c0510840b24ea5104638da83c039c410a1c253f2d0554062738a104b368008604aea712c041a410001748894e4132ae70dc4210020a118a0815134d346d2513c20a3352240a46d01143dc0642bd51431a6d2115352181438558a611524b5108e8a5addba06165d18cc8f11026248f2946c231984c091c0cb56e0335fb2668a028340284016ea1d5840836fb9b83e0e05a84639fd12cb861d983010112846765746889676f312e31372e3133856c696e757800005b7663b55a4527d7d43f88487798555643364d3376d9b94a31826498304cd8633f72faa96edec4c2471c01dab3e7acefaa8cf2718bb5fc358ff758c986a982853fbd7e9b00a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0211a0aa45ddc02992a14df5914307c2541b275571d1fb9b1e70f14d6328461dba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794be807dddb074639cd9fa61b47676c064fc50d62ca00c72c47f58cdbc93d96c0de42170fcd493a6c8f52dbf2a48007a056d98355202a021f2b3fcea5f7aaa8f20e33ba67e2cf9443cef9c677b1539e2647882e2ab452ca0e9b86284169565b52f7992bd854c166fa4b8502913365b2cea7c8c2690f6834db90100c56412220b1836164a55846ecc701100600c0718545235003035a425b113917a6114d64881801000c8159030e40052214200914888171a20464cd94b32af3200a483a2c030d1e6614d3029c9a1a028e430d92448135028c214b56b42e8a8da44220806a54baa2e953c0b19009142ac802f1b08ea250135468827013800eb48401182c22c015268a2e2bc96d0dc40be41042f6d86142302ac3309be5900a03028be8220401c91b0100d00cb7142e00e50166c1805040a900522ec00bfe242000000862502081c4fc31000520901425641ad402124037f505386421d4e100ae8a8297875c90d77d26821021042cba7218409800ec889d8b01802020a0201ed58aa0284016ea1d684083f329583908df484639fd12fb861d983010112846765746889676f312e31372e3133856c696e757800005b7663b55a3b2bd95822c241ee047708ae9ca2c605eb36a16fcd1a971443b1255ea98ee216086a9e92bb52848f99ce0afcd5485bde47075e64778c2f66a949f0d22504df01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0656268cd8e612dbe4fd3eb4d546cbc3b71e57ac396c5b9b975488e7a1236f86da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794cc8e6d00c17eb431350c6c50d8b8f05176b90b11a01f8fde897379b878743526153c0af60b3c1915b89c339f7bd7a35523bd33ab1ba079140c5af546f5f7e9f8765fb33b3d44d89a440e7682d87223ecc3e61c0676bba0a0a00bddb60fa91d4d17b97f9b68f497bbb44a7c61646e19f5e49cfb48af76bdb901008624073c1e0012304680502c8802212f710404041025a0042111000c010100400000456a402130502314885180805692a8ac0000882800145210610801a500063094231810002981452a082a89084d382030300108c628a0a43d040c8c000a2d801032341a960c0241000100b8885aa10822604485341c000664d61300314c04110042000c01800800e015130102181222259f051480062c2912e0410d068922264290faf88ba818200434a262ee2348e5ca4025030411591a117103201a212821120442101a005e0c400809581012102101410c406427319606b092a42ae821c01000c00109014207411210050400025ac80c405848c978020b801680e14a8f0284016ea1d7840836f3648359aa1884639fd132b861d983010112846765746889676f312e31372e3133856c696e757800005b7663b53ee87f6349403fe40204bc647cd517aab53651cdc29e5f69e811c4f176f3b28e6d801e90dddc695a8e8e531c5d2406c86e930592ea1361c32dd2d167c85afdf600a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0332078fc0d3bd8e4d9bbaa6251a03677ececf98b37d0ac0a182eed90d251164ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ce2fd7544e0b2cc94692d4a704debef7bcb61328a034d2ef3160a06d3ed862bda817d1b40e40e9210c650e3b4890e5b9f825ac5db0a00173f511d8856e3297fb80a051f2a991138ff57f482ad8cc467d2412ca0e4656a03b6d792432099652a390fcf9b3c6d1db1046044ab49aa2689e3c90b28a13320db9010060751f40c74c165a42053025a0931518a0235bd2bcc165c02c518112980c3fd024a24560f48c5240a3260f2a345d8f20aa830ab9a87b18335f8c23d69d367948b03220a30120876b6135156e99a360b8709af22914545ebac43666aaca0b2c4253183c314f2a7e21036f39e584208c8e4f6560f1a1e8663c0e240e19143d6f7f1459901046cb717007a09e5524e6dc21942f45a59e3b430c11984b4147825a2327a743f51deff4327e90542797cf4200484470e9e19b0f4579182ba5600629283124bd060199316607c9b5ef86427b3260669b4685293d18dec010cf3daae9211039f70b9f9d80d95b71741201c8818650889e044b1863e1866a0f4283a94a160284016ea1d884083f2a5683a4a32884639fd135b861d983010112846765746889676f312e31372e3133856c696e757800005b7663b5706db41fb5cecd664ec85f66a718966a8cb423622390c8a0e87a83ae361e911c6bdc2743193c954726e45dc445b1c5a3fc51614d8a6c0decff75e8269c2544c200a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea02f601b318ec4cc1de09aca45a409c235c60803a2983c7b740f1a825d36a5bb0ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794d1d6bf74282782b0b3eb1413c901d6ecf02e8e28a0feb91adbc056648743b59e5f46d9f4a6c2cdb652f23999da4fd1388d875442aba0148fabbfff39d0bb08f5efa897790057890688c27b07381ea21993773be3e574a00f13f82271037170b0939fb870890b163f233b80ca4e4d7bcee0dd059c1e77c7b90100482003900204439ac0041342ca7002408808226c1c168d002015008400a09164030006e18ce0141047b8a2f08066228085944080827aca00560ef10010a44a880210ec008000c5938130d10cad9015b4e01237e1025e20b2807400088e194f01004519281fa644620205815200000cab1ab00011a40c34140825a23964034610118b20000e01202804a4108080c1010064240401c5400a2eec05014911cd6a3222030e504608f0137c06241322db2100430022010082b50904403131614a610927120006100340435083020dc8a23a0026652b0a22c0cc10a259a042081aec211c1006110861d0504d0430008101040842182018680a844a069392020020489c0284016ea1d9840836eb2d83892bd484639fd138b861d883010112846765746888676f312e31392e32856c696e75780000005b7663b5c2df77037264db29bb3198dd7c518f11e4adac7dbea2bfd8784b874cbe0b9839039eacec0e2ba7641dad877de2043861d9562ebec29373b988c2b2ae74505e3f01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea0bb9615180b11613d317044cc7e5f1b1473a2cc0541d5b36a42ab694a45a21adca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794e9ae3261a475a27bb1028f140bc2a7c843318afda06f7c5ddc54c1be027726e976042e00a04d551e9e3a8bb7011a11c3732fc16ff2a048c8c4de185849c03a5ff3ed8c630a42ff5ec1076275ecbde98213410e19a6d6a0255cba0529c2c9fa0d387086173489959b38524073822d50110fc4f04740e1d7b9010022214f016d0c1230522d001a81d280407018005cdc31810215d48820814101c00510544206228044d3b5845080860d7208e28ad00c3aa28a7b0c15424664e2029282a4020a292801412908c9c1bd03b2757d5048135420f3a48508008c20904080085b346b02a723a009190049029d851a2b007085880e8050665030000544845261b04e76590c6924e61e88a2d70008062d95c55e042c2c281992c1809a383aab8800001d8ad07a6a003239d3ca4142441e6920220207814c207080265a906821404422000a844a410042290a765602394c614bc589e819238104e6883fe8a3c0bc311503259469011c30000560002742852818436b4558828a488612f5589c0284016ea1da84083f2217837e6d4384639fd13bb861d983010112846765746889676f312e31372e3133856c696e757800005b7663b5a3fbb1383e889a9547b8b3d191de304707a35776593a974d3c8247aacfa2cc683482ce53a13996a036d5991b993c0cd5c3f0b047bd59c0c1e28c28f19ff83db401a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f9025ea013dbf66808dcb4d75f4c441c314327ef20d98bd57cd3b1a6323cca0969aec72fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ef0274e31810c9df02f98fafde0f841f4e66a1cda030d3b7e629a22f8f0644337fc7f6b597d0a09feb7b035c84ca8374997ed8bc0ba02bb37cab13137ebb70b85d69c6f6d4ead9f103878d8c130f3f6df0f172300b81a0eea403aabc4e4606157333a91a0767ea51a10b4fd82c8a133f3ce744a0c2c5c9b901006f24021445009730500e28d48006110050143206192c844020140ac82810813715020660e42b1018031014510002c250a00a1000420040305028030e00ec3a888a00035e04110a4597708088808840272818cc0f15540ea291a41602cc000400da091a2daaca2410200822cee001a8258e067042848226020425417040174500141011000ca1511806a096400400c8b306740405c622066839082046001a0a21ab0220012709005862403540628b0164a20600804ca0014360d9200c2402d829a1804822046040424402100310c2320826504020410c111167a3046b804ae02118503c4c49015840010410828112030048084c28c9cb4c481466836c002000040284016ea1db84084761388387781084639fd13eb861d883010112846765746888676f312e31382e32856c696e75780000005b7663b57c4fa9f941052ca2e7d1e1f07fdff9478bd9782e5849494beaa701a4a580e7c528f13d2bdac116022a2fe6adb66f077e2f560cbe511dc8342c4c7a984370552200a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"; +// +//TEST_F(xbsc_contract_fixture_t, test_init_error) { +// auto const extra_hex = "0xd983010112846765746889676f312e31372e3133856c696e757800005b7663b50bac492386862ad3df4b666bc096b0505bb694da2465176c461afb316ebc773c61faee85a6515daa295e26495cef6f69dfa69911d9d8e4f3bbadb89b2d4c407bbe49438ed859fe965b140dcf1aab71a93f349bbafec1551819b8be1efea2fc46ca749aa161dd481a114a2e761c554b641742c973867899d3685b1ded8013785d6623cc18d214320b6bb6475972b61c6014342d914470ec7ac2975be345796c2b73564052d8e469ed0721c4e53379dc3c912289307ae2f5b9e386cd1b50a4550696d957cb4900f03a8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a6f79b60359f141df90a0c745125b131caaffd12ac0e15a038eedfc68ba3c35c73fed5be4a07afb5b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b4dd66d7c2c7e57f628210187192fb89d4b99dd4be807dddb074639cd9fa61b47676c064fc50d62ccc8e6d00c17eb431350c6c50d8b8f05176b90b11ce2fd7544e0b2cc94692d4a704debef7bcb61328d1d6bf74282782b0b3eb1413c901d6ecf02e8e28e9ae3261a475a27bb1028f140bc2a7c843318afdef0274e31810c9df02f98fafde0f841f4e66a1cde65173e67ad6055ed95d06a951e68b409809834183e59c65399bd74e50598d2c2ec062ff5cbf618ed049280624b90132c557042c7d5df8ba58a29564ef1980b901"; +// auto const extra_bytes = from_hex(std::string{extra_hex}); +// auto const init_error = from_hex(init_error_hex); +// +// auto const item = RLP::decode_once(init_error); +// xeth_header_t header; +// std::error_code ec; +// header.decode_rlp(item.decoded[0], ec); +// assert(!ec); +// header.extra = extra_bytes; +// auto b = header.encode_rlp(); +// b += init_error; +// EXPECT_TRUE(contract.init(b, contract_state)); +//} +// +//} +//} diff --git a/tests/xevm_contract_runtime/test_evm_heco_client_contract.cpp b/tests/xevm_contract_runtime/test_evm_heco_client_contract.cpp index aa69f81bb..beb6b740a 100644 --- a/tests/xevm_contract_runtime/test_evm_heco_client_contract.cpp +++ b/tests/xevm_contract_runtime/test_evm_heco_client_contract.cpp @@ -1,123 +1,123 @@ -#include "tests/xevm_contract_runtime/test_evm_eth_bridge_contract_fixture.h" -#include "xbasic/xhex.h" -#include "xcommon/rlp.h" -#include "xevm_common/xabi_decoder.h" -#include "xevm_common/xcrosschain/xvalidators_snapshot.h" - -#define private public -#include "xevm_common/xcrosschain/xeth_header.h" -#include "xevm_contract_runtime/xevm_sys_contract_face.h" - -namespace top { -namespace tests { - -using namespace contract_runtime::evm::sys_contract; -using namespace evm_common; - -class xheco_contract_fixture_t : public testing::Test { -public: - xheco_contract_fixture_t() { - } - - void init() { - auto bstate = make_object_ptr( - evm_eth_bridge_contract_address.to_string(), (uint64_t)0, (uint64_t)0, std::string(), std::string(), (uint64_t)0, (uint32_t)0, (uint16_t)0); - auto canvas = make_object_ptr(); - bstate->new_string_map_var(data::system_contract::XPROPERTY_HEADERS, canvas.get()); - bstate->new_string_map_var(data::system_contract::XPROPERTY_HEADERS_SUMMARY, canvas.get()); - bstate->new_string_map_var(data::system_contract::XPROPERTY_ALL_HASHES, canvas.get()); - bstate->new_string_map_var(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, canvas.get()); - bstate->new_string_var(data::system_contract::XPROPERTY_LAST_HASH, canvas.get()); - auto bytes = (evm_common::h256(0)).asBytes(); - bstate->load_string_var(data::system_contract::XPROPERTY_LAST_HASH)->reset({bytes.begin(), bytes.end()}, canvas.get()); - contract_state = std::make_shared(bstate.get(), bstate.get()); - statectx = top::make_unique(contract_state); - statectx_observer = make_observer(statectx.get()); - context.address = common::xtop_eth_address::build_from("ff00000000000000000000000000000000000004"); - context.caller = common::xtop_eth_address::build_from("f8a1e199c49c2ae2682ecc5b4a8838b39bab1a38"); - } - - void SetUp() override { - init(); - } - - void TearDown() override { - } - - contract_runtime::evm::sys_contract::xevm_heco_client_contract_t contract; - data::xunitstate_ptr_t contract_state; - std::unique_ptr statectx; - observer_ptr statectx_observer; - contract_runtime::evm::sys_contract_context context; -}; - -#include "tests/xevm_contract_runtime/test_evm_heco_client_contract_data.cpp" - -// TEST(test, test) { -// auto rlp_bytes = from_hex(heco_sync_17276012_hex); -// // auto decode_items = RLP::decode(rlp_bytes); -// // printf("%lu, %lu\n", decode_items.decoded.size(), decode_items.remainder.size()); - -// auto left_bytes = std::move(rlp_bytes); -// while (left_bytes.size() != 0) { -// RLP::DecodedItem item = RLP::decode(left_bytes); -// auto decoded_size = item.decoded.size(); -// if (decoded_size < 4) { -// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); -// return; -// } -// left_bytes = std::move(item.remainder); -// xeth_header_t header; -// { -// auto item_header = RLP::decode_once(item.decoded[0]); -// auto header_bytes = item_header.decoded[0]; -// if (header.decode_rlp(header_bytes) == false) { -// xwarn("[xtop_evm_eth_bridge_contract::sync] decode header error"); -// return; -// } -// } -// header.print(); - -// auto validator_num = static_cast(evm_common::fromBigEndian(item.decoded[1])); -// if (decoded_size < validator_num + 2 + 1) { -// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); -// return; -// } - -// heco::xheco_snapshot_t snap; -// snap.number = static_cast(header.number - 1); -// snap.hash = header.parent_hash; -// for (uint64_t i = 0; i < validator_num; ++i) { -// snap.validators.insert(item.decoded[i + 2]); -// printf("validator: %s\n", to_hex(item.decoded[i + 2]).c_str()); -// } - -// auto recent_num = static_cast(evm_common::fromBigEndian(item.decoded[1 + validator_num + 1])); -// if (decoded_size < validator_num + 2 + 1 + recent_num) { -// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); -// return; -// } - -// for (uint64_t i = 0; i < recent_num; ++i) { -// uint64_t k = static_cast(evm_common::fromBigEndian(item.decoded[1 + validator_num + 1 + 1 + i * 2])); -// snap.recents[k] = item.decoded[1 + validator_num + 1 + 1 + i * 2 + 1]; -// printf("recents: %lu, %s\n", k, to_hex(item.decoded[1 + validator_num + 1 + 1 + i * 2 + 1]).c_str()); -// } -// snap.print(); -// } -// } - -TEST_F(xheco_contract_fixture_t, test_heco_init) { - auto bytes = top::from_hex(heco_init_17276000_hex); - EXPECT_TRUE(contract.init(bytes, contract_state)); -} - -TEST_F(xheco_contract_fixture_t, test_heco_sync) { - auto init_bytes = top::from_hex(heco_init_17276000_hex); - EXPECT_TRUE(contract.init(init_bytes, contract_state)); - auto sycn_bytes = top::from_hex(heco_sync_17276012_hex); - EXPECT_TRUE(contract.sync(sycn_bytes, contract_state)); -} - -} -} \ No newline at end of file +//#include "tests/xevm_contract_runtime/test_evm_eth_bridge_contract_fixture.h" +//#include "xbasic/xhex.h" +//#include "xcommon/rlp.h" +//#include "xevm_common/xabi_decoder.h" +//#include "xevm_common/xcrosschain/xvalidators_snapshot.h" +// +//#define private public +//#include "xevm_common/xcrosschain/xeth_header.h" +//#include "xevm_contract_runtime/xevm_sys_contract_face.h" +// +//namespace top { +//namespace tests { +// +//using namespace contract_runtime::evm::sys_contract; +//using namespace evm_common; +// +//class xheco_contract_fixture_t : public testing::Test { +//public: +// xheco_contract_fixture_t() { +// } +// +// void init() { +// auto bstate = make_object_ptr( +// evm_eth_bridge_contract_address.to_string(), (uint64_t)0, (uint64_t)0, std::string(), std::string(), (uint64_t)0, (uint32_t)0, (uint16_t)0); +// auto canvas = make_object_ptr(); +// bstate->new_string_map_var(data::system_contract::XPROPERTY_HEADERS, canvas.get()); +// bstate->new_string_map_var(data::system_contract::XPROPERTY_HEADERS_SUMMARY, canvas.get()); +// bstate->new_string_map_var(data::system_contract::XPROPERTY_ALL_HASHES, canvas.get()); +// bstate->new_string_map_var(data::system_contract::XPROPERTY_EFFECTIVE_HASHES, canvas.get()); +// bstate->new_string_var(data::system_contract::XPROPERTY_LAST_HASH, canvas.get()); +// auto bytes = (evm_common::h256(0)).asBytes(); +// bstate->load_string_var(data::system_contract::XPROPERTY_LAST_HASH)->reset({bytes.begin(), bytes.end()}, canvas.get()); +// contract_state = std::make_shared(bstate.get(), bstate.get()); +// statectx = top::make_unique(contract_state); +// statectx_observer = make_observer(statectx.get()); +// context.address = common::xtop_eth_address::build_from("ff00000000000000000000000000000000000004"); +// context.caller = common::xtop_eth_address::build_from("f8a1e199c49c2ae2682ecc5b4a8838b39bab1a38"); +// } +// +// void SetUp() override { +// init(); +// } +// +// void TearDown() override { +// } +// +// contract_runtime::evm::sys_contract::xevm_heco_client_contract_t contract; +// data::xunitstate_ptr_t contract_state; +// std::unique_ptr statectx; +// observer_ptr statectx_observer; +// contract_runtime::evm::sys_contract_context context; +//}; +// +//#include "tests/xevm_contract_runtime/test_evm_heco_client_contract_data.cpp" +// +//// TEST(test, test) { +//// auto rlp_bytes = from_hex(heco_sync_17276012_hex); +//// // auto decode_items = RLP::decode(rlp_bytes); +//// // printf("%lu, %lu\n", decode_items.decoded.size(), decode_items.remainder.size()); +// +//// auto left_bytes = std::move(rlp_bytes); +//// while (left_bytes.size() != 0) { +//// RLP::DecodedItem item = RLP::decode(left_bytes); +//// auto decoded_size = item.decoded.size(); +//// if (decoded_size < 4) { +//// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); +//// return; +//// } +//// left_bytes = std::move(item.remainder); +//// xeth_header_t header; +//// { +//// auto item_header = RLP::decode_once(item.decoded[0]); +//// auto header_bytes = item_header.decoded[0]; +//// if (header.decode_rlp(header_bytes) == false) { +//// xwarn("[xtop_evm_eth_bridge_contract::sync] decode header error"); +//// return; +//// } +//// } +//// header.print(); +// +//// auto validator_num = static_cast(evm_common::fromBigEndian(item.decoded[1])); +//// if (decoded_size < validator_num + 2 + 1) { +//// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); +//// return; +//// } +// +//// heco::xheco_snapshot_t snap; +//// snap.number = static_cast(header.number - 1); +//// snap.hash = header.parent_hash; +//// for (uint64_t i = 0; i < validator_num; ++i) { +//// snap.validators.insert(item.decoded[i + 2]); +//// printf("validator: %s\n", to_hex(item.decoded[i + 2]).c_str()); +//// } +// +//// auto recent_num = static_cast(evm_common::fromBigEndian(item.decoded[1 + validator_num + 1])); +//// if (decoded_size < validator_num + 2 + 1 + recent_num) { +//// xwarn("[xtop_evm_eth_bridge_contract::sync] rlp param error"); +//// return; +//// } +// +//// for (uint64_t i = 0; i < recent_num; ++i) { +//// uint64_t k = static_cast(evm_common::fromBigEndian(item.decoded[1 + validator_num + 1 + 1 + i * 2])); +//// snap.recents[k] = item.decoded[1 + validator_num + 1 + 1 + i * 2 + 1]; +//// printf("recents: %lu, %s\n", k, to_hex(item.decoded[1 + validator_num + 1 + 1 + i * 2 + 1]).c_str()); +//// } +//// snap.print(); +//// } +//// } +// +//TEST_F(xheco_contract_fixture_t, test_heco_init) { +// auto bytes = top::from_hex(heco_init_17276000_hex); +// EXPECT_TRUE(contract.init(bytes, contract_state)); +//} +// +//TEST_F(xheco_contract_fixture_t, test_heco_sync) { +// auto init_bytes = top::from_hex(heco_init_17276000_hex); +// EXPECT_TRUE(contract.init(init_bytes, contract_state)); +// auto sycn_bytes = top::from_hex(heco_sync_17276012_hex); +// EXPECT_TRUE(contract.sync(sycn_bytes, contract_state)); +//} +// +//} +//} \ No newline at end of file