From e64994d3493154e5e257285742a25aa6b4938abb Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 3 Sep 2024 13:17:55 -0500 Subject: [PATCH 01/11] Bump version to v1.0.0 --- CMakeLists.txt | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4be9848c6a..e7f395b01f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ set( CXX_STANDARD_REQUIRED ON) set(VERSION_MAJOR 1) set(VERSION_MINOR 0) set(VERSION_PATCH 0) -set(VERSION_SUFFIX rc3) +#set(VERSION_SUFFIX rc3) if(VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") diff --git a/README.md b/README.md index e9490780f2..3ebe2c7268 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ nodeos --full-version ``` You should see a [semantic version](https://semver.org) string followed by a `git` commit hash with no errors. For example: ``` -v3.1.2-0b64f879e3ebe2e4df09d2e62f1fc164cc1125d1 +v1.0.1-9026a03c09c9b4f93edca696b5eef259f0ab96b3 ``` ## Build and Install from Source @@ -84,7 +84,7 @@ cd spring ``` ### Step 2 - Checkout Release Tag or Branch -Choose which [release](https://github.com/AntelopeIO/spring/releases) or [branch](#branches) you would like to build, then check it out. If you are not sure, use the [latest release](https://github.com/AntelopeIO/spring/releases/latest). For example, if you want to build release 3.1.2 then you would check it out using its tag, `v3.1.2`. In the example below, replace `v0.0.0` with your selected release tag accordingly: +Choose which [release](https://github.com/AntelopeIO/spring/releases) or [branch](#branches) you would like to build, then check it out. If you are not sure, use the [latest release](https://github.com/AntelopeIO/spring/releases/latest). For example, if you want to build release 1.0.1 then you would check it out using its tag, `v1.0.1`. In the example below, replace `v0.0.0` with your selected release tag accordingly: ```bash git fetch --all --tags git checkout v0.0.0 From 3940511a518f371f7bd15ab11bc6647159352e87 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 08:21:17 -0500 Subject: [PATCH 02/11] Harden ordered_diff --- .../include/fc/container/ordered_diff.hpp | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index e2440d6ab9..10f63f19b5 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include #include @@ -9,6 +12,8 @@ namespace fc { * @class ordered_diff * @brief Provides ability to generate and apply diff of containers of type T * + * NOTE: Part of Spring Consensus. Used for finalizer and proposer policies. + * * Example use: * std::vector source = { 'a', 'b', 'f', 'c', 'd' }; * std::vector target = { 'b', 'f', 'c', 'd', 'e', 'h' }; @@ -39,48 +44,56 @@ class ordered_diff { if (s < source.size() && t < target.size()) { if (source[s] == target[t]) { // nothing to do, skip over - assert(s <= std::numeric_limits::max()); - assert(t <= std::numeric_limits::max()); + FC_ASSERT(s <= std::numeric_limits::max()); + FC_ASSERT(t <= std::numeric_limits::max()); ++s; ++t; } else { // not equal if (s == source.size() - 1 && t == target.size() - 1) { // both at end, insert target and remove source - assert(s <= std::numeric_limits::max()); - assert(t <= std::numeric_limits::max()); + FC_ASSERT(s <= std::numeric_limits::max()); + FC_ASSERT(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); + FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); + FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; ++t; } else if (s + 1 < source.size() && t + 1 < target.size() && source[s + 1] == target[t + 1]) { // misalignment, but next value equal, insert and remove - assert(s <= std::numeric_limits::max()); - assert(t <= std::numeric_limits::max()); + FC_ASSERT(s <= std::numeric_limits::max()); + FC_ASSERT(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); + FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); + FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; ++t; } else if (t + 1 < target.size() && source[s] == target[t + 1]) { // source equals next target, insert current target - assert(t <= std::numeric_limits::max()); + FC_ASSERT(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); + FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++t; } else { // source[s + 1] == target[t] // target matches next source, remove current source - assert(s <= std::numeric_limits::max()); + FC_ASSERT(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); + FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; } } } else if (s < source.size()) { // remove extra in source - assert(s <= std::numeric_limits::max()); + FC_ASSERT(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); + FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; } else if (t < target.size()) { // insert extra in target - assert(t <= std::numeric_limits::max()); + FC_ASSERT(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); + FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++t; } } @@ -94,16 +107,24 @@ class ordered_diff { template requires std::same_as, diff_result> static Container apply_diff(Container&& container, X&& diff) { + FC_ASSERT(diff.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); + FC_ASSERT(diff.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); + // Remove from the source based on diff.remove_indexes std::ptrdiff_t offset = 0; for (SizeType index : diff.remove_indexes) { + FC_ASSERT(index + offset <= container.size(), "diff.remove_indexes index ${idx} + offset ${o} not in range ${s}", + ("idx", index)("o", offset)("s", container.size())); container.erase(container.begin() + index + offset); --offset; } // Insert into the source based on diff.insert_indexes for (auto& [index, value] : diff.insert_indexes) { + FC_ASSERT(index <= container.size(), "diff.insert_indexes index ${idx} not in range ${s}", + ("idx", index)("s", container.size())); container.insert(container.begin() + index, std::move(value)); + FC_ASSERT(container.size() <= MAX_NUM_ARRAY_ELEMENTS); } return container; } From e33c9af83a41ed15a4c29157e107f125cfadc0ca Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 11:19:20 -0500 Subject: [PATCH 03/11] Correct FC_ASSERTs and check at beginning of loop --- .../libfc/include/fc/container/ordered_diff.hpp | 14 +++----------- libraries/libfc/test/test_ordered_diff.cpp | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index 10f63f19b5..400310b9d8 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -42,17 +42,15 @@ class ordered_diff { diff_result result; while (s < source.size() || t < target.size()) { if (s < source.size() && t < target.size()) { + FC_ASSERT(s < std::numeric_limits::max()); + FC_ASSERT(t < std::numeric_limits::max()); if (source[s] == target[t]) { // nothing to do, skip over - FC_ASSERT(s <= std::numeric_limits::max()); - FC_ASSERT(t <= std::numeric_limits::max()); ++s; ++t; } else { // not equal if (s == source.size() - 1 && t == target.size() - 1) { // both at end, insert target and remove source - FC_ASSERT(s <= std::numeric_limits::max()); - FC_ASSERT(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); @@ -61,8 +59,6 @@ class ordered_diff { ++t; } else if (s + 1 < source.size() && t + 1 < target.size() && source[s + 1] == target[t + 1]) { // misalignment, but next value equal, insert and remove - FC_ASSERT(s <= std::numeric_limits::max()); - FC_ASSERT(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); @@ -71,13 +67,11 @@ class ordered_diff { ++t; } else if (t + 1 < target.size() && source[s] == target[t + 1]) { // source equals next target, insert current target - FC_ASSERT(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++t; } else { // source[s + 1] == target[t] // target matches next source, remove current source - FC_ASSERT(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; @@ -85,13 +79,11 @@ class ordered_diff { } } else if (s < source.size()) { // remove extra in source - FC_ASSERT(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; } else if (t < target.size()) { // insert extra in target - FC_ASSERT(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++t; @@ -113,7 +105,7 @@ class ordered_diff { // Remove from the source based on diff.remove_indexes std::ptrdiff_t offset = 0; for (SizeType index : diff.remove_indexes) { - FC_ASSERT(index + offset <= container.size(), "diff.remove_indexes index ${idx} + offset ${o} not in range ${s}", + FC_ASSERT(index + offset < container.size(), "diff.remove_indexes index ${idx} + offset ${o} not in range ${s}", ("idx", index)("o", offset)("s", container.size())); container.erase(container.begin() + index + offset); --offset; diff --git a/libraries/libfc/test/test_ordered_diff.cpp b/libraries/libfc/test/test_ordered_diff.cpp index 6477c3f8a3..fe2f5c5eec 100644 --- a/libraries/libfc/test/test_ordered_diff.cpp +++ b/libraries/libfc/test/test_ordered_diff.cpp @@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { BOOST_TEST(source == target); } { // full - vector source(std::numeric_limits::max()+1); + vector source(std::numeric_limits::max()); std::iota(source.begin(), source.end(), 0); vector target(source.size()); std::reverse_copy(source.begin(), source.end(), target.begin()); From b6599b069cc75cd332d1ac05a6403b5ea6f87a69 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 11:47:50 -0500 Subject: [PATCH 04/11] Correct FC_ASSERTs and check at beginning of loop --- .../include/fc/container/ordered_diff.hpp | 22 +++++++++---------- libraries/libfc/test/test_ordered_diff.cpp | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index 400310b9d8..bab8c12891 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -41,51 +41,51 @@ class ordered_diff { diff_result result; while (s < source.size() || t < target.size()) { + FC_ASSERT(s < std::numeric_limits::max()); + FC_ASSERT(t < std::numeric_limits::max()); if (s < source.size() && t < target.size()) { - FC_ASSERT(s < std::numeric_limits::max()); - FC_ASSERT(t < std::numeric_limits::max()); if (source[s] == target[t]) { // nothing to do, skip over ++s; ++t; } else { // not equal if (s == source.size() - 1 && t == target.size() - 1) { + FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); + FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); // both at end, insert target and remove source result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); - FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); - FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; ++t; } else if (s + 1 < source.size() && t + 1 < target.size() && source[s + 1] == target[t + 1]) { + FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); + FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); // misalignment, but next value equal, insert and remove result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); - FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); - FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; ++t; } else if (t + 1 < target.size() && source[s] == target[t + 1]) { // source equals next target, insert current target + FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); result.insert_indexes.emplace_back(t, target[t]); - FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++t; } else { // source[s + 1] == target[t] // target matches next source, remove current source + FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); result.remove_indexes.push_back(s); - FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; } } } else if (s < source.size()) { // remove extra in source + FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); result.remove_indexes.push_back(s); - FC_ASSERT(result.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++s; } else if (t < target.size()) { // insert extra in target + FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); result.insert_indexes.emplace_back(t, target[t]); - FC_ASSERT(result.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); ++t; } } @@ -115,8 +115,8 @@ class ordered_diff { for (auto& [index, value] : diff.insert_indexes) { FC_ASSERT(index <= container.size(), "diff.insert_indexes index ${idx} not in range ${s}", ("idx", index)("s", container.size())); + FC_ASSERT(container.size() < MAX_NUM_ARRAY_ELEMENTS); container.insert(container.begin() + index, std::move(value)); - FC_ASSERT(container.size() <= MAX_NUM_ARRAY_ELEMENTS); } return container; } diff --git a/libraries/libfc/test/test_ordered_diff.cpp b/libraries/libfc/test/test_ordered_diff.cpp index fe2f5c5eec..16676a8ee8 100644 --- a/libraries/libfc/test/test_ordered_diff.cpp +++ b/libraries/libfc/test/test_ordered_diff.cpp @@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { BOOST_TEST(source == target); } { // full - vector source(std::numeric_limits::max()); + vector source(std::numeric_limits::max()-1); std::iota(source.begin(), source.end(), 0); vector target(source.size()); std::reverse_copy(source.begin(), source.end(), target.begin()); From 07d24f54c26ded1901b8856110a769c3cb95eda1 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 13:32:00 -0500 Subject: [PATCH 05/11] Move asserts to top of while loop --- libraries/libfc/include/fc/container/ordered_diff.hpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index bab8c12891..85fcc2cb42 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -43,6 +43,8 @@ class ordered_diff { while (s < source.size() || t < target.size()) { FC_ASSERT(s < std::numeric_limits::max()); FC_ASSERT(t < std::numeric_limits::max()); + FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); + FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); if (s < source.size() && t < target.size()) { if (source[s] == target[t]) { // nothing to do, skip over @@ -50,16 +52,12 @@ class ordered_diff { ++t; } else { // not equal if (s == source.size() - 1 && t == target.size() - 1) { - FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); - FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); // both at end, insert target and remove source result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); ++s; ++t; } else if (s + 1 < source.size() && t + 1 < target.size() && source[s + 1] == target[t + 1]) { - FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); - FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); // misalignment, but next value equal, insert and remove result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); @@ -67,24 +65,20 @@ class ordered_diff { ++t; } else if (t + 1 < target.size() && source[s] == target[t + 1]) { // source equals next target, insert current target - FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); result.insert_indexes.emplace_back(t, target[t]); ++t; } else { // source[s + 1] == target[t] // target matches next source, remove current source - FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); result.remove_indexes.push_back(s); ++s; } } } else if (s < source.size()) { // remove extra in source - FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); result.remove_indexes.push_back(s); ++s; } else if (t < target.size()) { // insert extra in target - FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); result.insert_indexes.emplace_back(t, target[t]); ++t; } From 6b55977531c2beb22abae298a5d565e68d8243dc Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 18:38:57 -0500 Subject: [PATCH 06/11] Revert invalid change to test --- libraries/libfc/test/test_ordered_diff.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/test/test_ordered_diff.cpp b/libraries/libfc/test/test_ordered_diff.cpp index 16676a8ee8..6477c3f8a3 100644 --- a/libraries/libfc/test/test_ordered_diff.cpp +++ b/libraries/libfc/test/test_ordered_diff.cpp @@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { BOOST_TEST(source == target); } { // full - vector source(std::numeric_limits::max()-1); + vector source(std::numeric_limits::max()+1); std::iota(source.begin(), source.end(), 0); vector target(source.size()); std::reverse_copy(source.begin(), source.end(), target.begin()); From 20e57941fe433e900ff07190cad01d80303ebd29 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 18:39:14 -0500 Subject: [PATCH 07/11] Add additional test cases --- libraries/libfc/test/test_ordered_diff.cpp | 73 ++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/libraries/libfc/test/test_ordered_diff.cpp b/libraries/libfc/test/test_ordered_diff.cpp index 6477c3f8a3..eeb9687dd3 100644 --- a/libraries/libfc/test/test_ordered_diff.cpp +++ b/libraries/libfc/test/test_ordered_diff.cpp @@ -3,6 +3,9 @@ #include #include +#include +#include + using namespace fc; BOOST_AUTO_TEST_SUITE(ordered_diff_tests) @@ -39,6 +42,13 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } + { // All elements removed, size 1 + vector source = {'a'}; + vector target; + auto result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + } { // All elements inserted vector source; vector target = {'a', 'b', 'c', 'd', 'e'}; @@ -46,6 +56,13 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } + { // All elements inserted, size 1 + vector source; + vector target = {'a'}; + auto result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + } { // No change vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = source; @@ -53,6 +70,13 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } + { // No change, size 1 + vector source = {'a'}; + vector target = source; + auto result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + } { // Mix of removals and inserts vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'a', 'c', 'e', 'f', 'g', 'h'}; @@ -74,6 +98,20 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } + { // Complete change, size 1 + vector source = {'a'}; + vector target = {'f'}; + auto result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + } + { // Complete change equal sizes + vector source = {'a', 'b', 'c', 'd'}; + vector target = {'f', 'g', 'h', 'i'}; + auto result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + } { // Diff order vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'e', 'd', 'c', 'b', 'a'}; @@ -81,6 +119,20 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } + { // Diff order, size 2 + vector source = {'a', 'b'}; + vector target = {'b', 'a'}; + auto result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + } + { // Diff order, size 2 + vector source = {'b', 'a'}; + vector target = {'a', 'b'}; + auto result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + } { // shift left vector source = {'a', 'b', 'c', 'd', 'e'}; vector target = {'b', 'c', 'd', 'e', 'f'}; @@ -119,6 +171,27 @@ BOOST_AUTO_TEST_CASE(ordered_diff_test) try { source = ordered_diff::apply_diff(std::move(source), result); BOOST_TEST(source == target); } + { // full, random + std::random_device rnd_device; + std::mt19937 mersenne_engine {rnd_device()}; + std::uniform_int_distribution dist {0, std::numeric_limits::max()}; + auto gen = [&](){ return dist(mersenne_engine); }; + vector source(std::numeric_limits::max()+1); + std::generate(source.begin(), source.end(), gen); + vector target(source.size()); + std::reverse_copy(source.begin(), source.end(), target.begin()); + auto result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + target.clear(); + result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + source.clear(); + result = ordered_diff::diff(source, target); + source = ordered_diff::apply_diff(std::move(source), result); + BOOST_TEST(source == target); + } { // non-unique full vector source(std::numeric_limits::max()*2); std::iota(source.begin(), source.begin()+std::numeric_limits::max(), 0); From 291b82adad7ba15233c3c556dba400509e88cdcc Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 18:41:19 -0500 Subject: [PATCH 08/11] Remove unneeded and undesired FC_ASSERT of MAX_NUM_ARRAY_ELEMENTS. Add size_type trait to template. Add FC_ASSERT outside of loop for source and target size range. Add back in approprate debug asserts and add some new ones. Replace invalid comment with correct one. --- .../include/fc/container/ordered_diff.hpp | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index 85fcc2cb42..0ae9384892 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -29,6 +29,8 @@ template && std::random_access_iterator::iterator> class ordered_diff { public: + using size_type = SizeType; + struct diff_result { Container remove_indexes; Container> insert_indexes; @@ -39,48 +41,65 @@ class ordered_diff { size_t s = 0; size_t t = 0; + FC_ASSERT(source.empty() || (source.size() - 1) <= std::numeric_limits::max()); + FC_ASSERT(target.empty() || (target.size() - 1) <= std::numeric_limits::max()); + diff_result result; while (s < source.size() || t < target.size()) { - FC_ASSERT(s < std::numeric_limits::max()); - FC_ASSERT(t < std::numeric_limits::max()); - FC_ASSERT(result.remove_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); - FC_ASSERT(result.insert_indexes.size() < MAX_NUM_ARRAY_ELEMENTS); + assert(s <= source.size()); + assert(t <= target.size()); if (s < source.size() && t < target.size()) { if (source[s] == target[t]) { // nothing to do, skip over ++s; ++t; + assert(s > 0 && t > 0); } else { // not equal if (s == source.size() - 1 && t == target.size() - 1) { // both at end, insert target and remove source + assert(s <= std::numeric_limits::max()); + assert(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); ++s; ++t; + assert(s > 0 && t > 0); } else if (s + 1 < source.size() && t + 1 < target.size() && source[s + 1] == target[t + 1]) { // misalignment, but next value equal, insert and remove + assert(s <= std::numeric_limits::max()); + assert(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); result.insert_indexes.emplace_back(t, target[t]); ++s; ++t; + assert(s > 0 && t > 0); } else if (t + 1 < target.size() && source[s] == target[t + 1]) { // source equals next target, insert current target + assert(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); ++t; - } else { // source[s + 1] == target[t] - // target matches next source, remove current source + assert(t > 0); + } else { + // not misalignment by one and source not equal to next target, so remove from source + // may be inserted later by other conditions if needed + assert(t <= std::numeric_limits::max()); result.remove_indexes.push_back(s); ++s; + assert(s > 0); } } } else if (s < source.size()) { // remove extra in source + assert(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); ++s; + assert(s > 0); } else if (t < target.size()) { // insert extra in target + assert(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); ++t; + assert(t > 0); } } @@ -93,9 +112,6 @@ class ordered_diff { template requires std::same_as, diff_result> static Container apply_diff(Container&& container, X&& diff) { - FC_ASSERT(diff.remove_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); - FC_ASSERT(diff.insert_indexes.size() <= MAX_NUM_ARRAY_ELEMENTS); - // Remove from the source based on diff.remove_indexes std::ptrdiff_t offset = 0; for (SizeType index : diff.remove_indexes) { @@ -109,7 +125,6 @@ class ordered_diff { for (auto& [index, value] : diff.insert_indexes) { FC_ASSERT(index <= container.size(), "diff.insert_indexes index ${idx} not in range ${s}", ("idx", index)("s", container.size())); - FC_ASSERT(container.size() < MAX_NUM_ARRAY_ELEMENTS); container.insert(container.begin() + index, std::move(value)); } return container; From bc1272fc5fd2aad7f1b011a38a3ac11f9cfaa603 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 18:46:41 -0500 Subject: [PATCH 09/11] Update static_assert to use ordered_diff size_type and add comment --- .../chain/include/eosio/chain/finality/finalizer_policy.hpp | 3 ++- .../chain/include/eosio/chain/finality/proposer_policy.hpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp index 66abe98841..86fedf0b42 100644 --- a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp +++ b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp @@ -6,8 +6,9 @@ namespace eosio::chain { - static_assert(std::numeric_limits::max() >= config::max_finalizers - 1); using finalizers_differ = fc::ordered_diff; + // verify finalizers_differ size_type can represent all values of max_finalizers + static_assert(std::numeric_limits::max() >= config::max_finalizers - 1); using finalizers_diff_t = finalizers_differ::diff_result; struct finalizer_policy_diff { diff --git a/libraries/chain/include/eosio/chain/finality/proposer_policy.hpp b/libraries/chain/include/eosio/chain/finality/proposer_policy.hpp index 3b5ebc7b29..4f171e7fd1 100644 --- a/libraries/chain/include/eosio/chain/finality/proposer_policy.hpp +++ b/libraries/chain/include/eosio/chain/finality/proposer_policy.hpp @@ -5,8 +5,9 @@ namespace eosio::chain { -static_assert(std::numeric_limits::max() >= config::max_proposers - 1); using producer_auth_differ = fc::ordered_diff; +// verify producer_auth_differ size_type can represent all values of max_proposers +static_assert(std::numeric_limits::max() >= config::max_proposers - 1); using producer_auth_diff_t = producer_auth_differ::diff_result; struct proposer_policy_diff { From 63a8cfbb07cd8e70366db31db76c21893ca9a598 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 19:08:08 -0500 Subject: [PATCH 10/11] Update comments --- .../chain/include/eosio/chain/finality/finalizer_policy.hpp | 3 ++- .../chain/include/eosio/chain/finality/proposer_policy.hpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp index 86fedf0b42..1fa8dbfe3f 100644 --- a/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp +++ b/libraries/chain/include/eosio/chain/finality/finalizer_policy.hpp @@ -7,7 +7,8 @@ namespace eosio::chain { using finalizers_differ = fc::ordered_diff; - // verify finalizers_differ size_type can represent all values of max_finalizers + // Verify finalizers_differ::size_type can represent all index values in the + // diff between two policies that could each hold up to max_finalizers entries. static_assert(std::numeric_limits::max() >= config::max_finalizers - 1); using finalizers_diff_t = finalizers_differ::diff_result; diff --git a/libraries/chain/include/eosio/chain/finality/proposer_policy.hpp b/libraries/chain/include/eosio/chain/finality/proposer_policy.hpp index 4f171e7fd1..207dec2973 100644 --- a/libraries/chain/include/eosio/chain/finality/proposer_policy.hpp +++ b/libraries/chain/include/eosio/chain/finality/proposer_policy.hpp @@ -6,7 +6,8 @@ namespace eosio::chain { using producer_auth_differ = fc::ordered_diff; -// verify producer_auth_differ size_type can represent all values of max_proposers +// Verify producer_auth_differ::size_type can represent all index values in the +// diff between two policies that could each hold up to max_proposers entries. static_assert(std::numeric_limits::max() >= config::max_proposers - 1); using producer_auth_diff_t = producer_auth_differ::diff_result; From be07a725f00e36310b313edd4a6fd8a5bab84eb0 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 4 Sep 2024 20:07:16 -0500 Subject: [PATCH 11/11] Removed unneeded asserts. Correct assert to assert on s instead of t --- libraries/libfc/include/fc/container/ordered_diff.hpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/libraries/libfc/include/fc/container/ordered_diff.hpp b/libraries/libfc/include/fc/container/ordered_diff.hpp index 0ae9384892..d028ad7a97 100644 --- a/libraries/libfc/include/fc/container/ordered_diff.hpp +++ b/libraries/libfc/include/fc/container/ordered_diff.hpp @@ -53,7 +53,6 @@ class ordered_diff { // nothing to do, skip over ++s; ++t; - assert(s > 0 && t > 0); } else { // not equal if (s == source.size() - 1 && t == target.size() - 1) { // both at end, insert target and remove source @@ -63,7 +62,6 @@ class ordered_diff { result.insert_indexes.emplace_back(t, target[t]); ++s; ++t; - assert(s > 0 && t > 0); } else if (s + 1 < source.size() && t + 1 < target.size() && source[s + 1] == target[t + 1]) { // misalignment, but next value equal, insert and remove assert(s <= std::numeric_limits::max()); @@ -72,20 +70,17 @@ class ordered_diff { result.insert_indexes.emplace_back(t, target[t]); ++s; ++t; - assert(s > 0 && t > 0); } else if (t + 1 < target.size() && source[s] == target[t + 1]) { // source equals next target, insert current target assert(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); ++t; - assert(t > 0); } else { // not misalignment by one and source not equal to next target, so remove from source // may be inserted later by other conditions if needed - assert(t <= std::numeric_limits::max()); + assert(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); ++s; - assert(s > 0); } } } else if (s < source.size()) { @@ -93,13 +88,11 @@ class ordered_diff { assert(s <= std::numeric_limits::max()); result.remove_indexes.push_back(s); ++s; - assert(s > 0); } else if (t < target.size()) { // insert extra in target assert(t <= std::numeric_limits::max()); result.insert_indexes.emplace_back(t, target[t]); ++t; - assert(t > 0); } }